aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/initrd.c40
-rw-r--r--src/main.c92
-rw-r--r--src/mem.c22
-rw-r--r--src/pmem.c178
-rw-r--r--src/proc.c29
-rw-r--r--src/tcb.c8
-rw-r--r--src/vmem.c35
7 files changed, 255 insertions, 149 deletions
diff --git a/src/initrd.c b/src/initrd.c
index caff8b3..242e373 100644
--- a/src/initrd.c
+++ b/src/initrd.c
@@ -115,53 +115,39 @@ static size_t init_nlen = ARRAY_SIZE(init_n) - 1; /* ignore trailing NULL */
pm_t get_initrdtop(const void *fdt)
{
int chosen_offset = fdt_path_offset(fdt, "/chosen");
- struct cell_info ci = get_cellinfo(fdt, chosen_offset);
+ int len = 0;
void *initrd_end_ptr = (void *)fdt_getprop(fdt, chosen_offset,
- "linux,initrd-end", NULL);
+ "linux,initrd-end", &len);
- /* fdt is only aware of physical memory pointers */
- return (pm_t)__va(fdt_load_int_ptr(ci.addr_cells, initrd_end_ptr));
+ catastrophic_assert(initrd_end_ptr);
+ return (pm_t)fdt_load_int_ptr(len / 4, initrd_end_ptr);
}
pm_t get_initrdbase(const void *fdt)
{
const int chosen_offset = fdt_path_offset(fdt, "/chosen");
- const struct cell_info ci = get_cellinfo(fdt, chosen_offset);
+ int len = 0;
void *initrd_base_ptr = (void *)fdt_getprop(fdt, chosen_offset,
- "linux,initrd-start", NULL);
+ "linux,initrd-start", &len);
- return (pm_t)__va(fdt_load_int_ptr(ci.addr_cells, initrd_base_ptr));
+ catastrophic_assert(initrd_base_ptr);
+ return (pm_t)fdt_load_int_ptr(len / 4, initrd_base_ptr);
}
-
-size_t get_init_size(const void *fdt)
+size_t get_initrdsize(const void *fdt)
{
- char *c = (char *)get_initrdbase(fdt);
- struct cpio_header *cp = __find_file(c, init_n, init_nlen);
- return convnum(cp->c_filesize, 8, 16);
+ pm_t start = get_initrdbase(fdt);
+ pm_t end = get_initrdtop(fdt);
+ return end - start;
}
vm_t get_init_base(const void *fdt)
{
char *c = (char *)get_initrdbase(fdt);
+ c = __va(c);
struct cpio_header *cp = __find_file(c, init_n, init_nlen);
size_t name_len = convnum(cp->c_namesize, 8, 16);
return ((vm_t)cp) + align_up(sizeof(struct cpio_header) + name_len, 4);
}
-
-stat_t move_init(const void *fdt, void *target)
-{
- const char *c = (const char *)get_initrdbase(fdt);
-
- const struct cpio_header *cp = __find_file(c, init_n, init_nlen);
- size_t name_len = convnum(cp->c_namesize, 8, 16);
- size_t file_len = convnum(cp->c_filesize, 8, 16);
-
- char *fp = (char *)cp;
- fp += align_up(sizeof(struct cpio_header) + name_len, 4);
-
- memmove(target, fp, file_len);
- return OK;
-}
diff --git a/src/main.c b/src/main.c
index 4647fed..19d52a2 100644
--- a/src/main.c
+++ b/src/main.c
@@ -19,6 +19,54 @@
#include <arch/smp.h>
#include <libfdt.h>
+static pm_t __fdt_ram_base(void *fdt)
+{
+ int mem_offset = fdt_path_offset(fdt, "/memory");
+ const void *mem_reg = fdt_getprop(fdt, mem_offset, "reg", NULL);
+
+ struct cell_info ci = get_cellinfo(fdt, mem_offset);
+ return (pm_t)fdt_load_reg_addr(ci, mem_reg, 0);
+}
+
+static pm_t __fdt_ram_size(void *fdt)
+{
+ int mem_offset = fdt_path_offset(fdt, "/memory");
+ const void *mem_reg = fdt_getprop(fdt, mem_offset, "reg", NULL);
+
+ /* here we actually want the root offset because /memory itself doesn't
+ * have children, I guess? */
+ struct cell_info ci = get_cellinfo(fdt, fdt_path_offset(fdt, "/"));
+ return (pm_t)fdt_load_reg_size(ci, mem_reg, 0);
+}
+
+void kernel(void *fdt, uintptr_t load_addr, struct vmem *d)
+{
+ fdt = __va(fdt);
+
+ /* dbg uses direct mapping at this point */
+ init_dbg(fdt);
+ /* start up debugging in kernel IO */
+ setup_io_dbg(d);
+
+ dbg_fdt(fdt);
+
+ setup_arch(fdt);
+
+ init_pmem(fdt, load_addr);
+
+ init_irq(fdt);
+ init_timer(fdt);
+
+ vm_t proc_fdt = 0, proc_initrd = 0;
+ init_proc(fdt, &proc_fdt, &proc_initrd);
+
+ /* try to bring up other cores on system */
+ smp_bringup(d, fdt);
+
+ /* start running init program */
+ run_init(cur_tcb(), proc_fdt, proc_initrd);
+}
+
/**
* Boot entry of kernel actual.
*
@@ -29,35 +77,33 @@
* @param ram_base RAM base.
* @return Should not.
*/
-void __main main(void *fdt, uintptr_t ram_base)
+void main(unsigned long hart, void *fdt, uintptr_t load_addr)
{
- set_ram_base(ram_base);
+ /* we have our own ways to get the current hart when we need it, but we
+ * have to get the function signature right */
+ (void)hart;
- /* convert physical address to virtual address */
- fdt = __va(fdt);
-
- /* dbg uses direct mapping at this point */
- init_dbg(fdt);
- setup_dmap_dbg();
- dbg_fdt(fdt);
+ pm_t ram_base = __fdt_ram_base(fdt);
+ pm_t ram_size = __fdt_ram_size(fdt);
+ set_ram_base(ram_base);
+ set_ram_size(ram_size);
- setup_arch(fdt);
+ init_mem(fdt);
- init_pmem(fdt);
- /* setup temporary virtual memory */
- struct vmem *b = init_vmem(fdt);
+ struct vmem *d = direct_mapping();
- /* start up debugging in kernel IO */
- setup_io_dbg(b);
+ to_kernelspace(fdt, load_addr, d, ram_base, VM_DMAP);
+ unreachable();
+}
- init_irq(fdt);
- init_timer(fdt);
- init_proc(fdt);
+#if GENERIC_UBOOT
+void main_go(size_t argc, char *argv[], uintptr_t load_addr)
+{
+ if (argc != 2)
+ return;
- /* try to bring up other cores on system */
- smp_bringup(b, fdt);
+ void *fdt = (void *)strtouintptr(argv[1]);
- /* start running init program */
- void *initrd = (void *)get_initrdbase(fdt);
- run_init(cur_tcb(), fdt, initrd);
+ main(0, fdt, load_addr);
}
+#endif
diff --git a/src/mem.c b/src/mem.c
index e3f98e7..68d323f 100644
--- a/src/mem.c
+++ b/src/mem.c
@@ -22,6 +22,7 @@ enum mm_order __mm_max_order;
* like __mm_*.
*/
pm_t ram_base;
+size_t ram_size;
enum mm_order nearest_order(size_t size)
{
@@ -32,12 +33,17 @@ enum mm_order nearest_order(size_t size)
return MM_O0;
}
-void init_mem(size_t max_order, size_t bits[10], size_t page_shift)
+void init_mem(void *fdt)
{
+ size_t max_order = 0;
+ size_t base_bits = 0;
+ size_t bits[NUM_ORDERS] = { 0 };
+ stat_pmem_conf(fdt, &max_order, &base_bits, bits);
+
__mm_max_order = max_order;
- __mm_page_shift = page_shift;
+ __mm_page_shift = base_bits;
- __mm_shifts[0] = page_shift;
+ __mm_shifts[0] = __mm_page_shift;
__mm_widths[0] = 1 << bits[0];
__mm_sizes[0] = 1 << __mm_page_shift;
@@ -53,7 +59,17 @@ void set_ram_base(uintptr_t base)
ram_base = base;
}
+void set_ram_size(size_t size)
+{
+ ram_size = size;
+}
+
uintptr_t get_ram_base()
{
return ram_base;
}
+
+size_t get_ram_size()
+{
+ return ram_size;
+}
diff --git a/src/pmem.c b/src/pmem.c
index 4da3f4c..bddefa8 100644
--- a/src/pmem.c
+++ b/src/pmem.c
@@ -436,77 +436,89 @@ static void __mark_area_used(pm_t base, pm_t top)
mark_used(BASE_PAGE, runner);
}
+struct avoid_region {
+ pm_t base;
+ pm_t size;
+};
+
+static bool overlaps(pm_t base1, pm_t size1, pm_t base2, pm_t size2)
+{
+ bool b = base1 >= base2 && base1 < base2 + size2;
+ bool t = base1 + size1 > base2 && base1 + size1 <= base2 + size2;
+ return b || t;
+}
+
/**
* Mark reserved memory region used, to avoid it getting accidentally allocated.
*
* @param fdt Global FDT pointer.
*/
-static void __mark_reserved_mem(void *fdt)
+static void __mark_reserved(pm_t ram_base, pm_t ram_size, size_t avoid_count,
+ struct avoid_region avoid[64])
+{
+ for (size_t i = 0; i < avoid_count; ++i) {
+ pm_t base = avoid[i].base;
+ pm_t size = avoid[i].size;
+
+ if (!overlaps(base, size, ram_base, ram_size))
+ continue;
+
+ pm_t top = base + size;
+ __mark_area_used(base, top);
+ info("marked [%lx - %lx] reserved\n", base, top);
+ }
+}
+
+static size_t build_reserved_map(size_t exists, struct avoid_region avoid[64],
+ void *fdt)
{
int rmem_offset = fdt_path_offset(fdt, "/reserved-memory");
struct cell_info ci = get_cellinfo(fdt, rmem_offset);
int node = 0;
fdt_for_each_subnode(node, fdt, rmem_offset) {
- uint8_t *rmem_reg =
- (uint8_t *)fdt_getprop(fdt, node, "reg", NULL);
+ uint8_t *rmem_reg = (uint8_t *)fdt_getprop(fdt, node, "reg",
+ NULL);
pm_t base = (pm_t)fdt_load_reg_addr(ci, rmem_reg, 0);
+ pm_t size = (pm_t)fdt_load_reg_size(ci, rmem_reg, 0);
- /** @todo make sure the top of a reserved memory area doesn't go
- * against our assumptions in FW_MAX_SIZE? */
- pm_t top = (pm_t)fdt_load_reg_size(ci, rmem_reg, 0) + base;
- __mark_area_used((pm_t)__va(base), (pm_t)__va(top));
- info("marked [%lx - %lx] reserved\n",
- (pm_t)__va(base), (pm_t)__va(top));
+ avoid[exists++] = (struct avoid_region){(pm_t)__va(base), size};
+ catastrophic_assert(exists < 64);
}
+
+ return exists;
}
-/**
- * Read top of RAM from FDT.
- *
- * @param fdt Global FDT pointer.
- * @return Physical address of top of RAM.
- */
-static pm_t __get_ramtop(void *fdt)
+static pm_t select_base(pm_t ram_base, pm_t ram_size, pm_t size,
+ pm_t avoid_count,
+ struct avoid_region avoid[64])
{
- int mem_offset = fdt_path_offset(fdt, "/memory");
- const void *mem_reg = fdt_getprop(fdt, mem_offset, "reg", NULL);
+ for (size_t i = 0; i < avoid_count; ++i) {
+ /* try placing things just after each avoidance region */
+ pm_t base = avoid[i].base + avoid[i].size;
- /* here we actually want the root offset because /memory itself doesn't
- * have children, I guess? */
- struct cell_info ci = get_cellinfo(fdt, fdt_path_offset(fdt, "/"));
- pm_t base = (pm_t)fdt_load_reg_addr(ci, mem_reg, 0);
- return (pm_t)fdt_load_reg_size(ci, mem_reg, 0) + base;
-}
+ /* any better alignment than this has to be manually handled
+ * outside of this function */
+ base = align_up(base, sizeof(long));
-/**
- * Read top of FDT.
- *
- * @param fdt Global FDT pointer.
- * @return Physical address of top of FDT.
- */
-static pm_t __get_fdttop(void *fdt)
-{
- const char *b = (const char *)fdt;
- return (pm_t)(b + fdt_totalsize(fdt));
-}
+ if (!overlaps(base, size, ram_base, ram_size))
+ continue;
-/**
- * Return base of FDT.
- *
- * Technically pretty useless, but here mainly for cohesion.
- *
- * @param fdt Global FDT pointer.
- * @return \c fdt.
- */
-static pm_t __get_fdtbase(void *fdt)
-{
- /* lol */
- return (pm_t)fdt;
+ for (size_t a = 0; a < avoid_count; ++a) {
+ if (overlaps(base, size, avoid[a].base, avoid[a].size))
+ goto retry;
+
+ }
+
+ return base;
+retry:
+ }
+
+ return 0;
}
-void init_pmem(void *fdt)
+void init_pmem(void *fdt, uintptr_t load_addr)
{
/** @todo should I keep the info outputs? I suppose it's nice to see
* if any assumption is being broken in the serial log, but in that case
@@ -515,14 +527,10 @@ void init_pmem(void *fdt)
*/
info("initializing pmem\n");
- size_t max_order = 0;
- size_t base_bits = 0;
- size_t bits[NUM_ORDERS] = { 0 };
- stat_pmem_conf(fdt, &max_order, &base_bits, bits);
- init_mem(max_order, bits, base_bits);
-
- pm_t ram_size = __get_ramtop(fdt) - get_ram_base();
+ /* here it's a bit easier to work with virtual RAM addresses, but
+ * physical ones could work just as well. */
pm_t ram_base = (pm_t)__va(get_ram_base());
+ pm_t ram_size = get_ram_size();
info("using ram range [%lx - %lx]\n",
ram_base, ram_base + ram_size);
@@ -530,23 +538,38 @@ void init_pmem(void *fdt)
/** @todo could probably improve error messages on failing to get fdt
* values */
pm_t initrd_base = get_initrdbase(fdt);
- pm_t initrd_top = get_initrdtop(fdt);
- info("found initrd at [%lx - %lx]\n", initrd_base, initrd_top);
+ pm_t initrd_size = get_initrdsize(fdt);
+ info("found initrd at [%lx - %lx]\n", initrd_base,
+ initrd_base + initrd_size);
- pm_t fdt_top = __get_fdttop(fdt);
- pm_t fdt_base = __get_fdtbase(fdt);
- info("found fdt at [%lx - %lx]\n", fdt_base, fdt_top);
+ pm_t fdt_base = (pm_t)fdt;
+ pm_t fdt_size = fdt_totalsize(fdt);
+ info("found fdt at [%lx - %lx]\n", fdt_base, fdt_base + fdt_size);
/* find probably most suitable contiguous region of ram for our physical
* ram map */
- /** @todo this really should check that there's enough space in RAM
- * instead of just forcing the pmap to be populated */
- pm_t pmap_base = align_up(MAX(initrd_top, fdt_top), BASE_PAGE_SIZE);
- info("choosing to place pmem map at %lx\n", pmap_base);
- size_t probe_size = probe_pmap(ram_base, ram_size, pmap_base);
+ size_t probe_size = probe_pmap(0, ram_size, 0);
info("pmem map probe size returned %lu\n", probe_size);
+ /* linker magicry */
+ extern char *__kernel_size;
+ /* avoidance regions, note that stack and so on is included in the
+ * kernel. Addresses can be outside RAM, in which case they are just
+ * ignored. */
+ struct avoid_region avoid[64] = {
+ {(pm_t)__va(load_addr), (pm_t)&__kernel_size},
+ {(pm_t)__va(initrd_base), initrd_size},
+ {(pm_t)__va(fdt_base), fdt_size}
+ };
+
+ size_t avoid_count = build_reserved_map(4, avoid, fdt);
+ pm_t pmap_base = select_base(ram_base, ram_size,
+ probe_size, avoid_count, avoid);
+
+ catastrophic_assert(pmap_base);
+ info("choosing to place pmem map at %lx\n", pmap_base);
+
size_t actual_size = populate_pmap(ram_base, ram_size, pmap_base);
info("pmem map actual size %lu\n", actual_size);
@@ -555,31 +578,10 @@ void init_pmem(void *fdt)
actual_size);
}
- /* mark init stack, this should be unmapped once we get to executing
- * processes */
- __mark_area_used(VM_STACK_BASE, VM_STACK_TOP);
- info("marked stack [%lx - %lx] used\n", VM_STACK_BASE, VM_STACK_TOP);
-
- /* mark kernel */
- /* this could be made more explicit, I suppose. */
- __mark_area_used(VM_KERN, VM_KERN + PM_KERN_SIZE);
- info("marked kernel [%lx - %lx] used\n", VM_KERN,
- VM_KERN + PM_KERN_SIZE);
-
- /* mark fdt and initrd */
- __mark_area_used(initrd_base, initrd_top);
- info("marked initrd [%lx - %lx] used\n", initrd_base, initrd_top);
-
- __mark_area_used(fdt_base, fdt_top);
- info("marked fdt [%lx - %lx] used\n", fdt_base, fdt_top);
-
- /* mark pmap */
- __mark_area_used(pmap_base, pmap_base + actual_size);
- info("marked pmap [%lx - %lx] used\n", pmap_base,
- pmap_base + actual_size);
+ avoid[avoid_count++] = (struct avoid_region){pmap_base, actual_size};
/* mark reserved mem */
- __mark_reserved_mem(fdt);
+ __mark_reserved(ram_base, ram_size, avoid_count, avoid);
init_mem_nodes();
diff --git a/src/proc.c b/src/proc.c
index 45d1e5e..f2d418f 100644
--- a/src/proc.c
+++ b/src/proc.c
@@ -9,12 +9,15 @@
#include <kmi/elf.h>
#include <kmi/proc.h>
#include <kmi/conf.h>
+#include <kmi/debug.h>
#include <kmi/string.h>
#include <kmi/initrd.h>
#include <arch/arch.h>
#include <arch/proc.h>
#include <arch/cpu.h>
+#include <libfdt.h>
+
stat_t prepare_proc(struct tcb *t, vm_t bin, vm_t interp)
{
vm_t entry = load_elf(t, bin, interp);
@@ -27,7 +30,7 @@ stat_t prepare_proc(struct tcb *t, vm_t bin, vm_t interp)
return OK;
}
-stat_t init_proc(void *fdt)
+stat_t init_proc(void *fdt, vm_t *proc_fdt, vm_t *proc_initrd)
{
init_tcbs();
@@ -42,18 +45,32 @@ stat_t init_proc(void *fdt)
/* force tcb for core */
tcb_assign(t);
- /* set current tcb */
- use_tcb(t);
+ t->notify_id = t->tid;
/* init process has all capabilities */
set_caps(t->caps, 0,
CAP_CAPS | CAP_PROC | CAP_SIGNAL | CAP_POWER | CAP_NOTIFY);
- t->notify_id = t->tid;
+ /* we shall try to map the fdt and initrd into the new address space, so
+ * save them here before we switch */
+ use_tcb(t);
- /* allocate stacks after ELF file to make sure nothing of importance
+ /* allocate stacks etc after ELF file to make sure nothing of importance
* clashes */
- return prepare_proc(t, get_init_base(fdt), 0);
+ prepare_proc(t, get_init_base(fdt), 0);
/** \todo start one thread per core, with special handling for init in
* that each thread starts at the entry point of init? */
+
+ *proc_fdt = map_fixed_mem(t,
+ (pm_t)fdt, fdt_totalsize(fdt),
+ VM_V | VM_R | VM_U);
+
+ pm_t initrd = (pm_t)__va(get_initrdbase(fdt));
+ *proc_initrd = map_fixed_mem(t,
+ initrd, get_initrdsize(fdt),
+ VM_V | VM_R | VM_U);
+
+ info("mapped fdt at %p\n", (void *)*proc_fdt);
+ info("mapped initrd at %p\n", (void *)*proc_initrd);
+ return OK;
}
diff --git a/src/tcb.c b/src/tcb.c
index 1287cef..ba134c6 100644
--- a/src/tcb.c
+++ b/src/tcb.c
@@ -74,7 +74,7 @@ static id_t __alloc_tid(struct tcb *t)
if (i == stop_tid)
return ERR_NF;
- if (get_tcb(i) || i == 0)
+ if (tcbs[i & (num_tids - 1)] || i == 0)
continue;
tcbs[i & (num_tids - 1)] = t;
@@ -210,6 +210,11 @@ static stat_t __destroy_thread_data(struct tcb *t)
destroy_vmem(t->rpc.vmem);
/* remove ourselves from the thread pool */
+ /** @todo this should be at the top of the function, and be wrapped in
+ * some kind of lock that checks that nobody reads the value while we're
+ * setting it to zero. get_tcb() should accordingly increment the
+ * reference count atomically. Also, an unget_tcb() is needed to
+ * decrement the reference count I guess? */
tcbs[t->tid] = 0;
/* forcefully free last struggling bits of memory */
@@ -228,6 +233,7 @@ stat_t destroy_thread(struct tcb *t)
hard_assert(!is_proc(t), ERR_INVAL);
/* mark us as zombies */
+ set_bits(t->state, TCB_ZOMBIE);
t->rid = 0;
/* remove reference to root process */
diff --git a/src/vmem.c b/src/vmem.c
index f52f43e..d041c80 100644
--- a/src/vmem.c
+++ b/src/vmem.c
@@ -232,6 +232,34 @@ vm_t alloc_fixed_uvmem(struct tcb *t, vm_t start, size_t size, vmflags_t flags)
return w;
}
+static vm_t map_fixed_region(struct vmem *b, vm_t v, pm_t p, size_t size,
+ vmflags_t flags, stat_t *status)
+{
+
+ vm_t w = v;
+ stat_t stat = OK;
+ size_t pages = size / BASE_PAGE_SIZE;
+ for (size_t i = 0; i < pages; ++i) {
+ stat = map_vpage(b, p, v, flags, BASE_PAGE);
+ v += BASE_PAGE_SIZE;
+ p += BASE_PAGE_SIZE;
+ }
+
+ if (status)
+ *status = stat;
+
+ return w;
+}
+
+vm_t map_fixed_mem(struct tcb *t, pm_t start, size_t size, vmflags_t flags)
+{
+ stat_t status = OK;
+ const vm_t v = alloc_region(&t->sp_r, size, &size, flags);
+ const vm_t w = map_fixed_region(t->proc.vmem, v, start, size, flags,
+ &status);
+ return w + (start % BASE_PAGE_SIZE);
+}
+
/* free_shared_uvmem shouldn't be needed, likely to work with free_uvmem */
stat_t alloc_shared_uvmem(struct tcb *s, struct tcb *c,
size_t size, vmflags_t sflags, vmflags_t cflags,
@@ -341,9 +369,14 @@ stat_t copy_allocd_wrapper(struct vmem *b, pm_t *offset, vm_t vaddr,
if (!new_page)
return INFO_TRGN;
- map_vpage(b, new_page, vaddr, flags, order);
+ /* set write flags temporarily */
+ vmflags_t wrflags = flags | VM_W;
+ map_vpage(b, new_page, vaddr, wrflags, order);
memcpy((void *)new_page, (void *)(paddr + *offset), order_size(order));
+ /* set actual flags */
+ map_vpage(b, new_page, vaddr, flags, order);
+
if (v_order > order)
*offset += order_size(order);
else