summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorstefan <stefan@s00.xyz>2023-04-15 05:02:02 +0000
committerstefan <stefan@s00.xyz>2023-04-15 05:02:02 +0000
commitaf1ce4b2e637ceb418ea72d51c49a3eee276a938 (patch)
tree4d6a33644f8489e4f582f6e320bd6581b94fb642
parent8cceb31dcaf4641d43f324fa3301b37859ebfade (diff)
downloadsv-af1ce4b2e637ceb418ea72d51c49a3eee276a938.tar.gz
added multiprocessor support
-rw-r--r--Makefile4
-rw-r--r--sys/Makefile3
-rw-r--r--sys/dev/sbi.c39
-rw-r--r--sys/include/printf.h1
-rw-r--r--sys/include/sbi.h74
-rw-r--r--sys/include/spinlock.h8
-rw-r--r--sys/kern/entry.S28
-rw-r--r--sys/kern/init.c34
-rw-r--r--sys/kern/printf.c18
-rw-r--r--sys/kern/spinlock.c33
10 files changed, 172 insertions, 70 deletions
diff --git a/Makefile b/Makefile
index 4406ac9..68e0301 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,11 @@
TARGET?=virt
+BUILD?=debug
CROSS_COMPILE?=riscv64-unknown-elf-
GDB_PORT?=1234
CFLAGS=-nostdlib -ffreestanding -mcmodel=medany -I${.CURDIR}/include
+.if ${BUILD}==debug
+CFLAGS+=-ggdb
+.endif
.export
sys: ${SRC} lib/build/libc.a
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 <sbi.h>
-
-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 <fdt.h>
#include <mm/kalloc.h>
#include <printf.h>
-#include <stdint.h>
#include <spinlock.h>
+#include <sbi.h>
+#include <stdint.h>
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 <printf.h>
#include <stdint.h>
+#include <spinlock.h>
#include <sbi.h>
#include <stdarg.h>
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 <asm.h>
#include <spinlock.h>
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();
}