aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2024-11-02 16:02:41 +0200
committerKimplul <kimi.h.kuparinen@gmail.com>2024-11-02 16:02:41 +0200
commit21efbba39340300a7ba9d5f4f94017f5ff956833 (patch)
treec9116d4e38a574a8edae7cdcebcd7569af9cb5a7
parentd127146846f4d6561e15000d1469b715dafdb627 (diff)
downloadkmi-21efbba39340300a7ba9d5f4f94017f5ff956833.tar.gz
kmi-21efbba39340300a7ba9d5f4f94017f5ff956833.zip
intial working sys_spawn
-rw-r--r--include/kmi/regions.h9
-rw-r--r--src/elf.c29
-rw-r--r--src/proc.c4
-rw-r--r--src/uapi/proc.c20
-rw-r--r--src/vmem.c2
-rw-r--r--tests/common/sys.h2
-rw-r--r--tests/spawn/init.c34
-rw-r--r--tests/spawn/source.mk1
-rw-r--r--tests/spawn/spawn.c18
9 files changed, 96 insertions, 23 deletions
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, &region_size, flags);
+ vm_t v = alloc_fixed_region(&t->uvmem.region, va, vaz, &region_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 <common/test.h>
+#include <common/cpio.h>
+
+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 <common/test.h>
+
+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();
+}