diff options
| -rw-r--r-- | Makefile | 13 | ||||
| -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 | ||||
| -rw-r--r-- | common/main.c | 10 | ||||
| -rw-r--r-- | common/mem.c | 16 | ||||
| -rw-r--r-- | common/pmem.c | 6 | ||||
| -rw-r--r-- | include/kmi/mem.h | 20 | ||||
| -rw-r--r-- | lib/dbg_fdt.c (renamed from lib/fdt_dbg.c) | 2 | ||||
| -rwxr-xr-x | scripts/gen-deps | 11 |
14 files changed, 146 insertions, 83 deletions
@@ -5,7 +5,7 @@ DEBUGFLAGS != [ $(RELEASE) ] \ && echo "-flto -O2 -DNDEBUG" \ || echo "-O0 -DDEBUG" -CFLAGS = -ffreestanding -nostdlib -static -fno-pie -std=c17 -Wall -Wextra -Wvla -D$(ARCH) -g +CFLAGS = -ffreestanding -nostdlib -fno-pie -std=c17 -Wall -Wextra -Wvla -D$(ARCH) -g -fpic DEPFLAGS = -MT $@ -MMD -MP -MF $@.d LINTFLAGS = -fsyntax-only PREPROCESS = -E @@ -13,7 +13,8 @@ LDFLAGS != [ $(LLVM) ] \ || echo -static-libgcc -lgcc BUILD = build -ARCH_BUILD = $(BUILD)/arch/$(ARCH) +ARCH_KERN_BUILD = $(BUILD)/kernel/arch/$(ARCH) +ARCH_INIT_BUILD = $(BUILD)/init/arch/$(ARCH) ARCH_SOURCE = arch/$(ARCH) all: kmi.bin @@ -35,9 +36,11 @@ COMPILER != [ $(LLVM) ] \ KERNEL_SOURCES != echo common/*.c common/uapi/*.c lib/*.c +# might consider renaming common, currently it refers to stuff common +# to all arches but clearly there are bits that are common to init and kernel +INIT_SOURCES != echo lib/fdt*.c common/fdt.c common/string.c CLEANUP := build deps.mk kernel.* init.* kmi.bin CLEANUP_CMD := -INIT_SOURCES := include arch/$(ARCH)/source.mk @@ -80,10 +83,10 @@ INIT_LD != ./scripts/gen-deps --init --link "$(INIT_LINK).S" $(INIT_LD): kernel.bin init.elf: $(INIT_OBJECTS) $(INIT_LD) - $(GENELF) -T $(INIT_LD) $(INIT_OBJECTS) -o init.elf $(LINK_FLAGS) + $(GENELF) $(INIT_FLAGS) -T $(INIT_LD) $(INIT_OBJECTS) -o init.elf $(LINK_FLAGS) kernel.elf: $(KERNEL_OBJECTS) $(KERNEL_LD) - $(GENELF) -T $(KERNEL_LD) $(KERNEL_OBJECTS) -o kernel.elf $(LINK_FLAGS) + $(GENELF) $(KERNEL_FLAGS) -T $(KERNEL_LD) $(KERNEL_OBJECTS) -o kernel.elf $(LINK_FLAGS) init.bin: init.elf $(OBJCOPY) $(OBJCOPY_FLAGS) init.elf init.bin 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 diff --git a/common/main.c b/common/main.c index 5248d2a..9eb6414 100644 --- a/common/main.c +++ b/common/main.c @@ -23,11 +23,17 @@ * Sets up all kernel subsystems and jumps into \c init program, does not * return. * - * @param fdt Global FDT pointer. + * @param fdt Global FDT pointer in physical memory. + * @param ram_base RAM base. * @return Should not. */ -void __main main(void *fdt) +void __main main(void *fdt, uintptr_t ram_base) { + set_ram_base(ram_base); + + /* convert physical address to virtual address */ + fdt = __va(fdt); + /* dbg uses direct mapping at this point */ init_dbg(fdt); setup_dmap_dbg(); diff --git a/common/mem.c b/common/mem.c index 69ba4d6..e3f98e7 100644 --- a/common/mem.c +++ b/common/mem.c @@ -17,6 +17,12 @@ size_t __mm_sizes[10]; size_t __mm_page_shift; enum mm_order __mm_max_order; +/** + * RAM base address. Not sure if it should be provided through a macro + * like __mm_*. + */ +pm_t ram_base; + enum mm_order nearest_order(size_t size) { for (enum mm_order order = max_order(); order >= MM_MIN; --order) @@ -41,3 +47,13 @@ void init_mem(size_t max_order, size_t bits[10], size_t page_shift) __mm_sizes[i] = 1UL << __mm_shifts[i]; } } + +void set_ram_base(uintptr_t base) +{ + ram_base = base; +} + +uintptr_t get_ram_base() +{ + return ram_base; +} diff --git a/common/pmem.c b/common/pmem.c index 16e6adf..22a1493 100644 --- a/common/pmem.c +++ b/common/pmem.c @@ -609,8 +609,8 @@ void init_pmem(void *fdt) stat_pmem_conf(fdt, &max_order, &base_bits, bits); init_mem(max_order, bits, base_bits); - pm_t ram_size = __get_ramtop(fdt) - RAM_BASE; - pm_t ram_base = (pm_t)__va(RAM_BASE); + pm_t ram_size = __get_ramtop(fdt) - get_ram_base(); + pm_t ram_base = (pm_t)__va(get_ram_base()); pm_t initrd_top = get_initrdtop(fdt); pm_t fdt_top = __get_fdttop(fdt); @@ -629,7 +629,7 @@ void init_pmem(void *fdt) /* mark init stack, this should be unmapped once we get to executing * processes */ - __mark_area_used((pm_t)__va(PM_STACK_BASE), (pm_t)__va(PM_STACK_TOP)); + __mark_area_used(VM_STACK_BASE, VM_STACK_TOP); /* mark kernel */ /* this could be made more explicit, I suppose. */ diff --git a/include/kmi/mem.h b/include/kmi/mem.h index a6c6bfa..f43ee08 100644 --- a/include/kmi/mem.h +++ b/include/kmi/mem.h @@ -92,7 +92,7 @@ * @param x Physical address. * @return Corresponding virtual address. */ -#define __va(x) (void *)(((uintptr_t)(x)) + VM_DMAP - RAM_BASE) +#define __va(x) (void *)(((uintptr_t)(x)) + VM_DMAP - get_ram_base()) /** * Convert virtual address to physical address in direct mapping. @@ -100,7 +100,7 @@ * @param x Virtual address. * @return Corresponding physical address. */ -#define __pa(x) (void *)(((uintptr_t)(x)) - VM_DMAP + RAM_BASE) +#define __pa(x) (void *)(((uintptr_t)(x)) - VM_DMAP + get_ram_base()) /** * Get page number of physical address. @@ -213,6 +213,22 @@ enum mm_order nearest_order(size_t size); */ void init_mem(size_t max_order, size_t shifts[10], size_t page_shift); +/** + * Set RAM base address for global access. + * For now supports only one RAM bank. + * + * @param base RAM base address. + */ +void set_ram_base(pm_t base); + +/** + * Get RAM base address. + * Very much assumes set_ram_base() has been called beforehand. + * + * @return RAM base address. + */ +pm_t get_ram_base(); + /** Base page size. */ #define BASE_PAGE_SIZE (order_size(BASE_PAGE)) diff --git a/lib/fdt_dbg.c b/lib/dbg_fdt.c index d2d4e7b..6d02442 100644 --- a/lib/fdt_dbg.c +++ b/lib/dbg_fdt.c @@ -2,7 +2,7 @@ /* Copyright 2021 - 2022, Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ /** - * @file fdt_dbg.c + * @file dbg_fdt.c * Dump fdt info to serial. */ diff --git a/scripts/gen-deps b/scripts/gen-deps index 674ead6..9a9ad6e 100755 --- a/scripts/gen-deps +++ b/scripts/gen-deps @@ -1,9 +1,9 @@ #!/bin/sh gencommon () { - lint="build/${s%.*}${1}.l" - dep="build/${s%.*}${1}.d" - obj="build/${s%.*}${1}" + lint="build/${path}/${s%.*}${1}.l" + dep="build/${path}/${s%.*}${1}.d" + obj="build/${path}/${s%.*}${1}" echo "${dep}:" >> deps.mk echo "-include ${dep}" >> deps.mk @@ -30,9 +30,11 @@ genrule () { case "${1}" in --kernel) kern=1 + path=kernel flags='$(KERN_FLAGS)' ;; --init) + path=init flags='$(INIT_FLAGS)' ;; esac @@ -48,7 +50,8 @@ case "${2}" in esac # create all subdirectories -mkdir -p $(echo "${3}" | xargs -n 1 dirname | uniq | sed 's|^|build/|g') +mkdir -p $(echo "${3}" | xargs -n 1 dirname | uniq | sed 's|^|build/init/|g') +mkdir -p $(echo "${3}" | xargs -n 1 dirname | uniq | sed 's|^|build/kernel/|g') for s in ${3} do |
