Added ELF loading from filesystem
This commit is contained in:
parent
0334dd73b7
commit
255af3f38c
@ -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.
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
],
|
||||
addLinkFlags = [ "-e _start_init"], -- this is only needed for init
|
||||
addLibraries = [ "mm", "getopt", "elf", "spawn",
|
||||
"grading"],
|
||||
"grading", "fs" ],
|
||||
architectures = allArchitectures
|
||||
}
|
||||
]
|
||||
|
||||
142
usr/init/main.c
142
usr/init/main.c
@ -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();
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user