From 96e5d8dc99010e2cec8bd2edf59545bd13f6f769 Mon Sep 17 00:00:00 2001 From: Kimplul Date: Sat, 28 May 2022 14:08:12 +0300 Subject: start implementing new proc/rpc handling + Essentially, separate root process and remote procedure call handling. I really should write down some documentation so I don't forget, but essentially: All threads share a common process virtual memory, and when a thread wants to make an rpc, it switches over to its own rpc vmem space that is linked to the remote process. --- common/dmem.c | 24 ++++++++++--- common/elf.c | 5 ++- common/proc.c | 4 +-- common/tcb.c | 91 ++++++++++++++++++++++++++++++++++++++------------ common/uapi/dispatch.c | 2 ++ common/vmem.c | 32 ++++++++++-------- 6 files changed, 114 insertions(+), 44 deletions(-) (limited to 'common') diff --git a/common/dmem.c b/common/dmem.c index 1d5608c..8bd9da3 100644 --- a/common/dmem.c +++ b/common/dmem.c @@ -5,6 +5,7 @@ * \todo Handle NUMA. */ +#include #include static struct mem_region_root pre_ram = { 0 }; @@ -61,6 +62,8 @@ stat_t dev_free_wrapper(struct vmem *b, pm_t *offset, vm_t vaddr, vm_t alloc_devmem(struct tcb *t, pm_t dev_start, size_t bytes, vmflags_t flags) { + hard_assert(t && is_proc(t), ERR_INVAL); + vm_t region = 0; if (dev_start < __pre_top) region = alloc_region(&pre_ram, bytes, 0, flags); @@ -71,14 +74,22 @@ vm_t alloc_devmem(struct tcb *t, pm_t dev_start, size_t bytes, vmflags_t flags) if (!region) return 0; - return map_fill_region(t->b_r, &dev_alloc_wrapper, dev_start, region, - bytes, flags, 0); + stat_t status = OK; + const vm_t w = map_fill_region(t->proc.vmem, &dev_alloc_wrapper, + dev_start, region, + bytes, flags, &status); + if (is_rpc(t) && status == INFO_SEFF) + clone_rpc_maps(t); + + return w; } stat_t free_devmem(struct tcb *t, vm_t dev_start) { + hard_assert(t && is_proc(t), ERR_INVAL); + pm_t dev_paddr = 0; - stat_vpage(t->b_r, dev_start, &dev_paddr, 0, 0); + stat_vpage(t->proc.vmem, dev_start, &dev_paddr, 0, 0); if (dev_paddr >= __pre_top && dev_paddr <= __post_base) return ERR_ADDR; @@ -94,8 +105,11 @@ stat_t free_devmem(struct tcb *t, vm_t dev_start) return ERR_NF; size_t region_size = __addr(m->end - m->start); - map_fill_region(t->b_r, &dev_free_wrapper, dev_paddr, dev_start, - region_size, 0, 0); + stat_t status = OK; + map_fill_region(t->proc.vmem, &dev_free_wrapper, dev_paddr, dev_start, + region_size, 0, &status); + if (is_rpc(t) && status == INFO_SEFF) + clone_rpc_maps(t); if (dev_paddr < __pre_top) free_region(&pre_ram, dev_paddr); diff --git a/common/elf.c b/common/elf.c index b88be89..88c5ddc 100644 --- a/common/elf.c +++ b/common/elf.c @@ -7,6 +7,7 @@ #include #include #include +#include static uint8_t __elf_to_uvflags(uint8_t elf_flags) { @@ -27,6 +28,8 @@ static uint8_t __elf_to_uvflags(uint8_t elf_flags) static void __map_exec(struct tcb *t, vm_t bin, uint8_t ei_c, vm_t phstart, size_t phnum, size_t phsize) { + hard_assert(t && is_proc(t), RETURN_VOID); + /* TODO: take alignment into consideration? */ /* TODO: take overlapping memory regions into account, probably mostly * by keeping track of previously allocated area and seeing if the @@ -51,7 +54,7 @@ static void __map_exec(struct tcb *t, vm_t bin, uint8_t ei_c, vm_t phstart, uint8_t elf_flags = program_header_prop(ei_c, runner, p_flags); uint8_t uvflags = __elf_to_uvflags(elf_flags); - map_allocd_region(t->b_r, start, vsz, default_flags, 0); + map_allocd_region(t->proc.vmem, start, vsz, default_flags, 0); vm_t vo = bin + program_header_prop(ei_c, runner, p_offset); vm_t vfz = program_header_prop(ei_c, runner, p_filesz); diff --git a/common/proc.c b/common/proc.c index 3f6da6d..bf8a4d1 100644 --- a/common/proc.c +++ b/common/proc.c @@ -18,7 +18,7 @@ stat_t prepare_proc(struct tcb *t, vm_t bin, vm_t interp) return ERR_INVAL; alloc_stacks(t); - prepare_thread(t); + set_thread(t, t->thread_stack_top); set_return(entry); return OK; } @@ -34,7 +34,7 @@ stat_t init_proc(void *fdt) /* set current tcb */ use_tcb(t); - use_vmem(t->b_r); + use_vmem(t->proc.vmem); /* allocate stacks after ELF file to make sure nothing of importance * clashes */ diff --git a/common/tcb.c b/common/tcb.c index 0809829..84218dc 100644 --- a/common/tcb.c +++ b/common/tcb.c @@ -63,7 +63,8 @@ static vm_t __setup_call_stack(struct tcb *t, size_t bytes) vmflags_t flags = VM_V | VM_R | VM_W | VM_U; for (size_t i = 1; i <= pages; ++i) { offset = alloc_page(BASE_PAGE, offset); - map_vpage(t->b_r, offset, PROC_STACK_TOP - BASE_PAGE_SIZE * i, + map_vpage(t->proc.vmem, offset, + PROC_STACK_TOP - BASE_PAGE_SIZE * i, flags, BASE_PAGE); } @@ -77,20 +78,21 @@ static vm_t __setup_thread_stack(struct tcb *t, size_t bytes) stat_t alloc_stacks(struct tcb *t) { - struct tcb *p = is_proc(t) ? t : t->proc; + /* get parent process */ + struct tcb *p = get_tcb(t->eid); t->thread_stack = __setup_thread_stack(p, __thread_stack_size); if (!t->thread_stack) return ERR_OOMEM; - t->call_stack = __setup_call_stack(p, __call_stack_size); - if (!t->call_stack) + /* call stack always starts at the same place in vmem. + * TODO: is this a security issue? */ + if (!__setup_call_stack(p, __call_stack_size)) return ERR_OOMEM; /* TODO: this only allows for a global stack size, what if a user wants * per thread stack sizes? */ t->thread_stack_top = t->thread_stack + __thread_stack_size; - t->call_stack_top = t->call_stack + __call_stack_size; return OK; } @@ -112,14 +114,17 @@ struct tcb *create_thread(struct tcb *p) if (likely(p)) { t->pid = p->pid; - t->proc = p; + t->proc.vmem = p->proc.vmem; } else { init_uvmem(t, UVMEM_START, UVMEM_END); + t->proc.vmem = create_vmem(); t->pid = t->tid; p = t; } - t->b_r = create_vmem(); + t->eid = t->pid; + t->rid = p->rid; + t->rpc.vmem = create_vmem(); return t; } @@ -149,13 +154,15 @@ struct tcb *create_proc(struct tcb *p) static stat_t __destroy_thread_data(struct tcb *t) { - /* free vmem */ - destroy_vmem(t->b_r); + /* free rpc vmem */ + destroy_vmem(t->rpc.vmem); /* free associated kernel stack and the structure itself */ vm_t bottom = align_down((vm_t)t, __o_size(MM_O0)); free_page(MM_O0, (pm_t)bottom); + /* TODO: free stacks */ + return OK; } @@ -168,11 +175,7 @@ stat_t destroy_thread(struct tcb *t) tcbs[t->tid] = 0; /* remove thread from process list */ - if (t->next) - t->next->prev = t->prev; - - if (t->prev) - t->prev->next = t->next; + detach_proc(get_rproc(t), t); return __destroy_thread_data(t); } @@ -182,13 +185,47 @@ stat_t destroy_proc(struct tcb *p) hard_assert(tcbs, ERR_NOINIT); hard_assert(is_proc(p), ERR_INVAL); - for (struct tcb *iter = p; (iter = iter->next);) + for (struct tcb *iter = p; (iter = iter->proc.next);) destroy_thread(iter); catastrophic_assert(destroy_uvmem(p)); return __destroy_thread_data(p); } +#define DEFINE_ATTACH(name, type) \ + stat_t name(struct tcb *r, struct tcb *t) \ + { \ + hard_assert(r != t, ERR_INVAL); \ + struct tcb *next = r->type.next; \ + t->type.next = next; \ +\ + if (next) { next->type.prev = t; } \ +\ + t->type.prev = r; \ + r->type.next = t; \ + return OK; \ + } + +DEFINE_ATTACH(attach_rpc, rpc); +DEFINE_ATTACH(attach_proc, proc); + +#define DEFINE_DETACH(name, type) \ + stat_t name(struct tcb *r, struct tcb *t) \ + { \ + MAYBE_UNUSED(r); \ + hard_assert(r != t, ERR_INVAL); \ + struct tcb *prev = t->type.prev; \ + struct tcb *next = t->type.next; \ +\ + if (prev) { prev->type.next = next; } \ + if (next) { next->type.prev = prev; } \ +\ + return OK; \ + } + +DEFINE_DETACH(detach_rpc, rpc); +DEFINE_DETACH(detach_proc, proc); + struct tcb *cur_tcb() { return cpu_tcb[cpu_id()]; @@ -197,10 +234,7 @@ struct tcb *cur_tcb() struct tcb *cur_proc() { struct tcb *t = cur_tcb(); - if (likely(is_proc(t))) - return t; - else - return t->proc; + return get_tcb(t->eid); } void use_tcb(struct tcb *t) @@ -215,12 +249,25 @@ struct tcb *get_tcb(id_t tid) return tcbs[tid]; } -stat_t clone_tcb_maps(struct tcb *r) +stat_t clone_rpc_maps(struct tcb *r) +{ + hard_assert(r && is_proc(r), ERR_INVAL); + struct tcb *t = r; + while ((t = t->rpc.next)) { + stat_t ret = clone_uvmem(r->proc.vmem, t->rpc.vmem); + if (ret) + return ret; + } + + return OK; +} + +stat_t clone_proc_maps(struct tcb *r) { hard_assert(r && is_proc(r), ERR_INVAL); struct tcb *t = r; - while ((t = t->next)) { - stat_t ret = clone_uvmem(r->b_r, t->b_r); + while ((t = t->proc.next)) { + stat_t ret = clone_uvmem(r->proc.vmem, t->proc.vmem); if (ret) return ret; } diff --git a/common/uapi/dispatch.c b/common/uapi/dispatch.c index 924a0ed..df211d5 100644 --- a/common/uapi/dispatch.c +++ b/common/uapi/dispatch.c @@ -3,6 +3,7 @@ * Syscall dispatch. */ +#include #include static const sys_t syscall_table[] = { @@ -39,6 +40,7 @@ static const sys_t syscall_table[] = { }; SYSCALL_DEFINE0(noop)(){ + info("sys_noop\n"); return (struct sys_ret){ OK, 0 }; } diff --git a/common/vmem.c b/common/vmem.c index 74701d8..230620f 100644 --- a/common/vmem.c +++ b/common/vmem.c @@ -19,7 +19,7 @@ static stat_t __free_mapped_region(struct tcb *t, struct mem_region *m) { stat_t status = OK; pm_t pa = __addr(m->end - m->start); - if (unmap_freed_region(t->b_r, m->start, pa, m->flags, &status)) + if (unmap_freed_region(t->proc.vmem, m->start, pa, m->flags, &status)) return ERR_MISC; return status; @@ -56,9 +56,13 @@ vm_t alloc_uvmem(struct tcb *t, size_t size, vmflags_t flags) stat_t status = OK; const vm_t v = alloc_region(&t->sp_r, size, &size, flags); - const vm_t w = map_allocd_region(t->b_r, v, size, flags, &status); - if (status == INFO_SEFF) - clone_tcb_maps(t); + const vm_t w = map_allocd_region(t->proc.vmem, v, size, flags, &status); + /* TODO: this could be changed so that each thread allocated the memory + * region for itself to start with, and only when someone tries to + * access it from some other thread, is it actually cloned. Would likely + * need some major reworkings, so this is good enough for now. */ + if (is_rpc(t) && status == INFO_SEFF) + clone_rpc_maps(t); return w; } @@ -69,10 +73,10 @@ vm_t alloc_fixed_uvmem(struct tcb *t, vm_t start, size_t size, vmflags_t flags) stat_t status = OK; const vm_t v = alloc_fixed_region(&t->sp_r, start, size, &size, flags); - const vm_t w = map_allocd_region(t->b_r, v, size, flags, &status); + const vm_t w = map_allocd_region(t->proc.vmem, v, size, flags, &status); - if (status == INFO_SEFF) - clone_tcb_maps(t); + if (is_rpc(t) && status == INFO_SEFF) + clone_rpc_maps(t); return w; } @@ -85,10 +89,10 @@ vm_t alloc_shared_uvmem(struct tcb *t, size_t size, vmflags_t flags) stat_t status = OK; const vm_t v = alloc_region(&t->sp_r, size, &size, flags | MR_SHARED | MR_OWNED); - const vm_t w = map_shared_region(t->b_r, v, size, flags, &status); + const vm_t w = map_shared_region(t->proc.vmem, v, size, flags, &status); - if (status == INFO_SEFF) - clone_tcb_maps(t); + if (is_rpc(t) && status == INFO_SEFF) + clone_rpc_maps(t); return w; } @@ -110,8 +114,8 @@ vm_t ref_shared_uvmem(struct tcb *t1, struct tcb *t2, vm_t va, vmflags_t flags) vm_t runner = v; for (; pages; --pages) { pm_t paddr; - stat_vpage(t1->b_r, v, &paddr, 0, 0); - map_vpage(t2->b_r, paddr, runner, flags, MM_O0); + stat_vpage(t1->proc.vmem, v, &paddr, 0, 0); + map_vpage(t2->proc.vmem, paddr, runner, flags, MM_O0); runner += __o_size(MM_O0); } @@ -128,8 +132,8 @@ stat_t free_uvmem(struct tcb *t, vm_t va) free_region(&t->sp_r, va); stat_t status = __free_mapped_region(t, m); - if (status == INFO_SEFF) - return clone_tcb_maps(t); + if (is_rpc(t) && status == INFO_SEFF) + return clone_rpc_maps(t); return status; } -- cgit v1.3