diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/debug.c | 4 | ||||
| -rw-r--r-- | src/tcb.c | 36 | ||||
| -rw-r--r-- | src/uapi/conf.c | 12 | ||||
| -rw-r--r-- | src/uapi/mem.c | 36 | ||||
| -rw-r--r-- | src/vmem.c | 131 |
5 files changed, 136 insertions, 83 deletions
diff --git a/src/debug.c b/src/debug.c index d87588d..950f73b 100644 --- a/src/debug.c +++ b/src/debug.c @@ -455,7 +455,7 @@ static size_t __print_sign(ssize_t value, size_t flags) * @return \see __integral_val(). */ #define __integral_len(value, base, flags) __integral_val((value), (base), \ - (flags), false) + (flags), false) /** * Print integral value as string. @@ -466,7 +466,7 @@ static size_t __print_sign(ssize_t value, size_t flags) * @return \see __integral_val(). */ #define __integral_print(value, base, flags) __integral_val((value), (base), \ - (flags), true) + (flags), true) /** * Print integral value. @@ -123,11 +123,14 @@ struct tcb *create_thread(struct tcb *p) assert(tcbs); vm_t bottom = alloc_page(KERNEL_STACK_PAGE_ORDER); + if (!bottom) + return NULL; + /* move tcb to top of kernel stack, keeping alignment in check * (hopefully) */ /** \todo check alignment */ - bottom = bottom + order_size(MM_O0) - sizeof(struct tcb); - struct tcb *t = (struct tcb *)align_down(bottom, sizeof(long)); + vm_t top = bottom + order_size(MM_O0) - sizeof(struct tcb); + struct tcb *t = (struct tcb *)align_down(top, sizeof(long)); memset(t, 0, sizeof(struct tcb)); id_t tid = __alloc_tid(t); @@ -141,9 +144,19 @@ struct tcb *create_thread(struct tcb *p) * structure, this works on riscv but in the event that other * systems don't we can easily turn this into a clone_uvmem. */ t->proc.vmem = p->proc.vmem; - } else { - t->proc.vmem = create_vmem(); - init_uvmem(t, UVMEM_START, UVMEM_END); + } + else { + if (!(t->proc.vmem = create_vmem())) { + free_page(MM_O0, bottom); + return NULL; + } + + if (init_uvmem(t)) { + destroy_vmem(t->proc.vmem); + free_page(MM_O0, bottom); + return NULL; + } + t->pid = t->tid; t->rid = t->tid; p = t; @@ -151,7 +164,16 @@ struct tcb *create_thread(struct tcb *p) t->eid = t->pid; t->rid = p->rid; - t->rpc.vmem = create_vmem(); + + if (!(t->rpc.vmem = create_vmem())) { + if (likely(p)) + return NULL; + + destroy_vmem(t->proc.vmem); + free_page(MM_O0, bottom); + return NULL; + } + setup_rpc_stack(t); reference_proc(p); @@ -191,7 +213,7 @@ struct tcb *create_proc(struct tcb *p) /* create a new thread outside the current process */ struct tcb *n = create_thread(NULL); if (!n) - return 0; + return NULL; if (p) __copy_proc(p, n); /* we have a parent process i.e. fork */ diff --git a/src/uapi/conf.c b/src/uapi/conf.c index 3a45d30..c8ec964 100644 --- a/src/uapi/conf.c +++ b/src/uapi/conf.c @@ -42,9 +42,10 @@ size_t rpc_stack_size() * * @param t Current tcb. * @param param Parameter to read. + * @param d0 Optional data argument for parameter. * @return \ref OK and parameter value. */ -SYSCALL_DEFINE1(conf_get)(struct tcb *t, sys_arg_t param) +SYSCALL_DEFINE2(conf_get)(struct tcb *t, sys_arg_t param, sys_arg_t d0) { /* anyone can read any current parameter, I don't think they should be * hidden. */ @@ -66,6 +67,15 @@ SYSCALL_DEFINE1(conf_get)(struct tcb *t, sys_arg_t param) val = get_ram_size(); break; + case CONF_PAGE_SIZE: + if (d0 < 0 || d0 > max_order()) { + val = 0; + break; + } + + val = order_size(d0); + break; + default: return_args1(t, ERR_NF); } diff --git a/src/uapi/mem.c b/src/uapi/mem.c index 49370fc..b4b2df8 100644 --- a/src/uapi/mem.c +++ b/src/uapi/mem.c @@ -24,10 +24,10 @@ 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; flags = sanitize_uvflags(flags); - if (!(start = alloc_uvmem(r, size, flags))) - return_args1(t, ERR_OOMEM); + vm_t start = alloc_uvmem(r, size, flags); + if (ERR_CODE(start)) + return_args1(t, start); return_args2(t, OK, start); } @@ -47,10 +47,10 @@ SYSCALL_DEFINE3(req_fixmem)(struct tcb *t, sys_arg_t fixed, sys_arg_t size, sys_arg_t flags) { struct tcb *r = get_cproc(t); - vm_t start = 0; flags = sanitize_uvflags(flags); - if (!(start = alloc_fixed_uvmem(r, fixed, size, flags))) - return_args1(t, ERR_OOMEM); + vm_t start = alloc_fixed_uvmem(r, fixed, size, flags); + if (ERR_CODE(start)) + return_args1(t, start); return_args2(t, OK, start); } @@ -97,10 +97,10 @@ SYSCALL_DEFINE3(req_pmem)(struct tcb *t, sys_arg_t paddr, sys_arg_t size, * that keeps track of used regions outside of RAM. We'll see. */ struct tcb *r = get_cproc(t); - vm_t start = 0; flags = sanitize_uvflags(flags); - if (!(start = alloc_devmem(r, paddr, size, flags))) - return_args1(t, ERR_OOMEM); + vm_t start = alloc_devmem(r, paddr, size, flags); + if (ERR_CODE(start)) + return_args1(t, start); return_args2(t, OK, start); } @@ -127,8 +127,9 @@ SYSCALL_DEFINE2(req_page)(struct tcb *t, sys_arg_t size, sys_arg_t flags) vm_t start = 0; size_t asize = 0; flags = sanitize_uvflags(flags); - if (!(start = alloc_uvpage(r, size, flags, &addr, &asize))) - return_args1(t, ERR_OOMEM); + start = alloc_uvpage(r, size, flags, &addr, &asize); + if (ERR_CODE(start)) + return_args1(t, start); return_args4(t, OK, start, addr, asize); } @@ -148,10 +149,10 @@ SYSCALL_DEFINE2(req_sharedmem)(struct tcb *t, sys_arg_t size, sys_arg_t flags) if (!has_cap(c->caps, CAP_SHARED)) return_args1(t, ERR_PERM); - vm_t start = 0; flags = sanitize_uvflags(flags); - if (!(start = alloc_shared_uvmem(c, size, flags))) - return_args1(t, ERR_OOMEM); + vm_t start = alloc_shared_uvmem(c, size, flags); + if (ERR_CODE(start)) + return_args1(t, start); return_args3(t, OK, start, size); } @@ -178,10 +179,11 @@ SYSCALL_DEFINE3(ref_sharedmem)(struct tcb *t, sys_arg_t tid, sys_arg_t addr, if (!r || zombie(r)) return_args1(t, ERR_INVAL); - vm_t start = 0; size_t size = 0; + size_t size = 0; flags = sanitize_uvflags(flags); - if (!(start = ref_shared_uvmem(r, c, addr, flags))) - return_args1(t, ERR_OOMEM); + vm_t start = ref_shared_uvmem(r, c, addr, flags); + if (ERR_CODE(start)) + return_args1(t, start); return_args3(t, OK, start, size); } @@ -14,11 +14,23 @@ #include <kmi/vmem.h> #include <arch/vmem.h> -stat_t init_uvmem(struct tcb *t, vm_t base, vm_t top) +stat_t init_uvmem(struct tcb *t) { t->uvmem.owner = t->tid; t->uvmem.vmem = t->proc.vmem; - return init_region(&t->uvmem.region, base, top); + + stat_t ret = OK; + if ((ret = init_region(&t->uvmem.region, UVMEM_START, UVMEM_END))) + return ret; + + /* if a user really wants to use the first page for something, they'll + * have to free it first, 'accepting' that no null-page is dangerous. */ + size_t size = 0; + vm_t v = alloc_fixed_region(&t->uvmem.region, + UVMEM_START, BASE_PAGE_SIZE, &size, + MR_NONBACKED); + assert(v == UVMEM_START && size == BASE_PAGE_SIZE); + return OK; } /** @@ -40,6 +52,12 @@ static stat_t __copy_mapped_region(struct tcb *d, struct tcb *s, size_t size = end - start; vm_t v = alloc_fixed_region(&d->uvmem.region, start, size, &size, m->flags); + if (ERR_CODE(v)) + return v; + + if (is_set(m->flags, MR_NONBACKED)) + return v; + assert(v == start); /* note that we use uvmem.vmem instead of proc.vmem, this is just to @@ -76,6 +94,8 @@ static stat_t __copy_shared_region(struct tcb *d, struct mem_region *m) size_t size = end - start; vm_t v = alloc_fixed_region(&d->uvmem.region, start, size, &size, m->flags); + if (ERR_CODE(v)) + return v; assert(v == start); stat_t res = clone_region(d->uvmem.vmem, s->uvmem.vmem, start, v, size, @@ -107,8 +127,11 @@ static vm_t __clone_shared_region(struct tcb *d, struct tcb *s, reference_proc(s); size_t size = end - start; - vm_t v = alloc_shared_region(&d->uvmem.region, size, &size, m->flags, - s->rid); + vm_t v = alloc_shared_region(&d->uvmem.region, size, &size, + MR_NONBACKED | m->flags, s->rid); + if (ERR_CODE(v)) + return v; + stat_t res = clone_region(d->uvmem.vmem, s->uvmem.vmem, start, v, size, flags); if (res == OK) @@ -118,7 +141,7 @@ static vm_t __clone_shared_region(struct tcb *d, struct tcb *s, unreference_proc(s); free_region(&d->uvmem.region, v); unmap_fixed_region(d->uvmem.vmem, v, size); - return NULL; + return res; } /** @@ -127,44 +150,23 @@ static vm_t __clone_shared_region(struct tcb *d, struct tcb *s, * @param t Current thread. * @param m Memory region to free. */ -static void __free_private_mapping(struct tcb *t, struct mem_region *m) +static void __free_mapping(struct tcb *t, struct mem_region *m) { + struct tcb *owner = get_tcb(m->pid); + if (owner) + unreference_proc(owner); + + if (is_set(m->flags, MR_NONBACKED)) + return; + pm_t start = __addr(m->start); pm_t end = __addr(m->end); size_t size = end - start; - unmap_region(t->proc.vmem, start, size); -} - -/** - * Unmap shared region and free associated physical pages if they're not being - * used by the other process. - * - * @param t Current thread. - * @param m Memory region to free. - */ -static void __free_shared_mapping(struct tcb *t, struct mem_region *m) -{ - vm_t start = __addr(m->start); - vm_t end = __addr(m->end); - unreference_proc(get_tcb(m->pid)); - - size_t bytes = end - start; - unmap_fixed_region(t->proc.vmem, start, bytes); -} - -/** - * Convenience function for freeing mapped regions. - * - * @param t Thread to work in. - * @param m Memory region to free. - */ -static void __free_mapping(struct tcb *t, struct mem_region *m) -{ - if (m->pid != 0) - return __free_shared_mapping(t, m); - - return __free_private_mapping(t, m); + if (m->pid) + unmap_fixed_region(t->proc.vmem, start, size); + else + unmap_region(t->proc.vmem, start, size); } void clear_uvmem(struct tcb *t) @@ -174,13 +176,11 @@ void clear_uvmem(struct tcb *t) struct mem_region *m = find_closest_used_region(&t->uvmem.region, 0); for (; m; m = m->next) { - if (is_region_kept(m)) { + if (is_region_kept(m)) continue; - } - if (!is_set(m->flags, MR_USED)) { + if (!is_set(m->flags, MR_USED)) continue; - } __free_mapping(t, m); free_known_region(&t->uvmem.region, m); @@ -243,10 +243,14 @@ vm_t alloc_uvmem(struct tcb *t, size_t size, vmflags_t flags) assert(t && is_proc(t)); const vm_t v = alloc_region(&t->uvmem.region, size, &size, flags); - if (map_region(t->proc.vmem, v, size, max_order(), flags)) { + if (ERR_CODE(v)) + return v; + + stat_t ret = OK; + if ((ret = map_region(t->proc.vmem, v, size, max_order(), flags))) { unmap_region(t->proc.vmem, v, size); free_region(&t->uvmem.region, v); - return NULL; + return ret; } return v; @@ -258,10 +262,14 @@ vm_t alloc_fixed_uvmem(struct tcb *t, vm_t start, size_t size, vmflags_t flags) const vm_t v = alloc_fixed_region(&t->uvmem.region, start, size, &size, flags); - if (map_region(t->proc.vmem, v, size, max_order(), flags)) { + if (ERR_CODE(v)) + return v; + + stat_t ret = OK; + if ((ret = map_region(t->proc.vmem, v, size, max_order(), flags))) { unmap_region(t->proc.vmem, v, size); free_region(&t->uvmem.region, v); - return NULL; + return ret; } return v; @@ -269,14 +277,20 @@ vm_t alloc_fixed_uvmem(struct tcb *t, vm_t start, size_t size, vmflags_t flags) vm_t map_fixed_uvmem(struct tcb *t, pm_t start, size_t size, vmflags_t flags) { + assert(is_aligned(start, BASE_PAGE_SIZE)); + const vm_t v = alloc_region(&t->uvmem.region, size, &size, flags); - if (map_fixed_region(t->proc.vmem, v, start, size, flags)) { + if (ERR_CODE(v)) + return v; + + stat_t ret = OK; + if ((ret = map_fixed_region(t->proc.vmem, v, start, size, flags))) { unmap_region(t->proc.vmem, v, size); free_region(&t->uvmem.region, v); - return NULL; + return ret; } - return v + (start % BASE_PAGE_SIZE); + return v; } vm_t alloc_uvpage(struct tcb *t, size_t size, vmflags_t flags, pm_t *startp, @@ -286,19 +300,20 @@ vm_t alloc_uvpage(struct tcb *t, size_t size, vmflags_t flags, pm_t *startp, size = order_size(order); const vm_t v = alloc_region(&t->uvmem.region, size, &size, flags); - if (!v) - return 0; + if (ERR_CODE(v)) + return v; pm_t start = alloc_page(order); if (!start) { free_region(&t->uvmem.region, size); - return 0; + return ERR_OOMEM; } - if (map_fixed_region(t->proc.vmem, v, start, size, flags)) { + stat_t ret = OK; + if ((ret = map_fixed_region(t->proc.vmem, v, start, size, flags))) { unmap_region(t->proc.vmem, v, size); free_region(&t->uvmem.region, v); - return NULL; + return ret; } *startp = (pm_t)__pa(start); @@ -313,11 +328,15 @@ vm_t alloc_shared_uvmem(struct tcb *s, size_t size, vmflags_t flags) assert(s && is_proc(s)); const vm_t v = alloc_region(&s->uvmem.region, size, &size, MR_SHARED | flags); + if (ERR_CODE(v)) + return v; + /* use base pages to make clone more likely to succeed */ - if (map_region(s->proc.vmem, v, size, BASE_PAGE, flags)) { + stat_t ret = OK; + if ((ret = map_region(s->proc.vmem, v, size, BASE_PAGE, flags))) { unmap_region(s->proc.vmem, v, size); free_region(&s->uvmem.region, v); - return NULL; + return ret; } return v; |
