From 89d7cf197b2cae130565467bdfad5d5ef5fed2dd Mon Sep 17 00:00:00 2001 From: Kimplul Date: Tue, 9 Jul 2024 19:24:12 +0300 Subject: allow regions to have reserved areas + A reserved area is an area at the start of the region that should not be used unless explicitly asked for, for example null pages. As such, a small correction to my previous commit message: There's no danger in not locking req_mem() etc, as a null page will only be allocated when explicitly asked for. --- src/debug.c | 4 ++-- src/dmem.c | 4 ++-- src/regions.c | 45 +++++++++++++++++++++++++++++++++++++++------ src/vmem.c | 21 ++++++--------------- 4 files changed, 49 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/debug.c b/src/debug.c index 950f73b..d87588d 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. diff --git a/src/dmem.c b/src/dmem.c index 91ddb02..d21a9c5 100644 --- a/src/dmem.c +++ b/src/dmem.c @@ -24,8 +24,8 @@ stat_t init_devmem(pm_t ram_base, pm_t ram_top) /* -1 being the effective highest address possible */ size_t post_pages = __pages(-1) - ram_pages - pre_pages; - init_region(&pre_ram, 0, pre_pages); - init_region(&post_ram, ram_top, post_pages); + init_region(&pre_ram, 0, pre_pages, 0); + init_region(&post_ram, ram_top, post_pages, 0); return OK; } diff --git a/src/regions.c b/src/regions.c index ca99971..1aa318d 100644 --- a/src/regions.c +++ b/src/regions.c @@ -113,6 +113,8 @@ static struct mem_region *__insert_free_region(struct mem_region_root *r, } else if (start < t->start) { + /* note that blocks with smaller addresses go to the + * left */ n = sp_left(n); d = SP_LEFT; } @@ -165,7 +167,8 @@ static struct mem_region *__insert_used_region(struct mem_region_root *r, return m; } -stat_t init_region(struct mem_region_root *r, vm_t start, size_t arena_size) +stat_t init_region(struct mem_region_root *r, vm_t start, size_t arena_size, + size_t reserved) { /* convert bytes to pages */ start = __page(start); @@ -173,8 +176,11 @@ stat_t init_region(struct mem_region_root *r, vm_t start, size_t arena_size) struct mem_region *m = get_mem_node(); m->start = start; m->end = start + arena_size; - __insert_free_region(r, m); + r->reserved = __page(reserved); + r->start = m->start; + r->end = m->end; + __insert_free_region(r, m); return OK; } @@ -311,16 +317,45 @@ struct mem_region *find_free_region(struct mem_region_root *r, size_t size, size_t offset = __page(po_align(__addr(size))); struct mem_region *quick_best = 0; struct sp_node *n = sp_root(&r->free_regions); - while (n) { + + /* always go right, both to find a larger block and a higher + * address (generally avoid going towards the NULL page) */ + for (; n; n = sp_right(n)) { struct mem_region *t = mem_container(n); vm_t start = align_up(t->start, offset); - size_t qsize = t->end - t->start; size_t bsize = 0; if (t->end >= start) bsize = t->end - start; + /* handle reserved region first */ + if (start < r->start + r->reserved) { + /* we would have to map reserved pages, go to next node + * if one exists */ + if (sp_right(n)) + continue; + + /* we're the only free region left to check, + * are we large enough to carve a chunk out of? */ + size_t offset = r->reserved - t->start; + if (size < qsize - offset) + return quick_best; + + /* we are, so let's set the alignment to match that at + * least some parts of this block should be skipped */ + + /* try to use page order alignment if possible */ + if (size <= bsize - offset) { + *align = start - t->start; + return t; + } + + /* otherwise, carve out a block at the top of this node. */ + *align = t->end - size; + return t; + } + if (!quick_best && size <= qsize) quick_best = t; @@ -328,8 +363,6 @@ struct mem_region *find_free_region(struct mem_region_root *r, size_t size, *align = start - t->start; return t; } - - n = sp_right(n); } return quick_best; diff --git a/src/vmem.c b/src/vmem.c index 52e7bd2..6fb5474 100644 --- a/src/vmem.c +++ b/src/vmem.c @@ -18,19 +18,10 @@ stat_t init_uvmem(struct tcb *t) { t->uvmem.owner = t->tid; t->uvmem.vmem = t->proc.vmem; - - 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; + /* reserve 64KiB (arbitrary number but should be large enough that + * nobody accidentally indexes above NULL enough to find real memory) */ + return init_region(&t->uvmem.region, UVMEM_START, + UVMEM_END - UVMEM_START, SZ_64K); } /** @@ -132,8 +123,8 @@ static vm_t __clone_shared_region(struct tcb *d, struct tcb *s, if (ERR_CODE(v)) return v; - stat_t res = clone_region(d->uvmem.vmem, s->uvmem.vmem, start, v, size, - flags); + stat_t res = clone_region(d->uvmem.vmem, s->uvmem.vmem, + start, v, size, flags); if (res == OK) return v; -- cgit v1.3