From af1ce4b2e637ceb418ea72d51c49a3eee276a938 Mon Sep 17 00:00:00 2001 From: stefan Date: Sat, 15 Apr 2023 05:02:02 +0000 Subject: added multiprocessor support --- sys/Makefile | 3 +- sys/dev/sbi.c | 39 -------------------------- sys/include/printf.h | 1 + sys/include/sbi.h | 74 +++++++++++++++++++++++++++++++++++++++++++++----- sys/include/spinlock.h | 8 ++++-- sys/kern/entry.S | 28 +++++++++++++++---- sys/kern/init.c | 34 +++++++++++++++++------ sys/kern/printf.c | 18 +++++++++++- sys/kern/spinlock.c | 33 ++++++++++++++++++---- 9 files changed, 168 insertions(+), 70 deletions(-) delete mode 100644 sys/dev/sbi.c (limited to 'sys') diff --git a/sys/Makefile b/sys/Makefile index 2cfd2bb..02ee0df 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -13,7 +13,6 @@ SRC=\ kern/printf.c\ kern/mm/kalloc.c\ kern/spinlock.c\ - dev/sbi.c\ dev/fdt/fdt.c @@ -23,6 +22,8 @@ ${BUILDDIR}/kernel.elf: ${SRC} -Wl,--defsym=LOAD_ADDR=${LOAD_ADDR}\ -Wl,--defsym=PAGE_SIZE=${PAGE_SIZE}\ -Wl,--defsym=NPROC=${NPROC}\ + -DLOAD_ADDR=${LOAD_ADDR}\ + -DNPROC=${NPROC}\ -DPAGE_SIZE=${PAGE_SIZE}\ -I ./include\ ${CFLAGS} -T kern/kernel.lds ${LDFLAGS}\ diff --git a/sys/dev/sbi.c b/sys/dev/sbi.c deleted file mode 100644 index 0c9e3f2..0000000 --- a/sys/dev/sbi.c +++ /dev/null @@ -1,39 +0,0 @@ -#include - -struct sbiret -sbi_ecall(int ext, int fid, unsigned long arg0, - unsigned long arg1, unsigned long arg2, - unsigned long arg3, unsigned long arg4, - unsigned long arg5) -{ - struct sbiret ret; - - register unsigned long a0 asm ("a0") = (unsigned long)(arg0); - register unsigned long a1 asm ("a1") = (unsigned long)(arg1); - register unsigned long a2 asm ("a2") = (unsigned long)(arg2); - register unsigned long a3 asm ("a3") = (unsigned long)(arg3); - register unsigned long a4 asm ("a4") = (unsigned long)(arg4); - register unsigned long a5 asm ("a5") = (unsigned long)(arg5); - register unsigned long a6 asm ("a6") = (unsigned long)(fid); - register unsigned long a7 asm ("a7") = (unsigned long)(ext); - asm volatile ("ecall" - : "+r" (a0), "+r" (a1) - : "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7) - : "memory"); - ret.err = a0; - ret.val = a1; - - return ret; -} - -void -sbi_console_putchar(int c) -{ - sbi_ecall(1, 0, c, 0, 0, 0, 0, 0); -} - -void -sbi_shutdown(void) -{ - sbi_ecall(8, 0, 0, 0, 0, 0, 0, 0); -} diff --git a/sys/include/printf.h b/sys/include/printf.h index 76debc3..fd9a092 100644 --- a/sys/include/printf.h +++ b/sys/include/printf.h @@ -2,6 +2,7 @@ #define _KPRINTF_H int puts(const char *); +void printf_init(void); void printf(const char *, ...); #endif /* _KPRINTF_H */ diff --git a/sys/include/sbi.h b/sys/include/sbi.h index 0dbcd02..1c0fc7f 100644 --- a/sys/include/sbi.h +++ b/sys/include/sbi.h @@ -1,16 +1,76 @@ -#ifndef _SBICALL_H -#define _SBICALL_H +#ifndef _SBI_H +#define _SBI_H struct sbiret { long err; long val; }; -struct sbiret sbi_ecall(int _eid, int _fid, unsigned long _a0, unsigned long _a1, - unsigned long _a2, unsigned long _a3, unsigned long _a4, unsigned long _a5); +#define SBI_SUCCESS 0 +#define SBI_ERR_FAILED -1 +#define SBI_ERR_NOT_SUPPORTED -2 +#define SBI_ERR_INVALD_PARAM -3 +#define SBI_ERR_DENIED -4 +#define SBI_ERR_INVALID_ADDRESS -5 +#define SBI_ERR_ALREADY_AVAILABLE -6 +#define SBI_ERR_ALREADY_STARTED -7 +#define SBI_ERR_ALREADY_STOPPED -8 -void sbi_console_putchar(int c); -void sbi_shutdown(void); +enum HART_STATUS { + STARTED, + STOPPED, + START_PENDING, + STOP_PENDING, + SUSPENDED, + SUSPEND_PENDING, + RESUME_PENDING +}; + +static inline struct sbiret +sbi_ecall(int ext, int fid, unsigned long arg0, + unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4, + unsigned long arg5) +{ + struct sbiret ret; + + register unsigned long a0 asm ("a0") = (unsigned long)(arg0); + register unsigned long a1 asm ("a1") = (unsigned long)(arg1); + register unsigned long a2 asm ("a2") = (unsigned long)(arg2); + register unsigned long a3 asm ("a3") = (unsigned long)(arg3); + register unsigned long a4 asm ("a4") = (unsigned long)(arg4); + register unsigned long a5 asm ("a5") = (unsigned long)(arg5); + register unsigned long a6 asm ("a6") = (unsigned long)(fid); + register unsigned long a7 asm ("a7") = (unsigned long)(ext); + asm volatile ("ecall" + : "+r" (a0), "+r" (a1) + : "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7) + : "memory"); + ret.err = a0; + ret.val = a1; + + return ret; +} + +static inline void +sbi_console_putchar(int c) +{ + sbi_ecall(1, 0, c, 0, 0, 0, 0, 0); +} + +static inline void +sbi_shutdown(void) +{ + sbi_ecall(8, 0, 0, 0, 0, 0, 0, 0); +} + +static inline struct sbiret +sbi_hart_start(unsigned long hartid, unsigned long start_addr, unsigned long opaque) +{ + struct sbiret r = sbi_ecall(0x48534D, 0, hartid, start_addr, opaque, 0, 0, 0); + return r; +} +#define _start_hart(tp, a) sbi_hart_start(tp, a, 0); -#endif /* _SBICALL_H */ +#endif /* _SBI_H */ diff --git a/sys/include/spinlock.h b/sys/include/spinlock.h index 3400445..ef81499 100644 --- a/sys/include/spinlock.h +++ b/sys/include/spinlock.h @@ -3,9 +3,13 @@ struct spinlock { int locked; - const char *name; + int tp; }; -void initlock(struct spinlock *, const char *); +void initlock(struct spinlock *); + +void acquire(struct spinlock *); + +void release(struct spinlock *); #endif /* _LOCK_H */ diff --git a/sys/kern/entry.S b/sys/kern/entry.S index 03ff76c..9bf72ea 100644 --- a/sys/kern/entry.S +++ b/sys/kern/entry.S @@ -1,8 +1,14 @@ .section ".text.init" +// entrypoint for boot hart(s). a0: hartid, a1: *fdt .globl _start -_start: - /* disable interrupts and poging */ + + +// entrypoint for other harts. a0: hartid, a1: unused for now +.global _mpentry + +_start: + /* disable interrupts and paging */ csrw satp, zero csrw sie, zero csrw sip, zero @@ -12,7 +18,9 @@ _start: la gp, __global_pointer$ .option pop - /* setup stack */ + /* setup stack. + * stack grows toward lower address so sp will mark end of frame. + */ addi t0, a0, 1 li t1, PAGE_SIZE la sp, __stack_start @@ -22,11 +30,11 @@ _start: /* setup thread pointer */ mv tp, a0 - /* the label _boot_hart is shared between threads. only one hart will branch before it is no longer 0 */ + /* the label _boot_hart is shared between threads. after the first atomic swap, all other harts will branch to mpentry */ li a2, 1 lla a3, _boot_hart amoswap.w a3, a2, (a3) - bnez a3, 2f + bnez a3, _mpentry /* clear the bss section */ la a2, __bss_start @@ -39,9 +47,16 @@ _start: call init j _spin +_mpentry: + /* satp = 0, sstatus.sie = 0, a0 = hartid, a1 = opaque */ + + call mpinit + /* shouldn't reach this point */ + j _spin + _spin: wfi - j _spin + j _spin .section ".data" _boot_hart: @@ -51,3 +66,4 @@ _boot_hart: /* linker imports */ .globl HEAP_START HEAP_START: .dword __heap_start + diff --git a/sys/kern/init.c b/sys/kern/init.c index 208df6d..a58d3bc 100644 --- a/sys/kern/init.c +++ b/sys/kern/init.c @@ -1,12 +1,17 @@ #include #include #include -#include #include +#include +#include extern uint64_t HEAP_START; -void +#define HLT()\ + for (;;)\ + asm("wfi") + +void init(unsigned long hartid, struct fdt_header *fdt) { @@ -22,14 +27,25 @@ init(unsigned long hartid, struct fdt_header *fdt) kalloc_init(); printf("done!\n"); // printf("printing free pages:\n"); - //walkfree(); + ///walkfree(); + printf("bringing up other harts...\n"); + // todo: detect harts from device tree can also be used for more conservative stack allocation + for (int i = 0; i < NPROC; ++i) { + if (i == hartid) { + printf("skipping hart #%d\n", i); + continue; + } + printf("starting hart #%d\n", i); + struct sbiret r = _start_hart(i, (unsigned long)LOAD_ADDR); + if (r.err != SBI_SUCCESS) + printf("ERROR"); + } } -/* non boot harts enter here */ -void -mpinit(unsigned long hartid, struct fdt_header *fdt) +void +mpinit(unsigned long hartid) { - unsigned char *uart = (unsigned char*)0x10000000; - *uart = hartid + '0'; - *(uart + 1) = '\n'; + printf("mpinit: %d", hartid); + HLT(); } + diff --git a/sys/kern/printf.c b/sys/kern/printf.c index dfd0657..89add9e 100644 --- a/sys/kern/printf.c +++ b/sys/kern/printf.c @@ -1,10 +1,14 @@ #include #include +#include #include #include static char digits[] = "0123456789abcdef"; +struct spinlock mutex; +int locked = 0; + int puts(const char *str) { @@ -52,9 +56,13 @@ void printf(const char *fmt, ...) { va_list ap; - int i, c; + int i, c, _locked; char *s; + _locked = locked; + if (_locked) + acquire(&mutex); + va_start(ap, fmt); for (i = 0; (c = fmt[i] & 0xff) != 0; i++) { @@ -82,4 +90,12 @@ printf(const char *fmt, ...) break; } } + if (_locked) + release(&mutex); +} + +void printf_init(void) +{ + initlock(&mutex); + locked = 1; } diff --git a/sys/kern/spinlock.c b/sys/kern/spinlock.c index a35b8ce..ade270f 100644 --- a/sys/kern/spinlock.c +++ b/sys/kern/spinlock.c @@ -1,15 +1,38 @@ +#include #include void -init_locklock(struct spinlock *l, const char *_name) +initlock(struct spinlock *l) { - l->name = _name; l->locked = 0; - l->cpu = 0; } void -acquire_lock(struct spinlock *l) +acquire(struct spinlock *l) { - asm volatile("csrr sie, zero"); + sie_disable(); + + if (l->locked) + return; + + while (__sync_lock_test_and_set(&l->locked, 1)) + ; + + __sync_synchronize(); +} + +void +release(struct spinlock *l) +{ + sie_disable(); // avoid deadlock + + if (l->locked) + return; // interrupts are still disabled, what to do here? + + /* fence */ + __sync_synchronize(); + + __sync_lock_release(&l->locked); + + sie_enable(); } -- cgit v1.2.3