aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/doxygen.conf1
-rw-r--r--src/dmem.c82
-rw-r--r--src/uapi/mem.c5
-rw-r--r--src/vmem.c81
4 files changed, 100 insertions, 69 deletions
diff --git a/docs/doxygen.conf b/docs/doxygen.conf
index af3be32..3e8930c 100644
--- a/docs/doxygen.conf
+++ b/docs/doxygen.conf
@@ -2435,6 +2435,7 @@ INCLUDE_FILE_PATTERNS =
PREDEFINED = DEBUG \
__GNUC__ \
riscv64 \
+ __riscv_xlen=64 \
riscv32 \
ASSERT
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;
}