diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-07-08 17:43:59 +0300 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-07-08 18:04:03 +0300 |
| commit | e134202611a50b358c147c92bfb8a7f443030b8b (patch) | |
| tree | ac7c31824adcf41a63e4d2c5e141f5149cc55b1a | |
| parent | 7e828ec1e1479ff9a8afe845539d08ca0dfada5f (diff) | |
| download | kmi-e134202611a50b358c147c92bfb8a7f443030b8b.tar.gz kmi-e134202611a50b358c147c92bfb8a7f443030b8b.zip | |
fix LLVM
+ Anything extern is right out as LLVM doesn't produce correct code for
them. Maybe if I added some extra attributes but I'm skeptical.
Replaced with static variables and getters/setters.
+ Inline ASM is apparently a bit buggy, so use an assembly stub when jumping to init.
+ Minimize work done in main() to minimize chance of LLVM doing something silly.
Still not 100% certain that I shouldn't just write the main() as an assembly stub
in arch/riscv64 to be absolutely sure everything works as intended.
+ Make .kernel.start section SHF_ALLOC, otherwise lld complains about
pc-relative addressing
Probably some other stuff as well that I'm forgetting right now. But at least with
LLVM14 LTO seems to work, which is pretty cool?
| -rw-r--r-- | arch/riscv64/conf/kernel-link.S | 19 | ||||
| -rw-r--r-- | arch/riscv64/kernel/arch.c | 13 | ||||
| -rw-r--r-- | arch/riscv64/kernel/arch.h | 16 | ||||
| -rw-r--r-- | arch/riscv64/kernel/proc.c | 38 | ||||
| -rw-r--r-- | arch/riscv64/kernel/smp.c | 6 | ||||
| -rw-r--r-- | arch/riscv64/kernel/start.S | 15 | ||||
| -rw-r--r-- | arch/riscv64/kernel/vmem.c | 12 | ||||
| -rw-r--r-- | arch/riscv64/source.mk | 8 | ||||
| -rw-r--r-- | include/arch/vmem.h | 6 | ||||
| -rw-r--r-- | include/kmi/bkl.h | 13 | ||||
| -rw-r--r-- | include/kmi/conf.h | 35 | ||||
| -rw-r--r-- | include/kmi/dmem.h | 12 | ||||
| -rw-r--r-- | include/kmi/mem.h | 110 | ||||
| -rw-r--r-- | scripts/makefile | 5 | ||||
| -rw-r--r-- | src/bkl.c | 13 | ||||
| -rw-r--r-- | src/debug.c | 2 | ||||
| -rw-r--r-- | src/irq.c | 4 | ||||
| -rw-r--r-- | src/main.c | 30 | ||||
| -rw-r--r-- | src/mem.c | 70 | ||||
| -rw-r--r-- | src/pmem.c | 9 | ||||
| -rw-r--r-- | src/regions.c | 2 | ||||
| -rw-r--r-- | src/tcb.c | 4 | ||||
| -rw-r--r-- | src/timer.c | 2 | ||||
| -rw-r--r-- | src/uapi/conf.c | 21 | ||||
| -rw-r--r-- | src/uapi/ipc.c | 2 |
25 files changed, 255 insertions, 212 deletions
diff --git a/arch/riscv64/conf/kernel-link.S b/arch/riscv64/conf/kernel-link.S index 88f2e75..e395e4a 100644 --- a/arch/riscv64/conf/kernel-link.S +++ b/arch/riscv64/conf/kernel-link.S @@ -5,12 +5,6 @@ OUTPUT_ARCH(riscv) ENTRY(main) SECTIONS { - /* This is apparently necessary. I *think* it is to tell the linker that - * the kernel should be able to run in the bottom half of the address - * space, but I don't know for sure and this feels like a fairly major - * hack. - * @todo look into this further. - */ . = ABSOLUTE(VM_KERNEL); __kernel_start = .; .text ALIGN(4K) : AT(0) { @@ -18,6 +12,14 @@ SECTIONS { *(.text*); } + /* place bss in between different load sections to force objcopy to + * output zeroes for it */ + .bss : { + *(.sbss*) + *(.bss*) + *(COMMON) + } + .rodata : { *(.rodata*) } @@ -27,12 +29,7 @@ SECTIONS { *(.sdata*) } - .bss : { - *(.sbss*) *(.bss*) *(COMMON) - } - __kernel_end = .; - __kernel_size = __kernel_end - __kernel_start; .garbage : { *(.note*) diff --git a/arch/riscv64/kernel/arch.c b/arch/riscv64/kernel/arch.c index 4561d8b..5dc50cf 100644 --- a/arch/riscv64/kernel/arch.c +++ b/arch/riscv64/kernel/arch.c @@ -13,7 +13,18 @@ #include "csr.h" #include "arch.h" -id_t __cpuid_to_hartid[MAX_CPUS]; +/** Array where indexing is done with CPU IDs, giving the corresponding hart ID. */ +static id_t __cpuid_to_hartid[MAX_CPUS]; + +id_t cpuid_to_hartid(id_t cpu) +{ + return __cpuid_to_hartid[cpu]; +} + +void set_hartid(id_t cpu, id_t hartid) +{ + __cpuid_to_hartid[cpu] = hartid; +} id_t hartid_to_cpuid(id_t hart) { diff --git a/arch/riscv64/kernel/arch.h b/arch/riscv64/kernel/arch.h index d38dad0..789b416 100644 --- a/arch/riscv64/kernel/arch.h +++ b/arch/riscv64/kernel/arch.h @@ -12,9 +12,6 @@ #include <kmi/vmem.h> -/** Actual map of cpu id to hart id. */ -extern id_t __cpuid_to_hartid[MAX_CPUS]; - /** * Map cpu id to hart id. * Defined as a macro to allow for stuff like @@ -23,15 +20,24 @@ extern id_t __cpuid_to_hartid[MAX_CPUS]; * @endcode * * @param x Hart ID. + * @return Corresponding CPU ID. + */ +id_t cpuid_to_hartid(id_t x); + +/** + * Create mapping between \p cpuid and \p hartid. + * + * @param cpuid CPU ID to map to \p hartid. + * @param hartid Hart ID to map to \p CPU ID. */ -#define cpuid_to_hartid(x) __cpuid_to_hartid[x] +void set_hartid(id_t cpuid, id_t hartid); /** * Find the cpu id that corresponds to hart id. * * @param hart Hart to find corresponding cpu id for. * @return Corresponding cpu id. 0 if not found, though this should maybe be a - * panic situation. + * panic situation. Currently just sets the core to sleep. */ id_t hartid_to_cpuid(id_t hart); diff --git a/arch/riscv64/kernel/proc.c b/arch/riscv64/kernel/proc.c index 73b0984..19bd52f 100644 --- a/arch/riscv64/kernel/proc.c +++ b/arch/riscv64/kernel/proc.c @@ -9,6 +9,7 @@ #include <kmi/tcb.h> #include <kmi/elf.h> #include <kmi/bkl.h> +#include <kmi/debug.h> #include <kmi/string.h> #include <arch/proc.h> @@ -16,6 +17,27 @@ #include "regs.h" #include "csr.h" +/** Assembly implementation for actually jumping to the init process, defined in + * start.S. Quite a few constants that could be implemented in assembly as well + * but this is maybe a bit more convenient. + * + * @param pid Should always be 0 to indicate that the kernel is the originator. + * @param tid Thread ID of the current thread. + * @param code Should always be SYS_USER_SPAWNED to indicate that a new core has + * come online. + * @param fdt Address of flattened device tree within userspace memory. + * @param initrd Ditto for initial ramdisk. + * @param proc Process ID, should be constant 1. + * @param stack_top Stack address. + */ +__noreturn void riscv_run_init(sys_arg_t pid, + sys_arg_t tid, + sys_arg_t code, + sys_arg_t fdt, + sys_arg_t initrd, + sys_arg_t proc, /* not strictly speaking necessary but eh */ + sys_arg_t stack_top); + void run_init(struct tcb *t, vm_t fdt, vm_t initrd) { csr_write(CSR_SSCRATCH, t); @@ -28,20 +50,10 @@ void run_init(struct tcb *t, vm_t fdt, vm_t initrd) * works for now. */ vm_t stack_top = t->thread_stack + t->thread_stack_size; + info("jumping to %lx\n", (long)t->callback); + bkl_unlock(); - __asm__ volatile ("mv sp, %0\n" - "li a0, %1\n" - "mv a1, %2\n" - "li a2, %3\n" - "mv a3, %4\n" - "mv a4, %5\n" - "li a5, %6\n" - "sret\n" - : - : "r" (stack_top), - "K" (0), "r" (t->tid), "K" (SYS_USER_SPAWNED), - "r" (fdt), "r" (initrd), "K" (1) - : "memory"); + riscv_run_init(0, t->tid, SYS_USER_SPAWNED, fdt, initrd, 1, stack_top); /* we should never reach this */ unreachable(); } diff --git a/arch/riscv64/kernel/smp.c b/arch/riscv64/kernel/smp.c index e48a216..425d3ce 100644 --- a/arch/riscv64/kernel/smp.c +++ b/arch/riscv64/kernel/smp.c @@ -59,7 +59,7 @@ void smp_bringup(struct vmem *b, void *fdt) extern void riscv_bringup(void); /* mark first hart available */ - cpuid_to_hartid(0) = -1; + set_hartid(0, -1); /* assume we're in default Sv mode, in the future this will have to be * fixed if we start implementing Sv48 etc. */ @@ -87,12 +87,12 @@ void smp_bringup(struct vmem *b, void *fdt) if (r.value == SBI_HART_STARTED) { /* there should ever only be one started hart */ assert(cpuid_to_hartid(0) == -1); - cpuid_to_hartid(0) = hartid; + set_hartid(0, hartid); continue; } /** @todo should check that cpus doesn't go over MAX_CPUS */ - cpuid_to_hartid(cpus++) = hartid; + set_hartid(cpus++, hartid); /** @todo try to remember to free these as well */ smp_init_stacks[hartid] = (void *)alloc_page(BASE_PAGE) + diff --git a/arch/riscv64/kernel/start.S b/arch/riscv64/kernel/start.S index 5a2ed61..3f2b3cb 100644 --- a/arch/riscv64/kernel/start.S +++ b/arch/riscv64/kernel/start.S @@ -1,10 +1,12 @@ +#include "asm.h" + #if GENERIC_UBOOT # define MAIN main_go #else # define MAIN main #endif -.section .kernel.start +.section ".kernel.start", "ax" .global _start _start: /* get load address */ @@ -15,6 +17,12 @@ lla sp, riscv_init_stack li t0, 4096 add sp, sp, t0 +lla t0, __kernel_start +lla t1, __kernel_end +lla t2, kernel_size +sub t0, t1, t0 +sr t0, 0(t2) + /* set thread pointer to zero so we don't accidentally try to use a tcb */ li tp, 0 @@ -32,3 +40,8 @@ add sp, sp, t1 lui t0, %hi(kernel) addi t0, t0, %lo(kernel) jr t0 + +.global riscv_run_init +riscv_run_init: +mv sp, a6 +sret diff --git a/arch/riscv64/kernel/vmem.c b/arch/riscv64/kernel/vmem.c index cb1eba0..9473f38 100644 --- a/arch/riscv64/kernel/vmem.c +++ b/arch/riscv64/kernel/vmem.c @@ -148,7 +148,7 @@ static bool __unused(pm_t b) */ static pm_t *__find_vmem(struct vmem *b, vm_t v, enum mm_order *o) { - enum mm_order top = __mm_max_order; + enum mm_order top = max_order(); if (o) *o = MM_O0; do { @@ -287,7 +287,7 @@ stat_t map_vpage(struct vmem *branch, pm_t paddr, vm_t vaddr, vmflags_t flags, enum mm_order order) { struct vmem *root = branch; - enum mm_order top = __mm_max_order; + enum mm_order top = max_order(); /* eventually we may want to keep track of page accesses, * but for now they're mainly a nuisance. */ @@ -316,7 +316,7 @@ stat_t map_vpage(struct vmem *branch, pm_t paddr, vm_t vaddr, vmflags_t flags, branch->leaf[idx] = (struct vmem *)to_pte((pm_t)__pa(paddr), vp_flags(flags)); - __add_graves(root, vm_to_index(vaddr, __mm_max_order)); + __add_graves(root, vm_to_index(vaddr, max_order())); return OK; } @@ -351,7 +351,7 @@ stat_t unmap_vpage(struct vmem *branch, vm_t vaddr) pm_t *pte = __find_vmem(branch, vaddr, 0); if (pte) { *pte = GRAVESTONE; - __remove_graves(branch, vm_to_index(vaddr, __mm_max_order)); + __remove_graves(branch, vm_to_index(vaddr, max_order())); return OK; } @@ -423,10 +423,10 @@ __aligned(4096) struct vmem kvmem; /* adding a third page entry would let us map the kernel at any 4KiB boundary * but eh, Linux seems fine with 2MiB so I guess I shall be as well. */ -struct vmem *init_mapping() +struct vmem *init_mapping(uintptr_t load_addr) { rpc_pages = order_size(MM_O1) / BASE_PAGE_SIZE; - kvmem.leaf[0] = (struct vmem *)to_pte(get_load_addr(), + kvmem.leaf[0] = (struct vmem *)to_pte(load_addr, VM_A | VM_G | VM_D | VM_R | VM_W | VM_X | VM_V); diff --git a/arch/riscv64/source.mk b/arch/riscv64/source.mk index 6e72c85..0c10bbc 100644 --- a/arch/riscv64/source.mk +++ b/arch/riscv64/source.mk @@ -1,15 +1,9 @@ KERNEL_LOCAL != echo $(ARCH_SOURCE)/kernel/*.[cS] -KERNEL_SOURCES += $(KERNEL_LOCAL) -INIT_SOURCES += $(ARCH_SOURCE)/init/*.[cS] +KERNEL_SOURCES := $(KERNEL_SOURCES) $(KERNEL_LOCAL) # this doesn't work for rv32, but fine for now */ ARCH_CFLAGS := $(ARCH_CFLAGS) -mcmodel=medany -# oof, LLVM's riscv support has become better since I last looked into -# it, but for some reason LTO still causes a crash. Meaning it has to be -# disabled again, though for a different reason than last time -OPTFLAGS != [ "$(LLVM)" != "0" ] && echo $(OPTFLAGS:-flto=) || echo $(OPTFLAGS) - run: $(ARCH_SOURCE)/conf/mkimage.sh $(ARCH) diff --git a/include/arch/vmem.h b/include/arch/vmem.h index e62c112..a19f555 100644 --- a/include/arch/vmem.h +++ b/include/arch/vmem.h @@ -148,10 +148,14 @@ vm_t setup_kernel_io(struct vmem *b, vm_t paddr); * address space and the kernel address space in the other. * Called at boot, not allowed to allocate memory. * + * @param load_addr Where in physical memory kernel was loaded to. Could in + * theory be fetched from \ref get_load_addr(), but the fewer globals are + * touched during initialization the better. + * * @return The vmem node used to build the address space. Probably statically * allocated. */ -struct vmem *init_mapping(); +struct vmem *init_mapping(uintptr_t load_addr); /** * Create new virtual memory space. diff --git a/include/kmi/bkl.h b/include/kmi/bkl.h index 9ea6ccd..39e3ef9 100644 --- a/include/kmi/bkl.h +++ b/include/kmi/bkl.h @@ -12,19 +12,10 @@ #include <kmi/lock.h> -/** Big Kenrel Lock. */ -extern spinlock_t bkl; - /** Lock the Big Kernel Lock. */ -static inline void bkl_lock() -{ - spin_lock(&bkl); -} +void bkl_lock(); /** Unlock the Big Kernel Lock. */ -static inline void bkl_unlock() -{ - spin_unlock(&bkl); -} +void bkl_unlock(); #endif /* KMI_BKL_H */ diff --git a/include/kmi/conf.h b/include/kmi/conf.h index 8e33a5f..02b8c4f 100644 --- a/include/kmi/conf.h +++ b/include/kmi/conf.h @@ -14,36 +14,25 @@ /** * Provides access to the runtime global parameter. - * \remark Note that runtime parameter passing is not yet implemented, and I might - * implement per-thread stack sizes as well. - * \global - * \todo This should probably be a function instead. - */ -extern size_t __thread_stack_size; - -/** - * Provides access to the runtime global parameter. - * Must be at most RPC_STACK_TOP - RPC_STACK_BASE. - * Essentially, each thread gets allocated this many bytes of total stack space - * that will be used during thread migrations. Each migration instance may at - * most take up __rpc_stack_size bytes, and during a thread migration the - * currently available free stack space is checked. - * - * Previous instances are unmapped, making them unaccessible to the current - * instance. + * @remark I might implement per-thread stack sizes at some point. * - * \see __thread_stack_size. - * \global - * \todo This should probably also be a function instead. + * @return Size of a regular thread stack, primarily just used to pass to \ref + * alloc_stack(). */ -extern size_t __call_stack_size; +size_t thread_stack_size(); /** * Provides access to the runtime global parameter. This sets the maximum size * a single rpc stack instance can be. * - * \global + * @return Size of one RPC stack entry, generally a single RPC shouldn't take + * up all of the available RPC stack space so we limit how much each call is + * allowed at a maximum, effectively enforcing a minimum number of RPC calls + * that a thread must be allowed to execute. + * + * I feel like this description is overly complicated but I can't think of a way + * to say it more clearly at the moment. */ -extern size_t __rpc_stack_size; +size_t rpc_stack_size(); #endif /* KMI_CONF_H */ diff --git a/include/kmi/dmem.h b/include/kmi/dmem.h index 6fd590f..697e55a 100644 --- a/include/kmi/dmem.h +++ b/include/kmi/dmem.h @@ -13,18 +13,6 @@ #include <kmi/types.h> #include <kmi/vmem.h> -/** Provides access to the global parameter. \global */ -extern pm_t __pre_base; - -/** Provides access to the global parameter. \global */ -extern pm_t __pre_top; - -/** Provides access to the global parameter. \global */ -extern pm_t __post_base; - -/** Provides access to the global parameter. \global */ -extern pm_t __post_top; - /** * Initialize device memory. * @note Currently I assume there is only one RAM region. This may not be the diff --git a/include/kmi/mem.h b/include/kmi/mem.h index e840683..6c62d31 100644 --- a/include/kmi/mem.h +++ b/include/kmi/mem.h @@ -13,6 +13,49 @@ #include <kmi/types.h> #include <arch/mem.h> +/** Maximum number of page orders allowed. Likely massively overkill. */ +#define NUM_ORDERS 10 + +/** Give names to page orders. */ +enum mm_order { + /** NULL marker. */ + MM_MIN = -1, + + /** Base order. */ + MM_O0 = 0, + + /** Order 1. */ + MM_O1 = 1, + + /** Order 2. */ + MM_O2 = 2, + + /** Order 3. */ + MM_O3 = 3, + + /** Order 4. */ + MM_O4 = 4, + + /** Order 5. */ + MM_O5 = 5, + + /** Order 6. */ + MM_O6 = 6, + + /** Order 7. */ + MM_O7 = 7, + + /** Order 8. */ + MM_O8 = 8, + + /** Order 9. */ + MM_O9 = 9, + + /** Number of orders */ + MM_NUM, +}; + + /** * Convert physical memory address \c paddr to index of page order \c order. * @@ -37,7 +80,7 @@ * @param order Order to query. * @return Starting offset of order bits. */ -#define order_shift(order) (__mm_shifts[order]) +size_t order_shift(enum mm_order order); /** * Get number of order bits in an address. @@ -45,7 +88,7 @@ * @param order Order to query. * @return Width in bits of order bits. */ -#define order_width(order) (__mm_widths[order]) +size_t order_width(enum mm_order order); /** * Get size of order, as in how many pages of one order lower it can contain. @@ -53,21 +96,21 @@ * @param order Order to query. * @return Number of pages of one order lower this order can contain. */ -#define order_size(order) (__mm_sizes[order]) +size_t order_size(enum mm_order order); /** * Get highest order supported by the current configuration. * * @return Max supported order. */ -#define max_order() (__mm_max_order) +enum mm_order max_order(); /** * Get base page shift. * * @return Page shift. */ -#define page_shift() (__mm_page_shift) +size_t page_shift(); /** * Get number of elements needed to represent this order. @@ -142,63 +185,6 @@ /** @} */ -/** Maximum number of page orders allowed. Likely massively overkill. */ -#define NUM_ORDERS 10 - -/** Give names to page orders. */ -enum mm_order { - /** NULL marker. */ - MM_MIN = -1, - - /** Base order. */ - MM_O0 = 0, - - /** Order 1. */ - MM_O1 = 1, - - /** Order 2. */ - MM_O2 = 2, - - /** Order 3. */ - MM_O3 = 3, - - /** Order 4. */ - MM_O4 = 4, - - /** Order 5. */ - MM_O5 = 5, - - /** Order 6. */ - MM_O6 = 6, - - /** Order 7. */ - MM_O7 = 7, - - /** Order 8. */ - MM_O8 = 8, - - /** Order 9. */ - MM_O9 = 9, - - /** Number of orders */ - MM_NUM, -}; - -/** Gives access to global page order shift information. \global */ -extern size_t __mm_shifts[NUM_ORDERS]; - -/** Gives access to global page order width information. \global */ -extern size_t __mm_widths[NUM_ORDERS]; - -/** Gives access to global page order size information. \global */ -extern size_t __mm_sizes[NUM_ORDERS]; - -/** Gives access to global base page shift. \global */ -extern size_t __mm_page_shift; - -/** Gives access to global maximum order size. \global */ -extern enum mm_order __mm_max_order; - /** * Find nearest order to size. * diff --git a/scripts/makefile b/scripts/makefile index 26b33ad..aa0bcac 100644 --- a/scripts/makefile +++ b/scripts/makefile @@ -47,7 +47,7 @@ COMPILER != [ "$(LLVM)" != "0" ] \ || echo $(CROSS_COMPILE)gcc -OBFLAGS = -ffreestanding -nostdlib -static -fno-pie -std=c17 -g +OBFLAGS = -ffreestanding -nostdlib -static -fpic -fno-pie -std=c17 -g WARNFLAGS = -Wall -Wextra -Wvla ARCH_CFLAGS = -D$(ARCH) @@ -61,8 +61,7 @@ LINK_FLAGS = $(LDFLAGS) $(ARCH_LDFLAGS) INCLUDE_FLAGS = -I include -include config.h -include arch/$(ARCH)/config.h # This makes sure .bss is loaded into the binary -OBJCOPY_FLAGS ?= -Obinary -R .garbage \ - --set-section-flags .bss=alloc,load,contents +OBJCOPY_FLAGS ?= -Obinary -R .garbage COMPILE = $(COMPILER) \ $(COMPILE_FLAGS) $(DEPFLAGS) $(INCLUDE_FLAGS) @@ -9,4 +9,15 @@ * Instanciation of the big kernel lock. */ -spinlock_t bkl = 0; +/** The Big Kernel Lock. */ +static spinlock_t bkl = 0; + +void bkl_lock() +{ + spin_lock(&bkl); +} + +void bkl_unlock() +{ + spin_unlock(&bkl); +} diff --git a/src/debug.c b/src/debug.c index 567911b..d87588d 100644 --- a/src/debug.c +++ b/src/debug.c @@ -392,7 +392,7 @@ static size_t __print_prefix(size_t base) case 16: return __puts("0x"); case 8: return __puts("0"); case 2: return __puts("0b"); - default: + default: break; } return 0; @@ -70,8 +70,8 @@ void handle_irq() struct tcb *t = get_tcb(tid); if (!t || orphan(t)) { info("tcb %llu dead at irq %llu\n", - (unsigned long long)tid, - (unsigned long long)id); + (unsigned long long)tid, + (unsigned long long)id); /* unregister irq handler */ irq_map[id] = 0; @@ -61,6 +61,15 @@ __noreturn void kernel(void *fdt, uintptr_t load_addr, struct vmem *d) /* we should be in kernelspace, so use the virtual address of our FDT. */ fdt = __va(fdt); + /** @todo some kind of lottery? */ + pm_t ram_base = __fdt_ram_base(fdt); + pm_t ram_size = __fdt_ram_size(fdt); + set_ram_base(ram_base); + set_ram_size(ram_size); + set_load_addr(load_addr); + + init_dbg(fdt); + /* start up debugging in kernel IO */ setup_io_dbg(d); @@ -102,27 +111,10 @@ __noreturn void main(unsigned long hart, void *fdt, uintptr_t load_addr) /* we have our own ways to get the current hart when we need it, but we * have to get the function signature right */ (void)hart; - - /* dbg uses direct mapping at this point, useful for early init asserts - * and so on */ - init_dbg(fdt); - - /** @todo some kind of lottery? */ - pm_t ram_base = __fdt_ram_base(fdt); - pm_t ram_size = __fdt_ram_size(fdt); - set_ram_base(ram_base); - set_ram_size(ram_size); - set_load_addr(load_addr); - init_mem(fdt); - /* we don't have any debug output just yet but still */ - /* also this is I guess more of an architecture limitation, should the - * whole of main() just be moved to arch? */ - assert(is_aligned(load_addr, order_size(MM_O1))); - - struct vmem *d = init_mapping(); - to_kernelspace(fdt, load_addr, d, ram_base); + struct vmem *d = init_mapping(load_addr); + to_kernelspace(fdt, load_addr, d, 0); unreachable(); } @@ -11,23 +11,57 @@ #include <kmi/vmem.h> #include <libfdt.h> -size_t __mm_shifts[10]; -size_t __mm_widths[10]; -size_t __mm_sizes[10]; -size_t __mm_page_shift; -enum mm_order __mm_max_order; +/** Page order shifts. */ +static size_t mm_shifts[10]; + +/** Page order widths. */ +static size_t mm_widths[10]; + +/** Page order sizes. */ +static size_t mm_sizes[10]; + +/** Base page shift, i.e. how many bits are just offsets within a page. */ +static size_t mm_page_shift; + +/** Maximum order supported by the current cpu. */ +static enum mm_order mm_max_order; + +size_t order_shift(enum mm_order order) +{ + return mm_shifts[order]; +} + +size_t order_size(enum mm_order order) +{ + return mm_sizes[order]; +} + +enum mm_order max_order() +{ + return mm_max_order; +} + +size_t order_width(enum mm_order order) +{ + return mm_widths[order]; +} + +size_t page_shift() +{ + return mm_page_shift; +} /** * RAM base address. Not sure if it should be provided through a macro * like __mm_*. */ -pm_t ram_base; +static pm_t ram_base; /** RAM size. */ -size_t ram_size; +static size_t ram_size; /** Load address. */ -pm_t load_addr; +static pm_t load_addr; enum mm_order nearest_order(size_t size) { @@ -40,22 +74,22 @@ enum mm_order nearest_order(size_t size) void init_mem(void *fdt) { - size_t max_order = 0; + size_t top_order = 0; size_t base_bits = 0; size_t bits[NUM_ORDERS] = { 0 }; - stat_pmem_conf(fdt, &max_order, &base_bits, bits); + stat_pmem_conf(fdt, &top_order, &base_bits, bits); - __mm_max_order = max_order; - __mm_page_shift = base_bits; + mm_max_order = top_order; + mm_page_shift = base_bits; - __mm_shifts[0] = __mm_page_shift; - __mm_widths[0] = 1 << bits[0]; - __mm_sizes[0] = 1 << __mm_page_shift; + mm_shifts[0] = mm_page_shift; + mm_widths[0] = 1 << bits[0]; + mm_sizes[0] = 1 << mm_page_shift; for (enum mm_order i = MM_O1; i <= max_order(); ++i) { - __mm_widths[i] = 1 << bits[i]; - __mm_shifts[i] = __mm_shifts[i - 1] + bits[i - 1]; - __mm_sizes[i] = 1UL << __mm_shifts[i]; + mm_widths[i] = 1 << bits[i]; + mm_shifts[i] = mm_shifts[i - 1] + bits[i - 1]; + mm_sizes[i] = 1UL << mm_shifts[i]; } } @@ -612,6 +612,11 @@ retry: return 0; } +/** Actual kernel size in bytes. Populated by `_start`, as I don't think we + * have enough control from C to get both LLVM and GCC to output correct code + * if this was just a virtual symbol defined in a linker file. */ +size_t kernel_size = 0; + void init_pmem(void *fdt, uintptr_t load_addr) { /** @todo should I keep the info outputs? I suppose it's nice to see @@ -650,13 +655,11 @@ void init_pmem(void *fdt, uintptr_t load_addr) size_t probe_size = probe_pmap(0, ram_size, 0); info("pmem map probe size returned %lu\n", probe_size); - /* linker magicry */ - extern char *__kernel_size; /* avoidance regions, note that stack and so on is included in the * kernel. Addresses can be outside RAM, in which case they are just * ignored. */ struct avoid_region avoid[64] = { - {(pm_t)__va(load_addr), (pm_t)&__kernel_size}, + {(pm_t)__va(load_addr), kernel_size}, {(pm_t)__va(initrd_base), initrd_size}, {(pm_t)__va(fdt_base), fdt_size} }; diff --git a/src/regions.c b/src/regions.c index b57b548..ca99971 100644 --- a/src/regions.c +++ b/src/regions.c @@ -259,7 +259,7 @@ static struct mem_region *__create_region(vm_t start, vm_t end, */ static size_t po_align(size_t s) { - for (size_t o = __mm_max_order; o > 0; --o) { + for (size_t o = max_order(); o > 0; --o) { if (s >= order_size(o)) return order_size(o); } @@ -102,14 +102,14 @@ stat_t alloc_stack(struct tcb *t) /* get parent process */ struct tcb *p = get_tcb(t->eid); - t->thread_stack = __setup_thread_stack(p, __thread_stack_size); + t->thread_stack = __setup_thread_stack(p, thread_stack_size()); if (!t->thread_stack) return ERR_OOMEM; /** \todo this only allows for a global stack size, what if a user wants * per thread stack sizes? I guess allocate them yourself in userspace * or something? */ - t->thread_stack_size = __thread_stack_size; + t->thread_stack_size = thread_stack_size(); return OK; } diff --git a/src/timer.c b/src/timer.c index 573ed7b..5583cd3 100644 --- a/src/timer.c +++ b/src/timer.c @@ -208,7 +208,7 @@ void handle_timer() struct tcb *r = get_tcb(tid); if (!r || orphan(r)) { info("tcb %llu dead at timer\n", - (unsigned long long)tid); + (unsigned long long)tid); bkl_unlock(); return; } diff --git a/src/uapi/conf.c b/src/uapi/conf.c index be9abfc..3a45d30 100644 --- a/src/uapi/conf.c +++ b/src/uapi/conf.c @@ -16,11 +16,24 @@ #include <arch/proc.h> -/** \todo stack size should really be set on a per-thread basis, and are the - * conf*-syscalls even necessary? */ -size_t __thread_stack_size = SZ_2M; -size_t __rpc_stack_size = SZ_512K; +/** \todo stack size should probably be set on a per-thread basis */ +/** Current global thread stack size. */ +static size_t __thread_stack_size = SZ_2M; + +/** Current global RPC stack entry size. */ +static size_t __rpc_stack_size = SZ_512K; + + +size_t thread_stack_size() +{ + return __thread_stack_size; +} + +size_t rpc_stack_size() +{ + return __rpc_stack_size; +} /** * Configuration parameter read syscall handler. diff --git a/src/uapi/ipc.c b/src/uapi/ipc.c index 3ac4727..3a28afa 100644 --- a/src/uapi/ipc.c +++ b/src/uapi/ipc.c @@ -133,7 +133,7 @@ static bool __enough_rpc_stack(struct tcb *t) /* if we can still fit an rpc stack into the call stack, we can safely * do the migration. */ - return top - BASE_PAGE_SIZE - __rpc_stack_size >= RPC_STACK_BASE; + return top - BASE_PAGE_SIZE - rpc_stack_size() >= RPC_STACK_BASE; } /** |
