diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2022-12-01 02:05:19 +0200 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2022-12-01 02:05:19 +0200 |
| commit | 131af4eec38752a27e6e56579fbf76178e022ec1 (patch) | |
| tree | 1940634f69a44395fc6945b25c5cbc8b68bba876 | |
| parent | e25f1e7a8f8f2320546ad4950464713d85b47785 (diff) | |
| download | kmi-131af4eec38752a27e6e56579fbf76178e022ec1.tar.gz kmi-131af4eec38752a27e6e56579fbf76178e022ec1.zip | |
start looking into memory handling
+ Now 10M alloc/frees succeed, which totals more memory than the virtual
machine has, so no too obvious leaks are occuring. For future
debugging speed, changed 10M to 1M.
+ Also quick fix to rpcs, stacks are now assigned. Not entirely sure why
they worked before this, but good that I found it.
| -rwxr-xr-x | arch/riscv64/conf/init | bin | 2720 -> 5088 bytes | |||
| -rw-r--r-- | arch/riscv64/conf/init.c | 31 | ||||
| -rw-r--r-- | arch/riscv64/conf/initrd | bin | 3072 -> 5632 bytes | |||
| -rw-r--r-- | arch/riscv64/kernel/proc.c | 7 | ||||
| -rw-r--r-- | common/mem_regions.c | 8 | ||||
| -rw-r--r-- | common/tcb.c | 10 | ||||
| -rw-r--r-- | common/uapi/ipc.c | 5 | ||||
| -rw-r--r-- | common/uapi/mem.c | 47 | ||||
| -rw-r--r-- | common/vmem.c | 10 | ||||
| -rw-r--r-- | include/apos/syscalls.h | 3 | ||||
| -rw-r--r-- | include/apos/tcb.h | 5 | ||||
| -rw-r--r-- | include/apos/uapi.h | 8 | ||||
| -rw-r--r-- | include/arch/proc.h | 9 |
13 files changed, 90 insertions, 53 deletions
diff --git a/arch/riscv64/conf/init b/arch/riscv64/conf/init Binary files differindex eba8186..0d99b80 100755 --- a/arch/riscv64/conf/init +++ b/arch/riscv64/conf/init diff --git a/arch/riscv64/conf/init.c b/arch/riscv64/conf/init.c index de9814e..4cd4cea 100644 --- a/arch/riscv64/conf/init.c +++ b/arch/riscv64/conf/init.c @@ -18,6 +18,7 @@ */ #include <stdint.h> +#include <stddef.h> #include "../../../include/apos/syscalls.h" struct sys_ret { @@ -184,6 +185,27 @@ static void sys_poweroff(long type) ecall(r); } +static void *sys_req_mem(size_t count) +{ + struct sys_ret r = {.a0 = SYS_REQ_MEM, .a1 = count, + .a2 = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 4)}; + r = ecall(r); + + if (r.a0) + print_value("sys_req_mem() failed with error ", r.a0); + + return (void *)r.a1; +} + +static void sys_free_mem(void *p) +{ + struct sys_ret r = {.a0 = SYS_FREE_MEM, .a1 = (long)p}; + r = ecall(r); + + if (r.a0) + print_value("sys_free_mem() failed with error ", r.a0); +} + void callback(long status, long tid, long d0, long d1, long d2, long d3) { (void)status; @@ -244,12 +266,19 @@ void _start() csr_read(CSR_TIME, i); start = i; n = 0; while (i < start + second) { - sys_ipc_req(1, d0, d1, d2, d3); + sys_ipc_req(1, n, d1, d2, d3); csr_read(CSR_TIME, i); n++; } print_value("IPC requests per second", n); + puts("Doing memory allocations...\n"); + for (i = 0; i < 1000000; ++i) { + char *p = sys_req_mem(10); + *p = 'c'; + sys_free_mem(p); + } + sys_poweroff(0); } diff --git a/arch/riscv64/conf/initrd b/arch/riscv64/conf/initrd Binary files differindex 905bbfe..8d36a5a 100644 --- a/arch/riscv64/conf/initrd +++ b/arch/riscv64/conf/initrd diff --git a/arch/riscv64/kernel/proc.c b/arch/riscv64/kernel/proc.c index 0f19789..d58b41b 100644 --- a/arch/riscv64/kernel/proc.c +++ b/arch/riscv64/kernel/proc.c @@ -63,6 +63,13 @@ void set_thread(struct tcb *t) r->tp = (long)t->thread_storage; } +void set_stack(struct tcb *t, vm_t s) +{ + /** @todo also set frame pointer on architectures that need it? */ + struct riscv_regs *r = (struct riscv_regs *)(t->regs) - 1; + r->sp = s; +} + vm_t get_stack(struct tcb *t) { struct riscv_regs *r = (struct riscv_regs *)(t->regs) - 1; diff --git a/common/mem_regions.c b/common/mem_regions.c index 8d066e7..eee9230 100644 --- a/common/mem_regions.c +++ b/common/mem_regions.c @@ -185,13 +185,15 @@ stat_t destroy_region(struct mem_region_root *r) * */ struct mem_region *find_used_region(struct mem_region_root *r, vm_t start) { + /** @todo check that start is aligned to page boundary? */ + vm_t ref = __page(start); struct sp_node *n = sp_root(&r->used_regions); while (n) { struct mem_region *t = mem_container(n); - if (start == t->start) + if (ref == t->start) return t; - if (start < t->start) + if (ref < t->start) n = sp_left(n); else n = sp_right(n); @@ -500,7 +502,7 @@ stat_t free_region(struct mem_region_root *r, vm_t start) if (!is_aligned(start, BASE_PAGE_SIZE)) return ERR_ALIGN; - struct mem_region *m = find_used_region(r, __page(start)); + struct mem_region *m = find_used_region(r, start); if (!m) return ERR_NF; diff --git a/common/tcb.c b/common/tcb.c index ef15788..fb2f934 100644 --- a/common/tcb.c +++ b/common/tcb.c @@ -435,7 +435,7 @@ struct call_ctx { id_t pid; }; -void save_context(struct tcb *t) +void enter_rpc(struct tcb *t) { vm_t rpc_stack = t->rpc_stack; if (is_rpc(t)) @@ -447,6 +447,10 @@ void save_context(struct tcb *t) rpc_stack = align_down(get_stack(t), BASE_PAGE_SIZE); + /* make sure updates are visible when swapping to the new virtual memory */ + mark_rpc_inaccessible(t, rpc_stack, t->rpc_stack); + use_vmem(t->rpc.vmem); + struct call_ctx *ctx = (struct call_ctx *)(rpc_stack) - 1; ctx->exec = t->exec; ctx->pid = t->pid; @@ -468,12 +472,12 @@ void save_context(struct tcb *t) * we'll handle it separately and if the process isn't going over the * limit just give it more. * */ - mark_rpc_inaccessible(t, rpc_stack, t->rpc_stack); t->rpc_stack = rpc_stack; t->regs = (vm_t)ctx; + set_stack(t, rpc_stack); } -void load_context(struct tcb *t) +void leave_rpc(struct tcb *t) { vm_t rpc_stack = t->rpc_stack + BASE_PAGE_SIZE; struct call_ctx *ctx = (struct call_ctx *)(rpc_stack) - 1; diff --git a/common/uapi/ipc.c b/common/uapi/ipc.c index 93717e4..70f5fe7 100644 --- a/common/uapi/ipc.c +++ b/common/uapi/ipc.c @@ -60,8 +60,7 @@ static void do_ipc(struct tcb *t, return_args(t, SYS_RET1(ERR_NOINIT)); clone_uvmem(r->proc.vmem, t->rpc.vmem); - use_vmem(t->rpc.vmem); - save_context(t); + enter_rpc(t); set_return(t, r->callback); attach_rpc(r, t); @@ -122,7 +121,7 @@ SYSCALL_DEFINE4(ipc_resp)(struct tcb *t, sys_arg_t d0, sys_arg_t d1, sys_arg_t d3) { struct tcb *r = get_cproc(t); - load_context(t); + leave_rpc(t); detach_rpc(r, t); if (is_rpc(t)) diff --git a/common/uapi/mem.c b/common/uapi/mem.c index 1de63f1..374bcbe 100644 --- a/common/uapi/mem.c +++ b/common/uapi/mem.c @@ -25,7 +25,8 @@ SYSCALL_DEFINE2(req_mem)(struct tcb *t, sys_arg_t size, sys_arg_t flags) { struct tcb *r = get_cproc(t); vm_t start = 0; - if ((start = alloc_uvmem(r, size, flags))) + /** @todo expose flags to users */ + if (!(start = alloc_uvmem(r, size, flags))) return_args(t, SYS_RET1(ERR_OOMEM)); return_args(t, SYS_RET2(OK, start)); @@ -46,7 +47,7 @@ SYSCALL_DEFINE3(req_fixmem)(struct tcb *t, sys_arg_t fixed, sys_arg_t size, { struct tcb *r = get_cproc(t); vm_t start = 0; - if ((start = alloc_fixed_uvmem(r, fixed, size, flags))) + if (!(start = alloc_fixed_uvmem(r, fixed, size, flags))) return_args(t, SYS_RET1(ERR_OOMEM)); return_args(t, SYS_RET2(OK, start)); @@ -65,15 +66,15 @@ SYSCALL_DEFINE1(free_mem)(struct tcb *t, sys_arg_t start) vm_t vm_start = (vm_t)start; stat_t status = OK; - if (vm_start > __pre_top && vm_start < __post_base) - status = free_uvmem(r, vm_start); - else - status = free_devmem(r, vm_start); + /* try freeing normal user memory first, if that fails, try device + * memory, otherwise just assume the address is borked. */ + if (!(status = free_uvmem(r, vm_start))) + return_args(t, SYS_RET1(OK)); - if (status) - return_args(t, SYS_RET1(ERR_NF)); + if (!(status = free_devmem(r, vm_start))) + return_args(t, SYS_RET1(OK)); - return_args(t, SYS_RET1(OK)); + return_args(t, SYS_RET1(status)); } /** @@ -96,7 +97,7 @@ SYSCALL_DEFINE3(req_pmem)(struct tcb *t, sys_arg_t paddr, sys_arg_t size, */ struct tcb *r = get_cproc(t); vm_t start = 0; - if ((start = alloc_devmem(r, paddr, size, flags))) + if (!(start = alloc_devmem(r, paddr, size, flags))) return_args(t, SYS_RET1(ERR_OOMEM)); return_args(t, SYS_RET2(OK, start)); @@ -110,34 +111,16 @@ SYSCALL_DEFINE3(req_pmem)(struct tcb *t, sys_arg_t paddr, sys_arg_t size, * @param flags Flags of allocation. * @return \ref OK and start of allocation when succesful, * \ref ERR_OOMEM and \c NULL otherwise. + * + * @todo should we also take the thread who should get the other end of the + * memory? */ SYSCALL_DEFINE2(req_sharedmem)(struct tcb *t, sys_arg_t size, sys_arg_t flags) { /** \todo check that requester is server */ struct tcb *r = get_cproc(t); vm_t start = 0; - if ((start = alloc_shared_uvmem(r, size, flags))) - return_args(t, SYS_RET1(ERR_OOMEM)); - - return_args(t, SYS_RET2(OK, start)); -} - -/** - * Reference shared memory syscall handler. - * - * @param t Current tcb. - * @param tid Thread ID of shared memory owner. - * @param va Start of shared memory in \c tid. - * @param flags Flags of reference. - * @return \ref OK and start of reference when succesful, - * \ref ERR_OOMEM and \c NULL otherwise. - */ -SYSCALL_DEFINE3(ref_sharedmem)(struct tcb *t, sys_arg_t tid, sys_arg_t va, - sys_arg_t flags) -{ - struct tcb *t2 = get_tcb(tid); - vm_t start = 0; - if ((start = ref_shared_uvmem(t, t2, va, flags))) + if (!(start = alloc_shared_uvmem(r, size, flags))) return_args(t, SYS_RET1(ERR_OOMEM)); return_args(t, SYS_RET2(OK, start)); diff --git a/common/vmem.c b/common/vmem.c index 56bc01a..a53ce6c 100644 --- a/common/vmem.c +++ b/common/vmem.c @@ -58,8 +58,10 @@ static stat_t __clone_mapped_region(struct tcb *d, struct tcb *s, 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->proc.vmem, m->start, pa, m->flags, &status)) + pm_t start = __addr(m->start); + pm_t end = __addr(m->end); + if (!unmap_freed_region(t->proc.vmem, start, end - start, m->flags, + &status)) return ERR_MISC; return status; @@ -196,13 +198,11 @@ stat_t free_uvmem(struct tcb *r, vm_t va) if (!m) return ERR_NF; - free_region(&r->sp_r, va); - stat_t status = __free_mapped_region(r, m); if (is_rpc(r) && status == INFO_SEFF) return clone_rpc_maps(r); - return status; + return free_known_region(&r->sp_r, m); } stat_t alloc_uvmem_wrapper(struct vmem *b, pm_t *offset, vm_t vaddr, diff --git a/include/apos/syscalls.h b/include/apos/syscalls.h index a5c805d..611765d 100644 --- a/include/apos/syscalls.h +++ b/include/apos/syscalls.h @@ -44,6 +44,9 @@ enum { /** Request memory at fixed virtual address. */ SYS_REQ_FIXMEM, + /** Request shared memory. */ + SYS_REQ_SHAREDMEM, + /** Free memory. */ SYS_FREE_MEM, /** @} */ diff --git a/include/apos/tcb.h b/include/apos/tcb.h index c56a2b3..9f10e2f 100644 --- a/include/apos/tcb.h +++ b/include/apos/tcb.h @@ -391,17 +391,18 @@ bool running(struct tcb *t); /** * Save thread context for rpc call. + * Assumes t->rpc is pointing to the correct virtual memory. * * @param t Thread whose context to save. */ -void save_context(struct tcb *t); +void enter_rpc(struct tcb *t); /** * Load thread context from rpc call. * * @param t Thread whose context to restore. */ -void load_context(struct tcb *t); +void leave_rpc(struct tcb *t); /** * Check that we have enough rpc stack. diff --git a/include/apos/uapi.h b/include/apos/uapi.h index 2a0dfcc..7bd00bb 100644 --- a/include/apos/uapi.h +++ b/include/apos/uapi.h @@ -363,15 +363,15 @@ SYSCALL_DECLARE3(req_fixmem, start, size, flags); * (server) frees it. * * @param t Current tcb. + * @param tid Thread to share memory with. * @param size Size of allocation. - * @param flags Flags of allocation. - * @param c Unused. - * @param d Unused. + * @param sflags Flags of allocation for server, that is \p t. + * @param cflags Flags of allocation for client, that is \p tid. * @param e Unused. * * Returns \ref OK and start of memory allocation. */ -SYSCALL_DECLARE2(req_sharedmem, size, flags); +SYSCALL_DECLARE4(req_sharedmem, tid, size, sflags, cflags); /** * Reference shared memory syscall. diff --git a/include/arch/proc.h b/include/arch/proc.h index 6a2c036..84954c0 100644 --- a/include/arch/proc.h +++ b/include/arch/proc.h @@ -49,6 +49,15 @@ struct sys_ret get_args(struct tcb *t); void set_thread(struct tcb *t); /** + * Set userspace stack. I think \ref set_thread() could be replaced with this, + * and it's more useful. + * + * @param t Thread whose stack to set. + * @param s Stack to give to thread. + */ +void set_stack(struct tcb *t, vm_t s); + +/** * Get current userspace stack. * * @param t Thread whose stack to query. |
