aboutsummaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-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
6 files changed, 164 insertions, 46 deletions
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);