diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-07-07 07:00:43 +0300 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-07-07 07:00:43 +0300 |
| commit | 122374c362ba8bb9082385da3c82e264ab594f15 (patch) | |
| tree | 0123fad5464aaf64f522d48f5069b35b90207aae | |
| parent | 03e12129927b0deba537a11bb5575bef93c57d0f (diff) | |
| download | kmi-122374c362ba8bb9082385da3c82e264ab594f15.tar.gz kmi-122374c362ba8bb9082385da3c82e264ab594f15.zip | |
smp now seems to work
+ Had some minor issues with a wraparound of size_t that effectively
meant that some regions were allocated twice. Also, booting should be
a bit more reliable now, turned out that the previous iteration of the
booting was just accidentally working due to the kernel being placed
'close enough' in RAM to where it was linked to. Fixed by allocating a
vmem of O1 that maps the kernel to a 2MiB boundary at boot, pretty
nifty.
| -rw-r--r-- | arch/riscv64/conf/init.c | 60 | ||||
| -rw-r--r-- | arch/riscv64/conf/kernel-link.S | 2 | ||||
| -rw-r--r-- | arch/riscv64/config.h | 6 | ||||
| -rw-r--r-- | arch/riscv64/kernel/core_bringup.S | 9 | ||||
| -rw-r--r-- | arch/riscv64/kernel/entry.S | 2 | ||||
| -rw-r--r-- | arch/riscv64/kernel/proc.c | 14 | ||||
| -rw-r--r-- | arch/riscv64/kernel/smp.c | 35 | ||||
| -rw-r--r-- | arch/riscv64/kernel/start.S | 11 | ||||
| -rw-r--r-- | arch/riscv64/kernel/vmem.c | 30 | ||||
| -rw-r--r-- | include/arch/vmem.h | 6 | ||||
| -rw-r--r-- | include/kmi/mem.h | 4 | ||||
| -rw-r--r-- | include/kmi/syscalls.h | 4 | ||||
| -rw-r--r-- | src/main.c | 5 | ||||
| -rw-r--r-- | src/pmem.c | 4 | ||||
| -rw-r--r-- | src/proc.c | 9 | ||||
| -rw-r--r-- | src/regions.c | 5 | ||||
| -rw-r--r-- | src/tcb.c | 6 |
17 files changed, 147 insertions, 65 deletions
diff --git a/arch/riscv64/conf/init.c b/arch/riscv64/conf/init.c index 6b1ce46..c61848e 100644 --- a/arch/riscv64/conf/init.c +++ b/arch/riscv64/conf/init.c @@ -274,24 +274,9 @@ static void *sys_req_sharedmem(long tid, unsigned long size, void **cbuf) static char *rw_buf = 0; static size_t rw_buf_size = 4096; -void callback(long pid, long tid, long d0, long d1, long d2, long d3) +static void sys_sleep() { - (void)tid; - if (d0 == 1) { - void *cbuf = 0; - rw_buf = sys_req_sharedmem(pid, rw_buf_size, &cbuf); - sys_ipc_resp((long)cbuf, rw_buf_size, 0, 0); - __builtin_unreachable(); - - } else if (d0 == 2) { - puts("Received string: "); - puts(rw_buf); - sys_ipc_resp(0, 0, 0, 0); - __builtin_unreachable(); - } - - sys_ipc_resp(0, 0, 0, 0); - __builtin_unreachable(); + ecall1(SYS_SLEEP); } #define CSR_TIME "0xc01" @@ -300,8 +285,19 @@ void callback(long pid, long tid, long d0, long d1, long d2, long d3) #define CSR_CYCLE "0xc00" -void _start() +static void handle_kernel(long a0, long a1, long d0, long d1, long d2, long d3) { + if (a1 != SYS_USER_BOOTED) + return; + + long tid = d0; + if (tid != 1) { + puts("Woo, more cores!\n"); + while (1) + sys_sleep(); + } + + /* otherwise */ sys_noop(); puts("Hello, world!\n"); @@ -322,9 +318,6 @@ void _start() print_value("Syscalls per second", n); print_value("Executed cycles per second", cend - cstart); - puts("Setting callback..."); - sys_ipc_server(callback); - puts("Starting fork():\n"); long pid = sys_fork(); if (pid != 0) { @@ -387,3 +380,28 @@ void _start() sys_poweroff(0); } + +void _start(long a0, long a1, long d0, long d1, long d2, long d3) +{ + if (a0 == 0) + handle_kernel(a0, a1, d0, d1, d2, d3); + + /* otherwise, implement test functionality */ + long pid = a0; + long tid = a1; + if (d0 == 1) { + void *cbuf = 0; + rw_buf = sys_req_sharedmem(pid, rw_buf_size, &cbuf); + sys_ipc_resp((long)cbuf, rw_buf_size, 0, 0); + __builtin_unreachable(); + + } else if (d0 == 2) { + puts("Received string: "); + puts(rw_buf); + sys_ipc_resp(0, 0, 0, 0); + __builtin_unreachable(); + } + + sys_ipc_resp(0, 0, 0, 0); + __builtin_unreachable(); +} diff --git a/arch/riscv64/conf/kernel-link.S b/arch/riscv64/conf/kernel-link.S index 832a886..88f2e75 100644 --- a/arch/riscv64/conf/kernel-link.S +++ b/arch/riscv64/conf/kernel-link.S @@ -11,7 +11,7 @@ SECTIONS { * hack. * @todo look into this further. */ - . = VM_DMAP; + . = ABSOLUTE(VM_KERNEL); __kernel_start = .; .text ALIGN(4K) : AT(0) { *(.kernel.start); diff --git a/arch/riscv64/config.h b/arch/riscv64/config.h index 2c513a5..952c0ca 100644 --- a/arch/riscv64/config.h +++ b/arch/riscv64/config.h @@ -32,6 +32,12 @@ /** Direct map offset. */ #define VM_DMAP (0xffffffc000000000) /* testing for now */ +/** Page reserved for kernel mapping in O1 */ +#define KERNEL_PAGE 510UL + +/** Kernel virtual address */ +#define VM_KERNEL (0xffffffff80000000) + /** Page reserved for kernel I/O. */ #define IO_PAGE 511UL diff --git a/arch/riscv64/kernel/core_bringup.S b/arch/riscv64/kernel/core_bringup.S index 83b017c..8a5a6f5 100644 --- a/arch/riscv64/kernel/core_bringup.S +++ b/arch/riscv64/kernel/core_bringup.S @@ -12,12 +12,17 @@ riscv_bringup: sfence.vma /* fetch the stack allocated to us at our hart index in smp_init_stacks */ - lla t0, smp_init_stacks + lui t0, %hi(smp_init_stacks) + addi t0, t0, %lo(smp_init_stacks) slli t1, a0, RW_SHIFT add t0, t0, t1 lr sp, 0(t0) mv tp, sp + /* calculate actual address in kernelspace where we should jump to */ + /* a0 has RAM base */ + lui t0, %hi(core_bringup) + addi t0, t0, %lo(core_bringup) + /* jump to C to handle rest of bringup */ - lla t0, core_bringup jr t0 diff --git a/arch/riscv64/kernel/entry.S b/arch/riscv64/kernel/entry.S index e37d5cc..6096844 100644 --- a/arch/riscv64/kernel/entry.S +++ b/arch/riscv64/kernel/entry.S @@ -130,7 +130,7 @@ fast_dispatch: csrr t5, CSR_SEPC sr t5, offsetof_exec(tp) /* jump to C */ - jal dispatch + call dispatch /* if we had a thread switch, load kernel stack of current thread and * restore its context */ /* get associated kernel stack */ diff --git a/arch/riscv64/kernel/proc.c b/arch/riscv64/kernel/proc.c index a4746b4..af4b2f3 100644 --- a/arch/riscv64/kernel/proc.c +++ b/arch/riscv64/kernel/proc.c @@ -18,9 +18,8 @@ void run_init(struct tcb *t, vm_t fdt, vm_t initrd) { - /** \todo actually map fdt and initrd into the target address space */ csr_write(CSR_SSCRATCH, t); - csr_write(CSR_SEPC, t->exec); + csr_write(CSR_SEPC, t->callback); /* gcc gives a warning 'the value of the stack pointer after an asm * statement must be the same as it was before the statement', so this * is technically speaking undefined behavior, I think. @@ -31,13 +30,16 @@ void run_init(struct tcb *t, vm_t fdt, vm_t initrd) vm_t stack_top = t->thread_stack + t->thread_stack_size; bkl_unlock(); __asm__ volatile ("mv sp, %0\n" - "mv a0, %1\n" - "mv a1, %2\n" + "li a0, %1\n" + "li a1, %2\n" "mv a2, %3\n" + "mv a3, %4\n" + "mv a4, %5\n" "sret\n" : - : "r" (stack_top), "r" (t->tid), "r" (fdt), - "r" (initrd) + : "r" (stack_top), + "K"(0), "K"(SYS_USER_BOOTED), + "r" (t->tid), "r" (fdt), "r" (initrd) : "memory"); /* we should never reach this */ unreachable(); diff --git a/arch/riscv64/kernel/smp.c b/arch/riscv64/kernel/smp.c index 74cc930..a878b90 100644 --- a/arch/riscv64/kernel/smp.c +++ b/arch/riscv64/kernel/smp.c @@ -7,9 +7,13 @@ */ #include <kmi/debug.h> -#include <arch/smp.h> +#include <kmi/bkl.h> #include <kmi/tcb.h> #include <libfdt.h> + +#include <arch/proc.h> +#include <arch/arch.h> +#include <arch/smp.h> #include "arch.h" #include "sbi.h" @@ -94,7 +98,10 @@ void smp_bringup(struct vmem *b, void *fdt) smp_init_stacks[hartid] = (void *)alloc_page(BASE_PAGE) + BASE_PAGE_SIZE; - pm_t bringup = (pm_t)__pa(riscv_bringup); + /* fixup physical address of bringup */ + pm_t bringup = (pm_t)riscv_bringup; + bringup = bringup - VM_KERNEL + get_load_addr(); + r = sbi_hart_start(hartid, bringup, satp); if (r.error) { @@ -111,8 +118,9 @@ void smp_bringup(struct vmem *b, void *fdt) * * @param hartid Hart that's being brought up. */ -void core_bringup(long hartid) +__noreturn void core_bringup(long hartid) { + bkl_lock(); /* assume smp_bringup assigned our cpuid correctly */ id_t cpuid = hartid_to_cpuid(hartid); @@ -125,12 +133,25 @@ void core_bringup(long hartid) /* add us as a thread to init program that cpu 0 is hopefully running by * now */ - struct tcb *t = create_thread(cpu_tcb(0)); + struct tcb *init = get_tcb(1); + assert(init); + + struct tcb *t = create_thread(init); + assert(t); + + alloc_stack(t); + /* init is special in that all threads jump to the entrypoint of the + * program */ + t->callback = init->callback; + t->exec = init->exec; t->cpu_id = cpuid; + /** @todo this is pretty hacky, should really be a separate function? */ + setup_irq(NULL); + setup_arch(NULL); tcb_assign(t); use_tcb(t); - /* eventually we should jump to init and start running stuff, but for - * now take it easy */ - while (1); + info("core %ld releasing BKL\n", (long)cpuid); + run_init(t, NULL, NULL); + unreachable(); } diff --git a/arch/riscv64/kernel/start.S b/arch/riscv64/kernel/start.S index 73a442e..5a2ed61 100644 --- a/arch/riscv64/kernel/start.S +++ b/arch/riscv64/kernel/start.S @@ -24,12 +24,11 @@ ret .section .text -/* a0 is fdt, a1 is load_addr, a2 is d, a3 is ram_base, a4 is DMAP */ +/* a0 is fdt, a1 is load_addr, a2 is d, a3 is ram_base */ .global to_kernelspace to_kernelspace: -lla t0, kernel -add t0, t0, a4 -sub t0, t0, a3 -add sp, sp, a4 -sub sp, sp, a3 +li t1, VM_DMAP +add sp, sp, t1 +lui t0, %hi(kernel) +addi t0, t0, %lo(kernel) jr t0 diff --git a/arch/riscv64/kernel/vmem.c b/arch/riscv64/kernel/vmem.c index 97b9cce..68869a3 100644 --- a/arch/riscv64/kernel/vmem.c +++ b/arch/riscv64/kernel/vmem.c @@ -416,14 +416,19 @@ long riscv_init_stack[4096 / sizeof(long)]; * and so the kernel itself has to be on a 4K boundary. */ __aligned(4096) struct vmem bootvmem; -struct vmem *direct_mapping() +/** Page entry for mapping kernel on a O1 page level, similar to how Linux does + * it. */ +__aligned(4096) struct vmem kvmem; + +struct vmem *init_mapping() { rpc_pages = order_size(MM_O1) / BASE_PAGE_SIZE; + kvmem.leaf[0] = (struct vmem *)to_pte(get_load_addr(), + VM_A | VM_G | VM_D | VM_R | VM_W | VM_X | VM_V); __populate_dmap(&bootvmem); populate_kvmem(&bootvmem); __use_vmem(&bootvmem, DEFAULT_Sv_MODE); - return &bootvmem; } @@ -456,16 +461,31 @@ void destroy_vmem(struct vmem *b) __destroy_branch(b); } +static void map_kernel(struct vmem *b) +{ + intptr_t addr = (pm_t)&kvmem; + + /* virtual memory is negative, unsure if this applies everywhere but I + * guess it's good enough for us */ + if (addr < 0) + addr = addr - VM_KERNEL + get_load_addr(); + + b->leaf[KERNEL_PAGE] = (struct vmem *)to_pte((pm_t)addr, VM_V); +} + stat_t populate_kvmem(struct vmem *b) { size_t flags = VM_V | VM_R | VM_W | VM_X | VM_G | VM_D | VM_A; - for (size_t i = KSTART_PAGE; i < IO_PAGE; ++i) + for (size_t i = KSTART_PAGE; i < KERNEL_PAGE; ++i) b->leaf[i] = (struct vmem *)to_pte( - get_ram_base() + TOP_PAGE_SIZE * (i - KSTART_PAGE), + TOP_PAGE_SIZE * (i - KSTART_PAGE), flags); - /* map in IO region */ + /* map in IO region if debugging is specified */ map_io_dbg(b); + + /* map actual kernel */ + map_kernel(b); return OK; } diff --git a/include/arch/vmem.h b/include/arch/vmem.h index 3daf232..e62c112 100644 --- a/include/arch/vmem.h +++ b/include/arch/vmem.h @@ -151,7 +151,7 @@ vm_t setup_kernel_io(struct vmem *b, vm_t paddr); * @return The vmem node used to build the address space. Probably statically * allocated. */ -struct vmem *direct_mapping(); +struct vmem *init_mapping(); /** * Create new virtual memory space. @@ -190,11 +190,9 @@ void clone_uvmem(struct vmem * restrict r, struct vmem * restrict b); * @param load_addr Address where kernel was loaded to. * @param direct_mapping Direct mapping vmem. * @param ram_base Physical base address of ram. - * @param dmap \ref VM_DMAP. */ __noreturn void to_kernelspace(void *fdt, uintptr_t load_addr, struct vmem *direct_mapping, - pm_t ram_base, - pm_t dmap); + pm_t ram_base); #endif /* KMI_ARCH_PAGES_H */ diff --git a/include/kmi/mem.h b/include/kmi/mem.h index d3c4da2..bf55c61 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 - get_ram_base()) +#define __va(x) (void *)(((uintptr_t)(x)) + VM_DMAP) /** * 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 + get_ram_base()) +#define __pa(x) (void *)(((uintptr_t)(x)) - VM_DMAP) /** * Get page number of physical address. diff --git a/include/kmi/syscalls.h b/include/kmi/syscalls.h index a94cdf1..93b99a3 100644 --- a/include/kmi/syscalls.h +++ b/include/kmi/syscalls.h @@ -176,6 +176,10 @@ enum sys_user { /** Thread has been orphaned. */ SYS_USER_ORPHANED, + + /** Core has booted an init thread. Only used during booting, should be + * handled specially. */ + SYS_USER_BOOTED, }; /** Which notifications have arrived. */ @@ -114,9 +114,8 @@ __noreturn void main(unsigned long hart, void *fdt, uintptr_t load_addr) init_mem(fdt); - struct vmem *d = direct_mapping(); - - to_kernelspace(fdt, load_addr, d, ram_base, VM_DMAP); + struct vmem *d = init_mapping(); + to_kernelspace(fdt, load_addr, d, ram_base); unreachable(); } @@ -397,8 +397,10 @@ static pm_t __maybe_populate_bucket(size_t n, pm_t cont, enum mm_order order, if (n) { struct mm_bmap *bmap = (struct mm_bmap *)cont; - if (populate) + if (populate) { + memset(bmap, 0, set_size); bmap->size = n; + } if (first && populate) __attach_set(bucket, bmap); @@ -59,17 +59,22 @@ stat_t init_proc(void *fdt, vm_t *proc_fdt, vm_t *proc_initrd) /* allocate stacks etc after ELF file to make sure nothing of importance * clashes */ prepare_proc(t, get_init_base(fdt), 0); + + /** In the init process, can the entry be the callback? Is that too + * unergonomic? */ + t->callback = t->exec; + /** \todo start one thread per core, with special handling for init in * that each thread starts at the entry point of init? */ *proc_fdt = map_fixed_uvmem(t, (pm_t)fdt, fdt_totalsize(fdt), - VM_V | VM_R | VM_U); + MR_SHARED | VM_V | VM_R | VM_U); pm_t initrd = (pm_t)__va(get_initrdbase(fdt)); *proc_initrd = map_fixed_uvmem(t, initrd, get_initrdsize(fdt), - VM_V | VM_R | VM_U); + MR_SHARED | VM_V | VM_R | VM_U); info("mapped fdt at %lx\n", *proc_fdt); info("mapped initrd at %lx\n", *proc_initrd); diff --git a/src/regions.c b/src/regions.c index 66ee546..f098f4f 100644 --- a/src/regions.c +++ b/src/regions.c @@ -316,7 +316,10 @@ struct mem_region *find_free_region(struct mem_region_root *r, size_t size, vm_t start = align_up(t->start, offset); size_t qsize = t->end - t->start; - size_t bsize = t->end - start; + + size_t bsize = 0; + if (t->end >= start) + bsize = t->end - start; if (!quick_best && size <= qsize) quick_best = t; @@ -120,14 +120,14 @@ void free_stack(struct tcb *t) struct tcb *create_thread(struct tcb *p) { - hard_assert(tcbs, 0); + assert(tcbs); vm_t bottom = alloc_page(KERNEL_STACK_PAGE_ORDER); /* move tcb to top of kernel stack, keeping alignment in check * (hopefully) */ /** \todo check alignment */ - struct tcb *t = (struct tcb *)align_down( - bottom + order_size(MM_O0) - sizeof(struct tcb), sizeof(long)); + bottom = bottom + order_size(MM_O0) - sizeof(struct tcb); + struct tcb *t = (struct tcb *)align_down(bottom, sizeof(long)); memset(t, 0, sizeof(struct tcb)); id_t tid = __alloc_tid(t); |
