kernel: re-implement sending handles via port messages

This commit is contained in:
2026-03-01 19:10:01 +00:00
parent b1bdb89ca4
commit 36c5ac7837
23 changed files with 399 additions and 168 deletions

View File

@@ -1,6 +1,7 @@
#include <kernel/arg.h>
#include <kernel/libc/string.h>
#include <kernel/libc/ctype.h>
#include <kernel/libc/string.h>
#include <mango/status.h>
static char g_cmdline[CMDLINE_MAX + 1] = {0};
@@ -81,7 +82,6 @@ static char *advance_to_next_arg(char *s, char *max)
return s;
}
const char *arg_value(const char *arg_name)
{
char *s = g_cmdline;

View File

@@ -124,9 +124,7 @@ extern kern_status_t channel_enqueue_msg(
extern kern_status_t channel_recv_msg(
struct channel *channel,
msgid_t *out_id,
struct iovec *out_data,
size_t out_data_count,
kern_msg_t *out_msg,
unsigned long *irq_flags)
{
struct wait_item waiter;
@@ -155,20 +153,47 @@ extern kern_status_t channel_recv_msg(
struct vm_region *src = sender->t_address_space,
*dst = receiver->t_address_space;
unsigned long f;
vm_region_lock_pair_irqsave(src, dst, &f);
kern_status_t status = vm_region_memmove_v(
dst,
0,
out_data,
out_data_count,
out_msg->msg_data,
out_msg->msg_data_count,
src,
0,
msg->msg_req_data,
msg->msg_req_data_count,
msg->msg_req.msg_data,
msg->msg_req.msg_data_count,
VM_REGION_COPY_ALL,
NULL);
if (status != KERN_OK) {
kmsg_reply_error(msg, status, &msg_lock_flags);
return status;
}
struct handle_table *src_table = sender->t_handles,
*dst_table = receiver->t_handles;
spin_lock_pair_irqsave(
&sender->t_handles_lock,
&receiver->t_handles_lock,
&f);
status = handle_table_transfer(
dst,
dst_table,
out_msg->msg_handles,
out_msg->msg_handles_count,
src,
src_table,
msg->msg_req.msg_handles,
msg->msg_req.msg_handles_count);
spin_unlock_pair_irqrestore(
&sender->t_handles_lock,
&receiver->t_handles_lock,
f);
vm_region_unlock_pair_irqrestore(src, dst, f);
if (status != KERN_OK) {
@@ -176,7 +201,7 @@ extern kern_status_t channel_recv_msg(
return status;
}
*out_id = msg->msg_id;
out_msg->msg_id = msg->msg_id;
spin_unlock_irqrestore(&msg->msg_lock, msg_lock_flags);
@@ -186,8 +211,7 @@ extern kern_status_t channel_recv_msg(
extern kern_status_t channel_reply_msg(
struct channel *channel,
msgid_t id,
const struct iovec *resp_data,
size_t resp_data_count,
const kern_msg_t *reply,
unsigned long *irq_flags)
{
unsigned long msg_lock_flags;
@@ -216,14 +240,40 @@ extern kern_status_t channel_reply_msg(
kern_status_t status = vm_region_memmove_v(
dst,
0,
msg->msg_resp_data,
msg->msg_resp_data_count,
msg->msg_resp.msg_data,
msg->msg_resp.msg_data_count,
src,
0,
resp_data,
resp_data_count,
reply->msg_data,
reply->msg_data_count,
VM_REGION_COPY_ALL,
NULL);
if (status != KERN_OK) {
kmsg_reply_error(msg, status, &msg_lock_flags);
return status;
}
struct handle_table *src_table = sender->t_handles,
*dst_table = receiver->t_handles;
spin_lock_pair_irqsave(
&sender->t_handles_lock,
&receiver->t_handles_lock,
&f);
status = handle_table_transfer(
dst,
dst_table,
msg->msg_resp.msg_handles,
msg->msg_resp.msg_handles_count,
src,
src_table,
reply->msg_handles,
reply->msg_handles_count);
spin_unlock_pair_irqrestore(
&sender->t_handles_lock,
&receiver->t_handles_lock,
f);
vm_region_unlock_pair_irqrestore(src, dst, f);
if (status != KERN_OK) {
@@ -241,7 +291,7 @@ extern kern_status_t channel_read_msg(
msgid_t id,
size_t offset,
struct vm_region *dest_region,
const struct iovec *dest_iov,
const kern_iovec_t *dest_iov,
size_t dest_iov_count,
size_t *nr_read)
{
@@ -270,8 +320,8 @@ extern kern_status_t channel_read_msg(
dest_iov_count,
src_region,
offset,
msg->msg_req_data,
msg->msg_req_data_count,
msg->msg_req.msg_data,
msg->msg_req.msg_data_count,
VM_REGION_COPY_ALL,
nr_read);
vm_region_unlock_pair_irqrestore(src_region, dest_region, f);
@@ -286,7 +336,7 @@ extern kern_status_t channel_write_msg(
msgid_t id,
size_t offset,
struct vm_region *src_region,
const struct iovec *src_iov,
const kern_iovec_t *src_iov,
size_t src_iov_count,
size_t *nr_written)
{
@@ -311,8 +361,8 @@ extern kern_status_t channel_write_msg(
kern_status_t status = vm_region_memmove_v(
dest_region,
0,
msg->msg_resp_data,
msg->msg_resp_data_count,
msg->msg_resp.msg_data,
msg->msg_resp.msg_data_count,
src_region,
offset,
src_iov,

View File

@@ -3,7 +3,9 @@
#include <kernel/object.h>
#include <kernel/sched.h>
#include <kernel/util.h>
#include <kernel/vm-region.h>
#include <kernel/vm.h>
#include <mango/types.h>
/* depth=3 gives a maximum of ~66.6 million handles */
#define MAX_TABLE_DEPTH 3
@@ -191,3 +193,144 @@ struct handle *handle_table_get_handle(
return &tab->t_handles.t_handle_list[handle_index];
}
kern_status_t handle_table_transfer(
struct vm_region *dst_region,
struct handle_table *dst,
kern_msg_handle_t *dst_handles,
size_t dst_handles_max,
struct vm_region *src_region,
struct handle_table *src,
kern_msg_handle_t *src_handles,
size_t src_handles_count)
{
kern_status_t status = KERN_OK;
size_t to_transfer = MIN(dst_handles_max, src_handles_count);
size_t i = 0;
for (size_t i = 0; i < to_transfer; i++) {
kern_msg_handle_t src_handle = {0}, dst_handle = {0};
virt_addr_t src_handle_addr
= (virt_addr_t)src_handles + (i * sizeof src_handle);
virt_addr_t dst_handle_addr
= (virt_addr_t)dst_handles + (i * sizeof dst_handle);
status = vm_region_read_kernel(
src_region,
src_handle_addr,
sizeof src_handle,
&src_handle,
NULL);
if (status != KERN_OK) {
src_handle.hnd_result = KERN_OK;
vm_region_write_kernel(
src_region,
src_handle_addr,
sizeof src_handle,
&src_handle,
NULL);
break;
}
struct handle *src_entry
= handle_table_get_handle(src, src_handle.hnd_value);
struct handle *dst_entry = NULL;
kern_handle_t dst_value = KERN_HANDLE_INVALID;
if (!src_entry) {
status = KERN_INVALID_ARGUMENT;
src_handle.hnd_result = KERN_OK;
vm_region_write_kernel(
src_region,
src_handle_addr,
sizeof src_handle,
&src_handle,
NULL);
break;
}
switch (src_handle.hnd_mode) {
case KERN_MSG_HANDLE_IGNORE:
break;
case KERN_MSG_HANDLE_MOVE:
status = handle_table_alloc_handle(
dst,
&dst_entry,
&dst_value);
if (status != KERN_OK) {
break;
}
dst_entry->h_object = src_entry->h_object;
dst_entry->h_flags = src_entry->h_flags;
object_add_handle(dst_entry->h_object);
handle_table_free_handle(src, src_handles[i].hnd_value);
dst_handle.hnd_mode = src_handles[i].hnd_mode;
dst_handle.hnd_value = dst_value;
dst_handle.hnd_result = KERN_OK;
break;
case KERN_MSG_HANDLE_COPY:
status = handle_table_alloc_handle(
dst,
&dst_entry,
&dst_value);
if (status != KERN_OK) {
break;
}
dst_entry->h_object = src_entry->h_object;
dst_entry->h_flags = src_entry->h_flags;
object_add_handle(dst_entry->h_object);
dst_handle.hnd_mode = src_handles[i].hnd_mode;
dst_handle.hnd_value = dst_value;
dst_handle.hnd_result = KERN_OK;
break;
default:
status = KERN_INVALID_ARGUMENT;
break;
}
src_handle.hnd_result = status;
vm_region_write_kernel(
src_region,
src_handle_addr,
sizeof src_handle,
&src_handle,
NULL);
vm_region_write_kernel(
dst_region,
dst_handle_addr,
sizeof dst_handle,
&dst_handle,
NULL);
}
for (; i < src_handles_count; i++) {
kern_msg_handle_t handle = {0};
virt_addr_t handle_addr
= (virt_addr_t)src_handles + (i * sizeof handle);
vm_region_read_kernel(
src_region,
handle_addr,
sizeof handle,
&handle,
NULL);
if (handle.hnd_mode != KERN_MSG_HANDLE_MOVE) {
continue;
}
struct handle *src_entry
= handle_table_get_handle(src, handle.hnd_value);
if (src_entry) {
object_remove_handle(src_entry->h_object);
handle_table_free_handle(src, handle.hnd_value);
}
}
return status;
}

View File

@@ -6,7 +6,7 @@
static bool read_iovec(
struct iovec_iterator *it,
size_t index,
struct iovec *out)
kern_iovec_t *out)
{
if (index >= it->it_nr_vecs) {
return false;
@@ -20,18 +20,18 @@ static bool read_iovec(
size_t nr_read = 0;
kern_status_t status = vm_region_read_kernel(
it->it_region,
(virt_addr_t)it->it_vecs + (index * sizeof(struct iovec)),
sizeof(struct iovec),
(virt_addr_t)it->it_vecs + (index * sizeof(kern_iovec_t)),
sizeof(kern_iovec_t),
out,
&nr_read);
return (status == KERN_OK && nr_read != sizeof(struct iovec));
return (status == KERN_OK && nr_read != sizeof(kern_iovec_t));
}
void iovec_iterator_begin_user(
struct iovec_iterator *it,
struct vm_region *region,
const struct iovec *vecs,
const kern_iovec_t *vecs,
size_t nr_vecs)
{
memset(it, 0x0, sizeof *it);
@@ -39,7 +39,7 @@ void iovec_iterator_begin_user(
it->it_vecs = vecs;
it->it_nr_vecs = nr_vecs;
struct iovec iov;
kern_iovec_t iov;
while (it->it_vec_ptr < nr_vecs) {
read_iovec(it, it->it_vec_ptr, &iov);
@@ -60,7 +60,7 @@ void iovec_iterator_begin_user(
void iovec_iterator_begin(
struct iovec_iterator *it,
const struct iovec *vecs,
const kern_iovec_t *vecs,
size_t nr_vecs)
{
memset(it, 0x0, sizeof *it);
@@ -97,7 +97,7 @@ void iovec_iterator_seek(struct iovec_iterator *it, size_t nr_bytes)
}
nr_bytes -= to_seek;
struct iovec iov;
kern_iovec_t iov;
it->it_vec_ptr++;
while (it->it_vec_ptr < it->it_nr_vecs) {

View File

@@ -78,10 +78,8 @@ kern_status_t port_disconnect(struct port *port)
kern_status_t port_send_msg(
struct port *port,
const struct iovec *req_data,
size_t req_data_count,
struct iovec *resp_data,
size_t resp_data_count,
const kern_msg_t *in_msg,
kern_msg_t *out_reply,
unsigned long *lock_flags)
{
if (port->p_status != PORT_READY) {
@@ -94,10 +92,8 @@ kern_status_t port_send_msg(
msg->msg_status = KMSG_WAIT_RECEIVE;
msg->msg_sender_thread = self;
msg->msg_sender_port = port;
msg->msg_req_data = req_data;
msg->msg_req_data_count = req_data_count;
msg->msg_resp_data = resp_data;
msg->msg_resp_data_count = resp_data_count;
memcpy(&msg->msg_req, in_msg, sizeof msg->msg_req);
memcpy(&msg->msg_resp, out_reply, sizeof msg->msg_req);
unsigned long flags;
channel_lock_irqsave(port->p_remote, &flags);

View File

@@ -1,8 +1,9 @@
#include <mango/status.h>
#include <mango/types.h>
#define ERROR_STRING_CASE(code) \
case code: \
return #code
#define ERROR_STRING_CASE(code) \
case code: \
return #code
const char *kern_status_string(kern_status_t status)
{