aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile13
-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
-rw-r--r--common/main.c10
-rw-r--r--common/mem.c16
-rw-r--r--common/pmem.c6
-rw-r--r--include/kmi/mem.h20
-rw-r--r--lib/dbg_fdt.c (renamed from lib/fdt_dbg.c)2
-rwxr-xr-xscripts/gen-deps11
14 files changed, 146 insertions, 83 deletions
diff --git a/Makefile b/Makefile
index 56e7254..89f8033 100644
--- a/Makefile
+++ b/Makefile
@@ -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