commit 7c287998a02dd6c4033142c34776fdaa04a0fb3d
parent 377b132bd6f86892da7f077ce8eb1ba1ce95d200
Author: Brian Swetland <swetland@frotz.net>
Date: Mon, 25 Apr 2022 01:07:47 -0700
bios: more features
- setup periodic timer (m mode)
- kick the svc sw interrupt when the timer interval rolls
- use vectored interrupts to split timer irqs from the fault handler
- use space above the machine stack for timer irq state and storage
- add bios.mk project file
Diffstat:
4 files changed, 115 insertions(+), 30 deletions(-)
diff --git a/bios/bios.c b/bios/bios.c
@@ -2,11 +2,14 @@
// Licensed under the Apache License, Version 2.0
#include <hw/riscv.h>
+#include <hw/riscv-clint.h>
#include <hw/debug.h>
+#include "bios.h"
#define SVC_ENTRY 0x80004000
-extern void mach_exception_entry(void);
+void mach_exception_entry(void);
+void enter_mode_s(uint32_t a0, uint32_t a1, uint32_t pc, uint32_t sp);
const char* cause(uint32_t n) {
if (n & 0x80000000U) {
@@ -43,10 +46,9 @@ const char* mode(uint32_t n) {
void mach_exception_handler(uint32_t regs[32]) {
uint32_t n = csr_read(CSR_MCAUSE);
+ uint32_t m = csr_read(CSR_MSTATUS);
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("** %s (in %s mode)\n\n", cause(n), mode((m >> MSTATUS_MPP_SHIFT) & 3));
xprintf("pc %08x ra %08x sp %08x gp %08x\n",
regs[0], regs[1], regs[2], regs[3]);
@@ -60,26 +62,13 @@ void mach_exception_handler(uint32_t regs[32]) {
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)
+#define CLINT_BASE 0x2000000
+#define TIME_TICK 10000000
+//#define TIME_TICK 0x10000000
+
void start(uint32_t hartid, uint32_t fdt) {
xprintf("** Frobozz Magic BIOS v0.1 **\n");
@@ -96,9 +85,32 @@ void start(uint32_t hartid, uint32_t fdt) {
//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);
+ csr_write(CSR_MTVEC, ((uintptr_t) mach_exception_entry) | 1);
+
+ // leaving room for the timer interrupt workspace above the stack
+ csr_write(CSR_MSCRATCH, SVC_ENTRY - IWS_SIZE);
+
+ xprintf("HARTID %08x\n", hartid);
+
+ uint32_t* iws = (void*) (SVC_ENTRY - IWS_SIZE);
+ uint32_t mtimecmp = CLINT_BASE + CLINT_MTIMECMP(hartid);
+ uint32_t mtime = CLINT_BASE + CLINT_MTIME;
+
+ iws[IWS_TIMECMP/4] = mtimecmp;
+ iws[IWS_TICKINC/4] = TIME_TICK;
+
+ // set initial tick
+ uint64_t next = *((uint64_t*) mtime) + TIME_TICK;
+ *((uint64_t*) mtimecmp) = next;
+
+ csr_set(CSR_MIE, INTb_MACH_TIMER);
+ xprintf("MIE %08x\n", csr_read(CSR_MIE));
+
+ // U/S allow access to all memory
+ csr_write(CSR_PMPCFG(0), PMP_CFG_A_TOR | PMP_CFG_X | PMP_CFG_W | PMP_CFG_R);
+ csr_write(CSR_PMPADDR(0), 0xFFFFFFFF);
+ //for (;;) ;
enter_mode_s(hartid, fdt, SVC_ENTRY, 0);
}
diff --git a/bios/bios.h b/bios/bios.h
@@ -0,0 +1,12 @@
+
+// offsets into the interrupt workspace
+
+#define IWS_TIMECMP 0x00
+#define IWS_TICKINC 0x04
+#define IWS_SAVE0 0x08
+#define IWS_SAVE1 0x0C
+#define IWS_SAVE2 0x10
+#define IWS_SAVE3 0x14
+#define IWS_SAVE4 0x18
+#define IWS_SIZE 0x40
+
diff --git a/bios/entry.S b/bios/entry.S
@@ -2,15 +2,76 @@
// Licensed under the Apache License, Version 2.0
#include <hw/riscv.h>
+#include "bios.h"
.globl mach_exception_entry
mach_exception_entry:
+ j mach_exception
+ j .
+ j .
+ j .
+ j .
+ j .
+ j .
+mach_timer_entry:
+ // swap active sp with value in MSCRATCH (exception stack)
+ // interupts have been disabled on exception entry
+ csrrw sp, CSR_MSCRATCH, sp
+
+ // use the workspace above the exception stack to save
+ // registers and get necessary data
+ sw t0, IWS_SAVE0(sp)
+ sw t1, IWS_SAVE1(sp)
+ sw t2, IWS_SAVE2(sp)
+ sw t3, IWS_SAVE3(sp)
+ sw t4, IWS_SAVE4(sp)
+
+ lw t0, IWS_TIMECMP(sp)
+ lw t1, IWS_TICKINC(sp)
+
+ // read last match lo/hi
+ lw t2, 0(t0)
+ lw t3, 4(t0)
+
+ add t1, t2, t1
+ // t4 is carry bit
+ sltu t4, t1, t2
+ add t3, t4, t3
+
+ // avoid spurious irq by ensuring we can't roll back
+ li t4, -1
+ sw t4, 0(t0)
+
+ sw t3, 4(t0)
+ sw t1, 0(t0)
+
+ // set S MODE SW INT pending
+ csrsi CSR_SIP, INTb_SVC_SW
+
+#if 0
+ li t0, 0x10000000
+ li t1, '!'
+ sb t1, 0(t0)
+#endif
+
+ // restore registers
+ lw t0, IWS_SAVE0(sp)
+ lw t1, IWS_SAVE1(sp)
+ lw t2, IWS_SAVE2(sp)
+ lw t3, IWS_SAVE3(sp)
+ lw t4, IWS_SAVE4(sp)
+
+ // swap back to previous sp
+ csrrw sp, CSR_MSCRATCH, sp
+ mret
+
+mach_exception:
// 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
+ addi sp, sp, - (32 * 4)
sw x1, 0x04(sp)
sw x3, 0x0C(sp)
sw x4, 0x10(sp)
@@ -54,12 +115,6 @@ mach_exception_entry:
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
diff --git a/project/bios.mk b/project/bios.mk
@@ -0,0 +1,6 @@
+
+APP_NAME := bios
+APP_SRC := hw/src/start.S bios/entry.S bios/bios.c
+APP_SRC += hw/src/debug.c $(LIBC_SRC)
+APP_LDSCRIPT := hw/bios.ld
+include make/app.mk