diff options
| -rw-r--r-- | TCB.txt | 4 | ||||
| -rw-r--r-- | TODO.txt | 4 | ||||
| -rw-r--r-- | arch/riscv64/kernel/entry.S | 7 | ||||
| -rw-r--r-- | arch/riscv64/kernel/vmem.c | 23 | ||||
| -rw-r--r-- | common/dmem.c | 17 | ||||
| -rw-r--r-- | common/elf.c | 2 | ||||
| -rw-r--r-- | common/mem_regions.c | 5 | ||||
| -rw-r--r-- | common/tcb.c | 15 | ||||
| -rw-r--r-- | common/uapi/ipc.c | 2 | ||||
| -rw-r--r-- | common/vmem.c | 71 | ||||
| -rw-r--r-- | include/apos/assert.h | 42 | ||||
| -rw-r--r-- | include/apos/dmem.h | 4 | ||||
| -rw-r--r-- | include/apos/mem.h | 2 | ||||
| -rw-r--r-- | include/apos/mem_regions.h | 7 | ||||
| -rw-r--r-- | include/apos/tcb.h | 5 | ||||
| -rw-r--r-- | include/apos/types.h | 3 | ||||
| -rw-r--r-- | include/apos/vmem.h | 18 | ||||
| -rw-r--r-- | include/arch/vmem.h | 2 |
18 files changed, 182 insertions, 51 deletions
@@ -14,3 +14,7 @@ elevated to a process is a new one allocated. Only when the last thread in a process is released is the memory released. Will still need to figure out exactly how device memory should be freed, since it's handled globally instead of per thread atm. + +Also, I suspect I may have made my life a bit too difficult with different sized +pages, as I'm having a hell of a time figuring out how `fork` should be +implemented :D @@ -2,7 +2,7 @@ + Implement more type operators in dbg, mainly intmax/uintmax and size_t -+ Add in mapping the same memory to two different processes ++ Add in mapping the same memory to two different processes (sort of?) + Create sensible thread handling + Add in init process loading + Make sure vmap is in 4K increments or whatever (fuck it, sure) @@ -14,7 +14,7 @@ details dumbass + Primarily memory should be allocated to a process through mmap-like functionality, but brk/sbrk can probably still be emulated. If s/brk maps memory that's later attempted to mmap, it fails, and vice versa. Apparently should be -acceptable by Unix standards. +acceptable by Unix standards. (or just make brk in libc a noop?) + Alignment can maybe still be used, though more in the sense of using larger pages? YES, CHECK common/vmem.c:map_fill_region! Should be implemented there as well diff --git a/arch/riscv64/kernel/entry.S b/arch/riscv64/kernel/entry.S index 0ff1a69..7f697b5 100644 --- a/arch/riscv64/kernel/entry.S +++ b/arch/riscv64/kernel/entry.S @@ -74,8 +74,11 @@ handle_exception: j restore_all handle_syscall: - /* TODO: CSR_EPC should be moved forward one instruction when dealing - * with syscalls */ + /* add 4 (size of ecall) to EPC to avoid running the same instruction + * twice */ + csrr s0, CSR_SEPC + addi s0, s0, 4 + csrw CSR_SEPC, s0 jal syscall_dispatch /* if we had a thread switch, load kernel stack of current thread and * restore its context */ diff --git a/arch/riscv64/kernel/vmem.c b/arch/riscv64/kernel/vmem.c index 46ddf29..7ffde86 100644 --- a/arch/riscv64/kernel/vmem.c +++ b/arch/riscv64/kernel/vmem.c @@ -45,10 +45,17 @@ static pm_t *__find_vmem(struct vm_branch *b, vm_t v, enum mm_order *o) stat_t mod_vpage(struct vm_branch *branch, vm_t vaddr, pm_t paddr, vmflags_t flags) { - pm_t *pte = __find_vmem(branch, vaddr, 0); + enum mm_order order; + pm_t *pte = __find_vmem(branch, vaddr, &order); if (pte) { *pte = to_pte((pm_t)__pa(paddr), vp_flags(flags)); - return OK; + /* if we're modifying a top level mapping, we will have to + * update the same one for all the other threads in this process + * */ + if (order == __mm_max_order) + return INFO_SEFF; + else + return OK; } return ERR_NF; @@ -115,7 +122,8 @@ stat_t map_vpage(struct vm_branch *branch, pm_t paddr, vm_t vaddr, branch->leaf[idx] = (struct vm_branch *)to_pte((pm_t)__pa(paddr), vp_flags(flags)); - return OK; + + return top == __mm_max_order ? INFO_SEFF : OK; } stat_t unmap_vpage(struct vm_branch *branch, vm_t vaddr) @@ -191,3 +199,12 @@ vm_t setup_kernel_io(struct vm_branch *b, vm_t paddr) return -SZ_1G + paddr - (gigapage * MM_GPAGE_SIZE); } #endif + +stat_t clone_vmbranch(struct vm_branch *r, struct vm_branch *b) +{ + /* TODO: error checking? */ + for (size_t i = 0; i <= CSTACK_PAGE; ++i) + b->leaf[i] = r->leaf[i]; + + return OK; +} diff --git a/common/dmem.c b/common/dmem.c index 59ea666..6c207c1 100644 --- a/common/dmem.c +++ b/common/dmem.c @@ -27,15 +27,17 @@ stat_t init_devmem(pm_t ram_base, pm_t ram_top) } stat_t dev_alloc_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr, - vmflags_t flags, enum mm_order order) + vmflags_t flags, enum mm_order order, void *data) { - map_vpage(b, *offset, vaddr, flags, order); + stat_t *status = (stat_t *)data; + /* TODO: remember to do something with this status info */ + *status = map_vpage(b, *offset, vaddr, flags, order); *offset += __o_size(order); return OK; } stat_t dev_free_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr, - vmflags_t flags, enum mm_order order) + vmflags_t flags, enum mm_order order, void *data) { UNUSED(offset); UNUSED(flags); @@ -43,9 +45,10 @@ stat_t dev_free_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr, enum mm_order v_order = 0; stat_vpage(b, vaddr, &paddr, &v_order, 0); if (order != v_order) - return REGION_TRY_AGAIN; + return INFO_TRGN; - unmap_vpage(b, vaddr); + stat_t *status = (stat_t *)data; + *status = unmap_vpage(b, vaddr); return OK; } @@ -62,7 +65,7 @@ vm_t alloc_devmem(struct tcb *t, pm_t dev_start, size_t bytes, vmflags_t flags) return 0; return map_fill_region(t->b_r, &dev_alloc_wrapper, dev_start, region, - bytes, flags); + bytes, flags, 0); } stat_t free_devmem(struct tcb *t, vm_t dev_start) @@ -85,7 +88,7 @@ stat_t free_devmem(struct tcb *t, vm_t dev_start) 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); + region_size, 0, 0); if (dev_paddr < __pre_top) free_region(&pre_ram, dev_paddr); diff --git a/common/elf.c b/common/elf.c index 459cacf..9af4f08 100644 --- a/common/elf.c +++ b/common/elf.c @@ -46,7 +46,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); + map_allocd_region(t->b_r, 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/mem_regions.c b/common/mem_regions.c index b0cbe0e..bbc894e 100644 --- a/common/mem_regions.c +++ b/common/mem_regions.c @@ -426,7 +426,8 @@ stat_t free_known_region(struct mem_region_root *r, struct mem_region *m) * permutations etc. which would be slow and I don't want to implement it. */ vm_t map_fill_region(struct vm_branch *b, region_callback_t *mem_handler, - pm_t offset, vm_t start, size_t bytes, vmflags_t flags) + pm_t offset, vm_t start, size_t bytes, vmflags_t flags, + void *data) { pm_t runner = __page(start); size_t pages = __pages(bytes); @@ -447,7 +448,7 @@ vm_t map_fill_region(struct vm_branch *b, region_callback_t *mem_handler, while (pages >= o_pages) { stat_t res = mem_handler(b, &offset, __addr(runner), - flags, top); + flags, top, data); if (res > 0) break; diff --git a/common/tcb.c b/common/tcb.c index bb1bcec..212e20f 100644 --- a/common/tcb.c +++ b/common/tcb.c @@ -4,7 +4,9 @@ #include <apos/pmem.h> #include <apos/nodes.h> #include <apos/types.h> +#include <apos/assert.h> #include <apos/string.h> +#include <arch/vmem.h> /* arguably exessively many globals... */ static id_t start_tid; @@ -98,3 +100,16 @@ struct tcb *get_tcb(id_t tid) return tcbs[tid]; } + +stat_t clone_tcb_maps(struct tcb *r) +{ + hard_assert(r && !r->parent, ERR_INVAL); + struct tcb *t = r; + while ((t = t->next)) { + stat_t ret = clone_vmbranch(r->b_r, t->b_r); + if (ret) + return ret; + } + + return OK; +} diff --git a/common/uapi/ipc.c b/common/uapi/ipc.c index bef9665..d7c9d16 100644 --- a/common/uapi/ipc.c +++ b/common/uapi/ipc.c @@ -14,7 +14,7 @@ SYSCALL_DEFINE1(ipc_server)(sys_arg_t callback) SYSCALL_DEFINE3(ipc_req)(sys_arg_t tid, sys_arg_t d0, sys_arg_t d1) { struct tcb *r = get_tcb(tid); - /* something like jump_to_callback(t, d0, d1) */ + /* something like jump_to_callback(t) */ return (struct sys_ret){ d0, d1 }; } diff --git a/common/vmem.c b/common/vmem.c index 989029a..817f851 100644 --- a/common/vmem.c +++ b/common/vmem.c @@ -1,4 +1,6 @@ #include <apos/mem_regions.h> +#include <apos/assert.h> +#include <apos/debug.h> #include <apos/bits.h> #include <apos/vmem.h> #include <arch/vmem.h> @@ -10,23 +12,46 @@ stat_t init_uvmem(struct tcb *t, vm_t base, vm_t top) vm_t alloc_uvmem(struct tcb *t, size_t size, vmflags_t flags) { - vm_t v = alloc_region(&t->sp_r, size, &size, flags); - return map_allocd_region(t->b_r, v, size, flags); + /* t exists and is the root tcb of the current process */ + hard_assert(t && !t->parent, ERR_INVAL); + + 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); + + return w; } vm_t alloc_fixed_uvmem(struct tcb *t, vm_t start, size_t size, vmflags_t flags) { - vm_t v = alloc_fixed_region(&t->sp_r, start, size, &size, flags); - return map_allocd_region(t->b_r, v, size, flags); + hard_assert(t && !t->parent, ERR_INVAL); + + 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); + + if (status == INFO_SEFF) + clone_tcb_maps(t); + + return w; } /* free_shared_uvmem shouldn't be needed, likely to work with free_uvmem */ vm_t alloc_shared_uvmem(struct tcb *t, size_t size, vmflags_t flags) { - /* TODO: proper error handling */ - vm_t v = alloc_region(&t->sp_r, size, &size, - flags | MR_SHARED | MR_OWNED); - return map_shared_region(t->b_r, v, size, flags); + hard_assert(t && t->parent, ERR_INVAL); + + 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); + + if (status == INFO_SEFF) + clone_tcb_maps(t); + + return w; } vm_t ref_shared_uvmem(struct tcb *t1, struct tcb *t2, vm_t va, vmflags_t flags) @@ -54,6 +79,7 @@ vm_t ref_shared_uvmem(struct tcb *t1, struct tcb *t2, vm_t va, vmflags_t flags) return v; } +/* TODO: assume tcb is root tcb? */ stat_t free_uvmem(struct tcb *t, vm_t va) { struct mem_region *m = find_used_region(&t->sp_r, va); @@ -64,26 +90,31 @@ stat_t free_uvmem(struct tcb *t, vm_t va) vmflags_t flags = m->flags; free_region(&t->sp_r, va); - unmap_freed_region(t->b_r, va, pa, flags); - return 0; + + stat_t status = OK; + unmap_freed_region(t->b_r, va, pa, flags, &status); + if (status == INFO_SEFF) + return clone_tcb_maps(t); + + return status; } stat_t alloc_uvmem_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr, - vmflags_t flags, enum mm_order order) + vmflags_t flags, enum mm_order order, void *data) { *offset = alloc_page(order, *offset); if (!*offset) - return REGION_TRY_AGAIN; /* try again */ + return INFO_TRGN; /* try again */ - map_vpage(b, *offset, vaddr, flags, order); - return OK; + stat_t ret = map_vpage(b, *offset, vaddr, flags, order); + return ret; } stat_t alloc_shared_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr, - vmflags_t flags, enum mm_order order) + vmflags_t flags, enum mm_order order, void *data) { if (order != MM_O0) - return REGION_TRY_AGAIN; + return INFO_TRGN; *offset = alloc_page(MM_O0, *offset); map_vpage(b, *offset, vaddr, flags, order); @@ -91,7 +122,7 @@ stat_t alloc_shared_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr, } stat_t free_uvmem_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr, - vmflags_t flags, enum mm_order order) + vmflags_t flags, enum mm_order order, void *data) { UNUSED(flags); UNUSED(offset); @@ -100,11 +131,13 @@ stat_t free_uvmem_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr, enum mm_order v_order = 0; stat_vpage(b, vaddr, &paddr, &v_order, 0); if (order != v_order) - return REGION_TRY_AGAIN; + return INFO_TRGN; - unmap_vpage(b, vaddr); + stat_t *status = (stat_t *)data; + *status = unmap_vpage(b, vaddr); /* don't free shared pages, unless they're owned */ if (!__is_set(flags, MR_SHARED) || __is_set(flags, MR_OWNED)) free_page(order, paddr); + return OK; } diff --git a/include/apos/assert.h b/include/apos/assert.h new file mode 100644 index 0000000..7200fd2 --- /dev/null +++ b/include/apos/assert.h @@ -0,0 +1,42 @@ +#ifndef APOS_ASSERT_H +#define APOS_ASSERT_H + +#include <apos/debug.h> +#include <apos/utils.h> + +/* TODO: should this exit or do something explosive like that? */ +#if !defined(DNDEBUG) +#define catastrophic_assert(x) \ + do { \ + if (x) { \ + err("catastrophic assertion failed: %s\n", QUOTE(x)); \ + while (1) \ + ; \ + } \ + } while (0); + +#define hard_assert(x, r) \ + do { \ + if (x) { \ + warn("hard assertion failed: %s\n", QUOTE(x)); \ + return r; \ + } \ + } while (0); + +#define soft_assert(x) \ + do { \ + if (x) { \ + info("soft assertion failed: %s\n", QUOTE(x)); \ + } \ + } while (0); +#else +#define catastrophic_assert(x) +#define hard_assert(x, r) +#define soft_assert(x) +#endif + +/* use when return value doesn't exist, like hard_assert(x, + * RETURN_VOID); */ +#define RETURN_VOID + +#endif /* APOS_ASSERT_H */ diff --git a/include/apos/dmem.h b/include/apos/dmem.h index d337e61..3ee93b6 100644 --- a/include/apos/dmem.h +++ b/include/apos/dmem.h @@ -14,8 +14,8 @@ vm_t alloc_devmem(struct tcb *t, pm_t dev_start, size_t bytes, vmflags_t flags); stat_t free_devmem(struct tcb *t, vm_t dev_start); stat_t dev_free_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr, - vmflags_t flags, enum mm_order t); + vmflags_t flags, enum mm_order t, void *); stat_t dev_alloc_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr, - vmflags_t flags, enum mm_order t); + vmflags_t flags, enum mm_order t, void *); #endif /* APOS_DEV_H */ diff --git a/include/apos/mem.h b/include/apos/mem.h index bc60f21..f3eded7 100644 --- a/include/apos/mem.h +++ b/include/apos/mem.h @@ -45,6 +45,8 @@ #define MR_SHARED (1 << 9) /* owner of shared region */ #define MR_OWNED (1 << 10) +/* copy on write */ +#define MR_COW (1 << 11) extern size_t __mm_shifts[10]; extern size_t __mm_widths[10]; diff --git a/include/apos/mem_regions.h b/include/apos/mem_regions.h index 7841dde..efe0592 100644 --- a/include/apos/mem_regions.h +++ b/include/apos/mem_regions.h @@ -41,11 +41,12 @@ struct mem_region *find_closest_used_region(struct mem_region_root *r, struct mem_region *find_free_region(struct mem_region_root *r, size_t size, size_t *align); -#define REGION_TRY_AGAIN 1 typedef stat_t region_callback_t(struct vm_branch *b, pm_t *offset, vm_t vaddr, - vmflags_t flags, enum mm_order order); + vmflags_t flags, enum mm_order order, + void *data); vm_t map_fill_region(struct vm_branch *b, region_callback_t *mem_handler, - pm_t offset, vm_t start, size_t bytes, vmflags_t flags); + pm_t offset, vm_t start, size_t bytes, vmflags_t flags, + void *data); #endif /* APOS_MEM_REGIONS_H */ diff --git a/include/apos/tcb.h b/include/apos/tcb.h index 821d822..11e1b5a 100644 --- a/include/apos/tcb.h +++ b/include/apos/tcb.h @@ -28,6 +28,9 @@ struct tcb { /* vm root branch */ struct vm_branch *b_r; + + struct tcb *parent; + struct tcb *next; }; void init_tcbs(); @@ -41,4 +44,6 @@ void use_tcb(struct tcb *); struct tcb *get_tcb(id_t tid); +stat_t clone_tcb_maps(struct tcb *); + #endif /* APOS_TCB_H */ diff --git a/include/apos/types.h b/include/apos/types.h index d413957..2f45857 100644 --- a/include/apos/types.h +++ b/include/apos/types.h @@ -197,6 +197,9 @@ enum { ERR_ALIGN = -2, /* wrong alignment */ ERR_NF = -1, /* not found */ OK = 0, /* OK */ + INFO_TRGN = 1, /* try again */ + INFO_SEFF = 2, /* side effects */ + INFO_CONT = 3, /* continue */ }; #include <types.h> /* arch-specific type definitions (pm_t/vm_t etc) */ diff --git a/include/apos/vmem.h b/include/apos/vmem.h index 17f998d..f1b0d19 100644 --- a/include/apos/vmem.h +++ b/include/apos/vmem.h @@ -15,20 +15,20 @@ stat_t free_uvmem(struct tcb *r, vm_t a); stat_t init_uvmem(struct tcb *r, vm_t base, vm_t top); stat_t alloc_uvmem_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr, - vmflags_t flags, enum mm_order order); + vmflags_t flags, enum mm_order order, void *data); stat_t alloc_shared_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr, - vmflags_t flags, enum mm_order order); + vmflags_t flags, enum mm_order order, void *data); stat_t free_uvmem_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr, - vmflags_t flags, enum mm_order order); + vmflags_t flags, enum mm_order order, void *data); -#define map_allocd_region(b, start, bytes, flags) \ - map_fill_region(b, &alloc_uvmem_wrapper, 0, start, bytes, flags) +#define map_allocd_region(b, start, bytes, flags, data) \ + map_fill_region(b, &alloc_uvmem_wrapper, 0, start, bytes, flags, data) -#define map_shared_region(b, start, bytes, flags) \ - map_fill_region(b, &alloc_shared_wrapper, 0, start, bytes, flags) +#define map_shared_region(b, start, bytes, flags, data) \ + map_fill_region(b, &alloc_shared_wrapper, 0, start, bytes, flags, data) -#define unmap_freed_region(b, start, bytes, flags) \ - map_fill_region(b, &free_uvmem_wrapper, 0, start, bytes, flags) +#define unmap_freed_region(b, start, bytes, flags, data) \ + map_fill_region(b, &free_uvmem_wrapper, 0, start, bytes, flags, data) #define vm_flags(x) ((x) & ~0xff) #define vp_flags(x) ((x)&0xff) diff --git a/include/arch/vmem.h b/include/arch/vmem.h index 182af11..74b0aa5 100644 --- a/include/arch/vmem.h +++ b/include/arch/vmem.h @@ -23,4 +23,6 @@ struct vm_branch *init_vmem(void *fdt); vm_t setup_kernel_io(struct vm_branch *b, vm_t paddr); #endif +stat_t clone_vmbranch(struct vm_branch *, struct vm_branch *); + #endif /* APOS_ARCH_PAGES_H */ |
