diff options
Diffstat (limited to 'arch/riscv64')
| -rw-r--r-- | arch/riscv64/conf/init-link.S | 13 | ||||
| -rw-r--r-- | arch/riscv64/conf/kmi.its | 4 | ||||
| -rw-r--r-- | arch/riscv64/config.h | 26 | ||||
| -rw-r--r-- | arch/riscv64/init/init.c | 88 | ||||
| -rw-r--r-- | arch/riscv64/init/start.S | 16 | ||||
| -rw-r--r-- | arch/riscv64/kernel/vmem.c | 2 | ||||
| -rw-r--r-- | arch/riscv64/source.mk | 2 |
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 |
