commit 61e8950b2e59fa247ccdaf0df1d0aaeff49ed7f2 Author: sam Date: Sat Apr 26 18:24:51 2025 +1200 first commit diff --git a/.cache/clangd/index/atomic_helpers.h.32E35DD60967E074.idx b/.cache/clangd/index/atomic_helpers.h.32E35DD60967E074.idx new file mode 100644 index 0000000..c3559f3 Binary files /dev/null and b/.cache/clangd/index/atomic_helpers.h.32E35DD60967E074.idx differ diff --git a/.cache/clangd/index/atomic_helpers.h.5A95DDE70BB8C83F.idx b/.cache/clangd/index/atomic_helpers.h.5A95DDE70BB8C83F.idx new file mode 100644 index 0000000..bbd4f85 Binary files /dev/null and b/.cache/clangd/index/atomic_helpers.h.5A95DDE70BB8C83F.idx differ diff --git a/.cache/clangd/index/kernel.c.888550018A9D5949.idx b/.cache/clangd/index/kernel.c.888550018A9D5949.idx new file mode 100644 index 0000000..5dc4088 Binary files /dev/null and b/.cache/clangd/index/kernel.c.888550018A9D5949.idx differ diff --git a/.cache/clangd/index/kernel.c.D9A3E99583D1279A.idx b/.cache/clangd/index/kernel.c.D9A3E99583D1279A.idx new file mode 100644 index 0000000..c750935 Binary files /dev/null and b/.cache/clangd/index/kernel.c.D9A3E99583D1279A.idx differ diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..c17e64a --- /dev/null +++ b/.clang-format @@ -0,0 +1,25 @@ +BasedOnStyle: WebKit +IndentWidth: 4 +TabWidth: 4 +UseTab: Never +AlignConsecutiveDeclarations: false +AlignConsecutiveAssignments: false +AlignTrailingComments: true +ColumnLimit: 105 +BreakBeforeBraces: Attach +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AllowShortFunctionsOnASingleLine: false +AllowShortLambdasOnASingleLine: false +PointerAlignment: Left +SpaceBeforeParens: Never +SpacesInParentheses: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: false +SpaceAfterCStyleCast: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeSquareBrackets: false +SpacesBeforeTrailingComments: 2 +PenaltyBreakAssignment: 1000 +NamespaceIndentation: All + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a78cba5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +compile_commands.json +kernel.elf +*.o diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..94a06e1 --- /dev/null +++ b/Makefile @@ -0,0 +1,34 @@ +TOOLCHAIN = riscv64-linux-gnu- +QEMU=qemu-system-riscv64 +KERNEL = kernel.elf + +CFLAGS=-march=rv64i_zicsr_d -mabi=lp64d -Wall -Wextra -Werror -O2 -g -Iinclude +LDFLAGS=-T linker.ld --no-dynamic-linker -m elf64lriscv -static -nostdlib +QEMUFLAGS=-nographic -serial mon:stdio --no-reboot + +CFILES = $(shell find -L -type f -name "*.c") +SFILES = $(shell find -L -type f -iname "*.s") +OBJ := $(addsuffix .o,$(CFILES)) $(addsuffix .o,$(SFILES)) + +$(KERNEL): $(OBJ) linker.ld + ${TOOLCHAIN}ld $(LDFLAGS) -o $(KERNEL) $(OBJ) + +%.c.o: %.c + $(TOOLCHAIN)gcc $(CFLAGS) -o $@ -c $< + +%.s.o: %.s + $(TOOLCHAIN)gcc $(CFLAGS) -o $@ -c $< + +%.S.o: %.S + $(TOOLCHAIN)gcc $(CFLAGS) -o $@ -c $< + +run: $(KERNEL) + qemu-system-riscv64 $(QEMUFLAGS) -kernel $(KERNEL) + +run-debug: $(KERNEL) + $(QEMU) -monitor none -s -S -kernel $(KERNEL) & + $(TOOLCHAIN)gdb $(KERNEL) -q -ex "target remote :1234" -ex "b *_start" -ex "c" -tui + killall $(QEMU) + +clean: + @rm $(OBJ) $(KERNEL) diff --git a/include/atomic_helpers.h b/include/atomic_helpers.h new file mode 100644 index 0000000..8d1bf7d --- /dev/null +++ b/include/atomic_helpers.h @@ -0,0 +1,17 @@ +#ifndef ATOMIC_HELPERS_H +#define ATOMIC_HELPERS_H + +#define csrr(reg) \ + ({ \ + uintptr_t temp; \ + __asm__ volatile("csrr %0, " #reg : "=r"(temp)); \ + temp; \ + }) + +#define csrw(reg, val) \ + ({ \ + uintptr_t temp = (uintptr_t)val; \ + __asm__ volatile("csrw " #reg ", %0" ::"r"(temp)); \ + }) + +#endif diff --git a/linker.ld b/linker.ld new file mode 100644 index 0000000..4a02be3 --- /dev/null +++ b/linker.ld @@ -0,0 +1,9 @@ +MEMORY { + rom (rwx) : ORIGIN = 0x80200000, LENGTH = 512K +} + +SECTIONS { + .init : { + *(.init) + } > rom +} diff --git a/src/entry.s b/src/entry.s new file mode 100644 index 0000000..d92bdcc --- /dev/null +++ b/src/entry.s @@ -0,0 +1,17 @@ +.global _start +.global sret_wrapper +.extern main + +.section .bss +stack: .space 4096 +stack_top: + +.section .init +_start: + la sp, stack_top + mv s0, sp + call main + sret +.loop: + wfi + j .loop diff --git a/src/kernel.c b/src/kernel.c new file mode 100644 index 0000000..da45d9a --- /dev/null +++ b/src/kernel.c @@ -0,0 +1,147 @@ +#include +#include +#include +#include "atomic_helpers.h" + +#define DEBUG_ECALL 0x4442434E + +typedef struct { + long error; + long value; +} sbiret; + +void trap_handler(); +void trap_handler_wrapper() __attribute__((naked)); + +void user_entry(); + +unsigned long strlen(const char* str) { + unsigned long len = 0; + while(str[len] != '\0') { + len++; + } + + return len; +} + +int main() { + csrw(stvec, trap_handler_wrapper); + csrw(sepc, user_entry); + + unsigned long sstatus = csrr(sstatus); + sstatus |= (1 << 5); + csrw(sstatus, sstatus); + + // _start in entry.s will do the sret +} + +void user_entry(void) { + while(1) { + __asm__ volatile("ecall"); + __asm__ volatile("unimp"); + } +} + +__attribute__((always_inline)) +inline sbiret sbi_ecall6(unsigned long number, unsigned long arg0, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) { + sbiret ret; + + __asm__ volatile("mv a7, %[number]\n" + "li a6, 0\n" + "mv a0, %[arg0]\n" + "mv a1, %[arg1]\n" + "mv a2, %[arg2]\n" + "mv a3, %[arg3]\n" + "mv a4, %[arg4]\n" + "mv a5, %[arg5]\n" + "ecall\n" + "mv %[err], a0\n" + "mv %[val], a1\n" + : [err] "=r"(ret.error), [val] "=r"(ret.value) + : [number] "r"(number), [arg0] "r"(arg0), [arg1] "r"(arg1), +[arg2] "r"(arg2),[arg3] "r"(arg3), [arg4] "r"(arg4),[arg5] "r"(arg5) + : "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7"); + + return ret; +} + +__attribute__((always_inline)) +inline sbiret sbi_ecall5(unsigned long number, unsigned long arg0, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4) { + return sbi_ecall6(number, arg0, arg1, arg2, arg3, arg4, 0); +} + +__attribute__((always_inline)) +inline sbiret sbi_ecall4(unsigned long number, unsigned long arg0, unsigned long arg1, unsigned long arg2, unsigned long arg3) { + return sbi_ecall5(number, arg0, arg1, arg2, arg3, 0); +} + +__attribute__((always_inline)) +inline sbiret sbi_ecall3(unsigned long number, unsigned long arg0, unsigned long arg1, unsigned long arg2) { + return sbi_ecall4(number, arg0, arg1, arg2, 0); +} + +__attribute__((always_inline)) +inline sbiret sbi_ecall2(unsigned long number, unsigned long arg0, unsigned long arg1) { + return sbi_ecall3(number, arg0, arg1, 0); +} + +__attribute__((always_inline)) +inline sbiret sbi_ecall1(unsigned long number, unsigned long arg0) { + return sbi_ecall2(number, arg0, 0); +} + +__attribute__((always_inline)) +inline sbiret sbi_ecall0(unsigned long number) { + return sbi_ecall1(number, 0); +} + +sbiret console_debug_write(const char* str, unsigned long len) { + return sbi_ecall2(DEBUG_ECALL, len, (unsigned long)str); +} + +int puts(const char* str) { + sbiret ret; + if((ret = console_debug_write(str, strlen(str))).error != 0) { + return -1; + } + + if((ret = console_debug_write("\n", 1)).error != 0) { + return -1; + } + return 0; +} + +void trap_handler_wrapper() { + __asm__ volatile("call trap_handler\n" + "sret"); +} + +void trap_handler(void) { + unsigned long sepc = csrr(sepc); + unsigned long scause = csrr(scause); + unsigned long sstatus = csrr(sstatus); + + if(scause == 8) { + puts("hello world"); + + sepc += 4; + csrw(sepc, sepc); + goto exit; + } + + if(((sstatus >> 8) & 1) == 0) { + sepc += 4; + puts("exception occured in usermode, skipping past"); + csrw(sepc, sepc); + goto exit; + } else { + puts("exception occured in supervisor mode, panic"); + + while(1) { + __asm__ volatile("wfi"); + } + } + +exit: + return; +}