aboutsummaryrefslogtreecommitdiff
path: root/arch/riscv64
diff options
context:
space:
mode:
Diffstat (limited to 'arch/riscv64')
-rw-r--r--arch/riscv64/conf/kernel-link.S1
-rw-r--r--arch/riscv64/init/init.c148
-rw-r--r--arch/riscv64/init/start.S38
-rw-r--r--arch/riscv64/kernel/arch.c3
-rw-r--r--arch/riscv64/kernel/proc.c2
-rw-r--r--arch/riscv64/kernel/start.S36
-rw-r--r--arch/riscv64/kernel/vmem.c20
7 files changed, 55 insertions, 193 deletions
diff --git a/arch/riscv64/conf/kernel-link.S b/arch/riscv64/conf/kernel-link.S
index 181f49d..d93b642 100644
--- a/arch/riscv64/conf/kernel-link.S
+++ b/arch/riscv64/conf/kernel-link.S
@@ -26,6 +26,7 @@ SECTIONS {
}
__kernel_end = .;
+ __kernel_size = __kernel_end - __kernel_start;
.garbage : {
*(.note*)
diff --git a/arch/riscv64/init/init.c b/arch/riscv64/init/init.c
deleted file mode 100644
index a4fa696..0000000
--- a/arch/riscv64/init/init.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/* SPDX-License-Identifier: copyleft-next-0.3.1 */
-/* Copyright 2021 - 2022, Kim Kuparinen < kimi.h.kuparinen@gmail.com > */
-
-/**
- * @file init.c
- * riscv64 'bootstrap', move actual kernel into place and jump to virtual
- * memory.
- */
-
-#include <kmi/types.h>
-#include <kmi/attrs.h>
-#include <kmi/utils.h>
-#include <kmi/vmem.h>
-#include <arch/vmem.h>
-#include <libfdt.h>
-
-#include "../kernel/csr.h"
-
-void flush_tlb_full()
-{
- /** @todo could be nice to have a common set of features with kernel,
- * but for now this is good enough. */
- __asm__ volatile ("sfence.vma\n" ::: "memory");
-}
-
-/**
- * Create page table entry.
- * Copy from \ref arch/riscv64/kernel/vmem.c.
- *
- * @param a Virtual address.
- * @param f PTE flags.
- */
-#define to_pte(a, f) (((a) >> 12) << 10 | (f))
-
-/**
- * Get RAM base address from fdt.
- * @todo in case of multiple RAM banks, should try to just find one
- * of them and let the kernel figure the rest out. Kernel doesn't currently
- * support multiple RAM banks.
- *
- * @param fdt FDT pointer.
- * @return Physical address of ram base.
- */
-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_int_ptr(ci.addr_cells, mem_reg);
-}
-
-/**
- * Jump into virtual memory.
- *
- * @param load_addr Address where init has been loaded.
- * @param ram_base RAM base.
- */
-static void init_bootmem(uintptr_t load_addr, uintptr_t ram_base)
-{
- /* set all flags on, especially A and D since MMUs are allowed to raise
- * exceptions that we're not ready to handle if they're unset. */
- size_t flags = VM_V | VM_X | VM_R | VM_W | VM_D | VM_A;
-
- extern char *__kernel;
- extern char *__kernel_size;
- uintptr_t top = load_addr + (uintptr_t)&__kernel +
- (uintptr_t)&__kernel_size;
-
- /* this could be risky, as we might overwrite some bits of initrd or fdt
- * if they're allocated too close to the kernel payload.
- * @todo Allocate root_branch statically? */
- struct vmem *root_branch = (struct vmem *)align_up(top, SZ_4K);
-
- /* direct mapping (temp) */
- for (size_t i = 0; i <= CSTACK_PAGE; ++i)
- root_branch->leaf[i] = (struct vmem *)to_pte(TOP_PAGE_SIZE * i,
- flags);
-
- /* kernel (also sort of direct mapping) */
- flags |= VM_G;
- for (size_t i = KSTART_PAGE; i < IO_PAGE; ++i)
- root_branch->leaf[i] = (struct vmem *)to_pte(
- ram_base + TOP_PAGE_SIZE * (i - KSTART_PAGE), flags);
-
- /* kernel IO, map to 0 for now, will be updated in the future */
- root_branch->leaf[IO_PAGE] = (struct vmem *)to_pte(0, flags);
-
- uintmax_t mode = Sv39;
- switch (DEFAULT_Sv_MODE) {
- case Sv32: mode = SATP_MODE_Sv32; break;
- case Sv39: mode = SATP_MODE_Sv39; break;
- case Sv48: mode = SATP_MODE_Sv48; break;
- default: break;
- };
-
- flush_tlb_full();
- csr_write(CSR_SATP, mode | ((uintptr_t)root_branch >> 12));
-}
-
-/**
- * Relocate kernel proper.
- * @param load_addr Address to where init has been loaded.
- * Used in calculating kernel start address.
- */
-static void move_kernel(uintptr_t load_addr)
-{
- extern char *__kernel;
- extern char *__kernel_size;
-
- size_t sz = (size_t)&__kernel_size;
- char *src = load_addr + (char *)&__kernel;
- char *dst = (char *)VM_KERN;
- for (size_t i = 0; i < sz; ++i)
- dst[i] = src[i];
-}
-
-/**
- * Main driver for the init loader.
- *
- * @param fdt Global FDT pointer, provided by bootloader.
- * @param load_addr Address to where init has been loaded.
- */
-void init(void *fdt, pm_t load_addr)
-{
- extern void jump_to_kernel(void *fdt, pm_t ram_base, void *k);
-
- pm_t ram_base = __fdt_ram_base(fdt);
-
- init_bootmem(load_addr, ram_base);
- move_kernel(load_addr);
-
- jump_to_kernel(fdt, ram_base, (void *)VM_KERN);
-}
-
-#if GENERIC_UBOOT
-void init_go(int argc, char **argv, pm_t load_addr)
-{
- if (argc != 2)
- return;
-
- void *fdt = (void *)strtouintptr(argv[1]);
-
- /* fdt is passed as second argument, load address first but since we
- * already have it due to our ingenious _start, no need to parse it */
- init(fdt, load_addr);
-}
-#endif
diff --git a/arch/riscv64/init/start.S b/arch/riscv64/init/start.S
deleted file mode 100644
index b6394f7..0000000
--- a/arch/riscv64/init/start.S
+++ /dev/null
@@ -1,38 +0,0 @@
-/* SPDX-License-Identifier: copyleft-next-0.3.1 */
-/* Copyright 2021 - 2022, Kim Kuparinen < kimi.h.kuparinen@gmail.com > */
-
-/* generic u-boot passes argc and argv as if we were a regular
- * program, so our load address must be placed third.
- * If we have a 'custom' u-boot with kmi support, the fdt
- * will be passed to us directly, so the load address can go second.
- */
-#if GENERIC_UBOOT
-# define LOAD_REG a2
-# define INIT init_go
-#else
-# define LOAD_REG a1
-# define INIT init
-#endif
-
-.section .init
-.global _start
-/* Entry point to the kernel loader. */
-_start:
-/* get load address */
-auipc LOAD_REG, 0
-/* keep using bootloader stack for now */
-//li sp, PM_STACK_TOP
-/* make sure there's no garbage in tp, important for id assignment */
-li tp, 0
-call INIT
-// INIT shouldn't return, but if we do we might as well just jump back to u-boot
-// or wherever
-ret
-
-.section .text
-.global jump_to_kernel
-jump_to_kernel:
-li sp, VM_STACK_TOP // load virtual stack address
-li fp, 0
-li gp, 0
-jr a2 // jump to kernel
diff --git a/arch/riscv64/kernel/arch.c b/arch/riscv64/kernel/arch.c
index ff2c04c..ec4cf43 100644
--- a/arch/riscv64/kernel/arch.c
+++ b/arch/riscv64/kernel/arch.c
@@ -19,7 +19,7 @@ id_t hartid_to_cpuid(id_t hart)
if (cpuid_to_hartid(i) == hart)
return i;
- error("failed to match hart id %ld to cpu id\n", hart);
+ error("failed to match hart id %ld to cpu id\n", (long)hart);
/* default to zero, though this should maybe be a panic? */
return 0;
}
@@ -27,7 +27,6 @@ id_t hartid_to_cpuid(id_t hart)
pm_t branch_to_satp(struct vmem *branch, enum mm_mode mode)
{
/* Sv57 && Sv64 in the future? */
- branch = (struct vmem *)__pa(branch);
pm_t pn = (pm_t)(branch) >> page_shift();
pm_t m = DEFAULT_Sv_MODE;
diff --git a/arch/riscv64/kernel/proc.c b/arch/riscv64/kernel/proc.c
index 4e4d7ec..55ccbb8 100644
--- a/arch/riscv64/kernel/proc.c
+++ b/arch/riscv64/kernel/proc.c
@@ -15,7 +15,7 @@
#include "regs.h"
#include "csr.h"
-void run_init(struct tcb *t, void *fdt, void *initrd)
+void run_init(struct tcb *t, vm_t fdt, vm_t initrd)
{
/** \todo actually map fdt and initrd into the target address space */
csr_write(CSR_SSCRATCH, t);
diff --git a/arch/riscv64/kernel/start.S b/arch/riscv64/kernel/start.S
new file mode 100644
index 0000000..4978cc0
--- /dev/null
+++ b/arch/riscv64/kernel/start.S
@@ -0,0 +1,36 @@
+#if GENERIC_UBOOT
+# define MAIN main_go
+#else
+# define LOAD_REG a1
+# define MAIN main
+#endif
+
+.section .kernel.start
+.global _start
+_start:
+/* get load address */
+auipc a2, 0
+
+/* load initial stack */
+lla sp, riscv_init_stack
+li t0, 4096
+add sp, sp, t0
+
+/* set thread pointer to zero so we don't accidentally try to use a tcb */
+li tp, 0
+
+/* call main, whichever one is relevant */
+call MAIN
+ret
+
+.section .text
+
+/* a0 is fdt, a1 is load_addr, a2 is d, a3 is ram_base, a4 is DMAP */
+.global to_kernelspace
+to_kernelspace:
+lla t0, kernel
+add t0, t0, a4
+sub t0, t0, a3
+add sp, sp, a4
+sub sp, sp, a3
+jr t0
diff --git a/arch/riscv64/kernel/vmem.c b/arch/riscv64/kernel/vmem.c
index cc6f3ac..835f53d 100644
--- a/arch/riscv64/kernel/vmem.c
+++ b/arch/riscv64/kernel/vmem.c
@@ -399,13 +399,26 @@ static void __populate_dmap(struct vmem *branch)
/** How many base pages we use for the rpc stack. Used fairly often so calculate
* it at the start and then reference it. */
static size_t rpc_pages;
+long riscv_init_stack[4096 / sizeof(long)];
+__attribute__((aligned(4096))) struct vmem bootvmem;
+
+struct vmem *direct_mapping()
+{
+ rpc_pages = order_size(MM_O1) / BASE_PAGE_SIZE;
+
+ __populate_dmap(&bootvmem);
+ populate_kvmem(&bootvmem);
+ __use_vmem(&bootvmem, DEFAULT_Sv_MODE);
+
+ return &bootvmem;
+}
+
struct vmem *init_vmem(void *fdt)
{
UNUSED(fdt);
struct vmem *b = create_vmem();
__populate_dmap(b);
- rpc_pages = order_size(MM_O1) / BASE_PAGE_SIZE;
/* update which memory branch to use */
use_vmem(b);
return b;
@@ -415,14 +428,13 @@ struct vmem *create_vmem()
{
struct vmem *b = (struct vmem *)alloc_page(MM_KPAGE);
memset(b, 0, MM_KPAGE_SIZE);
-
populate_kvmem(b);
return b;
}
stat_t use_vmem(struct vmem *b)
{
- __use_vmem(b, DEFAULT_Sv_MODE);
+ __use_vmem(__pa(b), DEFAULT_Sv_MODE);
return OK;
}
@@ -457,7 +469,7 @@ vm_t setup_kernel_io(struct vmem *b, vm_t paddr)
* modifying, or during the startup stage where we don't have a tcb yet.
* I don't think checking the rpc context is necessary? */
if (!cur_tcb() || cur_tcb()->proc.vmem == b)
- flush_tlb((uintptr_t)pte_addr(b->leaf[IO_PAGE]));
+ flush_tlb_full();
return -TOP_PAGE_SIZE + paddr - addr;
}