From e9da1d29939a74e186afc39f2fce8e085764fea0 Mon Sep 17 00:00:00 2001 From: Kimplul Date: Sat, 6 Jul 2024 20:29:49 +0300 Subject: make dmem a bit more readable --- src/dmem.c | 82 ++++++++++++++++++++++++++-------------------------------- src/uapi/mem.c | 5 ++-- src/vmem.c | 81 +++++++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 99 insertions(+), 69 deletions(-) (limited to 'src') diff --git a/src/dmem.c b/src/dmem.c index ca311c2..b02b71b 100644 --- a/src/dmem.c +++ b/src/dmem.c @@ -17,48 +17,48 @@ static struct mem_region_root pre_ram = { 0 }; /** Region after RAM. */ static struct mem_region_root post_ram = { 0 }; -pm_t __pre_base = 0; -pm_t __pre_top = 0; -pm_t __post_base = 0; -pm_t __post_top = 0; - stat_t init_devmem(pm_t ram_base, pm_t ram_top) { - pm_t mem_top = (pm_t)-1; - - __pre_base = 0; - __pre_top = ram_base - 1; + size_t pre_pages = __pages(ram_base); + size_t ram_pages = __pages(ram_top - ram_base); + /* -1 being the effective highest address possible */ + size_t post_pages = __pages(-1) - ram_pages - pre_pages; - __post_base = ram_top; - __post_top = mem_top; + init_region(&pre_ram, 0, pre_pages); + init_region(&post_ram, ram_top, post_pages); + return OK; +} - size_t pre_pages = __pages(__pre_top); - size_t post_pages = __pages(__post_top) - __pages(__post_base); +/** + * Select between the area before RAM or after RAM, depending on \p addr. + * + * @param addr Physical address of device. + * @return Corresponding device memory region or NULL if \p addr is within RAM. + */ +static struct mem_region_root *__select_region(pm_t addr) +{ + if (addr < get_ram_base()) + return &pre_ram; - init_region(&pre_ram, __pre_base, pre_pages); - init_region(&post_ram, __post_base, post_pages); + if (addr > (get_ram_base() + get_ram_size())) + return &post_ram; - return OK; + return NULL; } -vm_t alloc_devmem(struct tcb *t, pm_t dev_start, size_t bytes, vmflags_t flags) +vm_t alloc_devmem(struct tcb *t, pm_t start, size_t bytes, vmflags_t flags) { hard_assert(t && is_proc(t), ERR_INVAL); - struct mem_region_root *region = NULL; - if (dev_start < __pre_top) - region = &pre_ram; - - else if (dev_start > __post_base) - region = &post_ram; - else + struct mem_region_root *region = __select_region(start); + if (!region) return NULL; vm_t v = alloc_region(region, bytes, &bytes, flags); if (!v) return NULL; - if (map_fixed_region(t->proc.vmem, v, dev_start, bytes, flags)) { + if (map_fixed_region(t->proc.vmem, v, start, bytes, flags)) { unmap_region(t->proc.vmem, v, bytes); free_region(region, v); return NULL; @@ -67,36 +67,26 @@ vm_t alloc_devmem(struct tcb *t, pm_t dev_start, size_t bytes, vmflags_t flags) return v; } -stat_t free_devmem(struct tcb *t, vm_t dev_start) +stat_t free_devmem(struct tcb *t, vm_t start) { hard_assert(t && is_proc(t), ERR_INVAL); + pm_t addr = 0; + stat_vpage(t->proc.vmem, start, &addr, NULL, NULL); - pm_t dev_paddr = 0; - stat_vpage(t->proc.vmem, dev_start, &dev_paddr, 0, 0); - - if (dev_paddr >= __pre_top && dev_paddr <= __post_base) - return ERR_ADDR; + struct mem_region_root *region = __select_region((pm_t)__pa(addr)); + if (!region) + return ERR_INVAL; - struct mem_region *m = 0; - if (dev_paddr < __pre_top) - m = find_used_region(&pre_ram, dev_start); - - else if (dev_paddr > __post_base) - m = find_used_region(&post_ram, dev_start); + struct mem_region *m = find_used_region(region, start); if (!m) return ERR_NF; - vm_t start = __addr(m->start); + vm_t base = __addr(m->start); vm_t end = __addr(m->end); - size_t size = end - start; - unmap_fixed_region(t->proc.vmem, start, size); - - if (dev_paddr < __pre_top) - free_region(&pre_ram, dev_start); - - else if (dev_paddr > __post_base) - free_region(&post_ram, dev_start); + size_t size = end - base; + unmap_fixed_region(t->proc.vmem, base, size); + free_region(region, base); return OK; } diff --git a/src/uapi/mem.c b/src/uapi/mem.c index 932027b..17823a1 100644 --- a/src/uapi/mem.c +++ b/src/uapi/mem.c @@ -65,15 +65,14 @@ SYSCALL_DEFINE3(req_fixmem)(struct tcb *t, sys_arg_t fixed, sys_arg_t size, SYSCALL_DEFINE1(free_mem)(struct tcb *t, sys_arg_t start) { struct tcb *r = get_cproc(t); - vm_t vm_start = (vm_t)start; stat_t status = OK; /* 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))) + if (!(status = free_uvmem(r, start))) return_args1(t, OK); - if (!(status = free_devmem(r, vm_start))) + if (!(status = free_devmem(r, start))) return_args1(t, OK); return_args1(t, status); diff --git a/src/vmem.c b/src/vmem.c index c713ced..2b9ab59 100644 --- a/src/vmem.c +++ b/src/vmem.c @@ -22,7 +22,7 @@ stat_t init_uvmem(struct tcb *t, vm_t base, vm_t top) } /** - * Clone process memory region. + * Copy process memory region. * * @param d Destination tcb. * @param s Source tcb. @@ -34,20 +34,58 @@ stat_t init_uvmem(struct tcb *t, vm_t base, vm_t top) static stat_t __copy_mapped_region(struct tcb *d, struct tcb *s, struct mem_region *m) { - vm_t start = m->start * order_size(BASE_PAGE); - vm_t end = m->end * order_size(BASE_PAGE); + vm_t start = m->start * BASE_PAGE_SIZE; + vm_t end = m->end * BASE_PAGE_SIZE; + + size_t size = end - start; + vm_t v = alloc_fixed_region(&d->uvmem.region, start, size, &size, + m->flags); + catastrophic_assert(v == start); + + /* note that we use uvmem.vmem instead of proc.vmem, this is just to + * make sure that zombies don't eat our brains */ + stat_t res = copy_region(d->uvmem.vmem, s->uvmem.vmem, v, v, size); + if (res == OK) + return OK; + + /* cleanup on error */ + free_region(&d->uvmem.region, v); + unmap_region(d->uvmem.vmem, v, size); + return res; +} + +/** + * Copy shared regions to new process. In these cases, we want to both allocate + * a fixed region and map some fixed physical memory. + * + * @param d 'Destination' + * @param m Shared memory region. + * @return \ref OK on success, some error code otherwise. + */ +static stat_t __copy_shared_region(struct tcb *d, struct mem_region *m) +{ + struct tcb *s = get_tcb(m->pid); + if (!s) + return ERR_NF; + + vm_t start = m->start * BASE_PAGE_SIZE; + vm_t end = m->end * BASE_PAGE_SIZE; + + reference_proc(s); size_t size = end - start; vm_t v = alloc_fixed_region(&d->uvmem.region, start, size, &size, m->flags); + catastrophic_assert(v == start); - stat_t res = copy_region(d->proc.vmem, s->proc.vmem, v, v, size); + stat_t res = clone_region(d->uvmem.vmem, s->uvmem.vmem, start, v, size, + m->flags); if (res == OK) return OK; /* cleanup on error */ free_region(&d->uvmem.region, v); - unmap_region(d->proc.vmem, v, size); + unmap_fixed_region(d->uvmem.vmem, v, size); return res; } @@ -71,7 +109,7 @@ static vm_t __clone_shared_region(struct tcb *d, struct tcb *s, size_t size = end - start; vm_t v = alloc_shared_region(&d->uvmem.region, size, &size, m->flags, s->rid); - stat_t res = clone_region(d->proc.vmem, s->proc.vmem, start, v, size, + stat_t res = clone_region(d->uvmem.vmem, s->uvmem.vmem, start, v, size, flags); if (res == OK) return v; @@ -79,7 +117,7 @@ static vm_t __clone_shared_region(struct tcb *d, struct tcb *s, /* cleanup on error */ unreference_proc(s); free_region(&d->uvmem.region, v); - unmap_fixed_region(d->proc.vmem, v, size); + unmap_fixed_region(d->uvmem.vmem, v, size); return NULL; } @@ -89,11 +127,12 @@ 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_mapped_private_region(struct tcb *t, struct mem_region *m) +static void __free_private_mapping(struct tcb *t, struct mem_region *m) { pm_t start = __addr(m->start); pm_t end = __addr(m->end); size_t size = end - start; + unmap_region(t->proc.vmem, start, size); } @@ -104,7 +143,7 @@ static void __free_mapped_private_region(struct tcb *t, struct mem_region *m) * @param t Current thread. * @param m Memory region to free. */ -static void __free_mapped_shared_region(struct tcb *t, struct mem_region *m) +static void __free_shared_mapping(struct tcb *t, struct mem_region *m) { vm_t start = __addr(m->start); vm_t end = __addr(m->end); @@ -120,12 +159,12 @@ static void __free_mapped_shared_region(struct tcb *t, struct mem_region *m) * @param t Thread to work in. * @param m Memory region to free. */ -static void __free_mapped_region(struct tcb *t, struct mem_region *m) +static void __free_mapping(struct tcb *t, struct mem_region *m) { if (m->pid != 0) - return __free_mapped_shared_region(t, m); + return __free_shared_mapping(t, m); - return __free_mapped_private_region(t, m); + return __free_private_mapping(t, m); } void clear_uvmem(struct tcb *t) @@ -143,7 +182,7 @@ void clear_uvmem(struct tcb *t) continue; } - __free_mapped_region(t, m); + __free_mapping(t, m); free_known_region(&t->uvmem.region, m); } } @@ -158,8 +197,7 @@ void purge_uvmem(struct tcb *t) if (!is_set(m->flags, MR_USED)) continue; - /* free memory associated with region */ - __free_mapped_region(t, m); + __free_mapping(t, m); } /* actually destroy region, will clear out all nodes automatically */ @@ -183,14 +221,17 @@ stat_t copy_uvmem(struct tcb *d, struct tcb *s) * through all regions which is likely a slight bit slower. */ stat_t ret = OK; struct mem_region *m = find_first_region(&s->uvmem.region); - while (m) { - if (is_region_used(m)) + for (; m; m = m->next) { + if (!is_region_used(m)) + continue; + + if (m->pid == 0) ret = __copy_mapped_region(d, s, m); + else + ret = __copy_shared_region(d, m); if (ret) return ret; - - m = m->next; } return ret; @@ -273,7 +314,7 @@ stat_t free_uvmem(struct tcb *r, vm_t va) if (!m) return ERR_NF; - __free_mapped_region(r, m); + __free_mapping(r, m); free_known_region(&r->uvmem.region, m); return OK; } -- cgit v1.3