From f2300b433e152968a0fcabd79fb9d0f5fda6bca3 Mon Sep 17 00:00:00 2001 From: Kimplul Date: Thu, 23 Dec 2021 18:23:50 +0200 Subject: Added alloc_fixed_region + Not used at the moment anywhere, but should come in handy when emulating stuff like (s)brk and when mapping ELF stuff --- common/vmem.c | 100 ++++++++++++++++++++++++++++++++++++++++----------- include/apos/utils.h | 2 ++ 2 files changed, 82 insertions(+), 20 deletions(-) diff --git a/common/vmem.c b/common/vmem.c index 3795d0b..70ef24e 100644 --- a/common/vmem.c +++ b/common/vmem.c @@ -177,6 +177,32 @@ static size_t po_align(size_t s) return 0; } +static struct sp_mem *sp_find_used_closest(struct sp_reg_root *r, vm_t start) +{ + struct sp_mem *closest = 0; + size_t md = (size_t)(-1); + struct sp_node *n = sp_root(r->used_regions); + while(n){ + struct sp_mem *t = mem_container(n); + size_t d = ABS((ssize_t)start - (ssize_t)t->start); + + if(d == 0) /* exact match */ + return t; + + if(d < md){ /* closest so far */ + closest = t; + md = d; + } + + if(start < t->start) + n = sp_left(n); + else + n = sp_right(n); + } + + return closest; +} + /* should probably document this a bit better but in short, look for the "best" * free block, meaning one that is hopefully aligned so as to allow us to later * map it to higher order pages. If no block is found such that that is @@ -211,27 +237,14 @@ static struct sp_mem *sp_find_free_best(struct sp_reg_root *r, size_t size, size return quick_best; } -/* apparently Linux doesn't necessarily give a shit about mmap hints, so I'll - * just ignore them for now. Note that alloc_region should only be used when - * mmap is called with MAP_ANON, all other situations should be handled in some - * fs server */ -vm_t alloc_region(struct sp_reg_root *r, - size_t size, size_t *actual_size) +static size_t sp_use_region(struct sp_reg_root *r, struct sp_mem *m, + size_t pages, size_t align) { - *actual_size = align_up(size, BASE_PAGE_SIZE); - size_t pages = __page(*actual_size); - - /* find best fitting, alignment etc. */ - size_t align = 0; - struct sp_mem *m = sp_find_free_best(r, pages, &align); - if(!m) - return 0; - sp_remove(&sp_root(r->free_regions), &m->sp_n); vm_t pre_start = m->start; vm_t pre_end = pre_start + align; - + vm_t start = pre_end; vm_t end = start + pages; @@ -243,8 +256,6 @@ vm_t alloc_region(struct sp_reg_root *r, m->prev = n; if(n->prev) n->prev->next = n; - - sp_free_insert_region(r, n); } if(post_start != post_end){ @@ -252,8 +263,6 @@ vm_t alloc_region(struct sp_reg_root *r, m->next = n; if(n->next) n->next->prev = n; - - sp_free_insert_region(r, n); } m->end = end; @@ -263,6 +272,57 @@ vm_t alloc_region(struct sp_reg_root *r, return __addr(start); } +/* apparently Linux doesn't necessarily give a shit about mmap hints, so I'll + * just ignore them for now. Note that alloc_region should only be used when + * mmap is called with MAP_ANON, all other situations should be handled in some + * fs server */ +vm_t alloc_region(struct sp_reg_root *r, + size_t size, size_t *actual_size) +{ + *actual_size = align_up(size, BASE_PAGE_SIZE); + size_t pages = __page(*actual_size); + + /* find best fitting, alignment etc. */ + size_t align = 0; + struct sp_mem *m = sp_find_free_best(r, pages, &align); + if(!m) + return 0; + + return sp_use_region(r, m, pages, align); +} + + +vm_t alloc_fixed_region(struct sp_reg_root *r, + vm_t start, size_t size, size_t *actual_size) +{ + *actual_size = align_up(size, BASE_PAGE_SIZE); + size_t pages = __page(*actual_size); + start = __page(start); + + struct sp_mem *m = sp_find_used_closest(r, start); + if(!m) + return 0; + + /* locate actual region where start is between the region start and end */ + while(!((m->start <= start) && (start <= m->end))){ + if(start < m->start) + m = m->next; + else + m = m->prev; + } + + /* if region is already in use, forget it */ + if(is_region_used(m->flags)) + return 0; + + /* region is too small */ + if(start + pages > m->end) + return 0; + + /* actually start marking region used */ + return sp_use_region(r, m, pages, start - m->start); +} + static void __sp_try_coalesce_prev(struct sp_reg_root *r, struct sp_mem *m) { while(m){ diff --git a/include/apos/utils.h b/include/apos/utils.h index b973d49..f1e79fa 100644 --- a/include/apos/utils.h +++ b/include/apos/utils.h @@ -1,6 +1,8 @@ #ifndef APOS_UTILS_H #define APOS_UTILS_H +#define ABS(a) (a < 0 ? -a : a) + #define MAX(a, b) ((a) >= (b) ? (a) : (b)) #define MAX3(a, b, c) (MAX(a, b) >= MAX(b, c) ? MAX(a, b) : MAX(b, c)) #define MAX4(a, b, c, d) (MAX3(a, b, c) >= MAX3(b, c, d) ? MAX3(a, b, c) : MAX3(b, c, d)) -- cgit v1.3