aboutsummaryrefslogtreecommitdiff
path: root/arch/riscv/init/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/riscv/init/init.c')
-rw-r--r--arch/riscv/init/init.c135
1 files changed, 93 insertions, 42 deletions
diff --git a/arch/riscv/init/init.c b/arch/riscv/init/init.c
index ca04bcd..1e04d34 100644
--- a/arch/riscv/init/init.c
+++ b/arch/riscv/init/init.c
@@ -7,12 +7,12 @@
#include <apos/utils.h>
#include <libfdt.h>
#include <pages.h>
+#include <vmem.h>
#include <csr.h>
-#include <vmap.h>
struct pmem_layout {
- pm_t base;
- pm_t top;
+ paddr_t base;
+ paddr_t top;
};
struct cell_info {
@@ -55,7 +55,7 @@ static struct pmem_layout get_memlayout(void *fdt)
/* if riscv128 comes around we will probably see addr_cells == 4, but
* I'm not too concerned about it at the moment */
- pm_t base = (pm_t)fdt_load_int_ptr(ci.addr_cells, mem_reg);
+ paddr_t base = (paddr_t)fdt_load_int_ptr(ci.addr_cells, mem_reg);
if(ci.addr_cells == 2)
mem_reg += sizeof(fdt64_t);
@@ -63,7 +63,7 @@ static struct pmem_layout get_memlayout(void *fdt)
mem_reg += sizeof(fdt32_t);
/* -1 because base is a legitimate memory address */
- pm_t top = (pm_t)fdt_load_int_ptr(ci.size_cells, mem_reg) + base - 1;
+ paddr_t top = (paddr_t)fdt_load_int_ptr(ci.size_cells, mem_reg) + base - 1;
return (struct pmem_layout){base, top};
}
@@ -79,6 +79,7 @@ static enum serial_dev_t serial_dev_enum(const char *dev_name)
return -1;
}
+static void* uart_ptr_glbl = 0;
static void init_debug(void *fdt)
{
int chosen_offset = fdt_path_offset(fdt, "/chosen");
@@ -98,7 +99,8 @@ static void init_debug(void *fdt)
void *reg_ptr = (void *)fdt_getprop(fdt, stdout_offset, "reg", NULL);
void *uart_ptr = 0;
- uart_ptr = (void *)(pm_t)fdt_load_int_ptr(ci.addr_cells, reg_ptr);
+ uart_ptr = (void *)(paddr_t)fdt_load_int_ptr(ci.addr_cells, reg_ptr);
+ uart_ptr_glbl = uart_ptr;
dbg_init(uart_ptr, dev);
}
@@ -107,16 +109,16 @@ static void init_debug(void *fdt)
#define init_debug(...)
#endif
-static pm_t get_kerneltop()
+static paddr_t get_kerneltop()
{
/* interesting, for some reason if I define these to be just char
* pointers I get some wacky values. Not sure why that would be, but
* this works. */
extern char __init_end, __kernel_size;
- return (pm_t)&__init_end + (pm_t)&__kernel_size;
+ return (paddr_t)&__init_end + (paddr_t)&__kernel_size;
}
-static pm_t get_initrdtop(void *fdt)
+static paddr_t get_initrdtop(void *fdt)
{
int chosen_offset = fdt_path_offset(fdt, "/chosen");
struct cell_info ci = get_cellinfo(fdt, chosen_offset);
@@ -124,10 +126,10 @@ static pm_t get_initrdtop(void *fdt)
void *initrd_end_ptr = (void *)fdt_getprop(fdt, chosen_offset,
"linux,initrd-end", NULL);
- return (pm_t)fdt_load_int_ptr(ci.addr_cells, initrd_end_ptr);
+ return (paddr_t)fdt_load_int_ptr(ci.addr_cells, initrd_end_ptr);
}
-static pm_t get_initrdbase(void *fdt)
+static paddr_t get_initrdbase(void *fdt)
{
int chosen_offset = fdt_path_offset(fdt, "/chosen");
struct cell_info ci = get_cellinfo(fdt, chosen_offset);
@@ -135,43 +137,26 @@ static pm_t get_initrdbase(void *fdt)
void *initrd_base_ptr = (void *)fdt_getprop(fdt, chosen_offset,
"linux,initrd-start", NULL);
- return (pm_t)fdt_load_int_ptr(ci.addr_cells, initrd_base_ptr);
+ return (paddr_t)fdt_load_int_ptr(ci.addr_cells, initrd_base_ptr);
}
-static pm_t get_fdttop(void *fdt)
+static paddr_t get_fdttop(void *fdt)
{
const char *b = (const char *)fdt;
- return (pm_t)(b + fdt_totalsize(fdt));
+ return (paddr_t)(b + fdt_totalsize(fdt));
}
-static pm_t get_fdtbase(void *fdt)
+static paddr_t get_fdtbase(void *fdt)
{
/* lol */
- return (pm_t)fdt;
+ return (paddr_t)fdt;
}
-static void mark_area_used(pm_t base, pm_t top)
+static void mark_area_used(paddr_t base, paddr_t top)
{
size_t area_left = top - base;
- while(area_left >= MM_TPAGE_SIZE){
- mark_used(MM_TPAGE, base);
- area_left -= MM_TPAGE_SIZE;
- base += MM_TPAGE_SIZE;
- }
-
- while(area_left >= MM_GPAGE_SIZE){
- mark_used(MM_GPAGE, base);
- area_left -= MM_GPAGE_SIZE;
- base += MM_GPAGE_SIZE;
- }
-
- while(area_left >= MM_MPAGE_SIZE){
- mark_used(MM_MPAGE, base);
- area_left -= MM_MPAGE_SIZE;
- base += MM_MPAGE_SIZE;
- }
-
-
+ /* TODO: add in a method to make sure that we use as large mappings as
+ * possible. */
while(area_left >= MM_KPAGE_SIZE){
mark_used(base, MM_KPAGE);
area_left -= MM_KPAGE_SIZE;
@@ -182,15 +167,32 @@ static void mark_area_used(pm_t base, pm_t top)
mark_used(base, MM_KPAGE_SIZE);
}
+static void mark_reserved_mem(void *fdt)
+{
+ int rmem_offset = fdt_path_offset(fdt, "/reserved-memory/mmode_resv0");
+ struct cell_info ci = get_reginfo(fdt, "/reserved-memory/mmode_resv0");
+ uint8_t *rmem_reg = (uint8_t *)fdt_getprop(fdt, rmem_offset, "reg", NULL);
+
+ paddr_t base = (paddr_t)fdt_load_int_ptr(ci.addr_cells, rmem_reg);
+
+ if(ci.addr_cells == 2)
+ rmem_reg += sizeof(fdt64_t);
+ else
+ rmem_reg += sizeof(fdt32_t);
+
+ paddr_t top = (paddr_t)fdt_load_int_ptr(ci.size_cells, rmem_reg) + base - 1;
+ mark_area_used(base, top);
+}
+
static void setup_pmem(void *fdt)
{
struct pmem_layout pmem = get_memlayout(fdt);
- pm_t initrd_top = get_initrdtop(fdt);
- pm_t kernel_top = get_kerneltop();
- pm_t fdt_top = get_fdttop(fdt);
+ paddr_t initrd_top = get_initrdtop(fdt);
+ paddr_t kernel_top = get_kerneltop();
+ paddr_t fdt_top = get_fdttop(fdt);
- pm_t top = MAX3(kernel_top, initrd_top, fdt_top);
+ paddr_t top = MAX3(kernel_top, initrd_top, fdt_top);
dbg("initrd_top:\t%#lx\n", initrd_top);
dbg("kernel_top:\t%#lx\n", kernel_top);
dbg("fdt_top:\t%#lx\n", fdt_top);
@@ -200,7 +202,7 @@ static void setup_pmem(void *fdt)
size_t probe_size = probe_pmap(pmem.base, pmem.top - pmem.base);
/* riscv handles two byte boundaries better than one byte, so align
* upwards */
- pm_t pmap_base = align_up(top + 1, 2);
+ paddr_t pmap_base = align_up(top + 1, 2);
size_t actual_size = populate_pmap(pmem.base, pmem.top - pmem.base,
pmap_base);
@@ -223,6 +225,51 @@ static void setup_pmem(void *fdt)
/* mark pmap */
mark_area_used(pmap_base, pmap_base + actual_size);
+
+ /* mark reserved mem */
+ mark_reserved_mem(fdt);
+}
+
+paddr_t move_kernel()
+{
+ extern char __init_end, __kernel_size;
+ paddr_t dst = alloc_page(MM_MPAGE, 0);
+ memmove((void *)dst, &__init_end, (size_t)&__kernel_size);
+
+ return dst;
+}
+
+struct vm_branch_t *prepare_vmem()
+{
+ paddr_t kernel_dst = move_kernel();
+
+ /* TODO: check if this actually works */
+ struct vm_branch_t *branch = (struct vm_branch_t *)alloc_page(MM_KPAGE, 0);
+ memset(branch, 0, sizeof(struct vm_branch_t));
+
+ /* TODO: check mapping flags, also iron out possible bugs etc in
+ * map_vmem */
+ /* map kernel */
+ map_vmem(branch, kernel_dst, VM_KERN, VM_R | VM_W | VM_G | VM_X | VM_V, MM_MPAGE);
+
+ /* map init */
+ map_vmem(branch, PM_KERN, PM_KERN, VM_R | VM_W | VM_X | VM_V, MM_MPAGE);
+
+ /* map stack */
+ map_vmem(branch, PM_STACK_BASE, PM_STACK_BASE, VM_R | VM_W | VM_V, MM_MPAGE);
+
+ /* map debug VERY UGLY GLOBALS BAH */
+ map_vmem(branch, (paddr_t)uart_ptr_glbl, (paddr_t)uart_ptr_glbl, VM_R | VM_W | VM_V, MM_KPAGE);
+
+ /* TODO: map more stuff */
+
+ return branch;
+}
+
+void start_vmem(struct vm_branch_t *branch)
+{
+ /* assume Sv48 and ASID 0*/
+ csr_write(CSR_SATP, SATP_MODE_48 | (((paddr_t)(branch)) >> 12));
}
void init(void *fdt)
@@ -231,6 +278,10 @@ void init(void *fdt)
dbg_fdt(fdt);
setup_pmem(fdt);
+ struct vm_branch_t *branch = prepare_vmem();
+ start_vmem(branch);
+
/* update_pmap(TODO: figure out where to place pmap in vmem); */
- /* TODO: jump to kernel */
+ void (*main)(void *uart) = (void (*)(void *))VM_KERN;
+ main(uart_ptr_glbl);
}