diff --git a/.clang-format b/.clang-format index 5ff1461..41e7b1a 100644 --- a/.clang-format +++ b/.clang-format @@ -6,10 +6,3 @@ ColumnLimit: 80 # Wrap lines after 80 characters AllowShortLoopsOnASingleLine: true AlwaysBreakTemplateDeclarations: true BreakConstructorInitializers: BeforeComma -AlignConsecutiveDeclarations: - Enabled: true - AcrossEmptyLines: false - AcrossComments: false - AlignCompound: false - AlignFunctionPointers: false - PadOperators: false diff --git a/.clangd b/.clangd deleted file mode 100644 index a2642ad..0000000 --- a/.clangd +++ /dev/null @@ -1,18 +0,0 @@ -CompileFlags: - Add: - - --target=riscv64-unknown-elf - - -mcmodel=medany - - -march=rv64gc - - -mabi=lp64 - - -ffreestanding - - -fno-common - - -nostdlib - - -mno-relax - - -I. - - -Ilib - - -fno-stack-protector - - -fno-pie - - -no-pie - - -ggdb - - -gdwarf-2 - - -fno-omit-frame-pointer diff --git a/Makefile b/Makefile index 8d0e4a2..2a2aade 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ OBJDUMP = $(TOOLPREFIX)-objdump ASFLAGS = -march=rv64gc -mabi=lp64 -LDFLAGS = -Tkernel.ld +LDFLAGS = -Tlink.ld LDFLAGS += -m elf64lriscv CFLAGS = -Wall -Werror -O @@ -17,7 +17,6 @@ CFLAGS += -march=rv64gc -mabi=lp64 CFLAGS += -ffreestanding -fno-common -nostdlib -mno-relax CFLAGS += -I. -CFLAGS += -Ilib CFLAGS += -fno-stack-protector # Prevents code that needs libc / runtime support CFLAGS += -MD # Generate header dependency files (.d) @@ -27,7 +26,7 @@ CFLAGS += -fno-omit-frame-pointer # More reliable backtraces in GDB all: kernel.elf -kernel.elf: entry.o start.o lib/string.o lib/proc.o lib/spinlock.o lib/proc.o +kernel.elf: entry.o start.o @echo LD $@ @$(LD) $(LDFLAGS) -o $@ $^ @@ -40,10 +39,10 @@ kernel.elf: entry.o start.o lib/string.o lib/proc.o lib/spinlock.o lib/proc.o @$(AS) $(ASFLAGS) -o $@ $< qemu: kernel.elf - @echo QEMU $< - @qemu-system-riscv64 -machine virt -bios none -nographic -m 128M -smp 4 -kernel kernel.elf + @echo QEMU $@ + @qemu-system-riscv64 -machine virt -bios none -nographic -kernel kernel.elf clean: - rm -f *.o *.elf *.d lib/*.o lib/*.d + rm -f *.o *.elf *.d -include *.d diff --git a/config.h b/config.h deleted file mode 100644 index 5c778ee..0000000 --- a/config.h +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Number of CPU's For now, this is hard-coded here. It will likely be - * dynamically discovered in the future. - */ -#define NCPU 3 - -/* Maximum number of files open */ -#define NOFILE 10 diff --git a/entry.S b/entry.S index b77ef37..6d7ff99 100644 --- a/entry.S +++ b/entry.S @@ -6,6 +6,20 @@ _entry: call _clear continue: + li t0, 0x10000000 # UART base address + li t1, 'E' # Character to print + sb t1, 0(t0) + li t1, 'n' + sb t1, 0(t0) + li t1, 't' + sb t1, 0(t0) + li t1, 'r' + sb t1, 0(t0) + li t1, 'y' + sb t1, 0(t0) + li t1, '\n' + sb t1, 0(t0) + # Set up a stack for C. la sp, stack0 li a0, 1024*4 # a0 = 4096 diff --git a/lib/proc.c b/lib/proc.c deleted file mode 100644 index aa28a41..0000000 --- a/lib/proc.c +++ /dev/null @@ -1,19 +0,0 @@ -#include - -struct Cpu cpus[NCPU]; - -// Must be called with interrupts disabled, -// to prevent race with process being moved -// to a different CPU. -int cpuid() { - int id = r_tp(); - return id; -} - -// Return this CPU's cpu struct. -// Interrupts must be disabled. -struct Cpu *mycpu(void) { - int id = cpuid(); - struct Cpu *c = &cpus[id]; - return c; -} diff --git a/lib/proc.h b/lib/proc.h deleted file mode 100644 index 67749a2..0000000 --- a/lib/proc.h +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include -#include -#include - -int cpuid(void); -struct Cpu *mycpu(void); - -/** Saved registers for kernel context switches. */ -struct Context {}; - -/** Per-CPU state. */ -struct Cpu { - struct Proc *proc; // The process running on this cpu, or null. - struct Context context; // swtch() here to enter scheduler(). - int noff; // Depth of push_off() nesting. - int intena; // Were interrupts enabled before push_off()? -}; - -extern struct Cpu cpus[NCPU]; - -/** Per-process state */ -struct Proc {}; diff --git a/lib/spinlock.c b/lib/spinlock.c deleted file mode 100644 index 7e7418d..0000000 --- a/lib/spinlock.c +++ /dev/null @@ -1,116 +0,0 @@ -/** - * Mutual exclusion spin locks. - * (Not mutexes as these are spinning locks). - */ - -// #include -#include -#include -#include - -// void panic(char *s) { for (;;); } -void panic(char *s) {} - -/** - * The aquire() and release() functions control ownership of the lock. - * To perform these operations, modern CPU's provide atomic instructions - * that prevent the cores from stepping on each other's toes, otherwise known - * as a deadlock. - * - * GCC provides a set of built-in functions that allow you to use atomic - * instructions in an architecture-independent way. These functions are - * defined in the GCC manual: - * - * See: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html - * See: https://en.wikipedia.org/wiki/Memory_barrier - * - * On RISC-V, sync_lock_test_and_set turns into an atomic swap: - * a5 = 1 - * s1 = &lk->locked - * amoswap.w.aq a5, a5, (s1) - * - * On RISC-V, sync_lock_release turns into an atomic swap: - * s1 = &lk->locked - * amoswap.w zero, zero, (s1) - * - * __sync_synchronize(); - * - * This function tells the C compiler and the processor to not move loads or - * stores past this point, to ensure that the critical section's memory - * references happen strictly after the lock is acquired/locked. - * On RISC-V, this emits a fence instruction. - */ - -/** Initialize spinlock */ -void initlock(struct spinlock *lk, char *name) { - lk->name = name; - lk->locked = 0; - lk->cpu = 0; -} - -/** - * Acquire the lock. - * Loops (spins) until the lock is acquired. - * Panics if the lock is already held by this cpu. - */ -void acquire(struct spinlock *lk) { - push_off(); // disable interrupts to avoid deadlock. - - if (holding(lk)) // If the lock is already held, panic. - panic("acquire"); - - // Spin until aquired. See file header for details - while (__sync_lock_test_and_set(&lk->locked, 1) != 0) { - } - __sync_synchronize(); // No loads/stores after this point - - // Record info about lock acquisition for holding() and debugging. - lk->cpu = mycpu(); -} - -/** - * Release the lock. - * Panics if the lock is not held. - */ -void release(struct spinlock *lk) { - if (!holding(lk)) // If the lock is not held, panic. - panic("release"); - - lk->cpu = 0; // 0 means unheld - __sync_synchronize(); // No loads/stores after this point - __sync_lock_release(&lk->locked); // Essentially lk->locked = 0 - - pop_off(); -} - -// Check whether this cpu is holding the lock. -// Interrupts must be off. -int holding(struct spinlock *lk) { - int r; - r = (lk->locked && lk->cpu == mycpu()); - return r; -} - -// push_off/pop_off are like intr_off()/intr_on() except that they are matched: -// it takes two pop_off()s to undo two push_off()s. Also, if interrupts -// are initially off, then push_off, pop_off leaves them off. - -void push_off(void) { - int old = intr_get(); - - intr_off(); - if (mycpu()->noff == 0) - mycpu()->intena = old; - mycpu()->noff += 1; -} - -void pop_off(void) { - struct Cpu *c = mycpu(); - if (intr_get()) - panic("pop_off - interruptible"); - if (c->noff < 1) - panic("pop_off"); - c->noff -= 1; - if (c->noff == 0 && c->intena) - intr_on(); -} diff --git a/lib/spinlock.h b/lib/spinlock.h deleted file mode 100644 index 48bcb27..0000000 --- a/lib/spinlock.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef KERNEL_SPINLOCK_H -#define KERNEL_SPINLOCK_H - -#include "types.h" - -/** Mutual exclusion spin lock */ -struct spinlock { - u32 locked; // Is the lock held? - - // NOTE: Perhaps feature gate this? - - // For debugging: - char *name; // Name of lock. - struct Cpu *cpu; // The cpu holding the lock. -}; - -/** - * Acquire the lock. - * Loops (spins) until the lock is acquired. - * Panics if the lock is already held by this cpu. - */ -void acquire(struct spinlock *); - -/** - * Check whether this cpu is holding the lock. - * Interrupts must be off. - */ -int holding(struct spinlock *); - -/** - * Initialize spinlock - */ -void initlock(struct spinlock *, char *); - -/** - * Release the lock. - * Panics if the lock is not held. - */ -void release(struct spinlock *); - -/** - * @brief push_off/pop_off are like intr_off()/intr_on() except that they are - * matched: it takes two pop_off()s to undo two push_off()s. Also, if - * interrupts are initially off, then push_off, pop_off leaves them off. - */ -void push_off(void); - -/** @copydoc pop_off */ -void pop_off(void); - -#endif diff --git a/lib/string.c b/lib/string.c deleted file mode 100644 index 7647d1f..0000000 --- a/lib/string.c +++ /dev/null @@ -1,39 +0,0 @@ -char *itoa(int value, char *str, int base) { - char *p = str; - char *p1, *p2; - unsigned int uvalue = value; - int negative = 0; - - if (base < 2 || base > 36) { - *str = '\0'; - return str; - } - - if (value < 0 && base == 10) { - negative = 1; - uvalue = -value; - } - - // Convert to string - do { - int digit = uvalue % base; - *p++ = (digit < 10) ? '0' + digit : 'a' + (digit - 10); - uvalue /= base; - } while (uvalue); - - if (negative) - *p++ = '-'; - - *p = '\0'; - - // Reverse string - p1 = str; - p2 = p - 1; - while (p1 < p2) { - char tmp = *p1; - *p1++ = *p2; - *p2-- = tmp; - } - - return str; -} diff --git a/lib/string.h b/lib/string.h deleted file mode 100644 index ceeb2a8..0000000 --- a/lib/string.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef KERNEL_STRING_H -#define KERNEL_STRING_H - -/** Integer to ascii */ -char *itoa(int value, char *str, int base); - -#endif diff --git a/kernel.ld b/link.ld similarity index 100% rename from kernel.ld rename to link.ld diff --git a/riscv.h b/riscv.h deleted file mode 100644 index b614112..0000000 --- a/riscv.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef RISCV_KERNEL_H -#define RISCV_KERNEL_H - -#include - -// Supervisor Status Register, sstatus - -/** Supervisor Previous Privilege */ -#define SSTATUS_SPP (1L << 8) // Previous mode, 1=Supervisor, 0=User - -/** Supervisor Previous Interrupt Enable */ -#define SSTATUS_SPIE (1L << 5) - -/** User Previous Interrupt Enable */ -#define SSTATUS_UPIE (1L << 4) - -/** Supervisor Interrupt Enable */ -#define SSTATUS_SIE (1L << 1) - -/** User Interrupt Enable */ -#define SSTATUS_UIE (1L << 0) - -/** Page Table Entry Type */ -typedef u64 pte_t; - -/** Page Table Type */ -typedef u64 *pagetable_t; // 512 PTEs - -/** Returns the current hart id */ -static inline u64 r_mhartid() { - u64 x; - asm volatile("csrr %0, mhartid" : "=r"(x)); - return x; -} - -/** Read thread pointer */ -static inline u64 r_tp() { - u64 x; - asm volatile("mv %0, tp" : "=r"(x)); - return x; -} - -/** - * Read the value of the sstatus register. - * (Supervisor Status Register) - */ -static inline u64 r_sstatus() { - u64 x; - asm volatile("csrr %0, sstatus" : "=r"(x)); - return x; -} - -/** - * Write a value to the sstatus register. - * (Supervisor Status Register) - */ -static inline void w_sstatus(u64 x) { - asm volatile("csrw sstatus, %0" : : "r"(x)); -} - -/** Enable device interrupts */ -static inline void intr_on() { w_sstatus(r_sstatus() | SSTATUS_SIE); } - -/** Disable device interrupts */ -static inline void intr_off() { w_sstatus(r_sstatus() & ~SSTATUS_SIE); } - -/** Are device interrupts enabled? */ -static inline int intr_get() { - u64 x = r_sstatus(); - return (x & SSTATUS_SIE) != 0; -} - -#endif diff --git a/start.c b/start.c index 0a9ca9b..46c6bfc 100644 --- a/start.c +++ b/start.c @@ -1,10 +1,11 @@ -#include -#include -#include -#include +/* + * Number of CPU's For now, this is hard-coded here. It will likely be in a + * header, or dynamically discovered in the future + */ +#define NCPU 3 /* QEMU memory maps a UART device here. */ -#define UART_BASE ((volatile char *)0x10000000) +#define UART_BASE ((char *)0x10000000) /** Send a single character to the UART device */ void uart_putc(char c) { *UART_BASE = c; } @@ -22,27 +23,9 @@ void uart_puts(const char *s) { */ char stack0[4096 * NCPU] __attribute__((aligned(16))); -/* Keep this here and sync on it until we have synchronized printf */ -struct spinlock sl = {0}; -volatile int greeted = 0; - /* This is where entry.S drops us of. All cores land here */ void start() { - - u64 a = r_mhartid(); - - acquire(&sl); - - if (!greeted) { - uart_puts("Hello Neptune!\n"); - greeted = 1; - } - - uart_puts("Hart number: "); - uart_putc(a + '0'); - uart_putc('\n'); - - release(&sl); + uart_puts("Hello Neptune!\n"); /* Here we will do a bunch of initialization steps */ diff --git a/types.h b/types.h deleted file mode 100644 index f0780a4..0000000 --- a/types.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -typedef unsigned long u64;