diff --git a/include/aos/aos_urpc.h b/include/aos/aos_urpc.h index c6b7f11..aa9779b 100644 --- a/include/aos/aos_urpc.h +++ b/include/aos/aos_urpc.h @@ -2,31 +2,45 @@ #define _LIB_BARRELFISH_AOS_URPC_H #include - -#define RPC_URPC_FRAME_SIZE (ROUND_UP(sizeof(struct aos_urpc_meta), PAGE_SIZE) + PAGE_SIZE) +#include struct aos_urpc_meta { - volatile bool call_in_progress; - - - uintptr_t msg_type; - size_t arg_size; - uintptr_t arg0; - uintptr_t arg1; - struct capability arg_cap; - - errval_t ret_errval; - size_t ret_size; - uintptr_t ret0; - uintptr_t ret1; - uint8_t has_ret_cap; - struct capability ret_cap; + volatile uint8_t call_in_progress; + uintptr_t a0; + uintptr_t a1; + uintptr_t a2; + uintptr_t a3; + struct capability cap; }; +struct aos_urpc_frame { + struct aos_urpc_meta meta_to_app; + struct aos_urpc_meta meta_to_bsp; + uint8_t padding[PAGE_SIZE - 2 * sizeof(struct aos_urpc_meta)]; + uint8_t shared_mem_to_app[PAGE_SIZE]; + uint8_t shared_mem_to_bsp[PAGE_SIZE]; +}; + +STATIC_ASSERT_SIZEOF(struct aos_urpc_frame, MON_URPC_SIZE); + struct aos_urpc { - struct aos_urpc_meta *urpc; + struct aos_urpc_meta *meta; void *shared_mem; }; +struct aos_urpc_server { + struct generic_rpc_server g; + struct aos_urpc_meta *meta; + struct thread_sem sem; +}; + +int urpc_server(void *arg); + +errval_t do_aos_urpc( + struct aos_urpc *rpc, uintptr_t msg_type, + struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1, + struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1 +); + #endif // _LIB_BARRELFISH_AOS_URPC_H diff --git a/include/barrelfish_kpi/init.h b/include/barrelfish_kpi/init.h index 883aace..4465180 100644 --- a/include/barrelfish_kpi/init.h +++ b/include/barrelfish_kpi/init.h @@ -54,7 +54,7 @@ */ // Supports at least #MON_URPC_CHANNEL_LEN // Change #MON_URPC_CHANNEL_LEN if changing this -#define MON_URPC_SIZE (2 * BASE_PAGE_SIZE) +#define MON_URPC_SIZE (3 * BASE_PAGE_SIZE) /** diff --git a/include/spawn/rpc_server.h b/include/spawn/rpc_server.h index 9bda61a..c62d16a 100644 --- a/include/spawn/rpc_server.h +++ b/include/spawn/rpc_server.h @@ -3,9 +3,13 @@ #include -struct aos_rpc_server { - struct lmp_chan *chan; +struct generic_rpc_server { void *shared_mem; +}; + +struct aos_rpc_server { + struct generic_rpc_server g; + struct lmp_chan *chan; struct capref ret_cap; errval_t ret_err; @@ -14,6 +18,12 @@ struct aos_rpc_server { uintptr_t ret1; }; +typedef errval_t (*rpc_handler_t)( + struct generic_rpc_server *rpc, + struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1, + struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1 +); + /** * Initialize an aos_rpc_server struct. */ diff --git a/lib/aos/aos_urpc.c b/lib/aos/aos_urpc.c index 078e028..8c35325 100644 --- a/lib/aos/aos_urpc.c +++ b/lib/aos/aos_urpc.c @@ -14,38 +14,39 @@ #include #include +#include +#include +#include -__attribute__((__used__)) -static errval_t do_aos_urpc( +extern coreid_t my_core_id; +extern rpc_handler_t rpc_handlers[RPC_MTYPE_COUNT]; + +errval_t do_aos_urpc( struct aos_urpc *rpc, uintptr_t msg_type, struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1, struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1 ) { errval_t err; - rpc->urpc->msg_type = msg_type; + assert(rpc->meta->call_in_progress == 0); - struct capability arg_cap_info; - err = cap_direct_identify(arg_cap, &arg_cap_info); - if (err_is_fail(err)) return err_push(err, LIB_ERR_CAP_IDENTIFY); - // only allow ram capabilities or frame capabilities to be sent to other cores - assert(arg_cap_info.type == ObjType_RAM || arg_cap_info.type == ObjType_Frame); + assert(capref_is_null(arg_cap)); + rpc->meta->cap.type = ObjType_Null; - rpc->urpc->arg_cap = arg_cap_info; - - rpc->urpc->arg_size = arg_size; - rpc->urpc->arg0 = arg0; - rpc->urpc->arg1 = arg1; + rpc->meta->a0 = msg_type; + rpc->meta->a1 = arg_size; + rpc->meta->a2 = arg0; + rpc->meta->a3 = arg1; // memory barrier __asm volatile ( "dmb sy\n" ); - rpc->urpc->call_in_progress = 1; + rpc->meta->call_in_progress = 1; // wait until the rpc call completes - while(rpc->urpc->call_in_progress) { + while(rpc->meta->call_in_progress) { // yield the thread because there might be useful stuff to do... thread_yield(); } @@ -56,15 +57,97 @@ static errval_t do_aos_urpc( ); // read the response - if (ret_size != NULL) *ret_size = rpc->urpc->ret_size; - if (ret0 != NULL) *ret0 = rpc->urpc->ret0; - if (ret1 != NULL) *ret1 = rpc->urpc->ret1; + if (ret_size != NULL) *ret_size = rpc->meta->a1; + if (ret0 != NULL) *ret0 = rpc->meta->a2; + if (ret1 != NULL) *ret1 = rpc->meta->a3; - if(ret_cap != NULL && rpc->urpc->has_ret_cap) { + if(ret_cap != NULL && rpc->meta->cap.type == ObjType_RAM) { err = slot_alloc(ret_cap); - ram_forge(*ret_cap, rpc->urpc->ret_cap.u.ram.base, rpc->urpc->ret_cap.u.ram.bytes, ); + if (err_is_fail(err)) return err_push(err, LIB_ERR_SLOT_ALLOC); + err = ram_forge(*ret_cap, rpc->meta->cap.u.ram.base, rpc->meta->cap.u.ram.bytes, my_core_id); + if (err_is_fail(err)) return err; } - return rpc->urpc->ret_errval; + return rpc->meta->a0; +} + + +static void urpc_server_handler(void *arg) { + struct aos_urpc_server *urpc = arg; + errval_t err; + + uintptr_t msg_type = urpc->meta->a0; + uintptr_t arg_size = urpc->meta->a1; + uintptr_t arg0 = urpc->meta->a2; + uintptr_t arg1 = urpc->meta->a3; + + struct capref ret_cap = NULL_CAP; + urpc->meta->a1 = 0; + urpc->meta->a2 = 0; + urpc->meta->a3 = 0; + if (msg_type >= RPC_MTYPE_COUNT) { + err = AOS_ERR_RPC_UNKNOWN_MSG_TYPE; + } else if (arg_size > RPC_SHARED_SIZE) { + err = AOS_ERR_RPC_ARG_TOO_BIG; + } else { + rpc_handler_t handler = rpc_handlers[msg_type]; + if (handler == NULL) { + err = AOS_ERR_RPC_UNKNOWN_MSG_TYPE; + } else { + err = handler( + &urpc->g, + NULL_CAP, arg_size, arg0, arg1, + &ret_cap, &urpc->meta->a1, &urpc->meta->a2, &urpc->meta->a3 + ); + } + } + urpc->meta->a0 = err; + if (!capref_is_null(ret_cap)) { + err = cap_direct_identify(ret_cap, &urpc->meta->cap); + if (err_is_fail(err)) { + DEBUG_ERR(err, "in cap_direct_identify while handling URPC"); + abort(); + } + // only allow ram capabilities or frame capabilities to be sent to other cores + assert(urpc->meta->cap.type == ObjType_RAM || urpc->meta->cap.type == ObjType_Frame); + } + + // memory barrier + __asm volatile ( + "dmb sy\n" + ); + + // tell the other side that we are done + urpc->meta->call_in_progress = false; + + // Unblock the URPC thread + thread_sem_post(&urpc->sem); +} + +int urpc_server(void *arg) { + struct aos_urpc_server *urpc = arg; + struct waitset *default_ws = get_default_waitset(); + struct waitset_chanstate chan; + waitset_chanstate_init(&chan, CHANTYPE_OTHER); + + thread_sem_init(&urpc->sem, 0); + + while (true) { + // wait until an rpc call arrives + while(urpc->meta->call_in_progress == false) { + // yield the thread because there might be useful stuff to do... + thread_yield(); + } + + // memory barrier + __asm volatile ( + "dmb sy\n" + ); + + // handle the URPC on the same thread that handles regular RPCs, to avoid concurrency for the handlers + waitset_chan_trigger_closure(default_ws, &chan, MKCLOSURE(urpc_server_handler, urpc)); + + // wait until the rpc is handled + thread_sem_wait(&urpc->sem); + } } - \ No newline at end of file diff --git a/lib/spawn/rpc_server.c b/lib/spawn/rpc_server.c index 7ec040a..b5b7822 100644 --- a/lib/spawn/rpc_server.c +++ b/lib/spawn/rpc_server.c @@ -4,20 +4,15 @@ #include #include -typedef errval_t (*rpc_handler_t)( - struct aos_rpc_server *rpc, - struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1, - struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1 -); - -static rpc_handler_t rpc_handlers[RPC_MTYPE_COUNT]; +extern coreid_t my_core_id; +rpc_handler_t rpc_handlers[RPC_MTYPE_COUNT]; static void rpc_server_handle_recv(void *arg); static void rpc_server_send_reply(void *arg); void rpc_server_init(struct aos_rpc_server *rpc, struct lmp_chan *chan, void *shared_mem) { rpc->chan = chan; - rpc->shared_mem = shared_mem; + rpc->g.shared_mem = shared_mem; } void rpc_server_register_recv(struct aos_rpc_server *rpc) { @@ -51,7 +46,7 @@ static void rpc_server_handle_recv(void *arg) { err = AOS_ERR_RPC_UNKNOWN_MSG_TYPE; } else { err = handler( - rpc, + &rpc->g, arg_cap, msg.words[1], msg.words[2], msg.words[3], &rpc->ret_cap, &rpc->ret_size, &rpc->ret0, &rpc->ret1 ); @@ -90,7 +85,7 @@ static void rpc_server_send_reply(void *arg) { // RPC handlers static errval_t handle_rpc_send_number( - struct aos_rpc_server *rpc, + struct generic_rpc_server *rpc, struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1, struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1 ) { @@ -102,7 +97,7 @@ static errval_t handle_rpc_send_number( } static errval_t handle_rpc_send_string( - struct aos_rpc_server *rpc, + struct generic_rpc_server *rpc, struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1, struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1 ) { @@ -117,7 +112,7 @@ static errval_t handle_rpc_send_string( } static errval_t handle_rpc_get_ram_cap( - struct aos_rpc_server *rpc, + struct generic_rpc_server *rpc, struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1, struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1 ) { @@ -136,7 +131,7 @@ static errval_t handle_rpc_get_ram_cap( } static errval_t handle_rpc_serial_getchar( - struct aos_rpc_server *rpc, + struct generic_rpc_server *rpc, struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1, struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1 ) { @@ -150,7 +145,7 @@ static errval_t handle_rpc_serial_getchar( } static errval_t handle_rpc_serial_putchar( - struct aos_rpc_server *rpc, + struct generic_rpc_server *rpc, struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1, struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1 ) { @@ -165,7 +160,7 @@ static errval_t handle_rpc_serial_putchar( } static errval_t handle_rpc_serial_write( - struct aos_rpc_server *rpc, + struct generic_rpc_server *rpc, struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1, struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1 ) { @@ -177,7 +172,7 @@ static errval_t handle_rpc_serial_write( } static errval_t handle_rpc_serial_read( - struct aos_rpc_server *rpc, + struct generic_rpc_server *rpc, struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1, struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1 ) { @@ -189,7 +184,7 @@ static errval_t handle_rpc_serial_read( } static errval_t handle_rpc_process_spawn( - struct aos_rpc_server *rpc, + struct generic_rpc_server *rpc, struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1, struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1 ) { @@ -201,17 +196,21 @@ static errval_t handle_rpc_process_spawn( grading_rpc_handler_process_spawn(cmdline, core); - struct spawninfo *si = malloc(sizeof(struct spawninfo)); + if (core != my_core_id) { + struct spawninfo *si = malloc(sizeof(struct spawninfo)); - char *argv[MAX_CMDLINE_ARGS]; - int argc; - spawn_parse_cmd(cmdline, &argc, argv); + char *argv[MAX_CMDLINE_ARGS]; + int argc; + spawn_parse_cmd(cmdline, &argc, argv); - return spawn_load_argv(argc, argv, si, (domainid_t *)ret0); + return spawn_load_argv(argc, argv, si, (domainid_t *)ret0); + } + assert(core == 0); // Spawning from core 1 on core 0 is not supported. + abort(); // TODO } static errval_t handle_rpc_process_get_name( - struct aos_rpc_server *rpc, + struct generic_rpc_server *rpc, struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1, struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1 ) { @@ -244,7 +243,7 @@ static errval_t handle_rpc_process_get_name( } static errval_t handle_rpc_process_get_all_pids( - struct aos_rpc_server *rpc, + struct generic_rpc_server *rpc, struct capref arg_cap, size_t arg_size, uintptr_t arg0, uintptr_t arg1, struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1 ) { @@ -271,7 +270,7 @@ static errval_t handle_rpc_process_get_all_pids( } -static rpc_handler_t rpc_handlers[RPC_MTYPE_COUNT] = { +rpc_handler_t rpc_handlers[RPC_MTYPE_COUNT] = { [RPC_MTYPE_SEND_NUMBER] = handle_rpc_send_number, [RPC_MTYPE_SEND_STRING] = handle_rpc_send_string, [RPC_MTYPE_GET_RAM_CAP] = handle_rpc_get_ram_cap, diff --git a/usr/init/main.c b/usr/init/main.c index 3091867..7d46ed9 100644 --- a/usr/init/main.c +++ b/usr/init/main.c @@ -28,6 +28,7 @@ #include #include +#include struct bootinfo *bi; @@ -35,6 +36,30 @@ struct bootinfo *bi; coreid_t my_core_id; struct platform_info platform_info; +// only valid on app core +static struct aos_urpc urpc_to_bsp; + +// only valid on app core +static struct aos_urpc_server urpc_to_app_server; + +// only valid on bsp core +struct aos_urpc urpc_to_app; + + +static errval_t ram_alloc_remote_core(struct capref *ret, size_t size, size_t alignment) +{ + errval_t err; + + err = do_aos_urpc( + &urpc_to_bsp, RPC_MTYPE_GET_RAM_CAP, + NULL_CAP, 0, size, alignment, + ret, NULL, NULL, NULL + ); + if (err_is_fail(err)) return err_push(err, LIB_ERR_RAM_ALLOC); + + return SYS_ERR_OK; +} + static int bsp_main(int argc, char *argv[]) { errval_t err; @@ -61,11 +86,11 @@ bsp_main(int argc, char *argv[]) { // TODO: Spawn system processes, boot second core etc. here - + // A URPC frame, to hold the cross-core communication channels that you // will implement in Section 7.16. struct capref urpc_frame; - err = frame_alloc(&urpc_frame, RPC_URPC_FRAME_SIZE, NULL); + err = frame_alloc(&urpc_frame, MON_URPC_SIZE, NULL); if(err_is_fail(err)) return err_push(err, LIB_ERR_FRAME_ALLOC); struct frame_identity urpc_frame_id; @@ -85,20 +110,17 @@ bsp_main(int argc, char *argv[]) { USER_PANIC("Platform not implemented"); } - void *addr; - paging_map_frame(get_current_paging_state(), &addr, PAGE_SIZE, urpc_frame); - assert(err_is_ok(err)); - *(uint8_t *)addr = 123; + void *urpc_addr; + err = paging_map_frame(get_current_paging_state(), &urpc_addr, MON_URPC_SIZE, urpc_frame); + if (err_is_fail(err)) return err; + memset(urpc_addr, 0, MON_URPC_SIZE); // memory barrier __asm volatile ( "dmb sy\n" ); - cpu_idcache_wbinv_range((uintptr_t)addr, 64); - // memory barrier - __asm volatile ( - "dmb sy\n" - ); + cpu_idcache_wbinv_range((uintptr_t)urpc_addr, MON_URPC_SIZE); + // TODO rueegges: can we get the mpid in a better way? err = coreboot(1, "boot_armv8_generic", cpu_driver_name, "init", urpc_frame_id); if (err_is_fail(err)) return err_push(err, MON_ERR_SPAWN_CORE); @@ -107,20 +129,16 @@ bsp_main(int argc, char *argv[]) { // err = coreboot(3, "boot_armv8_generic", cpu_driver_name, "init", urpc_frame_id); // if (err_is_fail(err)) return err_push(err, MON_ERR_SPAWN_CORE); - while(*(volatile uint8_t *)addr == 123){ - cpu_idcache_wbinv_range((uintptr_t)addr, 64); - // memory barrier - __asm volatile ( - "dmb sy\n" - ); - }; + struct aos_urpc_frame *urpc = urpc_addr; - // memory barrier - __asm volatile ( - "dmb sy\n" - ); + struct aos_urpc_server *urpc_to_bsp_server = malloc(sizeof(struct aos_urpc_server)); + urpc_to_bsp_server->g.shared_mem = &urpc->shared_mem_to_bsp; + urpc_to_bsp_server->meta = &urpc->meta_to_bsp; + thread_create(urpc_server, urpc_to_bsp_server); + + urpc_to_app.shared_mem = &urpc->shared_mem_to_app; + urpc_to_app.meta = &urpc->meta_to_app; - debug_printf("Got response\n"); // Grading grading_test_late(); @@ -164,23 +182,17 @@ app_main(int argc, char *argv[]) { // TODO: Spawn system processes etc. here - // test communication - struct capref cap_urpc = { - .cnode = { .croot = CPTR_ROOTCN, .cnode = CPTR_TASKCN_BASE, .level = CNODE_TYPE_OTHER, }, - .slot = TASKCN_SLOT_MON_URPC - }; - void *addr; - err = paging_map_frame(get_current_paging_state(), &addr, PAGE_SIZE, cap_urpc); - if(err_is_fail(err)) { - USER_PANIC_ERR(err, "failed to map urpc frame"); - } - assert(*(uint8_t *)addr == 123); - *(uint8_t *)addr = 21; - cpu_idcache_wbinv_range((uintptr_t)addr, 64); - // memory barrier - __asm volatile ( - "dmb sy\n" - ); + struct aos_urpc_frame *urpc = (void*)MON_URPC_VBASE; + + urpc_to_bsp.shared_mem = &urpc->shared_mem_to_bsp; + urpc_to_bsp.meta = &urpc->meta_to_bsp; + + urpc_to_app_server.g.shared_mem = &urpc->shared_mem_to_app; + urpc_to_app_server.meta = &urpc->meta_to_app; + + ram_alloc_set(ram_alloc_remote_core); + + thread_create(urpc_server, &urpc_to_app_server); // Grading grading_test_late();