os-workshop

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit f6fa58cce08278734144b46f83c95cab99ee4f42
parent 059eaa4cce639f1a77e5412c6c24040422ae7c9a
Author: Brian Swetland <swetland@frotz.net>
Date:   Sun, 24 Apr 2022 12:25:09 -0700

bios: tiny bios to handle startup in machine mode

- install a trap handler to dump state on exceptions
- switch to supervisor mode before starting the app/kernel
- bios at 0x80000000 (start of ram, up to 32k)
- app/kernel at 0x80004000 (just above the bios)
- adjust link scripts, qemu arguments, etc
- todo: delegate user mode faults to supervisor mode

Diffstat:
MMakefile | 3++-
Abios/bios.c | 104+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abios/entry.S | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Chw/simple.ld -> hw/bios.ld | 0
Mhw/simple.ld | 2+-
5 files changed, 175 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile @@ -10,8 +10,9 @@ V := @ # defaults for Ubuntu, can override with local.mk XTOOLCHAIN ?= /usr/bin/riscv64-unknown-elf- QEMU ?= /usr/bin/qemu-system-riscv32 +QEMUBIOS := out/bios.elf -QFLAGS := -machine virt -bios none -nographic +QFLAGS := -machine virt -bios $(QEMUBIOS) -nographic QFLAGS.GDB := $(QFLAGS) -gdb tcp::7777 -S ifeq ($(wildcard $(XTOOLCHAIN)gcc),) diff --git a/bios/bios.c b/bios/bios.c @@ -0,0 +1,104 @@ +// Copyright 2022, Brian Swetland <swetland@frotz.net> +// Licensed under the Apache License, Version 2.0 + +#include <hw/riscv.h> +#include <hw/debug.h> + +#define SVC_ENTRY 0x80004000 + +extern void mach_exception_entry(void); + +const char* cause(uint32_t n) { + if (n & 0x80000000U) { + return "Interrupt"; + } else { + switch(n & 0x7FFFFFFFU) { + case 0: return "Instruction Address Misaligned"; + case 1: return "Instruction Address Fault"; + case 2: return "Illegal Instruction"; + case 3: return "Breakpoint"; + case 4: return "Load Address Misaligned"; + case 5: return "Load Address Fault"; + case 6: return "Store Address Misaligned"; + case 7: return "Store Address Fault"; + case 8: return "User Mode ECALL"; + case 9: return "Supervisor Mode ECALL"; + case 10: return "Machine Mode ECALL"; + case 12: return "Instruction Page Fault"; + case 13: return "Load Page Fault"; + case 14: return "Store Page Fault"; + } + } + return "Unknown"; +} + +const char* mode(uint32_t n) { + switch (n) { + case 0: return "User"; + case 1: return "Supervisor"; + case 3: return "Machine Mode"; + default: return "???"; + } +} + +void mach_exception_handler(uint32_t regs[32]) { + uint32_t n = csr_read(CSR_MCAUSE); + xprintf("\n** MACHINE EXCEPTION %08x %08x\n", n, csr_read(CSR_MTVAL)); + xprintf("** %s\n", cause(n)); + n = csr_read(CSR_MSTATUS); + xprintf("** in %s mode\n\n", mode((n >> MSTATUS_MPP_SHIFT) & 3)); + + xprintf("pc %08x ra %08x sp %08x gp %08x\n", + regs[0], regs[1], regs[2], regs[3]); + xprintf("tp %08x t0 %08x t1 %08x t2 %08x\n", + regs[4], regs[5], regs[6], regs[7]); + xprintf("fp %08x s1 %08x a0 %08x a1 %08x\n", + regs[8], regs[9], regs[10], regs[11]); + xprintf("a2 %08x a3 %08x a4 %08x a5 %08x\n", + regs[12], regs[13], regs[14], regs[15]); + xprintf("\n** HALT\n"); + for (;;) ; +} + +void enter_mode_u(uint32_t a0, uint32_t a1, uint32_t pc, uint32_t sp); +void enter_mode_s(uint32_t a0, uint32_t a1, uint32_t pc, uint32_t sp); + +#if 0 +void user_start(uint32_t user_pc, uint32_t user_sp) { + xprintf("Hello, User Mode %08x %08x\n", user_pc, user_sp); + + // illegal write from user mode + // csr_write(CSR_MEPC, 0x42); + + // syscall + asm volatile ("ecall"); + + for (;;) ; +} +#endif + +#define INT_LIST (INTb_SVC_SW|INTb_SVC_TIMER|INTb_SVC_EXTERN) +#define EXC_LIST (EXCb_ECALL_UMODE) + +void start(uint32_t hartid, uint32_t fdt) { + xprintf("** Frobozz Magic BIOS v0.1 **\n"); + + // delegate interrupts and exceptions + //xprintf("MIDELEG %08x MEDELEG %08x\n", + // csr_read(CSR_MIDELEG), csr_read(CSR_MEDELEG)); + csr_set(CSR_MIDELEG, INT_LIST); + csr_set(CSR_MEDELEG, EXC_LIST); + //xprintf("MIDELEG %08x MEDELEG %08x\n\n", + // csr_read(CSR_MIDELEG), csr_read(CSR_MEDELEG)); + + // set previous status to S_MODE, previous interrupt status ENABLED + csr_write(CSR_MSTATUS, (PRIV_S << MSTATUS_MPP_SHIFT) | MSTATUS_MPIE); + //xprintf("MSTATUS %08x\n", csr_read(CSR_MSTATUS)); + + // set mach exception vector and stack pointer + csr_write(CSR_MTVEC, (uintptr_t) mach_exception_entry); + csr_write(CSR_MSCRATCH, SVC_ENTRY); + + enter_mode_s(hartid, fdt, SVC_ENTRY, 0); +} + diff --git a/bios/entry.S b/bios/entry.S @@ -0,0 +1,68 @@ +// Copyright 2022, Brian Swetland <swetland@frotz.net> +// Licensed under the Apache License, Version 2.0 + +#include <hw/riscv.h> + +.globl mach_exception_entry +mach_exception_entry: + // swap active sp with value in MSCRATCH (exception stack) + // interupts have been disabled on exception entry + csrrw sp, CSR_MSCRATCH, sp + + // save previous registers to stack + addi sp, sp, - 32 * 4 + sw x1, 0x04(sp) + sw x3, 0x0C(sp) + sw x4, 0x10(sp) + sw x5, 0x14(sp) + sw x6, 0x18(sp) + sw x7, 0x1C(sp) + sw x8, 0x20(sp) + sw x9, 0x24(sp) + sw x10, 0x28(sp) + sw x11, 0x2C(sp) + sw x12, 0x30(sp) + sw x13, 0x34(sp) + sw x14, 0x38(sp) + sw x15, 0x3C(sp) + sw x16, 0x40(sp) + sw x17, 0x44(sp) + sw x18, 0x48(sp) + sw x19, 0x4C(sp) + sw x20, 0x50(sp) + sw x21, 0x54(sp) + sw x22, 0x58(sp) + sw x23, 0x5C(sp) + sw x24, 0x60(sp) + sw x25, 0x64(sp) + sw x26, 0x68(sp) + sw x27, 0x6C(sp) + sw x28, 0x70(sp) + sw x29, 0x74(sp) + sw x30, 0x78(sp) + sw x31, 0x7C(sp) + mv a0, sp + + // save previous pc (hw stashed it in MEPC) + csrr t0, CSR_MEPC + sw t0, 0x00(sp) + + // save previous sp (we stashed it in MSCRATCH) + csrr t0, CSR_MSCRATCH + sw t0, 0x08(sp) + + j mach_exception_handler + j . + +.globl enter_mode_u +enter_mode_u: // (a0, a1, user_pc, user_sp) + csrw CSR_SEPC, a2 + mv sp, a3 + sret + +.globl enter_mode_s +enter_mode_s: // (a0, a1, svc_pc, svc_sp) + csrw CSR_MEPC, a2 + mv sp, a3 + mret + diff --git a/hw/simple.ld b/hw/bios.ld diff --git a/hw/simple.ld b/hw/simple.ld @@ -3,7 +3,7 @@ ENTRY(_start) SECTIONS { - . = 0x80000000; + . = 0x80004000; .start : { *(.start) } .text : { *(.text*) } .rodata : { *(.rodata*) }