aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2022-05-22 15:05:39 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2022-05-22 15:05:39 +0300
commit5793a61eb824a7b97e9bab5913b595a778205cef (patch)
treef31931b924058cb6474b80cd02472940ad8cfcd5
parenta4851206bef5ceecef18b3fde5be6918a67cca21 (diff)
downloadkmi-5793a61eb824a7b97e9bab5913b595a778205cef.tar.gz
kmi-5793a61eb824a7b97e9bab5913b595a778205cef.zip
improved tcb handling in preparation for processes
-rw-r--r--arch/riscv64/kernel/vmem.c23
-rw-r--r--common/mem_regions.c34
-rw-r--r--common/proc.c7
-rw-r--r--common/tcb.c98
-rw-r--r--common/uapi/dispatch.c3
-rw-r--r--common/uapi/ipc.c17
-rw-r--r--common/vmem.c51
-rw-r--r--include/apos/assert.h13
-rw-r--r--include/apos/mem_regions.h5
-rw-r--r--include/apos/syscalls.h3
-rw-r--r--include/apos/tcb.h21
-rw-r--r--include/apos/uapi.h3
-rw-r--r--include/apos/vmem.h2
-rw-r--r--include/arch/vmem.h6
14 files changed, 220 insertions, 66 deletions
diff --git a/arch/riscv64/kernel/vmem.c b/arch/riscv64/kernel/vmem.c
index 7ffde86..0285f39 100644
--- a/arch/riscv64/kernel/vmem.c
+++ b/arch/riscv64/kernel/vmem.c
@@ -168,16 +168,28 @@ static void __start_vmem(struct vm_branch *branch, enum mm_mode m)
struct vm_branch *init_vmem(void *fdt)
{
UNUSED(fdt);
+ struct vm_branch *b = create_vmem();
+ /* update which memory branch to use */
+ __start_vmem(b, Sv39);
+ return b;
+}
+
+struct vm_branch *create_vmem()
+{
struct vm_branch *b = (struct vm_branch *)alloc_page(MM_KPAGE, 0);
memset(b, 0, MM_KPAGE_SIZE);
- populate_root_branch(b);
- /* update which memory branch to use */
- __start_vmem(b, Sv39);
+ populate_kvmem(b);
return b;
}
-void populate_root_branch(struct vm_branch *b)
+stat_t destroy_vmem(struct vm_branch *b)
+{
+ free_page(MM_KPAGE, (pm_t)b);
+ return OK;
+}
+
+stat_t populate_kvmem(struct vm_branch *b)
{
size_t flags = VM_V | VM_R | VM_W | VM_X | VM_G;
for (size_t i = KSTART_PAGE; i < IO_PAGE; ++i)
@@ -187,6 +199,7 @@ void populate_root_branch(struct vm_branch *b)
/* map kernel IO to zero for now, this will be overridden later
* (if at all) */
b->leaf[IO_PAGE] = (struct vm_branch *)to_pte(0, flags);
+ return OK;
}
#if defined(DEBUG)
@@ -200,7 +213,7 @@ vm_t setup_kernel_io(struct vm_branch *b, vm_t paddr)
}
#endif
-stat_t clone_vmbranch(struct vm_branch *r, struct vm_branch *b)
+stat_t clone_uvmem(struct vm_branch *r, struct vm_branch *b)
{
/* TODO: error checking? */
for (size_t i = 0; i <= CSTACK_PAGE; ++i)
diff --git a/common/mem_regions.c b/common/mem_regions.c
index bbc894e..9f8f98e 100644
--- a/common/mem_regions.c
+++ b/common/mem_regions.c
@@ -6,7 +6,6 @@
#define mark_region_used(r) __set_bit(r, MR_USED)
#define mark_region_unused(r) __clear_bit(r, MR_USED)
-#define region_used(r) __is_set(r, MR_USED)
/* pretty major slowdown when we get to some really massive numbers, not
* entirely sure why. Will need to check up on this at some point, have I
@@ -121,17 +120,22 @@ static void __destroy_region(struct sp_node *n)
if (!n)
return;
- __destroy_region(sp_left(n));
- __destroy_region(sp_right(n));
+ if (sp_left(n))
+ __destroy_region(sp_left(n));
+
+ if (sp_right(n))
+ __destroy_region(sp_right(n));
struct mem_region *m = mem_container(n);
free_mem_node(m);
}
-void destroy_region(struct mem_region_root *r)
+stat_t destroy_region(struct mem_region_root *r)
{
__destroy_region(sp_root(&r->free_regions));
__destroy_region(sp_root(&r->used_regions));
+ /* TODO: error checking? */
+ return OK;
}
/* interestingly this is now the main bottleneck :D
@@ -245,6 +249,18 @@ struct mem_region *find_free_region(struct mem_region_root *r, size_t size,
return quick_best;
}
+struct mem_region *find_first_region(struct mem_region_root *r)
+{
+ /* get used region with smallest address, likely also close to the start
+ * of the linked list */
+ struct mem_region *m = find_closest_used_region(r, 0);
+ while (m->prev) {
+ m = m->prev;
+ }
+
+ return m;
+}
+
static vm_t __partition_region(struct mem_region_root *r, struct mem_region *m,
size_t pages, size_t align, vmflags_t flags)
{
@@ -332,7 +348,7 @@ vm_t alloc_fixed_region(struct mem_region_root *r, vm_t start, size_t size,
}
/* if region is already in use, forget it */
- if (region_used(m->flags))
+ if (is_region_used(m))
return 0;
/* region is too small */
@@ -346,11 +362,11 @@ vm_t alloc_fixed_region(struct mem_region_root *r, vm_t start, size_t size,
static void __try_coalesce_prev(struct mem_region_root *r, struct mem_region *m)
{
while (m) {
- if (!m || region_used(m->flags))
+ if (!m || is_region_used(m))
return;
struct mem_region *p = m->prev;
- if (!p || region_used(p->flags))
+ if (!p || is_region_used(p))
return;
m->start = p->start;
@@ -369,11 +385,11 @@ static void __try_coalesce_prev(struct mem_region_root *r, struct mem_region *m)
static void __try_coalesce_next(struct mem_region_root *r, struct mem_region *m)
{
while (m) {
- if (!m || region_used(m->flags))
+ if (!m || is_region_used(m))
return;
struct mem_region *n = m->next;
- if (!n || region_used(n->flags))
+ if (!n || is_region_used(n))
return;
m->end = n->end;
diff --git a/common/proc.c b/common/proc.c
index 8793d00..8824c5a 100644
--- a/common/proc.c
+++ b/common/proc.c
@@ -29,12 +29,13 @@ stat_t init_proc(void *fdt, struct vm_branch *b)
{
init_tcbs();
- /* todo: cleanup or something */
- struct tcb *t = new_thread();
+ /* TODO: cleanup or something */
+ struct tcb *t = create_thread(NULL);
if (!t)
return ERR_OOMEM;
- t->b_r = b;
+ /* use existing branch */
+ t->b_r = b;
init_uvmem(t, UVMEM_START, UVMEM_END);
/* TODO: this stuff should be placed in __sys_exec */
diff --git a/common/tcb.c b/common/tcb.c
index 212e20f..32c31e1 100644
--- a/common/tcb.c
+++ b/common/tcb.c
@@ -2,6 +2,7 @@
#include <arch/cpu.h>
#include <apos/mem.h>
#include <apos/pmem.h>
+#include <apos/vmem.h>
#include <apos/nodes.h>
#include <apos/types.h>
#include <apos/assert.h>
@@ -12,7 +13,6 @@
static id_t start_tid;
static size_t num_tids;
-static struct node_root root;
static struct tcb **tcbs;
/* if we ever support systems with massive amounts of cpus, this should probably
@@ -31,8 +31,7 @@ void init_tcbs()
void destroy_tcbs()
{
- destroy_nodes(&root);
- free_page(MM_O2, (pm_t)tcbs);
+ free_page(MM_O1, (pm_t)tcbs);
}
static id_t __alloc_tid(struct tcb *t)
@@ -50,10 +49,9 @@ static id_t __alloc_tid(struct tcb *t)
return ERR_NF;
}
-struct tcb *new_thread()
+struct tcb *create_thread(struct tcb *p)
{
- if (unlikely(!tcbs))
- return 0;
+ hard_assert(tcbs, 0);
vm_t bottom = alloc_page(MM_O0, 0);
/* move tcb to top of kernel stack, keeping alignment in check
@@ -67,20 +65,80 @@ struct tcb *new_thread()
tcbs[tid] = t;
t->tid = tid;
+ if (p) {
+ t->pid = p->pid;
+ t->proc = p;
+ } else {
+ t->pid = t->tid;
+ }
+
return t;
}
-void destroy_thread(struct tcb *t)
+static stat_t __clone_proc(struct tcb *p, struct tcb *n)
+{
+ /* TODO: clone memory regions, and mark them MR_COW, as well as copy
+ * bm_branch tree but with VM_W off, also at some point write COW
+ * handler */
+ return OK;
+}
+
+struct tcb *create_proc(struct tcb *p)
{
- if (unlikely(!tcbs))
- return;
+ hard_assert(tcbs, 0);
- /* remove thread id from list */
- tcbs[t->tid] = 0;
+ /* create a new thread outside the current process */
+ struct tcb *n = create_thread(0);
+ n->b_r = create_vmem();
- /* free associated kernel stack */
+ if (likely(p))
+ __clone_proc(p, n); /* we have a parent thread */
+ else
+ init_uvmem(n, UVMEM_START, UVMEM_END);
+
+ return n;
+}
+
+static stat_t __destroy_thread_data(struct tcb *t)
+{
+ /* free vm_branch */
+ destroy_vmem(t->b_r);
+
+ /* free associated kernel stack and the structure itself */
vm_t bottom = align_down((vm_t)t, __o_size(MM_O0));
free_page(MM_O0, (pm_t)bottom);
+
+ return OK;
+}
+
+stat_t destroy_thread(struct tcb *t)
+{
+ hard_assert(tcbs, ERR_NOINIT);
+ hard_assert(!is_proc(t), ERR_INVAL);
+
+ /* remove thread id from list */
+ tcbs[t->tid] = 0;
+
+ /* remove thread from process list */
+ if (t->next)
+ t->next->prev = t->prev;
+
+ if (t->prev)
+ t->prev->next = t->next;
+
+ return __destroy_thread_data(t);
+}
+
+stat_t destroy_proc(struct tcb *p)
+{
+ hard_assert(tcbs, ERR_NOINIT);
+ hard_assert(is_proc(p), ERR_INVAL);
+
+ for (struct tcb *iter = p; (iter = iter->next);)
+ destroy_thread(iter);
+
+ catastrophic_assert(destroy_uvmem(p));
+ return __destroy_thread_data(p);
}
struct tcb *cur_tcb()
@@ -88,6 +146,15 @@ struct tcb *cur_tcb()
return cpu_tcb[cpu_id()];
}
+struct tcb *cur_proc()
+{
+ struct tcb *t = cur_tcb();
+ if (likely(is_proc(t)))
+ return t;
+ else
+ return t->proc;
+}
+
void use_tcb(struct tcb *t)
{
cpu_tcb[cpu_id()] = t;
@@ -95,18 +162,17 @@ void use_tcb(struct tcb *t)
struct tcb *get_tcb(id_t tid)
{
- if (unlikely(!tcbs))
- return 0;
+ hard_assert(tcbs, 0);
return tcbs[tid];
}
stat_t clone_tcb_maps(struct tcb *r)
{
- hard_assert(r && !r->parent, ERR_INVAL);
+ hard_assert(r && is_proc(r), ERR_INVAL);
struct tcb *t = r;
while ((t = t->next)) {
- stat_t ret = clone_vmbranch(r->b_r, t->b_r);
+ stat_t ret = clone_uvmem(r->b_r, t->b_r);
if (ret)
return ret;
}
diff --git a/common/uapi/dispatch.c b/common/uapi/dispatch.c
index 97fc0d8..5e2e788 100644
--- a/common/uapi/dispatch.c
+++ b/common/uapi/dispatch.c
@@ -17,7 +17,8 @@ static const sys_t syscall_table[] = {
/* ipc */
[SYS_IPC_SERVER] = sys_ipc_server,
- [SYS_IPC_REQ] = sys_ipc_req,
+ [SYS_IPC_REQ_PROC] = sys_ipc_req_proc,
+ [SYS_IPC_REQ_THREAD] = sys_ipc_req_thread,
[SYS_IPC_RESP] = sys_ipc_resp,
/* proc */
diff --git a/common/uapi/ipc.c b/common/uapi/ipc.c
index d7c9d16..0d2d287 100644
--- a/common/uapi/ipc.c
+++ b/common/uapi/ipc.c
@@ -11,16 +11,23 @@ SYSCALL_DEFINE1(ipc_server)(sys_arg_t callback)
return (struct sys_ret){ OK, 0 };
}
-SYSCALL_DEFINE3(ipc_req)(sys_arg_t tid, sys_arg_t d0, sys_arg_t d1)
+SYSCALL_DEFINE3(ipc_req_proc)(sys_arg_t pid, sys_arg_t d0, sys_arg_t d1)
{
- struct tcb *r = get_tcb(tid);
- /* something like jump_to_callback(t) */
+ struct tcb *r = get_tcb(pid);
+ /* TODO: something like jump_to_callback(t) */
return (struct sys_ret){ d0, d1 };
}
-SYSCALL_DEFINE3(ipc_resp)(sys_arg_t tid, sys_arg_t d0, sys_arg_t d1)
+SYSCALL_DEFINE3(ipc_req_thread)(sys_arg_t tid, sys_arg_t d0, sys_arg_t d1)
{
- struct tcb *r = get_tcb(tid);
+ struct tcb *t = get_tcb(tid);
+ /* ditto */
+ return (struct sys_ret){ d0, d1 };
+}
+
+SYSCALL_DEFINE2(ipc_resp)(sys_arg_t d0, sys_arg_t d1)
+{
+ struct tcb *r = cur_tcb();
/* something like return_from_callback(t, r) */
return (struct sys_ret){ d0, d1 };
}
diff --git a/common/vmem.c b/common/vmem.c
index ff27ed8..b665491 100644
--- a/common/vmem.c
+++ b/common/vmem.c
@@ -10,10 +10,33 @@ stat_t init_uvmem(struct tcb *t, vm_t base, vm_t top)
return init_region(&t->sp_r, base, top);
}
+static stat_t __free_mapped_region(struct tcb *t, struct mem_region *m)
+{
+ stat_t status = OK;
+ pm_t pa = __addr(m->end - m->start);
+ if (unmap_freed_region(t->b_r, m->start, pa, m->flags, &status))
+ return ERR_MISC;
+
+ return status;
+}
+
+stat_t destroy_uvmem(struct tcb *t)
+{
+ struct mem_region *m = find_first_region(&t->sp_r);
+ while (m) {
+ /* free all memory associated with used regions */
+ if (is_region_used(m))
+ __free_mapped_region(t, m);
+ }
+
+ /* destroy region tree itself */
+ return destroy_region(&t->sp_r);
+}
+
vm_t alloc_uvmem(struct tcb *t, size_t size, vmflags_t flags)
{
- /* t exists and is the root tcb of the current process */
- hard_assert(t && !t->parent, ERR_INVAL);
+ /* t exists and is the process tcb of the current process */
+ hard_assert(t && is_proc(t), ERR_INVAL);
stat_t status = OK;
const vm_t v = alloc_region(&t->sp_r, size, &size, flags);
@@ -26,7 +49,7 @@ vm_t alloc_uvmem(struct tcb *t, size_t size, vmflags_t flags)
vm_t alloc_fixed_uvmem(struct tcb *t, vm_t start, size_t size, vmflags_t flags)
{
- hard_assert(t && !t->parent, ERR_INVAL);
+ hard_assert(t && is_proc(t), ERR_INVAL);
stat_t status = OK;
const vm_t v = alloc_fixed_region(&t->sp_r, start, size, &size, flags);
@@ -41,7 +64,7 @@ vm_t alloc_fixed_uvmem(struct tcb *t, vm_t start, size_t size, vmflags_t flags)
/* free_shared_uvmem shouldn't be needed, likely to work with free_uvmem */
vm_t alloc_shared_uvmem(struct tcb *t, size_t size, vmflags_t flags)
{
- hard_assert(t && t->parent, ERR_INVAL);
+ hard_assert(t && is_proc(t), ERR_INVAL);
stat_t status = OK;
const vm_t v = alloc_region(&t->sp_r, size, &size,
@@ -86,13 +109,9 @@ stat_t free_uvmem(struct tcb *t, vm_t va)
if (!m)
return -1;
- pm_t pa = __addr(m->end - m->start);
-
- vmflags_t flags = m->flags;
free_region(&t->sp_r, va);
- stat_t status = OK;
- unmap_freed_region(t->b_r, va, pa, flags, &status);
+ stat_t status = __free_mapped_region(t, m);
if (status == INFO_SEFF)
return clone_tcb_maps(t);
@@ -107,7 +126,10 @@ stat_t alloc_uvmem_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr,
return INFO_TRGN; /* try again */
stat_t *status = (stat_t *)data, ret;
- ret = *status = map_vpage(b, *offset, vaddr, flags, order);
+ ret = map_vpage(b, *offset, vaddr, flags, order);
+ if (status)
+ *status = ret;
+
return (ret == INFO_SEFF) ? OK : ret;
}
@@ -120,7 +142,9 @@ stat_t alloc_shared_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr,
*offset = alloc_page(MM_O0, *offset);
stat_t *status = (stat_t *)data, ret;
- ret = *status = map_vpage(b, *offset, vaddr, flags, order);
+ ret = map_vpage(b, *offset, vaddr, flags, order);
+ if (status)
+ *status = ret;
return (ret == INFO_SEFF) ? OK : ret;
}
@@ -137,7 +161,10 @@ stat_t free_uvmem_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr,
return INFO_TRGN;
stat_t *status = (stat_t *)data, ret;
- ret = *status = unmap_vpage(b, vaddr);
+ ret = unmap_vpage(b, vaddr);
+ if (status)
+ *status = ret;
+
/* don't free shared pages, unless they're owned */
if (!__is_set(flags, MR_SHARED) || __is_set(flags, MR_OWNED))
free_page(order, paddr);
diff --git a/include/apos/assert.h b/include/apos/assert.h
index 7200fd2..f3d9a4d 100644
--- a/include/apos/assert.h
+++ b/include/apos/assert.h
@@ -8,24 +8,25 @@
#if !defined(DNDEBUG)
#define catastrophic_assert(x) \
do { \
- if (x) { \
- err("catastrophic assertion failed: %s\n", QUOTE(x)); \
+ if (unlikely(!(x))) { \
+ error("catastrophic assertion failed: %s\n", \
+ QUOTE(x)); \
while (1) \
; \
} \
} while (0);
#define hard_assert(x, r) \
- do { \
- if (x) { \
+ { \
+ if (unlikely(!(x))) { \
warn("hard assertion failed: %s\n", QUOTE(x)); \
return r; \
} \
- } while (0);
+ }
#define soft_assert(x) \
do { \
- if (x) { \
+ if (unlikely(!(x))) { \
info("soft assertion failed: %s\n", QUOTE(x)); \
} \
} while (0);
diff --git a/include/apos/mem_regions.h b/include/apos/mem_regions.h
index efe0592..9f09eff 100644
--- a/include/apos/mem_regions.h
+++ b/include/apos/mem_regions.h
@@ -7,10 +7,12 @@
#include <arch/vmem.h>
#define mem_container(ptr) container_of(ptr, struct mem_region, sp_n)
+#define is_region_used(r) __is_set(r->flags, MR_USED)
struct mem_region_root {
struct sp_root free_regions;
struct sp_root used_regions;
+ struct mem_region *first;
};
struct mem_region {
@@ -26,7 +28,7 @@ struct mem_region {
};
stat_t init_region(struct mem_region_root *r, vm_t start, size_t arena_size);
-void destroy_region(struct mem_region_root *r);
+stat_t destroy_region(struct mem_region_root *r);
vm_t alloc_region(struct mem_region_root *r, size_t size, size_t *actual_size,
vmflags_t flags);
@@ -35,6 +37,7 @@ vm_t alloc_fixed_region(struct mem_region_root *r, vm_t start, size_t size,
stat_t free_region(struct mem_region_root *r, vm_t start);
stat_t free_known_region(struct mem_region_root *r, struct mem_region *m);
+struct mem_region *find_first_region(struct mem_region_root *r);
struct mem_region *find_used_region(struct mem_region_root *r, vm_t start);
struct mem_region *find_closest_used_region(struct mem_region_root *r,
vm_t start);
diff --git a/include/apos/syscalls.h b/include/apos/syscalls.h
index 9346da3..e7b1cd5 100644
--- a/include/apos/syscalls.h
+++ b/include/apos/syscalls.h
@@ -25,7 +25,8 @@ enum {
* structure of the OS, but these following syscalls are probably
* required */
SYS_IPC_SERVER, /* inform kernel that process should be treated as a server */
- SYS_IPC_REQ, /* IPC request to server */
+ SYS_IPC_REQ_PROC, /* IPC request to server on behalf of process */
+ SYS_IPC_REQ_THREAD, /* IPC request to server on behalf of thread */
SYS_IPC_RESP, /* IPC response from server */
/* process management */
diff --git a/include/apos/tcb.h b/include/apos/tcb.h
index 11e1b5a..f31bf77 100644
--- a/include/apos/tcb.h
+++ b/include/apos/tcb.h
@@ -5,14 +5,24 @@
#include <apos/types.h>
#include <tcb.h> /* arch-specific data */
+/* process(/main) threads don't have any previous threads */
+#define is_proc(t) (!t->prev)
+
struct tcb {
struct arch_tcbd tcbd;
/* mapping data
* TODO: should mem_region_root be renamed mem_root or something? feels
* kind of clunky */
- struct mem_region_root sp_r;
+ union {
+ /* if we're the main thread, we control the memory regions */
+ struct mem_region_root sp_r;
+ /* if we're not the main thread, we have a pointer to the main
+ * thread */
+ struct tcb *proc;
+ };
+ id_t pid;
id_t tid;
vm_t callback;
@@ -29,15 +39,18 @@ struct tcb {
/* vm root branch */
struct vm_branch *b_r;
- struct tcb *parent;
+ /* linked list of threads in this process */
struct tcb *next;
+ struct tcb *prev;
};
void init_tcbs();
void destroy_tcbs();
-struct tcb *new_thread();
-void destroy_thread(struct tcb *);
+struct tcb *create_thread(struct tcb *p);
+struct tcb *create_proc(struct tcb *p);
+stat_t destroy_thread(struct tcb *t);
+stat_t destroy_proc(struct tcb *p);
struct tcb *cur_tcb();
void use_tcb(struct tcb *);
diff --git a/include/apos/uapi.h b/include/apos/uapi.h
index a3b54d5..b3d345f 100644
--- a/include/apos/uapi.h
+++ b/include/apos/uapi.h
@@ -94,7 +94,8 @@ SYSCALL_DECLARE(free_timer);
/* ipc */
SYSCALL_DECLARE(ipc_server);
-SYSCALL_DECLARE(ipc_req);
+SYSCALL_DECLARE(ipc_req_proc);
+SYSCALL_DECLARE(ipc_req_thread);
SYSCALL_DECLARE(ipc_resp);
/* proc */
diff --git a/include/apos/vmem.h b/include/apos/vmem.h
index f1b0d19..036780f 100644
--- a/include/apos/vmem.h
+++ b/include/apos/vmem.h
@@ -12,7 +12,9 @@ vm_t alloc_shared_uvmem(struct tcb *r, size_t size, vmflags_t flags);
vm_t ref_shared_uvmem(struct tcb *r1, struct tcb *r2, vm_t va, vmflags_t flags);
stat_t free_uvmem(struct tcb *r, vm_t a);
+
stat_t init_uvmem(struct tcb *r, vm_t base, vm_t top);
+stat_t destroy_uvmem(struct tcb *r);
stat_t alloc_uvmem_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr,
vmflags_t flags, enum mm_order order, void *data);
diff --git a/include/arch/vmem.h b/include/arch/vmem.h
index 74b0aa5..5197c67 100644
--- a/include/arch/vmem.h
+++ b/include/arch/vmem.h
@@ -16,13 +16,15 @@ stat_t stat_vpage(struct vm_branch *branch, vm_t vaddr, pm_t *paddr,
void flush_tlb();
void flush_tlb_all();
-void populate_root_branch(struct vm_branch *b);
+stat_t populate_kvmem(struct vm_branch *b);
struct vm_branch *init_vmem(void *fdt);
#if defined(DEBUG)
vm_t setup_kernel_io(struct vm_branch *b, vm_t paddr);
#endif
-stat_t clone_vmbranch(struct vm_branch *, struct vm_branch *);
+struct vm_branch *create_vmem();
+stat_t destroy_vmem(struct vm_branch *);
+stat_t clone_uvmem(struct vm_branch *, struct vm_branch *);
#endif /* APOS_ARCH_PAGES_H */