lib: add libxpc to implement functionality needed by xpc interfaces

This commit is contained in:
2026-03-10 19:14:37 +00:00
parent b0fda122e0
commit aef0163017
10 changed files with 516 additions and 0 deletions

28
lib/libxpc/CMakeLists.txt Normal file
View File

@@ -0,0 +1,28 @@
file(GLOB sources
${CMAKE_CURRENT_SOURCE_DIR}/*.c)
file(GLOB headers
${CMAKE_CURRENT_SOURCE_DIR}/*.h
${CMAKE_CURRENT_SOURCE_DIR}/include/xpc/*.h)
set(public_include_dirs
${CMAKE_CURRENT_SOURCE_DIR}/include)
rosetta_add_library(
NAME libxpc SHARED STATIC
PUBLIC_INCLUDE_DIRS ${public_include_dirs}
SOURCES ${sources}
HEADERS ${headers})
sysroot_add_library(
NAME libxpc
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
sysroot_add_library(
NAME libxpc-static
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
target_link_libraries(libxpc libmango libc)
target_link_libraries(libxpc-static libmango libc-core)
#set_target_properties(libxpc-static PROPERTIES POSITION_INDEPENDENT_CODE FALSE)

59
lib/libxpc/buffer.c Normal file
View File

@@ -0,0 +1,59 @@
#include <mango/status.h>
#include <xpc/buffer.h>
#include <xpc/msg.h>
kern_status_t xpc_buffer_read(
const xpc_buffer_t *buf,
void *out,
size_t max,
size_t *nr_read)
{
if ((buf->buf_flags & (XPC_BUFFER_F_IN | XPC_BUFFER_F_REMOTE))
!= (XPC_BUFFER_F_IN | XPC_BUFFER_F_REMOTE)) {
return KERN_BAD_STATE;
}
size_t to_read = max;
if (to_read > buf->buf_len) {
to_read = buf->buf_len;
}
kern_status_t status
= xpc_msg_read(buf->buf_origin, buf->buf_offset, out, to_read);
if (status != KERN_OK) {
return status;
}
/* TODO */
*nr_read = to_read;
return KERN_OK;
}
kern_status_t xpc_buffer_write(
xpc_buffer_t *buf,
const void *in,
size_t len,
size_t *nr_written)
{
if ((buf->buf_flags & (XPC_BUFFER_F_OUT | XPC_BUFFER_F_REMOTE))
!= (XPC_BUFFER_F_OUT | XPC_BUFFER_F_REMOTE)) {
return KERN_BAD_STATE;
}
size_t to_write = len;
if (to_write > buf->buf_max) {
to_write = buf->buf_max;
}
kern_status_t status
= xpc_msg_write(buf->buf_origin, buf->buf_offset, in, to_write);
if (status != KERN_OK) {
return status;
}
/* TODO */
*nr_written = to_write;
return KERN_OK;
}

View File

@@ -0,0 +1,86 @@
#ifndef XPC_BUFFER_H_
#define XPC_BUFFER_H_
#include <stddef.h>
#include <xpc/status.h>
#define XPC_BUFFER_IN(msg, offset, size) \
{ \
.buf_flags = XPC_BUFFER_F_IN | XPC_BUFFER_F_REMOTE, \
.buf_origin = (msg), \
.buf_offset = (offset), \
.buf_len = (size), \
}
#define XPC_BUFFER_OUT(msg, offset, size) \
{ \
.buf_flags = XPC_BUFFER_F_OUT | XPC_BUFFER_F_REMOTE, \
.buf_origin = (msg), \
.buf_offset = (offset), \
.buf_len = (size), \
}
struct xpc_msg;
typedef enum xpc_buffer_flags {
/* the buffer can be read from */
XPC_BUFFER_F_IN = 0x01u,
/* the buffer can be written to */
XPC_BUFFER_F_OUT = 0x02u,
/* the buffer is backed by a buffer located in another address space.
* the buffer can only be accessed via xpc_buffer_read and/or
* xpc_buffer_write */
XPC_BUFFER_F_REMOTE = 0x04u,
/* free the buffer backing this buffer when the buffer is discarded.
* this is only used for out-buffers. the buffer must have been
* allocated using xpc_context_alloc, as it will be freed via a call
* to xpc_context_free */
XPC_BUFFER_F_FREE_ON_DISCARD = 0x08u,
} xpc_buffer_flags_t;
typedef struct xpc_buffer {
xpc_buffer_flags_t buf_flags;
union {
/* fields that are only valid if F_OUT is set */
struct {
/* only valid if F_OUT is set. specifies the maximum
* number of chars that can be written to buf_buf,
* including the null terminator. */
size_t buf_max;
/* only valid if F_OUT is set.
* if F_FREE_ON_DISCARD is set, must be either NULL or
* allocated via xpc_context_alloc */
const char *buf_ptr;
};
/* fields that are only valid if F_IN is set */
struct {
/* only valid if F_IN is set. offset of the buffer data
* within the associated message. used when reading
* buffer data from a message. */
size_t buf_offset;
};
};
/* only valid if F_REMOTE is set.
* used to read/write buffer data from/to the sender's address
* space. */
const struct xpc_msg *buf_origin;
/* valid for both F_IN and F_OUT buffers.
* F_IN: specifies the length of the incoming buffer data.
* F_OUT: specifies how many bytes from buf_ptr to send. */
size_t buf_len;
} xpc_buffer_t;
extern xpc_status_t xpc_buffer_read(
const xpc_buffer_t *s,
void *out,
size_t max,
size_t *nr_read);
extern xpc_status_t xpc_buffer_write(
xpc_buffer_t *s,
const void *in,
size_t len,
size_t *nr_written);
#endif

View File

@@ -0,0 +1,8 @@
#ifndef XPC_CONTEXT_H_
#define XPC_CONTEXT_H_
typedef struct xpc_context {
} xpc_context_t;
#endif

View File

@@ -0,0 +1,13 @@
#ifndef XPC_ENDPOINT_H_
#define XPC_ENDPOINT_H_
#include <mango/types.h>
typedef struct xpc_endpoint {
kern_handle_t e_channel;
tid_t e_task;
koid_t e_port;
msgid_t e_msg;
} xpc_endpoint_t;
#endif

View File

@@ -0,0 +1,53 @@
#ifndef XPC_MSG_H_
#define XPC_MSG_H_
#include <mango/types.h>
#include <stdbool.h>
#include <stdint.h>
#include <xpc/endpoint.h>
#define XPC_MSG_MAGIC 0x5850434D
typedef struct xpc_msg_header {
uint32_t hdr_magic;
uint32_t hdr_interface;
uint16_t hdr_func;
uint16_t hdr_status;
} xpc_msg_header_t;
typedef struct xpc_msg {
xpc_endpoint_t msg_sender;
xpc_msg_header_t msg_header;
size_t msg_handles_count;
kern_msg_handle_t msg_handles[KERN_MSG_MAX_HANDLES];
} xpc_msg_t;
extern void xpc_msg_header_init(
xpc_msg_header_t *msg,
unsigned long interface,
unsigned short func);
extern bool xpc_msg_header_validate(const xpc_msg_header_t *msg);
extern kern_status_t xpc_msg_recv(kern_handle_t channel, xpc_msg_t *out);
extern kern_status_t xpc_msg_read(
const xpc_msg_t *msg,
size_t offset,
void *p,
size_t count);
extern kern_status_t xpc_msg_write(
const xpc_msg_t *msg,
size_t offset,
const void *p,
size_t count);
extern kern_status_t xpc_msg_reply(
const xpc_msg_t *msg,
kern_iovec_t *iov,
size_t iov_count,
kern_msg_handle_t *handles,
size_t handle_count);
extern kern_status_t xpc_msg_reply_error(
const xpc_msg_t *msg,
unsigned short code);
#endif

View File

@@ -0,0 +1,12 @@
#ifndef XPC_STATUS_H_
#define XPC_STATUS_H_
typedef enum xpc_status {
XPC_SUCCESS = 0,
XPC_ERR_BAD_STATE,
XPC_ERR_INVALID_ARGUMENT,
XPC_ERR_NO_MEMORY,
XPC_ERR_MEMORY_FAULT,
} xpc_status_t;
#endif

View File

@@ -0,0 +1,85 @@
#ifndef XPC_STRING_H_
#define XPC_STRING_H_
#include <stddef.h>
#include <xpc/status.h>
#define XPC_STRING_NPOS ((size_t)-1)
#define XPC_STRING_IN(msg, offset, size) \
{ \
.s_flags = XPC_STRING_F_IN | XPC_STRING_F_REMOTE, \
.s_origin = (msg), \
.s_offset = (offset), \
.s_len = (size), \
}
#define XPC_STRING_OUT(msg, offset, size) \
{ \
.s_flags = XPC_STRING_F_OUT | XPC_STRING_F_REMOTE, \
.s_origin = (msg), \
.s_offset = (offset), \
.s_len = (size), \
}
struct xpc_msg;
typedef enum xpc_string_flags {
/* the string can be read from */
XPC_STRING_F_IN = 0x01u,
/* the string can be written to */
XPC_STRING_F_OUT = 0x02u,
/* the string is backed by a buffer located in another address space.
* the string can only be accessed via xpc_string_read and/or
* xpc_string_write */
XPC_STRING_F_REMOTE = 0x04u,
/* free the buffer backing this string when the string is discarded.
* this is only used for out-strings. the buffer must have been
* allocated using xpc_context_alloc, as it will be freed via a call
* to xpc_context_free */
XPC_STRING_F_FREE_ON_DISCARD = 0x08u,
} xpc_string_flags_t;
typedef struct xpc_string {
xpc_string_flags_t s_flags;
union {
struct {
/* only valid if F_OUT is set. specifies the maximum
* number of chars that can be written to s_buf,
* including the null terminator. */
size_t s_max;
/* only valid if F_OUT is set.
* if F_FREE_ON_DISCARD is set, must be either NULL or
* allocated via xpc_context_alloc */
const char *s_buf;
};
struct {
/* only valid if F_IN is set. offset of the string data
* within the associated message. used when reading
* string data from a message. */
size_t s_offset;
};
};
/* only valid if F_REMOTE is set.
* used to read/write string data from/to the sender's address space. */
const struct xpc_msg *s_origin;
/* valid for both F_IN and F_OUT strings.
* F_IN: specifies the length of the incoming string data.
* F_OUT: specifies how many characters from s_buf to send. */
size_t s_len;
} xpc_string_t;
extern xpc_status_t xpc_string_read(
const xpc_string_t *s,
char *out,
size_t max,
size_t *nr_read);
extern xpc_status_t xpc_string_write(
xpc_string_t *s,
const char *in,
size_t len,
size_t *nr_written);
#endif

112
lib/libxpc/msg.c Normal file
View File

@@ -0,0 +1,112 @@
#include <mango/msg.h>
#include <string.h>
#include <xpc/msg.h>
void xpc_msg_header_init(
xpc_msg_header_t *msg,
unsigned long interface,
unsigned short func)
{
memset(msg, 0x0, sizeof *msg);
msg->hdr_magic = XPC_MSG_MAGIC;
msg->hdr_interface = interface;
msg->hdr_func = func;
msg->hdr_status = 0;
}
bool xpc_msg_header_validate(const xpc_msg_header_t *msg)
{
return msg->hdr_magic == XPC_MSG_MAGIC;
}
kern_status_t xpc_msg_recv(kern_handle_t channel, xpc_msg_t *out)
{
kern_iovec_t iov = IOVEC(&out->msg_header, sizeof out->msg_header);
kern_msg_t msg = {
.msg_data = &iov,
.msg_data_count = 1,
.msg_handles = out->msg_handles,
.msg_handles_count = KERN_MSG_MAX_HANDLES,
};
kern_status_t status = msg_recv(channel, &msg);
if (status != KERN_OK) {
return status;
}
if (!xpc_msg_header_validate(&out->msg_header)) {
return KERN_INVALID_ARGUMENT;
}
out->msg_sender.e_channel = channel;
out->msg_sender.e_task = msg.msg_sender;
out->msg_sender.e_port = msg.msg_endpoint;
out->msg_sender.e_msg = msg.msg_id;
return KERN_OK;
}
kern_status_t xpc_msg_read(
const xpc_msg_t *msg,
size_t offset,
void *p,
size_t count)
{
kern_iovec_t iov = IOVEC(p, count);
size_t r = 0;
return msg_read(
msg->msg_sender.e_channel,
msg->msg_sender.e_msg,
offset,
&iov,
1,
&r);
}
kern_status_t xpc_msg_write(
const xpc_msg_t *msg,
size_t offset,
const void *p,
size_t count)
{
kern_iovec_t iov = IOVEC(p, count);
size_t w = 0;
return msg_write(
msg->msg_sender.e_channel,
msg->msg_sender.e_msg,
offset,
&iov,
1,
&w);
}
kern_status_t xpc_msg_reply(
const xpc_msg_t *msg,
kern_iovec_t *iov,
size_t iov_count,
kern_msg_handle_t *handles,
size_t handle_count)
{
kern_msg_t reply = MSG(iov, iov_count, handles, handle_count);
return msg_reply(
msg->msg_sender.e_channel,
msg->msg_sender.e_msg,
&reply);
}
kern_status_t xpc_msg_reply_error(const xpc_msg_t *msg, unsigned short code)
{
xpc_msg_header_t reply_data = {
.hdr_magic = XPC_MSG_MAGIC,
.hdr_interface = msg->msg_header.hdr_interface,
.hdr_func = msg->msg_header.hdr_func,
.hdr_status = code,
};
kern_iovec_t iov = IOVEC(&reply_data, sizeof reply_data);
kern_msg_t reply = MSG(&iov, 1, NULL, 0);
return msg_reply(
msg->msg_sender.e_channel,
msg->msg_sender.e_msg,
&reply);
}

60
lib/libxpc/string.c Normal file
View File

@@ -0,0 +1,60 @@
#include <mango/status.h>
#include <xpc/msg.h>
#include <xpc/string.h>
xpc_status_t xpc_string_read(
const xpc_string_t *s,
char *out,
size_t max,
size_t *nr_read)
{
if ((s->s_flags & (XPC_STRING_F_IN | XPC_STRING_F_REMOTE))
!= (XPC_STRING_F_IN | XPC_STRING_F_REMOTE)) {
return KERN_BAD_STATE;
}
size_t to_read = max - 1;
if (to_read > s->s_len) {
to_read = s->s_len;
}
kern_status_t status
= xpc_msg_read(s->s_origin, s->s_offset, out, to_read);
if (status != KERN_OK) {
return status;
}
out[to_read] = '\0';
/* TODO */
*nr_read = to_read;
return KERN_OK;
}
xpc_status_t xpc_string_write(
xpc_string_t *s,
const char *in,
size_t len,
size_t *nr_written)
{
if ((s->s_flags & (XPC_STRING_F_OUT | XPC_STRING_F_REMOTE))
!= (XPC_STRING_F_IN | XPC_STRING_F_REMOTE)) {
return KERN_BAD_STATE;
}
size_t to_write = len;
if (to_write > s->s_max - 1) {
to_write = s->s_max - 1;
}
kern_status_t status
= xpc_msg_write(s->s_origin, s->s_offset, in, to_write);
if (status != KERN_OK) {
return status;
}
/* TODO */
*nr_written = to_write;
return KERN_OK;
}