From 21efbba39340300a7ba9d5f4f94017f5ff956833 Mon Sep 17 00:00:00 2001 From: Kimplul Date: Sat, 2 Nov 2024 16:02:41 +0200 Subject: intial working sys_spawn --- include/kmi/regions.h | 9 +++++++++ src/elf.c | 29 ++++++++++++++--------------- src/proc.c | 4 ++-- src/uapi/proc.c | 20 ++++++++++++++++---- src/vmem.c | 2 +- tests/common/sys.h | 2 +- tests/spawn/init.c | 34 ++++++++++++++++++++++++++++++++++ tests/spawn/source.mk | 1 + tests/spawn/spawn.c | 18 ++++++++++++++++++ 9 files changed, 96 insertions(+), 23 deletions(-) create mode 100644 tests/spawn/init.c create mode 100644 tests/spawn/source.mk create mode 100644 tests/spawn/spawn.c diff --git a/include/kmi/regions.h b/include/kmi/regions.h index 74d4387..fe263ae 100644 --- a/include/kmi/regions.h +++ b/include/kmi/regions.h @@ -236,6 +236,15 @@ struct mem_region *find_first_region(struct mem_region_root *r); */ struct mem_region *find_used_region(struct mem_region_root *r, vm_t start); +/** + * Find used memory region inside which \p addr is. + * Note the significant difference from \ref find_used_region which requires the + * address to exactly match the start of a region. + * + * @param r Memory region root. + * @param addr Address to look for. + * @return Pointer to owning memory region or \c NULL if no such exists. + */ struct mem_region *find_addr_region(struct mem_region_root *r, vm_t addr); /** diff --git a/src/elf.c b/src/elf.c index 2cdcb8b..23f9b95 100644 --- a/src/elf.c +++ b/src/elf.c @@ -34,12 +34,13 @@ static uint8_t __elf_to_uvflags(uint8_t elf_flags) } static stat_t __elf_map_section(struct tcb *t, - vm_t va, size_t vaz, - vm_t vf, size_t vfz, - uint8_t flags) + vm_t va, size_t vaz, + vm_t vf, size_t vfz, + uint8_t flags) { size_t region_size; - vm_t v = alloc_fixed_region(&t->uvmem.region, va, vaz, ®ion_size, flags); + vm_t v = alloc_fixed_region(&t->uvmem.region, va, vaz, ®ion_size, + flags); if (!v) return ERR_INVAL; @@ -59,7 +60,9 @@ static stat_t __elf_map_section(struct tcb *t, memcpy((void *)page, (void *)(vf + runner), z); } - if (map_vpage(t->proc.vmem, page, va + runner, flags, BASE_PAGE)) { + if (map_vpage(t->proc.vmem, + page, va + runner, + flags, BASE_PAGE)) { free_page(BASE_PAGE, page); return ERR_OOMEM; } @@ -77,17 +80,16 @@ static stat_t __elf_map_section(struct tcb *t, * @param phstart Program header start. * @param phnum Number of program header entries. * @param phsize Size of page header entry. + * @param OK on success, something else otherwise. */ static stat_t __map_exec(struct tcb *t, - vm_t bin, - uint8_t ei_c, - vm_t phstart, - size_t phnum, - size_t phsize) + vm_t bin, + uint8_t ei_c, + vm_t phstart, + size_t phnum, + size_t phsize) { assert(t && is_proc(t)); - /* temporarily visit process virtual memory */ - use_vmem(t->proc.vmem); /* create empty vmem so we don't have to worry about possible overlaps */ struct vmem *new_vmem = create_vmem(); @@ -106,7 +108,6 @@ static stat_t __map_exec(struct tcb *t, destroy_vmem(new_vmem); t->uvmem = old_uvmem; t->proc.vmem = old_vmem; - use_vmem(t->rpc.vmem); return ERR_OOMEM; } @@ -133,7 +134,6 @@ static stat_t __map_exec(struct tcb *t, t->proc.vmem = old_vmem; t->uvmem = old_uvmem; - use_vmem(t->rpc.vmem); return ERR_OOMEM; } } @@ -146,7 +146,6 @@ static stat_t __map_exec(struct tcb *t, t->proc.vmem = new_vmem; t->uvmem = new_uvmem; - use_vmem(t->rpc.vmem); return OK; } diff --git a/src/proc.c b/src/proc.c index c1dfc64..090ae20 100644 --- a/src/proc.c +++ b/src/proc.c @@ -25,8 +25,6 @@ stat_t prepare_proc(struct tcb *t, vm_t bin, vm_t interp) return ERR_INVAL; t->callback = entry; - set_thread(t); - set_return(t, entry); return OK; } @@ -56,6 +54,8 @@ stat_t init_proc(void *fdt, vm_t *proc_fdt, vm_t *proc_initrd) * save them here before we switch */ use_tcb(t); + set_thread(t); + set_return(t, t->callback); set_stack(t, t->rpc_stack - BASE_PAGE_SIZE); stat_t ret = prepare_proc(t, get_init_base(fdt), 0); diff --git a/src/uapi/proc.c b/src/uapi/proc.c index 8d90687..51a1252 100644 --- a/src/uapi/proc.c +++ b/src/uapi/proc.c @@ -128,7 +128,11 @@ SYSCALL_DEFINE2(exec)(struct tcb *t, sys_arg_t bin, sys_arg_t interp) if (prepare_proc(t, bin, interp)) return_args1(t, ERR_INVAL); + set_thread(t); + set_return(t, t->callback); set_ret4(t, 0, t->tid, SYS_USER_SPAWNED, t->pid); + + flush_tlb_full(); } /** @@ -150,16 +154,24 @@ SYSCALL_DEFINE2(spawn)(struct tcb *t, sys_arg_t bin, sys_arg_t interp) if (!n) return_args1(t, ERR_OOMEM); - /** @todo copy over bin and interp into new process, this is not enough */ n->notify_id = c->notify_id; - stat_t ret = OK; - if ((ret = prepare_proc(n, bin, interp))) { + if (prepare_proc(n, bin, interp)) { /* this kills the thread */ orphanize(t); unorphanize(t); - return_args1(t, ret); + return_args1(t, ERR_INVAL); } + /** @todo should permissions be transferred? Probably, not but now there + * is a slightly annoying asymmetry between fork+exec vs spawn... */ + + /* temporarily switch to new thread to manipulate stack */ + use_tcb(n); + set_thread(n); + set_return(n, n->callback); + set_ret4(n, 0, n->tid, SYS_USER_SPAWNED, n->pid); + use_tcb(t); + return_args1(t, n->pid); } diff --git a/src/vmem.c b/src/vmem.c index 2752d23..76e0ece 100644 --- a/src/vmem.c +++ b/src/vmem.c @@ -330,7 +330,7 @@ vm_t map_shared_fixed_uvmem(struct tcb *t, pm_t start, size_t size, assert(is_aligned(start, BASE_PAGE_SIZE)); const vm_t v = alloc_shared_region(&t->uvmem.region, - size, &size, flags, 0); + size, &size, flags, 0); if (!v) return 0; diff --git a/tests/common/sys.h b/tests/common/sys.h index 3e98abf..0bee8bd 100644 --- a/tests/common/sys.h +++ b/tests/common/sys.h @@ -240,7 +240,7 @@ static inline enum sys_status sys_exec(uintptr_t bin, uintptr_t interp) /* negative IDs mean errors */ static inline id_t sys_spawn(uintptr_t bin, uintptr_t interp) { - struct sys_ret r = syscall2(SYS_EXEC, bin, interp); + struct sys_ret r = syscall2(SYS_SPAWN, bin, interp); return r.s; } diff --git a/tests/spawn/init.c b/tests/spawn/init.c new file mode 100644 index 0000000..8c25615 --- /dev/null +++ b/tests/spawn/init.c @@ -0,0 +1,34 @@ +#include +#include + +START(pid, tid, d0, d1, d2, d3) +{ + UNUSED(pid); + UNUSED(tid); + UNUSED(d0); + UNUSED(d1); + UNUSED(d2); + UNUSED(d3); + + check(pid == 0, "illegal pid for init\n"); + printf("finding spawn in cpio archive %lx...\n", d2); + struct cpio_header *cp = cpio_find_file((const void *)d2, + "spawn", sizeof("spawn") - 1); + + check(cp, "couldn't find spawn?\n"); + long name_len = convnum(cp->c_namesize, 8, 16); + uintptr_t spawn = (uintptr_t)(cp) + align_up(sizeof(struct cpio_header) + name_len, 4); + printf("found spawn at %lx\n", spawn); + + printf("doing spawn...\n"); + id_t new = sys_spawn(spawn, 0); + check(new > 1, "spawn failed?\n"); + + printf("giving spawn CAP_POWER\n"); + enum sys_status s = sys_set_cap(new, CAP_POWER); + check(s == OK, "CAP_POWER failed?\n"); + + printf("swapping to spawn\n"); + s = sys_swap(new); + check(s == OK, "swap to spawn failed?\n"); +} diff --git a/tests/spawn/source.mk b/tests/spawn/source.mk new file mode 100644 index 0000000..9a1f676 --- /dev/null +++ b/tests/spawn/source.mk @@ -0,0 +1 @@ +DO != ./scripts/gen-simple -n spawn -p init -p spawn diff --git a/tests/spawn/spawn.c b/tests/spawn/spawn.c new file mode 100644 index 0000000..67d64f8 --- /dev/null +++ b/tests/spawn/spawn.c @@ -0,0 +1,18 @@ +#include + +START(pid, tid, d0, d1, d2, d3) +{ + UNUSED(d2); + UNUSED(d3); + + printf("pid = %ld, tid = %ld, d0 = %ld, d1 = %ld\n", + pid, tid, d0, d1); + + check(pid == 0, "unexpected pid for spawn\n"); + check(tid == 2, "unexpected tid for spawn\n"); + check(d0 == SYS_USER_SPAWNED, "unexpected d0 for spawn\n"); + check(d1 == 2, "unexpected d1 for spawn\n"); + + printf("causing shutdown, assuming init gave us CAP_POWER\n"); + ok(); +} -- cgit v1.3