aboutsummaryrefslogtreecommitdiff
path: root/src/dmem.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dmem.c')
-rw-r--r--src/dmem.c77
1 files changed, 58 insertions, 19 deletions
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;
}