Added ELF loading from filesystem

This commit is contained in:
Sparchatus 2022-06-01 10:07:35 +00:00
parent 0334dd73b7
commit 255af3f38c
4 changed files with 224 additions and 33 deletions

View File

@ -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.

View File

@ -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);

View File

@ -21,7 +21,7 @@
],
addLinkFlags = [ "-e _start_init"], -- this is only needed for init
addLibraries = [ "mm", "getopt", "elf", "spawn",
"grading"],
"grading", "fs" ],
architectures = allArchitectures
}
]

View File

@ -33,6 +33,8 @@
#include <barrelfish_kpi/startup_arm.h>
#include <aos/performance.h>
#include <aos/deferred.h>
#include <fs/fs.h>
#include <aos/waitset_chan.h>
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();