From cd41ed1758f4842d7b78870385e16b579cc89c38 Mon Sep 17 00:00:00 2001 From: Kimplul Date: Sun, 25 Jan 2026 17:14:53 +0200 Subject: implement dmem semi-properly + Add tests and fix virtual mapping, this is enough to start writing proper userspace drivers --- src/dmem.c | 77 ++++++++++++++++++++++++++++++++++++++++------------- src/fdt.c | 15 ----------- src/uapi/dispatch.c | 2 +- src/uapi/mem.c | 4 +-- src/vmem.c | 9 +++++++ 5 files changed, 70 insertions(+), 37 deletions(-) delete mode 100644 src/fdt.c (limited to 'src') diff --git a/src/dmem.c b/src/dmem.c index d21a9c5..6b98003 100644 --- a/src/dmem.c +++ b/src/dmem.c @@ -19,13 +19,8 @@ static struct mem_region_root post_ram = { 0 }; stat_t init_devmem(pm_t ram_base, pm_t ram_top) { - 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; - - init_region(&pre_ram, 0, pre_pages, 0); - init_region(&post_ram, ram_top, post_pages, 0); + init_region(&pre_ram, 0, ram_base, 0); + init_region(&post_ram, ram_top, -1, 0); return OK; } @@ -54,39 +49,83 @@ vm_t alloc_devmem(struct tcb *t, pm_t start, size_t bytes, vmflags_t flags) if (!region) return NULL; - vm_t v = alloc_region(region, bytes, &bytes, flags); - if (!v) + /* carve out physical region (vm_t is misleading, this region is + * physical memory) */ + vm_t p = alloc_fixed_region(region, start, bytes, &bytes, flags); + if (!p) + return NULL; + + /* carve out virtual region */ + vm_t v = alloc_region(&t->uvmem.region, bytes, &bytes, flags | MR_DEV); + if (!v) { + free_region(region, p); return NULL; + } - if (map_fixed_region(t->proc.vmem, v, start, bytes, flags)) { + /* convert from literal physical address to direct mapping address, + * which map_* expects (kind of annoying to deal with, admittedly, is + * there maybe a better way to handle these things?) */ + p = (pm_t)__va(p); + if (map_fixed_region(t->proc.vmem, v, p, bytes, flags)) { unmap_region(t->proc.vmem, v, bytes); - free_region(region, v); + free_region(&t->uvmem.region, v); + free_region(region, p); return NULL; } return v; } -stat_t free_devmem(struct tcb *t, vm_t start) +stat_t free_known_devmem(struct tcb *t, struct mem_region *m) { assert(t && is_proc(t)); + + /* ensure region is a device memory region and is currently not shared */ + assert(is_set(m->flags, MR_DEV)); + assert(m->pid != 0 || m->refcount == 1); + pm_t addr = 0; - stat_vpage(t->proc.vmem, start, &addr, NULL, NULL); + stat_vpage(t->proc.vmem, __addr(m->start), &addr, NULL, NULL); - struct mem_region_root *region = __select_region((pm_t)__pa(addr)); + /* free physical device memory */ + pm_t p = (pm_t)__pa(addr); + struct mem_region_root *region = __select_region(p); if (!region) return ERR_INVAL; + free_region(region, p); - struct mem_region *m = find_used_region(region, start); - if (!m) - return ERR_NF; - + /* free virtual allocation associated with device mem */ vm_t base = __addr(m->start); vm_t end = __addr(m->end); + + /* free virtual memory associated with physical mapping */ size_t size = end - base; unmap_fixed_region(t->proc.vmem, base, size); - free_region(region, base); + free_known_region(&t->uvmem.region, m); + return OK; +} + +stat_t free_devmem(struct tcb *t, vm_t start) +{ + assert(t && is_proc(t)); + struct mem_region *m = find_used_region(&t->uvmem.region, start); + if (!m) + return ERR_NF; + + /* not a devmem region */ + if (!is_set(m->flags, MR_DEV)) + return ERR_INVAL; + + /* mapping is shared, can't free right now */ + if (m->pid == 0 && m->refcount > 1) + return ERR_INVAL; + + stat_t ret = free_known_devmem(t, m); + if (ret) + return ret; + + free_known_region(&t->uvmem.region, m); return OK; } diff --git a/src/fdt.c b/src/fdt.c deleted file mode 100644 index 677be7b..0000000 --- a/src/fdt.c +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: copyleft-next-0.3.1 */ -/* Copyright 2021 - 2022, Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ - -/** - * @file fdt.c - * Helper functions for handling the global FDT. - */ - -#include - -struct cell_info get_cellinfo(const void *fdt, const int offset) -{ - return (struct cell_info){ fdt_size_cells(fdt, offset), - fdt_address_cells(fdt, offset) }; -} diff --git a/src/uapi/dispatch.c b/src/uapi/dispatch.c index 2eef5bc..4d10bbe 100644 --- a/src/uapi/dispatch.c +++ b/src/uapi/dispatch.c @@ -49,7 +49,7 @@ void handle_syscall(sys_arg_t syscall, sys_arg_t a, sys_arg_t b, case SYS_NOOP: sys_noop(t, a, b, c, d, e); break; case SYS_PUTCH: sys_putch(t, a, b, c, d, e); break; case SYS_REQ_MEM: sys_req_mem(t, a, b, c, d, e); break; - case SYS_REQ_PMEM: sys_req_pmem(t, a, b, c, d, e); break; + case SYS_REQ_DMEM: sys_req_dmem(t, a, b, c, d, e); break; case SYS_REQ_PAGE: sys_req_page(t, a, b, c, d, e); break; case SYS_REQ_FIXMEM: sys_req_fixmem(t, a, b, c, d, e); break; case SYS_REQ_SHAREDMEM: sys_req_sharedmem(t, a, b, c, d, e); break; diff --git a/src/uapi/mem.c b/src/uapi/mem.c index 7a233a5..20abc96 100644 --- a/src/uapi/mem.c +++ b/src/uapi/mem.c @@ -82,7 +82,7 @@ SYSCALL_DEFINE1(free_mem)(struct tcb *t, sys_arg_t start) } /** - * Request physical memory syscall handler. + * Request device memory syscall handler. * * @param t Current tcb. * @param paddr Physical address to map. @@ -91,7 +91,7 @@ SYSCALL_DEFINE1(free_mem)(struct tcb *t, sys_arg_t start) * @return \ref OK and start of allocation when succesful, * otherwise an error code. */ -SYSCALL_DEFINE3(req_pmem)(struct tcb *t, sys_arg_t paddr, sys_arg_t size, +SYSCALL_DEFINE3(req_dmem)(struct tcb *t, sys_arg_t paddr, sys_arg_t size, sys_arg_t flags) { /* this will require some pondering, but essentially this syscall should diff --git a/src/vmem.c b/src/vmem.c index 76e0ece..afdac95 100644 --- a/src/vmem.c +++ b/src/vmem.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -197,6 +198,14 @@ static void __free_mapping(struct tcb *t, struct mem_region *m) if (is_set(m->flags, MR_NONBACKED)) return; + if (is_set(m->flags, MR_DEV)) { + stat_t ret = free_known_devmem(t, m); + MAYBE_UNUSED(ret); + + assert(ret == OK); + return; + } + pm_t start = __addr(m->start); pm_t end = __addr(m->end); size_t size = end - start; -- cgit v1.3