diff --git a/include/kernel/arg.h b/include/kernel/arg.h index 6b0cdde..93ad15b 100644 --- a/include/kernel/arg.h +++ b/include/kernel/arg.h @@ -1,8 +1,8 @@ #ifndef KERNEL_ARG_H_ #define KERNEL_ARG_H_ +#include #include -#include #define CMDLINE_MAX 4096 diff --git a/include/kernel/channel.h b/include/kernel/channel.h index 7488bd0..38941f7 100644 --- a/include/kernel/channel.h +++ b/include/kernel/channel.h @@ -25,15 +25,12 @@ 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); 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); extern kern_status_t channel_read_msg( @@ -41,7 +38,7 @@ extern kern_status_t channel_read_msg( msgid_t msg, 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); extern kern_status_t channel_write_msg( @@ -49,7 +46,7 @@ extern kern_status_t channel_write_msg( msgid_t msg, 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); diff --git a/include/kernel/console.h b/include/kernel/console.h index 347f416..c74e517 100644 --- a/include/kernel/console.h +++ b/include/kernel/console.h @@ -14,9 +14,10 @@ representing a serial port may allow both sending AND receiving over the port. */ -#include #include +#include #include +#include #ifdef __cplusplus extern "C" { diff --git a/include/kernel/handle.h b/include/kernel/handle.h index c9e9ddd..91908ea 100644 --- a/include/kernel/handle.h +++ b/include/kernel/handle.h @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -16,6 +17,7 @@ typedef uintptr_t handle_flags_t; struct task; struct object; +struct vm_region; struct handle_list; struct handle { @@ -54,4 +56,14 @@ extern struct handle *handle_table_get_handle( struct handle_table *tab, kern_handle_t handle); +extern 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); + #endif diff --git a/include/kernel/iovec.h b/include/kernel/iovec.h index 5545869..aa1957a 100644 --- a/include/kernel/iovec.h +++ b/include/kernel/iovec.h @@ -8,7 +8,7 @@ struct iovec_iterator { /* if this is set, we are iterating over a list of iovecs stored in * userspace, and must go through this region to retrieve the data. */ struct vm_region *it_region; - const struct iovec *it_vecs; + const kern_iovec_t *it_vecs; size_t it_nr_vecs; size_t it_vec_ptr; @@ -18,12 +18,12 @@ struct iovec_iterator { extern void iovec_iterator_begin( struct iovec_iterator *it, - const struct iovec *vecs, + const kern_iovec_t *vecs, size_t nr_vecs); extern void iovec_iterator_begin_user( struct iovec_iterator *it, struct vm_region *address_space, - const struct iovec *vecs, + const kern_iovec_t *vecs, size_t nr_vecs); extern void iovec_iterator_seek(struct iovec_iterator *it, size_t nr_bytes); diff --git a/include/kernel/locks.h b/include/kernel/locks.h index 83feacb..1db2d11 100644 --- a/include/kernel/locks.h +++ b/include/kernel/locks.h @@ -22,6 +22,38 @@ typedef __aligned(8) ml_hwlock_t spin_lock_t; #define spin_unlock_irqrestore(lck, flags) \ ml_hwlock_unlock_irqrestore(lck, flags); +static inline void spin_lock_pair_irqsave( + spin_lock_t *a, + spin_lock_t *b, + unsigned long *flags) +{ + if (a == b) { + spin_lock_irqsave(a, flags); + } else if (a < b) { + spin_lock_irqsave(a, flags); + spin_lock(b); + } else { + spin_lock_irqsave(b, flags); + spin_lock(a); + } +} + +static inline void spin_unlock_pair_irqrestore( + spin_lock_t *a, + spin_lock_t *b, + unsigned long flags) +{ + if (a == b) { + spin_unlock_irqrestore(a, flags); + } else if (a < b) { + spin_unlock(b); + spin_unlock_irqrestore(a, flags); + } else { + spin_unlock(a); + spin_unlock_irqrestore(b, flags); + } +} + #ifdef __cplusplus } #endif diff --git a/include/kernel/msg.h b/include/kernel/msg.h index 754686e..03c3848 100644 --- a/include/kernel/msg.h +++ b/include/kernel/msg.h @@ -23,10 +23,7 @@ struct msg { kern_status_t msg_result; struct port *msg_sender_port; struct thread *msg_sender_thread; - const struct iovec *msg_req_data; - size_t msg_req_data_count; - struct iovec *msg_resp_data; - size_t msg_resp_data_count; + kern_msg_t msg_req, msg_resp; }; #endif diff --git a/include/kernel/port.h b/include/kernel/port.h index 6977612..6472640 100644 --- a/include/kernel/port.h +++ b/include/kernel/port.h @@ -32,10 +32,8 @@ extern kern_status_t port_connect(struct port *port, struct channel *remote); extern kern_status_t port_disconnect(struct port *port); extern 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 *msg, + kern_msg_t *out_response, unsigned long *lock_flags); DEFINE_OBJECT_LOCK_FUNCTION(port, p_base) diff --git a/include/kernel/sched.h b/include/kernel/sched.h index 0a44e3c..40d5c9a 100644 --- a/include/kernel/sched.h +++ b/include/kernel/sched.h @@ -85,6 +85,7 @@ struct task { pmap_t t_pmap; struct vm_region *t_address_space; + spin_lock_t t_handles_lock; struct handle_table *t_handles; struct btree b_channels; diff --git a/include/kernel/syscall.h b/include/kernel/syscall.h index 7c7191d..b1b4373 100644 --- a/include/kernel/syscall.h +++ b/include/kernel/syscall.h @@ -153,32 +153,26 @@ extern kern_status_t sys_port_disconnect(kern_handle_t port); extern kern_status_t sys_msg_send( kern_handle_t port, - const struct iovec *req_data, - size_t req_data_count, - struct iovec *resp_data, - size_t resp_data_count); -extern kern_status_t sys_msg_recv( - kern_handle_t channel, - msgid_t *out_id, - struct iovec *out_data, - size_t out_data_count); + const kern_msg_t *msg, + kern_msg_t *out_reply); +extern kern_status_t sys_msg_recv(kern_handle_t channel, kern_msg_t *out_msg); + extern kern_status_t sys_msg_reply( kern_handle_t channel, msgid_t id, - const struct iovec *reply_data, - size_t reply_data_count); + const kern_msg_t *msg); extern kern_status_t sys_msg_read( kern_handle_t channel_handle, msgid_t id, size_t offset, - const struct iovec *iov, + const kern_iovec_t *iov, size_t iov_count, size_t *nr_read); extern kern_status_t sys_msg_write( kern_handle_t channel, msgid_t id, size_t offset, - const struct iovec *in, + const kern_iovec_t *in, size_t nr_in, size_t *nr_written); diff --git a/include/kernel/vm-region.h b/include/kernel/vm-region.h index 0a92f4b..3585337 100644 --- a/include/kernel/vm-region.h +++ b/include/kernel/vm-region.h @@ -177,11 +177,11 @@ extern kern_status_t vm_region_memmove( extern kern_status_t vm_region_memmove_v( struct vm_region *dest_region, size_t dest_offset, - const struct iovec *dest, + const kern_iovec_t *dest, size_t nr_dest, struct vm_region *src_region, size_t src_offset, - const struct iovec *src, + const kern_iovec_t *src, size_t nr_src, size_t bytes_to_move, size_t *nr_bytes_moved); diff --git a/kernel/arg.c b/kernel/arg.c index d423fbb..1cc82a6 100644 --- a/kernel/arg.c +++ b/kernel/arg.c @@ -1,6 +1,7 @@ #include -#include #include +#include +#include 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; diff --git a/kernel/channel.c b/kernel/channel.c index 0229cc1..5a4b217 100644 --- a/kernel/channel.c +++ b/kernel/channel.c @@ -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, diff --git a/kernel/handle.c b/kernel/handle.c index d25aa7c..24daa8f 100644 --- a/kernel/handle.c +++ b/kernel/handle.c @@ -3,7 +3,9 @@ #include #include #include +#include #include +#include /* 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; +} diff --git a/kernel/iovec.c b/kernel/iovec.c index f4c310f..262878a 100644 --- a/kernel/iovec.c +++ b/kernel/iovec.c @@ -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) { diff --git a/kernel/port.c b/kernel/port.c index 96742a8..df36293 100644 --- a/kernel/port.c +++ b/kernel/port.c @@ -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); diff --git a/kernel/status.c b/kernel/status.c index e7ae332..d57da62 100644 --- a/kernel/status.c +++ b/kernel/status.c @@ -1,8 +1,9 @@ #include +#include -#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) { diff --git a/libmango/include-user/mango/log.h b/libmango/include-user/mango/log.h index 6d91d41..f6ee613 100644 --- a/libmango/include-user/mango/log.h +++ b/libmango/include-user/mango/log.h @@ -2,6 +2,7 @@ #define MANGO_LOG_H_ #include +#include #undef TRACE @@ -9,18 +10,18 @@ extern kern_status_t kern_log(const char *s); #define kern_logf(...) \ do { \ - char s[128]; \ - snprintf(s, sizeof s, __VA_ARGS__); \ - kern_log(s); \ + char __logbuf[128]; \ + snprintf(__logbuf, sizeof __logbuf, __VA_ARGS__); \ + kern_log(__logbuf); \ } while (0) #ifdef TRACE #define kern_trace(...) kern_log(__VA_ARGS__) #define kern_tracef(...) \ do { \ - char s[128]; \ - snprintf(s, sizeof s, __VA_ARGS__); \ - kern_log(s); \ + char __logbuf[128]; \ + snprintf(__logbuf, sizeof __logbuf, __VA_ARGS__); \ + kern_log(__logbuf); \ } while (0) #else #define kern_trace(...) diff --git a/libmango/include-user/mango/msg.h b/libmango/include-user/mango/msg.h index 82e5ff0..51757d3 100644 --- a/libmango/include-user/mango/msg.h +++ b/libmango/include-user/mango/msg.h @@ -14,28 +14,21 @@ extern kern_status_t port_disconnect(kern_handle_t port); extern kern_status_t msg_send( kern_handle_t port, - const struct iovec *req_data, - size_t req_data_count, - struct iovec *resp_data, - size_t resp_data_count); + const kern_msg_t *msg, + kern_msg_t *out_response); -extern kern_status_t msg_recv( - kern_handle_t channel, - msgid_t *out_id, - struct iovec *out_data, - size_t out_data_count); +extern kern_status_t msg_recv(kern_handle_t channel, kern_msg_t *out); extern kern_status_t msg_reply( kern_handle_t channel, msgid_t id, - const struct iovec *reply_data, - size_t reply_data_count); + const kern_msg_t *response); extern kern_status_t msg_read( kern_handle_t channel, msgid_t id, size_t offset, - struct iovec *out, + kern_iovec_t *out, size_t out_count, size_t *nr_read); @@ -43,7 +36,7 @@ extern kern_status_t msg_write( kern_handle_t channel, msgid_t id, size_t offset, - const struct iovec *in, + const kern_iovec_t *in, size_t nr_in, size_t *nr_written); diff --git a/libmango/include/mango/status.h b/libmango/include/mango/status.h index 94f91bb..d70ea97 100644 --- a/libmango/include/mango/status.h +++ b/libmango/include/mango/status.h @@ -1,8 +1,6 @@ #ifndef MANGO_STATUS_H_ #define MANGO_STATUS_H_ -typedef unsigned int kern_status_t; - #define KERN_OK (0) #define KERN_UNIMPLEMENTED (1) #define KERN_NAME_EXISTS (2) diff --git a/libmango/include/mango/types.h b/libmango/include/mango/types.h index 2d45f38..e713bd0 100644 --- a/libmango/include/mango/types.h +++ b/libmango/include/mango/types.h @@ -4,29 +4,24 @@ #include #include -#define VM_PROT_READ 0x01u -#define VM_PROT_WRITE 0x02u -#define VM_PROT_EXEC 0x04u -#define VM_PROT_USER 0x08u -#define VM_PROT_SVR 0x10u -#define VM_PROT_NOCACHE 0x10u -#define VM_PROT_MAP_SPECIFIC 0x40u +#define VM_PROT_READ 0x01u +#define VM_PROT_WRITE 0x02u +#define VM_PROT_EXEC 0x04u +#define VM_PROT_USER 0x08u +#define VM_PROT_SVR 0x10u +#define VM_PROT_NOCACHE 0x10u +#define VM_PROT_MAP_SPECIFIC 0x40u -/* if this flag is set, other tasks can connect to this channel using - * the port_connect_* syscalls. - * if this flag is NOT set, only threads in the task that owns the channel - * can create ports connecting to it. */ -#define CHANNEL_F_ALLOW_DIRECT_CONNECTIONS 0x01u +#define VM_REGION_ANY_OFFSET ((off_t) - 1) +#define KERN_HANDLE_INVALID ((kern_handle_t)0xFFFFFFFF) -/* msg_reply: once the reply has been sent, disconnect the port that sent the - * original message */ -#define MSG_F_DISCONNECT_AFTER_REPLY 0x01u +#define KERN_CFG_INVALID 0x00u +#define KERN_CFG_PAGE_SIZE 0x01u -#define VM_REGION_ANY_OFFSET ((off_t) - 1) -#define KERN_HANDLE_INVALID ((kern_handle_t)0xFFFFFFFF) - -#define KERN_CFG_INVALID 0x00u -#define KERN_CFG_PAGE_SIZE 0x01u +#define KERN_MSG_MAX_HANDLES 64 +#define KERN_MSG_HANDLE_IGNORE 0 +#define KERN_MSG_HANDLE_MOVE 1 +#define KERN_MSG_HANDLE_COPY 2 #define IOVEC(p, len) \ { \ @@ -47,15 +42,30 @@ typedef uint64_t msgid_t; typedef uint64_t off_t; typedef uint64_t koid_t; typedef unsigned int tid_t; +typedef unsigned int kern_status_t; typedef uint32_t kern_handle_t; typedef uint32_t kern_config_key_t; typedef uint32_t vm_prot_t; typedef unsigned int umode_t; -struct iovec { +typedef struct { virt_addr_t io_base; size_t io_len; -}; +} kern_iovec_t; + +typedef struct { + unsigned int hnd_mode; + kern_handle_t hnd_value; + kern_status_t hnd_result; +} kern_msg_handle_t; + +typedef struct { + msgid_t msg_id; + kern_iovec_t *msg_data; + size_t msg_data_count; + kern_msg_handle_t *msg_handles; + size_t msg_handles_count; +} kern_msg_t; #endif diff --git a/syscall/msg.c b/syscall/msg.c index 6536f94..65c12e7 100644 --- a/syscall/msg.c +++ b/syscall/msg.c @@ -161,17 +161,17 @@ kern_status_t sys_port_disconnect(kern_handle_t port_handle) static bool validate_iovec( struct task *task, - const struct iovec *iov, + const kern_iovec_t *iov, size_t count, bool rw) { - if (!validate_access_r(task, iov, count * sizeof(struct iovec))) { + if (!validate_access_r(task, iov, count * sizeof(*iov))) { return false; } for (size_t i = 0; i < count; i++) { bool ok = false; - const struct iovec *vec = &iov[i]; + const kern_iovec_t *vec = &iov[i]; if (rw) { ok = validate_access_w(task, vec->io_base, vec->io_len); } else { @@ -186,23 +186,55 @@ static bool validate_iovec( return true; } -kern_status_t sys_msg_send( - kern_handle_t port_handle, - const struct iovec *req_data, - size_t req_data_count, - struct iovec *resp_data, - size_t resp_data_count) +static bool validate_msg(struct task *task, const kern_msg_t *msg, bool rw) { - struct task *self = current_task(); - - if (!validate_iovec(self, req_data, req_data_count, false)) { + if (!msg) { return false; } - if (!validate_iovec(self, resp_data, resp_data_count, true)) { + vm_prot_t flags; + if (rw) { + flags = VM_PROT_WRITE | VM_PROT_USER; + } else { + flags = VM_PROT_READ | VM_PROT_USER; + } + + if (!validate_access(task, msg, sizeof *msg, flags)) { return false; } + if (!validate_iovec(task, msg->msg_data, msg->msg_data_count, rw)) { + return false; + } + + size_t handle_buffer_len + = msg->msg_handles_count * sizeof(*msg->msg_handles); + if (!validate_access( + task, + msg->msg_handles, + handle_buffer_len, + flags)) { + return false; + } + + return true; +} + +kern_status_t sys_msg_send( + kern_handle_t port_handle, + const kern_msg_t *msg, + kern_msg_t *out_reply) +{ + struct task *self = current_task(); + + if (!validate_msg(self, msg, false)) { + return KERN_MEMORY_FAULT; + } + + if (!validate_msg(self, out_reply, true)) { + return KERN_MEMORY_FAULT; + } + unsigned long flags; task_lock_irqsave(self, &flags); @@ -230,32 +262,18 @@ kern_status_t sys_msg_send( } port_lock_irqsave(port, &flags); - status = port_send_msg( - port, - req_data, - req_data_count, - resp_data, - resp_data_count, - &flags); + status = port_send_msg(port, msg, out_reply, &flags); port_unlock_irqrestore(port, flags); object_unref(port_obj); return status; } -kern_status_t sys_msg_recv( - kern_handle_t channel_handle, - msgid_t *out_id, - struct iovec *out_data, - size_t out_data_count) +kern_status_t sys_msg_recv(kern_handle_t channel_handle, kern_msg_t *out_msg) { struct task *self = current_task(); - if (!validate_access_w(self, out_id, sizeof *out_id)) { - return KERN_MEMORY_FAULT; - } - - if (!validate_iovec(self, out_data, out_data_count, true)) { + if (!validate_msg(self, out_msg, true)) { return KERN_MEMORY_FAULT; } @@ -286,12 +304,7 @@ kern_status_t sys_msg_recv( } channel_lock_irqsave(channel, &flags); - status = channel_recv_msg( - channel, - out_id, - out_data, - out_data_count, - &flags); + status = channel_recv_msg(channel, out_msg, &flags); channel_unlock_irqrestore(channel, flags); object_unref(channel_obj); @@ -301,12 +314,11 @@ kern_status_t sys_msg_recv( kern_status_t sys_msg_reply( kern_handle_t channel_handle, msgid_t id, - const struct iovec *reply_data, - size_t reply_data_count) + const kern_msg_t *reply) { struct task *self = current_task(); - if (!validate_iovec(self, reply_data, reply_data_count, false)) { + if (!validate_msg(self, reply, true)) { return KERN_MEMORY_FAULT; } @@ -337,12 +349,7 @@ kern_status_t sys_msg_reply( } channel_lock_irqsave(channel, &flags); - status = channel_reply_msg( - channel, - id, - reply_data, - reply_data_count, - &flags); + status = channel_reply_msg(channel, id, reply, &flags); channel_unlock_irqrestore(channel, flags); object_unref(channel_obj); @@ -353,7 +360,7 @@ kern_status_t sys_msg_read( kern_handle_t channel_handle, msgid_t id, size_t offset, - const struct iovec *iov, + const kern_iovec_t *iov, size_t iov_count, size_t *nr_read) { @@ -412,7 +419,7 @@ kern_status_t sys_msg_write( kern_handle_t channel_handle, msgid_t id, size_t offset, - const struct iovec *iov, + const kern_iovec_t *iov, size_t iov_count, size_t *nr_written) { diff --git a/vm/vm-region.c b/vm/vm-region.c index 81dbe67..018fc27 100644 --- a/vm/vm-region.c +++ b/vm/vm-region.c @@ -1821,11 +1821,11 @@ kern_status_t vm_region_memmove( extern kern_status_t vm_region_memmove_v( struct vm_region *dest_region, size_t dest_offset, - const struct iovec *dest_vecs, + const kern_iovec_t *dest_vecs, size_t nr_dest_vecs, struct vm_region *src_region, size_t src_offset, - const struct iovec *src_vecs, + const kern_iovec_t *src_vecs, size_t nr_src_vecs, size_t bytes_to_move, size_t *nr_bytes_moved)