diff --git a/lib/aos/aos_rpc.c b/lib/aos/aos_rpc.c index 12ac19e..1ae2361 100644 --- a/lib/aos/aos_rpc.c +++ b/lib/aos/aos_rpc.c @@ -26,6 +26,8 @@ static errval_t do_aos_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 ) { + assert(rpc != NULL); + errval_t err; // Allocate slot if we expect a capability. diff --git a/lib/spawn/spawn.c b/lib/spawn/spawn.c index 3fdce19..22b1855 100644 --- a/lib/spawn/spawn.c +++ b/lib/spawn/spawn.c @@ -347,8 +347,72 @@ static errval_t spawn_serialize_vspace(struct spawninfo *si, struct paging_state return SYS_ERR_OK; } +static errval_t spawn_load_elf_from_fs(char *path, char **elf_base, size_t *elf_bytes) { + int res; + debug_printf("[spawn_load_elf_from_fs] %s\n", path); + // open the file + FILE *f = fopen(path, "r"); + if (f == NULL) return FS_ERR_OPEN; + + // get the number of bytes in the elf + res = fseek (f , 0 , SEEK_END); + if (res != 0) return FS_ERR_INVALID_FH; + *elf_bytes = ftell(f); + + // go back to the start so we can load to memory + rewind (f); + + // allocate the memory to load the elf + *elf_base = malloc(*elf_bytes); + if(*elf_base == NULL) return LIB_ERR_MALLOC_FAIL; + + // load the elf to memory + debug_printf("[spawn_load_elf_from_fs] reading elf file with %lu bytes\n", *elf_bytes); + size_t read_bytes = fread(*elf_base, 1, *elf_bytes, f); + if (read_bytes != *elf_bytes) return FS_ERR_READ; + + // close the file + res = fclose(f); + if (res != 0) return FS_ERR_CLOSE; + + return SYS_ERR_OK; +} + +static errval_t spawn_load_elf_from_multiboot(char *name, char **elf_base, size_t *elf_bytes) { + errval_t err; + + debug_printf("[spawn_load_elf_from_multiboot] %s\n", name); + + struct mem_region *module = multiboot_find_module(bi, name); + if (module == NULL) return SPAWN_ERR_FIND_MODULE; + *elf_bytes = module->mrmod_size; + + // Get the frame of the ELF + struct capref child_frame = { + .cnode = cnode_module, + .slot = module->mrmod_slot, + }; + + struct capability c; + err = cap_direct_identify(child_frame, &c); + if (err_is_fail(err)) return err; + gensize_t frame_size = get_size(&c); + if (frame_size < *elf_bytes) return SPAWN_ERR_MODULE_FRAME_TOO_SMALL; + + // Map the ELF into the current address space + err = paging_map_frame_attr( + get_current_paging_state(), (void **)elf_base, + frame_size, child_frame, VREGION_FLAGS_READ + ); + if (err_is_fail(err)) return err_push(err, SPAWN_ERR_MAP_MODULE); + + debug_printf("SPAWN: multiboot mapped %s, size: %"PRIuPTR", magic: %"PRIx8" %c%c%c\n", + name, *elf_bytes, (*elf_base)[0], (*elf_base)[1], (*elf_base)[2], (*elf_base)[3]); + + return SYS_ERR_OK; +} /** * (M2): Implement this function. @@ -410,32 +474,18 @@ errval_t spawn_load_argv(int argc, char *argv[], struct spawninfo *si, // } // printf("\n"); - struct mem_region *module = multiboot_find_module(bi, argv[0]); - if (module == NULL) return SPAWN_ERR_FIND_MODULE; - size_t elf_bytes = module->mrmod_size; - - // Get the frame of the ELF - struct capref child_frame = { - .cnode = cnode_module, - .slot = module->mrmod_slot, - }; - - struct capability c; - err = cap_direct_identify(child_frame, &c); - if (err_is_fail(err)) return err; - gensize_t frame_size = get_size(&c); - if (frame_size < elf_bytes) return SPAWN_ERR_MODULE_FRAME_TOO_SMALL; - - // Map the ELF into the current address space - char *elf_base; - err = paging_map_frame_attr( - get_current_paging_state(), (void **)&elf_base, - frame_size, child_frame, VREGION_FLAGS_READ - ); - if (err_is_fail(err)) return err_push(err, SPAWN_ERR_MAP_MODULE); - - debug_printf("SPAWN: mapped %s, size: %"PRIuPTR", magic: %"PRIx8" %c%c%c\n", - argv[0], elf_bytes, elf_base[0], elf_base[1], elf_base[2], elf_base[3]); + // if we get an absolute path then we load from the file system, otherwise from the multiboot + bool is_multiboot = argv[0][0] != '/'; + char *elf_base = NULL; + size_t elf_bytes = 0; + if (is_multiboot) { + err = spawn_load_elf_from_multiboot(argv[0], &elf_base, &elf_bytes); + } else { + err = spawn_load_elf_from_fs(argv[0], &elf_base, &elf_bytes); + } + if(err_is_fail(err)) return err; + assert(elf_base != NULL); + assert(elf_bytes != 0); // - Setup the child's cspace @@ -565,8 +615,13 @@ errval_t spawn_load_argv(int argc, char *argv[], struct spawninfo *si, // debug_printf("SPAWN: self paging state after loading:\n"); // pt_print_state(get_current_paging_state()); - err = paging_unmap(get_current_paging_state(), elf_base); - if (err_is_fail(err)) return err_push(err, LIB_ERR_PMAP_UNMAP); + if (is_multiboot) { + err = paging_unmap(get_current_paging_state(), elf_base); + if (err_is_fail(err)) return err_push(err, LIB_ERR_PMAP_UNMAP); + } else { + // cleanup elf buffer + free(elf_base); + } while (st.temp_mapping_head != NULL) { struct temp_mapping *tm = st.temp_mapping_head; err = paging_unmap(get_current_paging_state(), tm->addr); diff --git a/usr/init/Hakefile b/usr/init/Hakefile index dc1e393..7658acc 100644 --- a/usr/init/Hakefile +++ b/usr/init/Hakefile @@ -21,7 +21,7 @@ ], addLinkFlags = [ "-e _start_init"], -- this is only needed for init addLibraries = [ "mm", "getopt", "elf", "spawn", - "grading"], + "grading", "fs" ], architectures = allArchitectures } ] diff --git a/usr/init/main.c b/usr/init/main.c index fc00ff1..8208fb0 100644 --- a/usr/init/main.c +++ b/usr/init/main.c @@ -33,6 +33,8 @@ #include #include #include +#include +#include struct bootinfo *bi; @@ -64,6 +66,118 @@ static errval_t ram_alloc_remote_core(struct capref *ret, size_t size, size_t al return SYS_ERR_OK; } +static errval_t +initialize_self_rpc(void) { + errval_t err; + // we establish an rpc channel to ourselves so init can use UMP + // if we had plenty of time we could have done some nice abstraction over the + // rpc interface to do this but here we are + + struct capref rpc_shared_frame; + err = frame_alloc(&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( + get_current_paging_state(), &rpc_shared_memory, + RPC_SHARED_SIZE, rpc_shared_frame); + if (err_is_fail(err)) { + cap_delete(rpc_shared_frame); + return err; + } + + // server side + struct lmp_chan *self_chan_server = malloc(sizeof(struct lmp_chan)); + if (self_chan_server == NULL) return LIB_ERR_MALLOC_FAIL; + lmp_chan_init(self_chan_server); + err = endpoint_create(DEFAULT_LMP_BUF_WORDS, &self_chan_server->local_cap, &self_chan_server->endpoint); + if (err_is_fail(err)) return err_push(err, LIB_ERR_ENDPOINT_CREATE); + err = lmp_chan_alloc_recv_slot(self_chan_server); + if (err_is_fail(err)) return err_push(err, LIB_ERR_LMP_ALLOC_RECV_SLOT); + + // client side + + struct lmp_chan *self_chan_client = malloc(sizeof(struct lmp_chan)); + if (self_chan_client == NULL) return LIB_ERR_MALLOC_FAIL; + lmp_chan_init(self_chan_client); + err = endpoint_create(DEFAULT_LMP_BUF_WORDS, &self_chan_client->local_cap, &self_chan_client->endpoint); + if (err_is_fail(err)) return err_push(err, LIB_ERR_ENDPOINT_CREATE); + err = lmp_chan_alloc_recv_slot(self_chan_server); + if (err_is_fail(err)) return err_push(err, LIB_ERR_LMP_ALLOC_RECV_SLOT); + + self_chan_server->remote_cap = self_chan_client->local_cap; + self_chan_client->remote_cap = self_chan_server->local_cap; + struct aos_rpc_server *rpc_server = malloc(sizeof(struct aos_rpc_server)); + if (rpc_server == NULL) return LIB_ERR_MALLOC_FAIL; + rpc_server_init(rpc_server, self_chan_server, rpc_shared_memory); + rpc_server_register_recv(rpc_server); + + // set init rpc + struct aos_rpc *init_rpc = malloc(sizeof(struct aos_rpc)); + err = aos_rpc_init(init_rpc, self_chan_client, rpc_shared_memory); + if (err_is_fail(err)){ + return err_push(err, ERR_NOTIMP); + } + /* set init RPC client in our program state */ + set_init_rpc(init_rpc); + + return SYS_ERR_OK; +} + +static bool event_dispatching_active = false; +static int dispatch_on_waitset(void *arg) { + struct waitset *ws = arg; + while (event_dispatching_active) { + errval_t err = event_dispatch(ws); + if (err_is_fail(err)) { + DEBUG_ERR(err, "in event_dispatch"); + abort(); + } + } + return 0; +} + +static void noop_callback(void *arg) { +} + +__attribute__((__unused__)) +static struct waitset_chanstate self_rpc_waitset_chan; +static errval_t init_fs(void) { + errval_t err; + + // debug_printf("[init_fs]\n"); + + // create a thread dispatching so RPC works + event_dispatching_active = true; + struct thread *init_fs_dispatcher = thread_create_varstack_alloc(dispatch_on_waitset, get_default_waitset(), THREADS_DEFAULT_STACK_BYTES); + if (init_fs_dispatcher == NULL) return LIB_ERR_THREAD_CREATE; + + // initialize the filesystem + err = filesystem_init(); + if (err_is_fail(err)) return err; + + // debug_printf("[init_fs] filesystem_init done\n"); + + // wait for the dispatcher to finish + event_dispatching_active = false; + // give the dispatcher a skip + waitset_chanstate_init(&self_rpc_waitset_chan, CHANTYPE_OTHER); + err = waitset_chan_trigger_closure( + get_default_waitset(), + &self_rpc_waitset_chan, + MKCLOSURE(noop_callback, NULL) + ); + if (err_is_fail(err)) return err; + err = thread_join(init_fs_dispatcher, NULL); + if (err_is_fail(err)) return err; + + // debug_printf("[init_fs] done\n"); + + return SYS_ERR_OK; +} + static int bsp_main(int argc, char *argv[]) { errval_t err; @@ -127,10 +241,6 @@ bsp_main(int argc, char *argv[]) { 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); - // err = coreboot(2, "boot_armv8_generic", cpu_driver_name, "init", urpc_frame_id); - // if (err_is_fail(err)) return err_push(err, MON_ERR_SPAWN_CORE); - // 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); struct aos_urpc_frame *urpc = urpc_addr; @@ -162,6 +272,19 @@ bsp_main(int argc, char *argv[]) { DEBUG_ERR(err, "when spawning enet"); } + // requried to connect to UMP channels from init + err = initialize_self_rpc(); + if (err_is_fail(err)) { + DEBUG_ERR(err, "in initialize_self_rpc"); + abort(); + } + + // initialize the file system so it is available for spawning processes + err = init_fs(); + if (err_is_fail(err)) { + DEBUG_ERR(err, "when initializing the file system"); + } + // Grading grading_test_late(); @@ -324,6 +447,17 @@ app_main(int argc, char *argv[]) { DEBUG_ERR(err, "when spawning echoserver"); } + err = initialize_self_rpc(); + if (err_is_fail(err)) { + DEBUG_ERR(err, "in initialize_self_rpc"); + abort(); + } + + err = init_fs(); + if (err_is_fail(err)) { + DEBUG_ERR(err, "when initializing the file system"); + } + // Grading grading_test_late();