From 9750a752c398be4b68a6bacd5da73bc5ee0e0389 Mon Sep 17 00:00:00 2001 From: Sparchatus Date: Thu, 31 Mar 2022 07:59:00 +0000 Subject: [PATCH] Added: Terminal RPC, Spawn RPC, small abstraction fixes, automatic recv slot allocation in aos_rpc --- errors/errno.fugu | 1 + hake/menu.lst.armv8_a57_qemu | 2 +- include/aos/aos_rpc.h | 7 +++ include/spawn/spawn.h | 5 +++ lib/aos/aos_rpc.c | 42 ++++++++++++++++-- lib/aos/init.c | 39 +++++++++++++++-- lib/grading/test_spawn.c | 28 ++++++------ lib/spawn/rpc_server.c | 83 ++++++++++++++++++++++++++++++------ lib/spawn/spawn.c | 40 +++++++++++------ usr/hello/hello.c | 27 ++++++++++++ 10 files changed, 225 insertions(+), 49 deletions(-) diff --git a/errors/errno.fugu b/errors/errno.fugu index ed9b982..6290f61 100755 --- a/errors/errno.fugu +++ b/errors/errno.fugu @@ -1380,6 +1380,7 @@ errors aos AOS_ERR_ { 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", + failure RPC_PROCESS_UNKNOWN_PID "Requested process name for an unknown PID", }; // errors NIC driver diff --git a/hake/menu.lst.armv8_a57_qemu b/hake/menu.lst.armv8_a57_qemu index 45cdd62..49d5b1e 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 Aurel Jan Sandro +module /armv8/sbin/hello spawn module /armv8/sbin/memeater # End of file, this needs to have a certain length... diff --git a/include/aos/aos_rpc.h b/include/aos/aos_rpc.h index 3fdec7e..eb7dc64 100644 --- a/include/aos/aos_rpc.h +++ b/include/aos/aos_rpc.h @@ -27,6 +27,7 @@ enum rpc_mtype { RPC_MTYPE_GET_RAM_CAP, RPC_MTYPE_SERIAL_GETCHAR, RPC_MTYPE_SERIAL_PUTCHAR, + RPC_MTYPE_SERIAL_WRITE, RPC_MTYPE_PROCESS_SPAWN, RPC_MTYPE_PROCESS_GET_NAME, RPC_MTYPE_PROCESS_GET_ALL_PIDS, @@ -78,6 +79,12 @@ errval_t aos_rpc_serial_getchar(struct aos_rpc *chan, char *retc); */ errval_t aos_rpc_serial_putchar(struct aos_rpc *chan, char c); +/** + * \brief Send a list of characters to the serial port + */ +errval_t aos_rpc_serial_write(struct aos_rpc *chan, const char *buf, + size_t buf_len); + /** * \brief Request that the process manager start a new process * \arg cmdline the name of the process that needs to be spawned (without a diff --git a/include/spawn/spawn.h b/include/spawn/spawn.h index 36c1b67..6be94d0 100644 --- a/include/spawn/spawn.h +++ b/include/spawn/spawn.h @@ -63,6 +63,11 @@ struct spawninfo { struct aos_rpc_server rpc_server; }; +struct spawninfo *sawn_get_process_list(void); + +// parse a commandline into arguments +void spawn_parse_cmd(char *cmdline, int *argc, char **argv); + // Start a child process using the multiboot command line. Fills in si. errval_t spawn_load_by_name(char *binary_name, struct spawninfo * si, domainid_t *pid); diff --git a/lib/aos/aos_rpc.c b/lib/aos/aos_rpc.c index 87429c9..88fa9da 100644 --- a/lib/aos/aos_rpc.c +++ b/lib/aos/aos_rpc.c @@ -27,6 +27,11 @@ static errval_t do_aos_rpc( ) { errval_t err; + // allocate capability if we expect one and the recv slot is empty + if (ret_cap != NULL && rpc->chan->endpoint->k.recv_cptr == 0){ + lmp_chan_alloc_recv_slot(rpc->chan); + } + // Send call while (true) { err = lmp_chan_send4(rpc->chan, LMP_FLAG_YIELD | LMP_FLAG_SYNC, arg_cap, msg_type, arg_size, arg0, arg1); @@ -121,6 +126,36 @@ aos_rpc_serial_putchar(struct aos_rpc *rpc, char c) { ); } +// putchar for terminal printing is too slow so we send buffers instead +errval_t +aos_rpc_serial_write(struct aos_rpc *rpc, const char *buf, size_t buf_len) { + errval_t err; + + // split the buffer into chunks for sending + while(buf_len > 0) { + size_t chunk_len = buf_len; + if (chunk_len > RPC_SHARED_SIZE) { + chunk_len = RPC_SHARED_SIZE; + } + + memcpy(rpc->shared_mem, buf, chunk_len); + + err = do_aos_rpc( + rpc, RPC_MTYPE_SERIAL_WRITE, + NULL_CAP, chunk_len, 0, 0, + NULL, NULL, NULL, NULL + ); + if (err_is_fail(err)) { + return err; + } + + buf += chunk_len; + buf_len -= chunk_len; + } + + return SYS_ERR_OK; +} + errval_t aos_rpc_process_spawn(struct aos_rpc *rpc, char *cmdline, coreid_t core, domainid_t *newpid) { @@ -153,7 +188,8 @@ aos_rpc_process_get_name(struct aos_rpc *rpc, domainid_t pid, char **name) { 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); + memcpy(*name, rpc->shared_mem, name_len); + assert((*name)[name_len] == '\0'); return err; } @@ -164,7 +200,7 @@ aos_rpc_process_get_all_pids(struct aos_rpc *rpc, domainid_t **pids, // (M5): implement process id discovery size_t ret_len; errval_t err = do_aos_rpc( - rpc, RPC_MTYPE_PROCESS_GET_NAME, + rpc, RPC_MTYPE_PROCESS_GET_ALL_PIDS, NULL_CAP, 0, 0, 0, NULL, &ret_len, NULL, NULL ); @@ -172,7 +208,7 @@ aos_rpc_process_get_all_pids(struct aos_rpc *rpc, domainid_t **pids, *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); + memcpy(*pids, rpc->shared_mem, ret_len); return err; } diff --git a/lib/aos/init.c b/lib/aos/init.c index 8402662..2cc90fa 100644 --- a/lib/aos/init.c +++ b/lib/aos/init.c @@ -100,9 +100,8 @@ static void handle_init_recv(void *arg) struct lmp_chan *init_chan = (struct lmp_chan *)arg; struct lmp_recv_msg msg = LMP_RECV_MSG_INIT; - struct capref cap; - err = lmp_chan_recv(init_chan, &msg, &cap); + err = lmp_chan_recv(init_chan, &msg, NULL); assert(err_is_ok(err)); if (msg.words[0] == SYS_ERR_OK) { @@ -113,6 +112,32 @@ static void handle_init_recv(void *arg) } } +// TODO rueegges: allow partial write +static size_t aos_terminal_write(const char *buf, size_t len) +{ + errval_t err; + struct aos_rpc *rpc = aos_rpc_get_serial_channel(); + if (rpc == NULL) { + debug_printf("Attempted to printf before initializing rpc: %.*s\n", len, buf); + USER_PANIC("Make sure to initialize rpc before function barrelfish_libc_glue_init is called."); + return len; + } + + err = aos_rpc_serial_write(rpc, buf, len); + assert(err_is_ok(err)); + return len; +} + +// TODO rueegges: make more efficient? +static size_t aos_terminal_read(char *buf, size_t len) +{ + errval_t err; + struct aos_rpc *rpc = aos_rpc_get_serial_channel(); + err = aos_rpc_serial_getchar(rpc, buf); + assert(err_is_ok(err)); + return 1; +} + /* Set libc function pointers */ void barrelfish_libc_glue_init(void) { @@ -120,8 +145,14 @@ void barrelfish_libc_glue_init(void) // what we need for that // TODO: change these to use the user-space serial driver if possible // TODO: set these functions - _libc_terminal_read_func = dummy_terminal_read; - _libc_terminal_write_func = syscall_terminal_write; + // MARKER SHELL: replace functions for init domain or UART driver with non-remote calls + if(init_domain) { + _libc_terminal_read_func = dummy_terminal_read; + _libc_terminal_write_func = syscall_terminal_write; + } else { + _libc_terminal_read_func = aos_terminal_read; + _libc_terminal_write_func = aos_terminal_write; + } _libc_exit_func = libc_exit; _libc_assert_func = libc_assert; /* morecore func is setup by morecore_init() */ diff --git a/lib/grading/test_spawn.c b/lib/grading/test_spawn.c index 231afad..b5f37c7 100644 --- a/lib/grading/test_spawn.c +++ b/lib/grading/test_spawn.c @@ -16,19 +16,19 @@ void do_test_spawn(void) { } // wait for 10 seconds but handle events in the mean time - struct waitset *default_ws = get_default_waitset(); - struct timespec tt; - clock_gettime(CLOCK_REALTIME, &tt); - long start = time_to_ms(tt); - do { - if(err_is_ok(check_for_event(default_ws))){ - CHECK_ERR(event_dispatch(default_ws)); - } - clock_gettime(CLOCK_REALTIME, &tt); - } while(time_to_ms(tt) - start < 10000); + // struct waitset *default_ws = get_default_waitset(); + // struct timespec tt; + // clock_gettime(CLOCK_REALTIME, &tt); + // long start = time_to_ms(tt); + // do { + // if(err_is_ok(check_for_event(default_ws))){ + // CHECK_ERR(event_dispatch(default_ws)); + // } + // clock_gettime(CLOCK_REALTIME, &tt); + // } while(time_to_ms(tt) - start < 10000); - for(uint i = 0; i < PROCESS_COUNT; ++i) { - debug_printf("TEST_SPAWN: Killing %u\n", i); - CHECK_ERR(invoke_dispatcher_stop(si[i].dispatcher)); - } + // for(uint i = 0; i < PROCESS_COUNT; ++i) { + // debug_printf("TEST_SPAWN: Killing %u\n", i); + // CHECK_ERR(invoke_dispatcher_stop(si[i].dispatcher)); + // } } diff --git a/lib/spawn/rpc_server.c b/lib/spawn/rpc_server.c index 6e7f04e..80ea384 100644 --- a/lib/spawn/rpc_server.c +++ b/lib/spawn/rpc_server.c @@ -2,6 +2,7 @@ #include #include #include +#include typedef errval_t (*rpc_handler_t)( struct aos_rpc_server *rpc, @@ -138,9 +139,9 @@ static errval_t handle_rpc_serial_getchar( ) { grading_rpc_handler_serial_getchar(); - - // TODO - *ret0 = 'A'; + + // MARKER SHELL: Replace with UART call + *ret0 = getchar(); return LIB_ERR_NOT_IMPLEMENTED; } @@ -154,9 +155,27 @@ static errval_t handle_rpc_serial_putchar( grading_rpc_handler_serial_putchar(c); - // TODO + // MARKER SHELL: Replace with UART call + putchar(c); - return LIB_ERR_NOT_IMPLEMENTED; + return SYS_ERR_OK; +} + +static errval_t handle_rpc_serial_write( + 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 +) { + if (arg_size == 0 ) { + return ERR_INVALID_ARGS; + } + + // MARKER SHELL: Replace with UART call + for (size_t i = 0; i < arg_size; ++i){ + putchar(((char *)rpc->shared_mem)[i]); + } + + return SYS_ERR_OK; } static errval_t handle_rpc_process_spawn( @@ -172,10 +191,13 @@ static errval_t handle_rpc_process_spawn( grading_rpc_handler_process_spawn(cmdline, core); - // TODO - *ret0 = 0; + struct spawninfo *si = malloc(sizeof(struct spawninfo)); - return LIB_ERR_NOT_IMPLEMENTED; + char *argv[MAX_CMDLINE_ARGS]; + int argc; + spawn_parse_cmd(cmdline, &argc, argv); + + return spawn_load_argv(argc, argv, si, (domainid_t *)ret0); } static errval_t handle_rpc_process_get_name( @@ -187,11 +209,28 @@ static errval_t handle_rpc_process_get_name( grading_rpc_handler_process_get_name(pid); - // TODO - memcpy(rpc->shared_mem, "name", 5); - *ret_size = 5; + // search for the pid + char *name = NULL; + for (struct spawninfo *si = sawn_get_process_list(); si != NULL; si = si->next) { + if (si->pid == pid) { + name = si->binary_name; + break; + } + } - return LIB_ERR_NOT_IMPLEMENTED; + if (name == NULL) { + return AOS_ERR_RPC_PROCESS_UNKNOWN_PID; + } + + size_t name_len = strlen(name) + 1; + if(name_len > RPC_SHARED_SIZE) { + return AOS_ERR_RPC_RET_TOO_BIG; + } + + memcpy(rpc->shared_mem, name, name_len); + *ret_size = name_len; + + return SYS_ERR_OK; } static errval_t handle_rpc_process_get_all_pids( @@ -200,10 +239,25 @@ static errval_t handle_rpc_process_get_all_pids( struct capref *ret_cap, size_t *ret_size, uintptr_t *ret0, uintptr_t *ret1 ) { grading_rpc_handler_process_get_all_pids(); + + // size in bytes + size_t list_size = 0; + domainid_t *buf = rpc->shared_mem; - // TODO + // get all PIDs that fit into the given space + for (struct spawninfo *si = sawn_get_process_list(); si != NULL; si = si->next) { + if (list_size + sizeof(domainid_t) > RPC_SHARED_SIZE) { + return AOS_ERR_RPC_RET_TOO_BIG; + } - return LIB_ERR_NOT_IMPLEMENTED; + *buf = si->pid; + ++buf; + list_size += sizeof(domainid_t); + } + + *ret_size = list_size; + + return SYS_ERR_OK; } @@ -213,6 +267,7 @@ static rpc_handler_t rpc_handlers[RPC_MTYPE_COUNT] = { [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_SERIAL_WRITE] = handle_rpc_serial_write, [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 28ef2c9..575ea40 100644 --- a/lib/spawn/spawn.c +++ b/lib/spawn/spawn.c @@ -20,7 +20,9 @@ struct spawninfo *spawn_process_list = NULL; // TODO: handle "freeing" of PIDs in case we learn how to detect stopped child processes domainid_t spawn_last_pid = 1; - +struct spawninfo *sawn_get_process_list(void) { + return spawn_process_list; +} /** * \brief Set the base address of the .got (Global Offset Table) section of the ELF binary @@ -334,6 +336,13 @@ errval_t spawn_load_argv(int argc, char *argv[], struct spawninfo *si, // - Initialize the spawn_info struct // TODO + // copy name to spawninfo struct + size_t binary_name_len = strlen(argv[0]); + si->binary_name = malloc(binary_name_len); + if (si->binary_name == NULL) { + return LIB_ERR_MALLOC_FAIL; + } + memcpy(si->binary_name, argv[0], binary_name_len); // - Get the module from the multiboot image // and map it (take a look at multiboot.c) @@ -633,9 +642,23 @@ errval_t spawn_load_argv(int argc, char *argv[], struct spawninfo *si, si->pid = ++spawn_last_pid; *pid = si->pid; + // add to process list + si->next = spawn_process_list; + spawn_process_list = si; + return SYS_ERR_OK; } +void spawn_parse_cmd(char *cmdline, int *argc, char **argv){ + *argc = 0; + char *token = strtok(cmdline, " "); + while (token != NULL) { + argv[*argc] = token; + token = strtok(NULL, " "); + *argc += 1; + } +} + /** * (M2): Implement this function. * \brief Spawn a new dispatcher executing 'binary_name' @@ -665,22 +688,13 @@ errval_t spawn_load_by_name(char *binary_name, struct spawninfo * si, // printf("raw_arguments_str: %s\n", raw_arguments_str); // afeer: explode the raw_arguments_str into argv - char * argv[MAX_CMDLINE_ARGS]; - int argc = 0; - char * token = strtok(raw_arguments_str, " "); - while (token != NULL) { - argv[argc] = token; - token = strtok(NULL, " "); - argc += 1; - } + char *argv[MAX_CMDLINE_ARGS]; + int argc; + spawn_parse_cmd(raw_arguments_str, &argc, argv); // - Call spawn_load_argv err = spawn_load_argv(argc, argv, si, pid); if (err_is_fail(err)) return err; - // add to process list - si->next = spawn_process_list; - spawn_process_list = si; - return SYS_ERR_OK; } diff --git a/usr/hello/hello.c b/usr/hello/hello.c index 50d3d89..27ac44f 100644 --- a/usr/hello/hello.c +++ b/usr/hello/hello.c @@ -22,6 +22,7 @@ #include #define HELLO_CATCH_COMMAND "catch" +#define HELLO_SPAWN_COMMAND "spawn" int main(int argc, char *argv[]) { @@ -40,6 +41,32 @@ int main(int argc, char *argv[]) err = aos_rpc_send_string(rpc, "Hello World via RPC!"); if (err_is_fail(err)) USER_PANIC_ERR(err, "Failed to send RPC"); + // try to spawn a child using rpc + if (argc > 1 && !strncmp(argv[1], HELLO_SPAWN_COMMAND, sizeof(HELLO_SPAWN_COMMAND))) { + // start process + domainid_t pid; + rpc = aos_rpc_get_process_channel(); + err = aos_rpc_process_spawn(rpc, "hello Aurel Jan Sandro", 0, &pid); + if (err_is_fail(err)) USER_PANIC_ERR(err, "Failed to spawn process"); + printf("Started a new process!\n"); + + // get process name + char *name; + err = aos_rpc_process_get_name(rpc, pid, &name); + if (err_is_fail(err)) USER_PANIC_ERR(err, "Failed to get process name"); + printf("Process Name: %s\n", name); + + // get all PIDs + domainid_t *pids; + size_t pid_count; + err = aos_rpc_process_get_all_pids(rpc, &pids, &pid_count); + if (err_is_fail(err)) USER_PANIC_ERR(err, "Failed to get all PIDs"); + printf("PIDs:\n"); + for(size_t i = 0; i < pid_count; ++i) { + printf(" %lu\n", pids[i]); + } + } + // if we receive the catch command, RUN! if (argc > 1 && !strncmp(argv[1], HELLO_CATCH_COMMAND, sizeof(HELLO_CATCH_COMMAND))) { int iter = 0;