From 14063e60bec8a33f04569515eb4e1dd920242257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sch=C3=A4r?= Date: Wed, 30 Mar 2022 20:12:19 +0200 Subject: [PATCH] Implement RPC --- errors/errno.fugu | 6 +- hake/menu.lst.armv8_a57_qemu | 2 +- hake/menu.lst.armv8_imx8x | 2 +- include/aos/aos_rpc.h | 23 ++- include/barrelfish_kpi/domain_params.h | 1 + include/spawn/rpc_server.h | 28 ++++ include/spawn/spawn.h | 5 +- lib/aos/aos_rpc.c | 160 ++++++++++++++---- lib/aos/init.c | 38 +---- lib/grading/rpc.c | 10 +- lib/grading/test_spawn.c | 2 +- lib/spawn/Hakefile | 4 +- lib/spawn/rpc_server.c | 219 +++++++++++++++++++++++++ lib/spawn/spawn.c | 60 +++---- usr/hello/hello.c | 11 +- 15 files changed, 459 insertions(+), 112 deletions(-) create mode 100644 include/spawn/rpc_server.h create mode 100644 lib/spawn/rpc_server.c diff --git a/errors/errno.fugu b/errors/errno.fugu index ebbbac8..ed9b982 100755 --- a/errors/errno.fugu +++ b/errors/errno.fugu @@ -1323,7 +1323,7 @@ errors sfn NIC_ERR_{ failure IO "Error during card IO", failure INTR "Interrupted system call", failure NOSYS "Not implemented", - failure UNKNOWN "Uknown error", + failure UNKNOWN "Unknown error", failure TX_PKT "Error sending packet", failure RX_PKT "Error receiving packet", failure RX_DISCARD "Error, packet needs to be discared", @@ -1376,6 +1376,10 @@ errors vas VAS_ERR_ { errors aos AOS_ERR_ { failure LMP_SEND_FAILURE "Failure while sending AOS LMP message", failure LMP_MSGTYPE_UNKNOWN "Unknown message type for AOS LMP implementation", + failure RPC_UNEXPECTED_MSGTYPE "Received RPC message of unexpected type", + failure RPC_ARG_TOO_BIG "RPC argument is too big", + failure RPC_RET_TOO_BIG "RPC return value is too big", + failure RPC_UNKNOWN_MSG_TYPE "RPC with unknown message type", }; // errors NIC driver diff --git a/hake/menu.lst.armv8_a57_qemu b/hake/menu.lst.armv8_a57_qemu index fd9d662..45cdd62 100644 --- a/hake/menu.lst.armv8_a57_qemu +++ b/hake/menu.lst.armv8_a57_qemu @@ -5,7 +5,7 @@ bootdriver /armv8/sbin/boot_armv8_generic cpudriver /armv8/sbin/cpu_a57_qemu loglevel=3 serial=0x9000000 logmask=128 module /armv8/sbin/init -module /armv8/sbin/hello catch Aurel Jan Sandro +module /armv8/sbin/hello Aurel Jan Sandro module /armv8/sbin/memeater # End of file, this needs to have a certain length... diff --git a/hake/menu.lst.armv8_imx8x b/hake/menu.lst.armv8_imx8x index 7d4c96d..3332480 100644 --- a/hake/menu.lst.armv8_imx8x +++ b/hake/menu.lst.armv8_imx8x @@ -5,5 +5,5 @@ bootdriver /armv8/sbin/boot_armv8_generic cpudriver /armv8/sbin/cpu_imx8x module /armv8/sbin/init -module /armv8/sbin/hello catch Aurel Jan Sandro +module /armv8/sbin/hello Aurel Jan Sandro module /armv8/sbin/memeater \ No newline at end of file diff --git a/include/aos/aos_rpc.h b/include/aos/aos_rpc.h index ceacc4c..3fdec7e 100644 --- a/include/aos/aos_rpc.h +++ b/include/aos/aos_rpc.h @@ -17,23 +17,34 @@ #include +#define RPC_SHARED_SIZE PAGE_SIZE + // define some message types -#define RPC_MTYPE_CHILD_ENDPOINT 1UL -#define RPC_MTYPE_CHILD_ENDPOINT_OK 2UL -#define RPC_MTYPE_GET_RAM_CAP 3UL -#define RPC_MTYPE_GET_RAM_CAP_OK 4UL +enum rpc_mtype { + RPC_MTYPE_CHILD_ENDPOINT, + RPC_MTYPE_SEND_NUMBER, + RPC_MTYPE_SEND_STRING, + RPC_MTYPE_GET_RAM_CAP, + RPC_MTYPE_SERIAL_GETCHAR, + RPC_MTYPE_SERIAL_PUTCHAR, + RPC_MTYPE_PROCESS_SPAWN, + RPC_MTYPE_PROCESS_GET_NAME, + RPC_MTYPE_PROCESS_GET_ALL_PIDS, + RPC_MTYPE_COUNT // How many message types exist +}; /* An RPC binding, which may be transported over LMP or UMP. */ struct aos_rpc { - // TODO(M3): Add state struct lmp_chan *chan; + struct waitset ws; + void *shared_mem; }; /** * \brief Initialize an aos_rpc struct. */ -errval_t aos_rpc_init(struct aos_rpc *rpc); +errval_t aos_rpc_init(struct aos_rpc *rpc, struct lmp_chan *chan, void *shared_mem); /** diff --git a/include/barrelfish_kpi/domain_params.h b/include/barrelfish_kpi/domain_params.h index 43843d0..a720998 100644 --- a/include/barrelfish_kpi/domain_params.h +++ b/include/barrelfish_kpi/domain_params.h @@ -25,6 +25,7 @@ struct spawn_domain_params { char *envp[MAX_ENVIRON_VARS + 1]; ///< Environment strings; +1 for NULL terminator void *vspace_buf; ///< Serialised vspace data size_t vspace_buf_len; ///< Length of serialised vspace data + void *rpc_shared_memory; void *tls_init_base; ///< Address of initialised TLS data block size_t tls_init_len; ///< Length of initialised TLS data block size_t tls_total_len; ///< Total (initialised + BSS) TLS data length diff --git a/include/spawn/rpc_server.h b/include/spawn/rpc_server.h new file mode 100644 index 0000000..aae84d6 --- /dev/null +++ b/include/spawn/rpc_server.h @@ -0,0 +1,28 @@ +#ifndef _RPC_SERVER_H_ +#define _RPC_SERVER_H_ + +#include + +struct aos_rpc_server { + struct lmp_chan *chan; + struct waitset ws; + void *shared_mem; + + struct capref ret_cap; + errval_t ret_err; + size_t ret_size; + uintptr_t ret0; + uintptr_t ret1; +}; + +/** + * Initialize an aos_rpc_server struct. + */ +void rpc_server_init(struct aos_rpc_server *rpc, struct lmp_chan *chan, void *shared_mem); + +/** + * Start listening for RPCs. + */ +void rpc_server_register_recv(struct aos_rpc_server *rpc); + +#endif /* _RPC_SERVER_H_ */ diff --git a/include/spawn/spawn.h b/include/spawn/spawn.h index 0488733..36c1b67 100644 --- a/include/spawn/spawn.h +++ b/include/spawn/spawn.h @@ -17,6 +17,7 @@ #include "aos/slot_alloc.h" #include "aos/paging.h" +#include @@ -34,7 +35,7 @@ struct spawninfo { // when spawning a new dispatcher, // e.g. references to the child's // capabilities or paging state - + //afeer: see script page 84/85 struct cnoderef cspace_l1_cnode_info; struct capref cspace_l1_cnode_cap; @@ -58,6 +59,8 @@ struct spawninfo { struct capref vspace_cap_l0_pagetable; struct lmp_chan init_chan; + struct capref rpc_shared_frame; + struct aos_rpc_server rpc_server; }; // Start a child process using the multiboot command line. Fills in si. diff --git a/lib/aos/aos_rpc.c b/lib/aos/aos_rpc.c index 8656eb8..87429c9 100644 --- a/lib/aos/aos_rpc.c +++ b/lib/aos/aos_rpc.c @@ -17,74 +17,171 @@ +static void noop_callback(void *arg) { +} +static errval_t do_aos_rpc( + struct aos_rpc *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; + + // Send call + while (true) { + err = lmp_chan_send4(rpc->chan, LMP_FLAG_YIELD | LMP_FLAG_SYNC, arg_cap, msg_type, arg_size, arg0, arg1); + if (!err_is_fail(err)) break; + if (!lmp_err_is_transient(err)) { + return err_push(err, AOS_ERR_LMP_SEND_FAILURE); + } + err = lmp_chan_register_send(rpc->chan, &rpc->ws, MKCLOSURE(noop_callback, NULL)); + if (err_is_fail(err)) return err; + err = event_dispatch(&rpc->ws); + if (err_is_fail(err)) return err; + } + + // Receive return value + struct lmp_recv_msg recv = LMP_RECV_MSG_INIT; + while (!lmp_endpoint_can_recv(rpc->chan->endpoint)) { + err = lmp_chan_register_recv(rpc->chan, &rpc->ws, MKCLOSURE(noop_callback, NULL)); + if (err_is_fail(err)) return err; + err = event_dispatch(&rpc->ws); + if (err_is_fail(err)) return err; + } + err = lmp_chan_recv(rpc->chan, &recv, ret_cap); + assert(err_is_ok(err)); + + if (ret_size != NULL) *ret_size = recv.words[1]; + if (ret0 != NULL) *ret0 = recv.words[2]; + if (ret1 != NULL) *ret1 = recv.words[3]; + return recv.words[0]; +} errval_t aos_rpc_send_number(struct aos_rpc *rpc, uintptr_t num) { - // TODO: implement functionality to send a number over the channel + // Implement functionality to send a number over the channel // given channel and wait until the ack gets returned. - return SYS_ERR_OK; + return do_aos_rpc( + rpc, RPC_MTYPE_SEND_NUMBER, + NULL_CAP, 0, num, 0, + NULL, NULL, NULL, NULL); } errval_t aos_rpc_send_string(struct aos_rpc *rpc, const char *string) { - // TODO: implement functionality to send a string over the given channel + // Implement functionality to send a string over the given channel // and wait for a response. - return SYS_ERR_OK; + size_t string_size = strlen(string) + 1; + if (string_size > RPC_SHARED_SIZE) return AOS_ERR_RPC_ARG_TOO_BIG; + memcpy(rpc->shared_mem, string, string_size); + + return do_aos_rpc( + rpc, RPC_MTYPE_SEND_STRING, + NULL_CAP, string_size, 0, 0, + NULL, NULL, NULL, NULL + ); } errval_t aos_rpc_get_ram_cap(struct aos_rpc *rpc, size_t bytes, size_t alignment, struct capref *ret_cap, size_t *ret_bytes) { - // TODO: implement functionality to request a RAM capability over the + // Implement functionality to request a RAM capability over the // given channel and wait until it is delivered. - return SYS_ERR_OK; + return do_aos_rpc( + rpc, RPC_MTYPE_GET_RAM_CAP, + NULL_CAP, 0, bytes, alignment, + ret_cap, NULL, ret_bytes, NULL + ); } errval_t aos_rpc_serial_getchar(struct aos_rpc *rpc, char *retc) { - // TODO implement functionality to request a character from + // Implement functionality to request a character from // the serial driver. - return SYS_ERR_OK; + uintptr_t retval; + errval_t err = do_aos_rpc( + rpc, RPC_MTYPE_SERIAL_GETCHAR, + NULL_CAP, 0, 0, 0, + NULL, NULL, &retval, NULL); + *retc = retval; + return err; } errval_t aos_rpc_serial_putchar(struct aos_rpc *rpc, char c) { - // TODO implement functionality to send a character to the + // Implement functionality to send a character to the // serial port. - return SYS_ERR_OK; + return do_aos_rpc( + rpc, RPC_MTYPE_SERIAL_PUTCHAR, + NULL_CAP, 0, c, 0, + NULL, NULL, NULL, NULL + ); } errval_t aos_rpc_process_spawn(struct aos_rpc *rpc, char *cmdline, coreid_t core, domainid_t *newpid) { - // TODO (M5): implement spawn new process rpc - return SYS_ERR_OK; + // (M5): implement spawn new process rpc + size_t cmdline_size = strlen(cmdline) + 1; + if (cmdline_size > RPC_SHARED_SIZE) return AOS_ERR_RPC_ARG_TOO_BIG; + memcpy(rpc->shared_mem, cmdline, cmdline_size); + + uintptr_t retval; + errval_t err = do_aos_rpc( + rpc, RPC_MTYPE_PROCESS_SPAWN, + NULL_CAP, cmdline_size, core, 0, + NULL, NULL, &retval, NULL + ); + *newpid = retval; + return err; } errval_t aos_rpc_process_get_name(struct aos_rpc *rpc, domainid_t pid, char **name) { - // TODO (M5): implement name lookup for process given a process id - return SYS_ERR_OK; + // (M5): implement name lookup for process given a process id + size_t name_len; + errval_t err = do_aos_rpc( + rpc, RPC_MTYPE_PROCESS_GET_NAME, + NULL_CAP, 0, pid, 0, + NULL, &name_len, NULL, NULL + ); + if (err_is_fail(err)) return err; + *name = malloc(name_len); + if (*name == NULL) return LIB_ERR_MALLOC_FAIL; + memcpy(name, rpc->shared_mem, name_len); + return err; } errval_t aos_rpc_process_get_all_pids(struct aos_rpc *rpc, domainid_t **pids, size_t *pid_count) { - // TODO (M5): implement process id discovery - return SYS_ERR_OK; + // (M5): implement process id discovery + size_t ret_len; + errval_t err = do_aos_rpc( + rpc, RPC_MTYPE_PROCESS_GET_NAME, + NULL_CAP, 0, 0, 0, + NULL, &ret_len, NULL, NULL + ); + if (err_is_fail(err)) return err; + *pid_count = ret_len / sizeof(**pids); + *pids = malloc(ret_len); + if (*pids == NULL) return LIB_ERR_MALLOC_FAIL; + memcpy(pids, rpc->shared_mem, ret_len); + return err; } // We are allowed to change the signature for this one -errval_t aos_rpc_init(struct aos_rpc *rpc) +errval_t aos_rpc_init(struct aos_rpc *rpc, struct lmp_chan *chan, void *shared_mem) { - // TODO! + rpc->chan = chan; + rpc->shared_mem = shared_mem; + waitset_init(&rpc->ws); return SYS_ERR_OK; } @@ -93,9 +190,8 @@ errval_t aos_rpc_init(struct aos_rpc *rpc) */ struct aos_rpc *aos_rpc_get_init_channel(void) { - //TODO: Return channel to talk to init process - debug_printf("aos_rpc_get_init_channel NYI\n"); - return NULL; + // Return channel to talk to init process + return get_init_rpc(); } /** @@ -103,10 +199,9 @@ struct aos_rpc *aos_rpc_get_init_channel(void) */ struct aos_rpc *aos_rpc_get_memory_channel(void) { - //TODO: Return channel to talk to memory server process (or whoever - //implements memory server functionality) - debug_printf("aos_rpc_get_memory_channel NYI\n"); - return NULL; + // Return channel to talk to memory server process (or whoever + // implements memory server functionality) + return get_init_rpc(); } /** @@ -114,10 +209,9 @@ struct aos_rpc *aos_rpc_get_memory_channel(void) */ struct aos_rpc *aos_rpc_get_process_channel(void) { - //TODO: Return channel to talk to process server process (or whoever - //implements process server functionality) - debug_printf("aos_rpc_get_process_channel NYI\n"); - return NULL; + // Return channel to talk to process server process (or whoever + // implements process server functionality) + return get_init_rpc(); } /** @@ -125,9 +219,7 @@ struct aos_rpc *aos_rpc_get_process_channel(void) */ struct aos_rpc *aos_rpc_get_serial_channel(void) { - //TODO: Return channel to talk to serial driver/terminal process (whoever - //implements print/read functionality) - debug_printf("aos_rpc_get_serial_channel NYI\n"); - return NULL; + // Return channel to talk to serial driver/terminal process (whoever + // implements print/read functionality) + return get_init_rpc(); } - diff --git a/lib/aos/init.c b/lib/aos/init.c index 2e72f9a..8402662 100644 --- a/lib/aos/init.c +++ b/lib/aos/init.c @@ -83,7 +83,6 @@ static size_t dummy_terminal_read(char *buf, size_t len) return 0; } -// TODO rueegges: putting it here for now. Not sure how to do rcp abstraction yet static int event_init_dispatch_thread(void *arg) { errval_t err; @@ -95,8 +94,6 @@ static int event_init_dispatch_thread(void *arg) } } -// TODO rueegges: putting it here for now. Not sure how to do rcp abstraction yet -// receive messages sent by the init static void handle_init_recv(void *arg) { errval_t err; @@ -106,31 +103,13 @@ static void handle_init_recv(void *arg) struct capref cap; err = lmp_chan_recv(init_chan, &msg, &cap); - if (err_is_fail(err)) { - if (lmp_err_is_transient(err)) { - err = lmp_endpoint_register(init_chan->endpoint, get_default_waitset(), MKCLOSURE(handle_init_recv, init_chan)); - if (err_is_fail(err)) { - USER_PANIC_ERR(err, "Could not reregister after failed init_chan cap receive"); - } - } else { - USER_PANIC_ERR(err, "Failure in child channel"); - } - return; - } + assert(err_is_ok(err)); - switch(msg.words[0]){ - case RPC_MTYPE_CHILD_ENDPOINT_OK: - debug_printf("Received child init OK\n"); - init_chan_initialized = true; - break; - default: - USER_PANIC("Unknown rpc message type."); - break; - } - - err = lmp_endpoint_register(init_chan->endpoint, get_default_waitset(), MKCLOSURE(handle_init_recv, init_chan)); - if (err_is_fail(err)) { - USER_PANIC_ERR(err, "[handle_init_recv]: Could not register endpoint after receiving message"); + if (msg.words[0] == SYS_ERR_OK) { + debug_printf("Received child init OK\n"); + init_chan_initialized = true; + } else { + USER_PANIC("Child LMP initialization failed."); } } @@ -207,6 +186,7 @@ errval_t barrelfish_init_onthread(struct spawn_domain_params *params) // TODO MILESTONE 3: register ourselves with init /* allocate lmp channel structure */ struct lmp_chan *init_chan = malloc(sizeof(struct lmp_chan)); + lmp_chan_init(init_chan); /* create local endpoint */ err = endpoint_create(DEFAULT_LMP_BUF_WORDS, &init_chan->local_cap, &init_chan->endpoint); if (err_is_fail(err)) { @@ -232,7 +212,7 @@ errval_t barrelfish_init_onthread(struct spawn_domain_params *params) } /* initialize init RPC client with lmp channel */ struct aos_rpc *init_rpc = malloc(sizeof(struct aos_rpc)); - err = aos_rpc_init(init_rpc); + err = aos_rpc_init(init_rpc, init_chan, params->rpc_shared_memory); if (err_is_fail(err)){ return err_push(err, ERR_NOTIMP); } @@ -261,7 +241,7 @@ errval_t barrelfish_init_onthread(struct spawn_domain_params *params) void barrelfish_init_disabled(dispatcher_handle_t handle, bool init_dom_arg); void barrelfish_init_disabled(dispatcher_handle_t handle, bool init_dom_arg) { - ; init_domain = init_dom_arg; + init_domain = init_dom_arg; disp_init_disabled(handle); thread_init_disabled(handle, init_dom_arg); } diff --git a/lib/grading/rpc.c b/lib/grading/rpc.c index 99c0023..b869090 100644 --- a/lib/grading/rpc.c +++ b/lib/grading/rpc.c @@ -6,34 +6,42 @@ #include -void grading_rpc_handle_number(uintptr_t val) +void grading_rpc_handle_number(uintptr_t val) { + debug_printf("grading_rpc_handle_number(%"PRIuPTR")\n", val); } void grading_rpc_handler_string(const char* string) { + debug_printf("grading_rpc_handler_string(\"%s\")\n", string); } void grading_rpc_handler_serial_getchar(void) { + debug_printf("grading_rpc_handler_serial_getchar()\n"); } void grading_rpc_handler_serial_putchar(char c) { + debug_printf("grading_rpc_handler_serial_putchar(0x%"PRIx8")\n", c); } void grading_rpc_handler_ram_cap(size_t bytes, size_t alignment) { + debug_printf("grading_rpc_handler_ram_cap(0x%"PRIxPTR", 0x%"PRIxPTR")\n", bytes, alignment); } void grading_rpc_handler_process_spawn(char* cmdline, coreid_t core) { + debug_printf("grading_rpc_handler_process_spawn(\"%s\", %"PRIuCOREID")\n", cmdline, core); } void grading_rpc_handler_process_get_name(domainid_t pid) { + debug_printf("grading_rpc_handler_process_get_name(%"PRIuDOMAINID")\n", pid); } void grading_rpc_handler_process_get_all_pids(void) { + debug_printf("grading_rpc_handler_process_get_all_pids()\n"); } diff --git a/lib/grading/test_spawn.c b/lib/grading/test_spawn.c index e0eb407..231afad 100644 --- a/lib/grading/test_spawn.c +++ b/lib/grading/test_spawn.c @@ -3,7 +3,7 @@ #include #include -#define PROCESS_COUNT 5 +#define PROCESS_COUNT 1 void do_test_spawn(void) { // spawn multiple processes diff --git a/lib/spawn/Hakefile b/lib/spawn/Hakefile index 1b404aa..a550f90 100644 --- a/lib/spawn/Hakefile +++ b/lib/spawn/Hakefile @@ -7,13 +7,13 @@ -- ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. -- -- Hakefile for lib/spawn --- +-- -------------------------------------------------------------------------- [ build library { target = "spawn", - cFiles = [ "spawn.c" ], + cFiles = [ "spawn.c", "rpc_server.c" ], addLibraries = [ "elf", "argv", "multiboot" ] }, build library { diff --git a/lib/spawn/rpc_server.c b/lib/spawn/rpc_server.c new file mode 100644 index 0000000..6e7f04e --- /dev/null +++ b/lib/spawn/rpc_server.c @@ -0,0 +1,219 @@ +#include +#include +#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]; + +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; +} + +void rpc_server_register_recv(struct aos_rpc_server *rpc) { + errval_t err = lmp_chan_register_recv(rpc->chan, get_default_waitset(), MKCLOSURE(rpc_server_handle_recv, rpc)); + if (err_is_fail(err)) { + DEBUG_ERR(err, "Could not register receive handler"); + } +} + +static void rpc_server_handle_recv(void *arg) { + errval_t err; + struct aos_rpc_server *rpc = (struct aos_rpc_server *)arg; + + struct lmp_recv_msg msg = LMP_RECV_MSG_INIT; + struct capref arg_cap; + + err = lmp_chan_recv(rpc->chan, &msg, &arg_cap); + assert(err_is_ok(err)); + + rpc->ret_cap = NULL_CAP; + rpc->ret_size = 0; + rpc->ret0 = 0; + rpc->ret1 = 0; + if (msg.words[0] >= RPC_MTYPE_COUNT) { + err = AOS_ERR_RPC_UNKNOWN_MSG_TYPE; + } else if (msg.words[1] > RPC_SHARED_SIZE) { + err = AOS_ERR_RPC_ARG_TOO_BIG; + } else { + rpc_handler_t handler = rpc_handlers[msg.words[0]]; + if (handler == NULL) { + err = AOS_ERR_RPC_UNKNOWN_MSG_TYPE; + } else { + err = handler( + rpc, + arg_cap, msg.words[1], msg.words[2], msg.words[3], + &rpc->ret_cap, &rpc->ret_size, &rpc->ret0, &rpc->ret1 + ); + } + } + rpc->ret_err = err; + + rpc_server_send_reply(rpc); +} + +static void rpc_server_send_reply(void *arg) { + struct aos_rpc_server *rpc = (struct aos_rpc_server *)arg; + errval_t err; + + err = lmp_chan_send4( + rpc->chan, LMP_FLAG_YIELD | LMP_FLAG_SYNC, + rpc->ret_cap, rpc->ret_err, rpc->ret_size, rpc->ret0, rpc->ret1 + ); + if (err_is_fail(err)) { + if (!lmp_err_is_transient(err)) { + DEBUG_ERR(err, "Could not send RPC reply"); + return; + } + // Cannot send right now, try again later + err = lmp_chan_register_send(rpc->chan, &rpc->ws, MKCLOSURE(rpc_server_send_reply, arg)); + if (err_is_fail(err)) { + DEBUG_ERR(err, "Could not register send handler"); + return; + } + } + + // Sent reply, wait for next RPC call + rpc_server_register_recv(rpc); +} + +// RPC handlers + +static errval_t handle_rpc_send_number( + 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 +) { + uintptr_t num = arg0; + + grading_rpc_handle_number(num); + + return SYS_ERR_OK; +} + +static errval_t handle_rpc_send_string( + 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 +) { + const char* string = rpc->shared_mem; + if (arg_size == 0 || string[arg_size - 1] != '\0') { + return ERR_INVALID_ARGS; + } + + grading_rpc_handler_string(string); + + return SYS_ERR_OK; +} + +static errval_t handle_rpc_get_ram_cap( + 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 +) { + size_t bytes = arg0; + size_t alignment = arg1; + + grading_rpc_handler_ram_cap(bytes, alignment); + + // TODO + *ret0 = bytes; + + return LIB_ERR_NOT_IMPLEMENTED; +} + +static errval_t handle_rpc_serial_getchar( + 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 +) { + + grading_rpc_handler_serial_getchar(); + + // TODO + *ret0 = 'A'; + + return LIB_ERR_NOT_IMPLEMENTED; +} + +static errval_t handle_rpc_serial_putchar( + 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 +) { + char c = arg0; + + grading_rpc_handler_serial_putchar(c); + + // TODO + + return LIB_ERR_NOT_IMPLEMENTED; +} + +static errval_t handle_rpc_process_spawn( + 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 +) { + char *cmdline = rpc->shared_mem; + coreid_t core = arg0; + if (arg_size == 0 || cmdline[arg_size - 1] != '\0') { + return ERR_INVALID_ARGS; + } + + grading_rpc_handler_process_spawn(cmdline, core); + + // TODO + *ret0 = 0; + + return LIB_ERR_NOT_IMPLEMENTED; +} + +static errval_t handle_rpc_process_get_name( + 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 +) { + domainid_t pid = arg0; + + grading_rpc_handler_process_get_name(pid); + + // TODO + memcpy(rpc->shared_mem, "name", 5); + *ret_size = 5; + + return LIB_ERR_NOT_IMPLEMENTED; +} + +static errval_t handle_rpc_process_get_all_pids( + 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 +) { + grading_rpc_handler_process_get_all_pids(); + + // TODO + + return LIB_ERR_NOT_IMPLEMENTED; +} + + +static 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, + [RPC_MTYPE_SERIAL_GETCHAR] = handle_rpc_serial_getchar, + [RPC_MTYPE_SERIAL_PUTCHAR] = handle_rpc_serial_putchar, + [RPC_MTYPE_PROCESS_SPAWN] = handle_rpc_process_spawn, + [RPC_MTYPE_PROCESS_GET_NAME] = handle_rpc_process_get_name, + [RPC_MTYPE_PROCESS_GET_ALL_PIDS] = handle_rpc_process_get_all_pids, +}; diff --git a/lib/spawn/spawn.c b/lib/spawn/spawn.c index 9a187be..28ef2c9 100644 --- a/lib/spawn/spawn.c +++ b/lib/spawn/spawn.c @@ -47,46 +47,23 @@ static void armv8_set_registers(void *arch_load_info, disabled_area->regs[REG_OFFSET(PIC_REGISTER)] = got_base; } -// receive messages sent by the child static void handle_child_recv(void *arg) { errval_t err; - struct lmp_chan *init_chan = (struct lmp_chan *)arg; + struct spawninfo *si = (struct spawninfo *)arg; struct lmp_recv_msg msg = LMP_RECV_MSG_INIT; struct capref cap; - err = lmp_chan_recv(init_chan, &msg, &cap); - if (err_is_fail(err)) { - if (lmp_err_is_transient(err)) { - err = lmp_endpoint_register(init_chan->endpoint, get_default_waitset(), MKCLOSURE(handle_child_recv, init_chan)); - if (err_is_fail(err)) { - USER_PANIC_ERR(err, "Could not reregister after failed init_chan cap receive"); - } - } else { - USER_PANIC_ERR(err, "Failure in child channel"); - } - return; - } + err = lmp_chan_recv(&si->init_chan, &msg, &cap); + assert(err_is_ok(err)); switch(msg.words[0]){ case RPC_MTYPE_CHILD_ENDPOINT: debug_printf("SPAWN: Received child init_chan endpoint\n"); - init_chan->remote_cap = cap; - err = lmp_chan_send1(init_chan, LMP_FLAG_YIELD | LMP_FLAG_SYNC, NULL_CAP, RPC_MTYPE_CHILD_ENDPOINT_OK); + si->init_chan.remote_cap = cap; + err = lmp_chan_send1(&si->init_chan, LMP_FLAG_YIELD | LMP_FLAG_SYNC, NULL_CAP, SYS_ERR_OK); if (err_is_fail(err)) { - USER_PANIC_ERR(err, "Failed to send RPC_MTYPE_CHILD_ENDPOINT_OK"); - } - break; - case RPC_MTYPE_GET_RAM_CAP: - debug_printf("[handle_init_recv]: RPC_MTYPE_GET_RAM_CAP\n"); - - size_t requested_size = msg.words[1]; - struct capref new_ram_cap; - frame_alloc(&new_ram_cap, requested_size, NULL); - - err = lmp_chan_send1(init_chan, LMP_FLAG_YIELD | LMP_FLAG_SYNC, NULL_CAP, RPC_MTYPE_GET_RAM_CAP_OK); - if (err_is_fail(err)) { - USER_PANIC_ERR(err, "Failed to send RPC_MTYPE_GET_RAM_CAP_OK"); + USER_PANIC_ERR(err, "Failed to send reply"); } break; default: @@ -94,10 +71,7 @@ static void handle_child_recv(void *arg) { break; } - err = lmp_endpoint_register(init_chan->endpoint, get_default_waitset(), MKCLOSURE(handle_child_recv, init_chan)); - if (err_is_fail(err)) { - USER_PANIC_ERR(err, "Could not reregister after failed init_chan cap receive"); - } + rpc_server_register_recv(&si->rpc_server); } struct temp_mapping { @@ -594,6 +568,22 @@ errval_t spawn_load_argv(int argc, char *argv[], struct spawninfo *si, return err_push(err, SPAWN_ERR_SERIALISE_VSPACE); } + // Create shared memory for RPC + err = frame_alloc(&si->rpc_shared_frame, RPC_SHARED_SIZE, NULL); + if (err_is_fail(err)) return err_push(err, LIB_ERR_FRAME_ALLOC); + + void *rpc_shared_memory; + err = paging_map_frame_attr( + get_current_paging_state(), &rpc_shared_memory, + RPC_SHARED_SIZE, si->rpc_shared_frame, VREGION_FLAGS_READ_WRITE); + if (err_is_fail(err)) return err; + + err = paging_map_frame_attr( + &child_paging_state, &domain_params->rpc_shared_memory, + RPC_SHARED_SIZE, si->rpc_shared_frame, VREGION_FLAGS_READ_WRITE); + if (err_is_fail(err)) return err; + + // afeer: TODO: what do i put here? do we need to set these fields to some value? // domain_params->tls_init_base = NULL; // domain_params->tls_init_len = 0; @@ -624,9 +614,11 @@ errval_t spawn_load_argv(int argc, char *argv[], struct spawninfo *si, err = paging_unmap(get_current_paging_state(), arguments_page_in_self); if (err_is_fail(err)) return err_push(err, LIB_ERR_PMAP_UNMAP); + rpc_server_init(&si->rpc_server, &si->init_chan, rpc_shared_memory); + // Receive the child's endpoint for the init channel lmp_chan_alloc_recv_slot(&si->init_chan); - err = lmp_endpoint_register(si->init_chan.endpoint, get_default_waitset(), MKCLOSURE(handle_child_recv, &si->init_chan)); + err = lmp_chan_register_recv(&si->init_chan, get_default_waitset(), MKCLOSURE(handle_child_recv, si)); if (err_is_fail(err)) return err; // - Make the new dispatcher runnable diff --git a/usr/hello/hello.c b/usr/hello/hello.c index bc1975a..50d3d89 100644 --- a/usr/hello/hello.c +++ b/usr/hello/hello.c @@ -18,19 +18,28 @@ #include #include +#include #include #define HELLO_CATCH_COMMAND "catch" int main(int argc, char *argv[]) { + errval_t err; printf("Hello, world!\n"); - + printf("argv:\n"); for(int i = 0; i < argc; ++i) { printf(" %d -> %s\n", i, argv[i]); } + struct aos_rpc *rpc = aos_rpc_get_init_channel(); + err = aos_rpc_send_number(rpc, 1234); + if (err_is_fail(err)) USER_PANIC_ERR(err, "Failed to send RPC"); + + err = aos_rpc_send_string(rpc, "Hello World via RPC!"); + if (err_is_fail(err)) USER_PANIC_ERR(err, "Failed to send RPC"); + // if we receive the catch command, RUN! if (argc > 1 && !strncmp(argv[1], HELLO_CATCH_COMMAND, sizeof(HELLO_CATCH_COMMAND))) { int iter = 0;