aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TCB.txt4
-rw-r--r--TODO.txt4
-rw-r--r--arch/riscv64/kernel/entry.S7
-rw-r--r--arch/riscv64/kernel/vmem.c23
-rw-r--r--common/dmem.c17
-rw-r--r--common/elf.c2
-rw-r--r--common/mem_regions.c5
-rw-r--r--common/tcb.c15
-rw-r--r--common/uapi/ipc.c2
-rw-r--r--common/vmem.c71
-rw-r--r--include/apos/assert.h42
-rw-r--r--include/apos/dmem.h4
-rw-r--r--include/apos/mem.h2
-rw-r--r--include/apos/mem_regions.h7
-rw-r--r--include/apos/tcb.h5
-rw-r--r--include/apos/types.h3
-rw-r--r--include/apos/vmem.h18
-rw-r--r--include/arch/vmem.h2
18 files changed, 182 insertions, 51 deletions
diff --git a/TCB.txt b/TCB.txt
index 4f262b4..4b7bf37 100644
--- a/TCB.txt
+++ b/TCB.txt
@@ -14,3 +14,7 @@ elevated to a process is a new one allocated. Only when the last thread in a
process is released is the memory released. Will still need to figure out
exactly how device memory should be freed, since it's handled globally instead
of per thread atm.
+
+Also, I suspect I may have made my life a bit too difficult with different sized
+pages, as I'm having a hell of a time figuring out how `fork` should be
+implemented :D
diff --git a/TODO.txt b/TODO.txt
index 20f86a3..6c98139 100644
--- a/TODO.txt
+++ b/TODO.txt
@@ -2,7 +2,7 @@
+ Implement more type operators in dbg, mainly intmax/uintmax and size_t
-+ Add in mapping the same memory to two different processes
++ Add in mapping the same memory to two different processes (sort of?)
+ Create sensible thread handling
+ Add in init process loading
+ Make sure vmap is in 4K increments or whatever (fuck it, sure)
@@ -14,7 +14,7 @@ details dumbass
+ Primarily memory should be allocated to a process through mmap-like
functionality, but brk/sbrk can probably still be emulated. If s/brk maps memory
that's later attempted to mmap, it fails, and vice versa. Apparently should be
-acceptable by Unix standards.
+acceptable by Unix standards. (or just make brk in libc a noop?)
+ Alignment can maybe still be used, though more in the sense of using larger
pages? YES, CHECK common/vmem.c:map_fill_region! Should be implemented there as
well
diff --git a/arch/riscv64/kernel/entry.S b/arch/riscv64/kernel/entry.S
index 0ff1a69..7f697b5 100644
--- a/arch/riscv64/kernel/entry.S
+++ b/arch/riscv64/kernel/entry.S
@@ -74,8 +74,11 @@ handle_exception:
j restore_all
handle_syscall:
- /* TODO: CSR_EPC should be moved forward one instruction when dealing
- * with syscalls */
+ /* add 4 (size of ecall) to EPC to avoid running the same instruction
+ * twice */
+ csrr s0, CSR_SEPC
+ addi s0, s0, 4
+ csrw CSR_SEPC, s0
jal syscall_dispatch
/* if we had a thread switch, load kernel stack of current thread and
* restore its context */
diff --git a/arch/riscv64/kernel/vmem.c b/arch/riscv64/kernel/vmem.c
index 46ddf29..7ffde86 100644
--- a/arch/riscv64/kernel/vmem.c
+++ b/arch/riscv64/kernel/vmem.c
@@ -45,10 +45,17 @@ static pm_t *__find_vmem(struct vm_branch *b, vm_t v, enum mm_order *o)
stat_t mod_vpage(struct vm_branch *branch, vm_t vaddr, pm_t paddr,
vmflags_t flags)
{
- pm_t *pte = __find_vmem(branch, vaddr, 0);
+ enum mm_order order;
+ pm_t *pte = __find_vmem(branch, vaddr, &order);
if (pte) {
*pte = to_pte((pm_t)__pa(paddr), vp_flags(flags));
- return OK;
+ /* if we're modifying a top level mapping, we will have to
+ * update the same one for all the other threads in this process
+ * */
+ if (order == __mm_max_order)
+ return INFO_SEFF;
+ else
+ return OK;
}
return ERR_NF;
@@ -115,7 +122,8 @@ stat_t map_vpage(struct vm_branch *branch, pm_t paddr, vm_t vaddr,
branch->leaf[idx] =
(struct vm_branch *)to_pte((pm_t)__pa(paddr), vp_flags(flags));
- return OK;
+
+ return top == __mm_max_order ? INFO_SEFF : OK;
}
stat_t unmap_vpage(struct vm_branch *branch, vm_t vaddr)
@@ -191,3 +199,12 @@ vm_t setup_kernel_io(struct vm_branch *b, vm_t paddr)
return -SZ_1G + paddr - (gigapage * MM_GPAGE_SIZE);
}
#endif
+
+stat_t clone_vmbranch(struct vm_branch *r, struct vm_branch *b)
+{
+ /* TODO: error checking? */
+ for (size_t i = 0; i <= CSTACK_PAGE; ++i)
+ b->leaf[i] = r->leaf[i];
+
+ return OK;
+}
diff --git a/common/dmem.c b/common/dmem.c
index 59ea666..6c207c1 100644
--- a/common/dmem.c
+++ b/common/dmem.c
@@ -27,15 +27,17 @@ stat_t init_devmem(pm_t ram_base, pm_t ram_top)
}
stat_t dev_alloc_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr,
- vmflags_t flags, enum mm_order order)
+ vmflags_t flags, enum mm_order order, void *data)
{
- map_vpage(b, *offset, vaddr, flags, order);
+ stat_t *status = (stat_t *)data;
+ /* TODO: remember to do something with this status info */
+ *status = map_vpage(b, *offset, vaddr, flags, order);
*offset += __o_size(order);
return OK;
}
stat_t dev_free_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr,
- vmflags_t flags, enum mm_order order)
+ vmflags_t flags, enum mm_order order, void *data)
{
UNUSED(offset);
UNUSED(flags);
@@ -43,9 +45,10 @@ stat_t dev_free_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr,
enum mm_order v_order = 0;
stat_vpage(b, vaddr, &paddr, &v_order, 0);
if (order != v_order)
- return REGION_TRY_AGAIN;
+ return INFO_TRGN;
- unmap_vpage(b, vaddr);
+ stat_t *status = (stat_t *)data;
+ *status = unmap_vpage(b, vaddr);
return OK;
}
@@ -62,7 +65,7 @@ vm_t alloc_devmem(struct tcb *t, pm_t dev_start, size_t bytes, vmflags_t flags)
return 0;
return map_fill_region(t->b_r, &dev_alloc_wrapper, dev_start, region,
- bytes, flags);
+ bytes, flags, 0);
}
stat_t free_devmem(struct tcb *t, vm_t dev_start)
@@ -85,7 +88,7 @@ stat_t free_devmem(struct tcb *t, vm_t dev_start)
size_t region_size = __addr(m->end - m->start);
map_fill_region(t->b_r, &dev_free_wrapper, dev_paddr, dev_start,
- region_size, 0);
+ region_size, 0, 0);
if (dev_paddr < __pre_top)
free_region(&pre_ram, dev_paddr);
diff --git a/common/elf.c b/common/elf.c
index 459cacf..9af4f08 100644
--- a/common/elf.c
+++ b/common/elf.c
@@ -46,7 +46,7 @@ static void __map_exec(struct tcb *t, vm_t bin, uint8_t ei_c, vm_t phstart,
uint8_t elf_flags = program_header_prop(ei_c, runner, p_flags);
uint8_t uvflags = __elf_to_uvflags(elf_flags);
- map_allocd_region(t->b_r, start, vsz, default_flags);
+ map_allocd_region(t->b_r, start, vsz, default_flags, 0);
vm_t vo = bin + program_header_prop(ei_c, runner, p_offset);
vm_t vfz = program_header_prop(ei_c, runner, p_filesz);
diff --git a/common/mem_regions.c b/common/mem_regions.c
index b0cbe0e..bbc894e 100644
--- a/common/mem_regions.c
+++ b/common/mem_regions.c
@@ -426,7 +426,8 @@ stat_t free_known_region(struct mem_region_root *r, struct mem_region *m)
* permutations etc. which would be slow and I don't want to implement it.
*/
vm_t map_fill_region(struct vm_branch *b, region_callback_t *mem_handler,
- pm_t offset, vm_t start, size_t bytes, vmflags_t flags)
+ pm_t offset, vm_t start, size_t bytes, vmflags_t flags,
+ void *data)
{
pm_t runner = __page(start);
size_t pages = __pages(bytes);
@@ -447,7 +448,7 @@ vm_t map_fill_region(struct vm_branch *b, region_callback_t *mem_handler,
while (pages >= o_pages) {
stat_t res = mem_handler(b, &offset, __addr(runner),
- flags, top);
+ flags, top, data);
if (res > 0)
break;
diff --git a/common/tcb.c b/common/tcb.c
index bb1bcec..212e20f 100644
--- a/common/tcb.c
+++ b/common/tcb.c
@@ -4,7 +4,9 @@
#include <apos/pmem.h>
#include <apos/nodes.h>
#include <apos/types.h>
+#include <apos/assert.h>
#include <apos/string.h>
+#include <arch/vmem.h>
/* arguably exessively many globals... */
static id_t start_tid;
@@ -98,3 +100,16 @@ struct tcb *get_tcb(id_t tid)
return tcbs[tid];
}
+
+stat_t clone_tcb_maps(struct tcb *r)
+{
+ hard_assert(r && !r->parent, ERR_INVAL);
+ struct tcb *t = r;
+ while ((t = t->next)) {
+ stat_t ret = clone_vmbranch(r->b_r, t->b_r);
+ if (ret)
+ return ret;
+ }
+
+ return OK;
+}
diff --git a/common/uapi/ipc.c b/common/uapi/ipc.c
index bef9665..d7c9d16 100644
--- a/common/uapi/ipc.c
+++ b/common/uapi/ipc.c
@@ -14,7 +14,7 @@ SYSCALL_DEFINE1(ipc_server)(sys_arg_t callback)
SYSCALL_DEFINE3(ipc_req)(sys_arg_t tid, sys_arg_t d0, sys_arg_t d1)
{
struct tcb *r = get_tcb(tid);
- /* something like jump_to_callback(t, d0, d1) */
+ /* something like jump_to_callback(t) */
return (struct sys_ret){ d0, d1 };
}
diff --git a/common/vmem.c b/common/vmem.c
index 989029a..817f851 100644
--- a/common/vmem.c
+++ b/common/vmem.c
@@ -1,4 +1,6 @@
#include <apos/mem_regions.h>
+#include <apos/assert.h>
+#include <apos/debug.h>
#include <apos/bits.h>
#include <apos/vmem.h>
#include <arch/vmem.h>
@@ -10,23 +12,46 @@ stat_t init_uvmem(struct tcb *t, vm_t base, vm_t top)
vm_t alloc_uvmem(struct tcb *t, size_t size, vmflags_t flags)
{
- vm_t v = alloc_region(&t->sp_r, size, &size, flags);
- return map_allocd_region(t->b_r, v, size, flags);
+ /* t exists and is the root tcb of the current process */
+ hard_assert(t && !t->parent, ERR_INVAL);
+
+ stat_t status = OK;
+ const vm_t v = alloc_region(&t->sp_r, size, &size, flags);
+ const vm_t w = map_allocd_region(t->b_r, v, size, flags, &status);
+ if (status == INFO_SEFF)
+ clone_tcb_maps(t);
+
+ return w;
}
vm_t alloc_fixed_uvmem(struct tcb *t, vm_t start, size_t size, vmflags_t flags)
{
- vm_t v = alloc_fixed_region(&t->sp_r, start, size, &size, flags);
- return map_allocd_region(t->b_r, v, size, flags);
+ hard_assert(t && !t->parent, ERR_INVAL);
+
+ stat_t status = OK;
+ const vm_t v = alloc_fixed_region(&t->sp_r, start, size, &size, flags);
+ const vm_t w = map_allocd_region(t->b_r, v, size, flags, &status);
+
+ if (status == INFO_SEFF)
+ clone_tcb_maps(t);
+
+ return w;
}
/* 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)
{
- /* TODO: proper error handling */
- vm_t v = alloc_region(&t->sp_r, size, &size,
- flags | MR_SHARED | MR_OWNED);
- return map_shared_region(t->b_r, v, size, flags);
+ hard_assert(t && t->parent, ERR_INVAL);
+
+ stat_t status = OK;
+ const vm_t v = alloc_region(&t->sp_r, size, &size,
+ flags | MR_SHARED | MR_OWNED);
+ const vm_t w = map_shared_region(t->b_r, v, size, flags, &status);
+
+ if (status == INFO_SEFF)
+ clone_tcb_maps(t);
+
+ return w;
}
vm_t ref_shared_uvmem(struct tcb *t1, struct tcb *t2, vm_t va, vmflags_t flags)
@@ -54,6 +79,7 @@ vm_t ref_shared_uvmem(struct tcb *t1, struct tcb *t2, vm_t va, vmflags_t flags)
return v;
}
+/* TODO: assume tcb is root tcb? */
stat_t free_uvmem(struct tcb *t, vm_t va)
{
struct mem_region *m = find_used_region(&t->sp_r, va);
@@ -64,26 +90,31 @@ stat_t free_uvmem(struct tcb *t, vm_t va)
vmflags_t flags = m->flags;
free_region(&t->sp_r, va);
- unmap_freed_region(t->b_r, va, pa, flags);
- return 0;
+
+ stat_t status = OK;
+ unmap_freed_region(t->b_r, va, pa, flags, &status);
+ if (status == INFO_SEFF)
+ return clone_tcb_maps(t);
+
+ return status;
}
stat_t alloc_uvmem_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr,
- vmflags_t flags, enum mm_order order)
+ vmflags_t flags, enum mm_order order, void *data)
{
*offset = alloc_page(order, *offset);
if (!*offset)
- return REGION_TRY_AGAIN; /* try again */
+ return INFO_TRGN; /* try again */
- map_vpage(b, *offset, vaddr, flags, order);
- return OK;
+ stat_t ret = map_vpage(b, *offset, vaddr, flags, order);
+ return ret;
}
stat_t alloc_shared_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr,
- vmflags_t flags, enum mm_order order)
+ vmflags_t flags, enum mm_order order, void *data)
{
if (order != MM_O0)
- return REGION_TRY_AGAIN;
+ return INFO_TRGN;
*offset = alloc_page(MM_O0, *offset);
map_vpage(b, *offset, vaddr, flags, order);
@@ -91,7 +122,7 @@ stat_t alloc_shared_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr,
}
stat_t free_uvmem_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr,
- vmflags_t flags, enum mm_order order)
+ vmflags_t flags, enum mm_order order, void *data)
{
UNUSED(flags);
UNUSED(offset);
@@ -100,11 +131,13 @@ stat_t free_uvmem_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr,
enum mm_order v_order = 0;
stat_vpage(b, vaddr, &paddr, &v_order, 0);
if (order != v_order)
- return REGION_TRY_AGAIN;
+ return INFO_TRGN;
- unmap_vpage(b, vaddr);
+ stat_t *status = (stat_t *)data;
+ *status = unmap_vpage(b, vaddr);
/* don't free shared pages, unless they're owned */
if (!__is_set(flags, MR_SHARED) || __is_set(flags, MR_OWNED))
free_page(order, paddr);
+
return OK;
}
diff --git a/include/apos/assert.h b/include/apos/assert.h
new file mode 100644
index 0000000..7200fd2
--- /dev/null
+++ b/include/apos/assert.h
@@ -0,0 +1,42 @@
+#ifndef APOS_ASSERT_H
+#define APOS_ASSERT_H
+
+#include <apos/debug.h>
+#include <apos/utils.h>
+
+/* TODO: should this exit or do something explosive like that? */
+#if !defined(DNDEBUG)
+#define catastrophic_assert(x) \
+ do { \
+ if (x) { \
+ err("catastrophic assertion failed: %s\n", QUOTE(x)); \
+ while (1) \
+ ; \
+ } \
+ } while (0);
+
+#define hard_assert(x, r) \
+ do { \
+ if (x) { \
+ warn("hard assertion failed: %s\n", QUOTE(x)); \
+ return r; \
+ } \
+ } while (0);
+
+#define soft_assert(x) \
+ do { \
+ if (x) { \
+ info("soft assertion failed: %s\n", QUOTE(x)); \
+ } \
+ } while (0);
+#else
+#define catastrophic_assert(x)
+#define hard_assert(x, r)
+#define soft_assert(x)
+#endif
+
+/* use when return value doesn't exist, like hard_assert(x,
+ * RETURN_VOID); */
+#define RETURN_VOID
+
+#endif /* APOS_ASSERT_H */
diff --git a/include/apos/dmem.h b/include/apos/dmem.h
index d337e61..3ee93b6 100644
--- a/include/apos/dmem.h
+++ b/include/apos/dmem.h
@@ -14,8 +14,8 @@ vm_t alloc_devmem(struct tcb *t, pm_t dev_start, size_t bytes, vmflags_t flags);
stat_t free_devmem(struct tcb *t, vm_t dev_start);
stat_t dev_free_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr,
- vmflags_t flags, enum mm_order t);
+ vmflags_t flags, enum mm_order t, void *);
stat_t dev_alloc_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr,
- vmflags_t flags, enum mm_order t);
+ vmflags_t flags, enum mm_order t, void *);
#endif /* APOS_DEV_H */
diff --git a/include/apos/mem.h b/include/apos/mem.h
index bc60f21..f3eded7 100644
--- a/include/apos/mem.h
+++ b/include/apos/mem.h
@@ -45,6 +45,8 @@
#define MR_SHARED (1 << 9)
/* owner of shared region */
#define MR_OWNED (1 << 10)
+/* copy on write */
+#define MR_COW (1 << 11)
extern size_t __mm_shifts[10];
extern size_t __mm_widths[10];
diff --git a/include/apos/mem_regions.h b/include/apos/mem_regions.h
index 7841dde..efe0592 100644
--- a/include/apos/mem_regions.h
+++ b/include/apos/mem_regions.h
@@ -41,11 +41,12 @@ struct mem_region *find_closest_used_region(struct mem_region_root *r,
struct mem_region *find_free_region(struct mem_region_root *r, size_t size,
size_t *align);
-#define REGION_TRY_AGAIN 1
typedef stat_t region_callback_t(struct vm_branch *b, pm_t *offset, vm_t vaddr,
- vmflags_t flags, enum mm_order order);
+ vmflags_t flags, enum mm_order order,
+ void *data);
vm_t map_fill_region(struct vm_branch *b, region_callback_t *mem_handler,
- pm_t offset, vm_t start, size_t bytes, vmflags_t flags);
+ pm_t offset, vm_t start, size_t bytes, vmflags_t flags,
+ void *data);
#endif /* APOS_MEM_REGIONS_H */
diff --git a/include/apos/tcb.h b/include/apos/tcb.h
index 821d822..11e1b5a 100644
--- a/include/apos/tcb.h
+++ b/include/apos/tcb.h
@@ -28,6 +28,9 @@ struct tcb {
/* vm root branch */
struct vm_branch *b_r;
+
+ struct tcb *parent;
+ struct tcb *next;
};
void init_tcbs();
@@ -41,4 +44,6 @@ void use_tcb(struct tcb *);
struct tcb *get_tcb(id_t tid);
+stat_t clone_tcb_maps(struct tcb *);
+
#endif /* APOS_TCB_H */
diff --git a/include/apos/types.h b/include/apos/types.h
index d413957..2f45857 100644
--- a/include/apos/types.h
+++ b/include/apos/types.h
@@ -197,6 +197,9 @@ enum {
ERR_ALIGN = -2, /* wrong alignment */
ERR_NF = -1, /* not found */
OK = 0, /* OK */
+ INFO_TRGN = 1, /* try again */
+ INFO_SEFF = 2, /* side effects */
+ INFO_CONT = 3, /* continue */
};
#include <types.h> /* arch-specific type definitions (pm_t/vm_t etc) */
diff --git a/include/apos/vmem.h b/include/apos/vmem.h
index 17f998d..f1b0d19 100644
--- a/include/apos/vmem.h
+++ b/include/apos/vmem.h
@@ -15,20 +15,20 @@ 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 alloc_uvmem_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr,
- vmflags_t flags, enum mm_order order);
+ vmflags_t flags, enum mm_order order, void *data);
stat_t alloc_shared_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr,
- vmflags_t flags, enum mm_order order);
+ vmflags_t flags, enum mm_order order, void *data);
stat_t free_uvmem_wrapper(struct vm_branch *b, pm_t *offset, vm_t vaddr,
- vmflags_t flags, enum mm_order order);
+ vmflags_t flags, enum mm_order order, void *data);
-#define map_allocd_region(b, start, bytes, flags) \
- map_fill_region(b, &alloc_uvmem_wrapper, 0, start, bytes, flags)
+#define map_allocd_region(b, start, bytes, flags, data) \
+ map_fill_region(b, &alloc_uvmem_wrapper, 0, start, bytes, flags, data)
-#define map_shared_region(b, start, bytes, flags) \
- map_fill_region(b, &alloc_shared_wrapper, 0, start, bytes, flags)
+#define map_shared_region(b, start, bytes, flags, data) \
+ map_fill_region(b, &alloc_shared_wrapper, 0, start, bytes, flags, data)
-#define unmap_freed_region(b, start, bytes, flags) \
- map_fill_region(b, &free_uvmem_wrapper, 0, start, bytes, flags)
+#define unmap_freed_region(b, start, bytes, flags, data) \
+ map_fill_region(b, &free_uvmem_wrapper, 0, start, bytes, flags, data)
#define vm_flags(x) ((x) & ~0xff)
#define vp_flags(x) ((x)&0xff)
diff --git a/include/arch/vmem.h b/include/arch/vmem.h
index 182af11..74b0aa5 100644
--- a/include/arch/vmem.h
+++ b/include/arch/vmem.h
@@ -23,4 +23,6 @@ struct vm_branch *init_vmem(void *fdt);
vm_t setup_kernel_io(struct vm_branch *b, vm_t paddr);
#endif
+stat_t clone_vmbranch(struct vm_branch *, struct vm_branch *);
+
#endif /* APOS_ARCH_PAGES_H */