From e134202611a50b358c147c92bfb8a7f443030b8b Mon Sep 17 00:00:00 2001 From: Kimplul Date: Mon, 8 Jul 2024 17:43:59 +0300 Subject: 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? --- src/bkl.c | 13 ++++++++++- src/debug.c | 2 +- src/irq.c | 4 ++-- src/main.c | 30 +++++++++---------------- src/mem.c | 70 ++++++++++++++++++++++++++++++++++++++++++--------------- src/pmem.c | 9 +++++--- src/regions.c | 2 +- src/tcb.c | 4 ++-- src/timer.c | 2 +- src/uapi/conf.c | 21 +++++++++++++---- src/uapi/ipc.c | 2 +- 11 files changed, 106 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/bkl.c b/src/bkl.c index aa7bd53..6ee58f4 100644 --- a/src/bkl.c +++ b/src/bkl.c @@ -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; diff --git a/src/irq.c b/src/irq.c index 582a06f..1e33623 100644 --- a/src/irq.c +++ b/src/irq.c @@ -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; diff --git a/src/main.c b/src/main.c index f3c5e17..12d8514 100644 --- a/src/main.c +++ b/src/main.c @@ -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(); } diff --git a/src/mem.c b/src/mem.c index 89657e8..5512d82 100644 --- a/src/mem.c +++ b/src/mem.c @@ -11,23 +11,57 @@ #include #include -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]; } } diff --git a/src/pmem.c b/src/pmem.c index bed10a4..47bb319 100644 --- a/src/pmem.c +++ b/src/pmem.c @@ -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); } diff --git a/src/tcb.c b/src/tcb.c index ea00d3d..053ea6f 100644 --- a/src/tcb.c +++ b/src/tcb.c @@ -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 -/** \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; } /** -- cgit v1.3