aboutsummaryrefslogtreecommitdiff
path: root/arch/riscv64
diff options
context:
space:
mode:
Diffstat (limited to 'arch/riscv64')
-rw-r--r--arch/riscv64/conf/init-link.S13
-rw-r--r--arch/riscv64/conf/kmi.its4
-rw-r--r--arch/riscv64/config.h26
-rw-r--r--arch/riscv64/init/init.c88
-rw-r--r--arch/riscv64/init/start.S16
-rw-r--r--arch/riscv64/kernel/vmem.c2
-rw-r--r--arch/riscv64/source.mk2
7 files changed, 85 insertions, 66 deletions
diff --git a/arch/riscv64/conf/init-link.S b/arch/riscv64/conf/init-link.S
index 600304f..0933fbb 100644
--- a/arch/riscv64/conf/init-link.S
+++ b/arch/riscv64/conf/init-link.S
@@ -5,11 +5,13 @@ OUTPUT_ARCH(riscv)
ENTRY(_start)
SECTIONS {
- . = ABSOLUTE(PM_KERN_BASE);
- __init_start = .;
+ /* slight hack, the binary is position independent code but technically
+ not a PIE, so avoid globals and just add the load address to external
+ addresses. */
+ __init_start = 0;
/* objcopy only copies these three sections (as far as I'm aware) into the
- produces binary, so __init_end should point to the correct location in the
+ produced binary, so __init_end should point to the correct location in the
final binary
*/
.text ALIGN(4K) : AT(0) {
@@ -29,7 +31,10 @@ SECTIONS {
*(.sbss*) *(.bss*) *(COMMON)
}
- __init_end = . ;
+ .top : {
+ *(.top*)
+ }
+
__kernel_size = <KERNEL_SIZE>;
.garbage : {
diff --git a/arch/riscv64/conf/kmi.its b/arch/riscv64/conf/kmi.its
index 0494030..768f98b 100644
--- a/arch/riscv64/conf/kmi.its
+++ b/arch/riscv64/conf/kmi.its
@@ -12,8 +12,8 @@
arch = "riscv";
os = "kmi";
compression = "none";
- load = <0x80240000>;
- entry = <0x80240000>;
+ load = <0x80260000>;
+ entry = <0x80260000>;
hash-1 {
algo = "sha1";
};
diff --git a/arch/riscv64/config.h b/arch/riscv64/config.h
index 1d4a6e0..3eb2e72 100644
--- a/arch/riscv64/config.h
+++ b/arch/riscv64/config.h
@@ -22,7 +22,7 @@
/* --- START ARCH USER CONFIG VALUES --- */
/** Physical address to where the OS image will be loaded. */
-#define RAM_BASE 0x80000000
+//#define RAM_BASE 0x80000000
/* --- END ARCH USER CONFIG VALUES --- */
/* don't touch >:( */
@@ -37,20 +37,14 @@
/** \todo UBSAN is getting pretty close to this limit, should it be raised? */
#define PM_KERN_SIZE (SZ_256K)
-/** Physical address to where the kernel proper will be relocated. */
-#define PM_KERN_BASE (RAM_BASE + FW_MAX_SIZE + PM_KERN_SIZE)
+/** Virtual memory stack base. In this case, right after the kernel. */
+#define VM_STACK_BASE (VM_KERN + PM_KERN_SIZE)
-/** Highest allowed physical address where kernel stuff may lie. */
-#define PM_KERN_TOP (PM_KERN_BASE + PM_KERN_SIZE)
+/** Size of virtual memory stack. */
+#define VM_STACK_SIZE (SZ_4K)
-/** Physical memory stack base. In this case, right after the kernel. */
-#define PM_STACK_BASE (PM_KERN_BASE + PM_KERN_SIZE)
-
-/** Size of physical memory stack. */
-#define PM_STACK_SIZE (SZ_256K)
-
-/** Top of physical memory stack. */
-#define PM_STACK_TOP (PM_STACK_BASE + PM_STACK_SIZE)
+/** Top of virtual memory stack. */
+#define VM_STACK_TOP (VM_STACK_BASE + VM_STACK_SIZE)
#if defined(riscv64)
/* 64bit */
@@ -67,7 +61,11 @@
/** Direct mapping starts from this page. */
#define KSTART_PAGE 256UL
-/** The RPC stack page. */
+/**
+ * The RPC stack page.
+ * @todo this should be page before KSTART, but currently
+ * RPC_STACK_TOP is too low (why? was there a reason to place it so low?) and overlaps.
+ */
#define CSTACK_PAGE 248UL
/** User virtual memory space start. */
diff --git a/arch/riscv64/init/init.c b/arch/riscv64/init/init.c
index 08462f6..92f8053 100644
--- a/arch/riscv64/init/init.c
+++ b/arch/riscv64/init/init.c
@@ -12,12 +12,9 @@
#include <kmi/utils.h>
#include <kmi/vmem.h>
#include <arch/vmem.h>
-#include "../kernel/csr.h"
+#include <libfdt.h>
-/** Temporary virtual memory space.
- * Assume 64bit riscv for now.
- */
-struct vmem *root_branch;
+#include "../kernel/csr.h"
/**
* Create page table entry.
@@ -28,22 +25,44 @@ struct vmem *root_branch;
*/
#define to_pte(a, f) (((a) >> 12) << 10 | (f))
-/** Jump into virtual memory. */
-static void init_bootmem()
+/**
+ * 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)
+{
+ struct cell_info ci = get_reginfo(fdt, "/memory");
+ int mem_offset = fdt_path_offset(fdt, "/memory");
+ uint8_t *mem_reg = (uint8_t *)fdt_getprop(fdt, mem_offset, "reg", NULL);
+ 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)
{
size_t flags = VM_V | VM_X | VM_R | VM_W;
- extern char *__init_end;
+ extern char *__kernel;
extern char *__kernel_size;
- uintptr_t top = (uintptr_t)&__init_end + (uintptr_t)&__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? */
- root_branch = (struct vmem *)align_up(top, SZ_4K);
+ struct vmem *root_branch = (struct vmem *)align_up(top, SZ_4K);
/* direct mapping (temp) */
- for (size_t i = 0; i < CSTACK_PAGE; ++i)
+ for (size_t i = 0; i <= CSTACK_PAGE; ++i)
root_branch->leaf[i] = (struct vmem *)to_pte(TOP_PAGE_SIZE * i,
flags);
@@ -51,7 +70,7 @@ static void init_bootmem()
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);
+ 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);
@@ -66,48 +85,37 @@ static void init_bootmem()
csr_write(CSR_SATP, mode | ((uintptr_t)root_branch >> 12));
}
-/** Relocate kernel proper. */
-static void move_kernel()
+/**
+ * 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 *__init_end;
+ extern char *__kernel;
extern char *__kernel_size;
- unsigned long sz = (unsigned long)&__kernel_size;
- char *src = (char *)&__init_end;
+ 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];
}
/**
- * Convert an existing physical address in a register to a virtual address.
- * There is probably an easier way to do this, but this seems to work alright.
- *
- * @param reg Register to modify.
- */
-#define __va_reg(reg) \
- { \
- vm_t reg = 0; \
- __asm__ ("mv %0, " QUOTE(reg) : "=r" (reg)::); \
- reg = (vm_t)__va(reg); \
- __asm__ ("mv " QUOTE(reg) ", %0" ::"rK" (reg) :); \
- }
-
-/**
* 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)
+void init(void *fdt, pm_t load_addr)
{
- extern char *__init_end;
- extern void jump_to_kernel(void *k, void *fdt);
+ extern void jump_to_kernel(void *fdt, pm_t ram_base, void *k);
+
+ pm_t ram_base = __fdt_ram_base(fdt);
- init_bootmem();
- move_kernel();
- __va_reg(sp);
- __va_reg(fp);
- __va_reg(gp);
+ init_bootmem(load_addr, ram_base);
+ move_kernel(load_addr);
- jump_to_kernel((void *)VM_KERN, __va(fdt));
+ jump_to_kernel(fdt, ram_base, (void *)VM_KERN);
}
diff --git a/arch/riscv64/init/start.S b/arch/riscv64/init/start.S
index b54f685..759c409 100644
--- a/arch/riscv64/init/start.S
+++ b/arch/riscv64/init/start.S
@@ -5,8 +5,10 @@
.global _start
/* Entry point to the kernel loader. */
_start:
-/* load static stack */
-li sp, PM_STACK_TOP
+/* get load address */
+auipc a1, 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
@@ -14,6 +16,12 @@ call init
.section .text
.global jump_to_kernel
jump_to_kernel:
-mv a2, a0 // store kernel addr
-mv a0, a1 // move fdt pointer to first argument
+li sp, VM_STACK_TOP // load virtual stack address
+li fp, 0
+li gp, 0
jr a2 // jump to kernel
+
+/* there should be a kernel payload after this address */
+.section .top
+.global __kernel
+__kernel:
diff --git a/arch/riscv64/kernel/vmem.c b/arch/riscv64/kernel/vmem.c
index 6fd7069..d0cac2c 100644
--- a/arch/riscv64/kernel/vmem.c
+++ b/arch/riscv64/kernel/vmem.c
@@ -427,7 +427,7 @@ stat_t populate_kvmem(struct vmem *b)
size_t flags = VM_V | VM_R | VM_W | VM_X | VM_G;
for (size_t i = KSTART_PAGE; i < IO_PAGE; ++i)
b->leaf[i] = (struct vmem *)to_pte(
- RAM_BASE + TOP_PAGE_SIZE * (i - KSTART_PAGE), flags);
+ get_ram_base() + TOP_PAGE_SIZE * (i - KSTART_PAGE), flags);
/* map in IO region */
map_io_dbg(b);
diff --git a/arch/riscv64/source.mk b/arch/riscv64/source.mk
index 384f75a..5de5309 100644
--- a/arch/riscv64/source.mk
+++ b/arch/riscv64/source.mk
@@ -21,7 +21,7 @@ run:
include $(ARCH_SOURCE)/asm/source.mk
# dependecy generation
-$(ARCH_BUILD)/kernel/entry.o: $(ARCH_SOURCE)/kernel/gen/asm-offsets.h
+$(ARCH_KERN_BUILD)/kernel/entry.o: $(ARCH_SOURCE)/kernel/gen/asm-offsets.h
# full cleanup
CLEANUP_CMD := $(ARCH_SOURCE)/conf/rmimage.sh