os-workshop

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

commit 8f4ca9f20812474b2a1ddad67296c89b920b1015
parent 2bd8d0d84f351f2935ff5accfd5417de8168f690
Author: Brian Swetland <swetland@frotz.net>
Date:   Thu, 12 May 2022 15:57:49 -0700

shuffle stuff around

- nuke the old traps.c app
- context.h defines standard layouts for saving register state
- boot/entry/S and hw/src/trap-entry-single-stack.S and
  hw/src/context-switch.S conform to these layouts
- update boot, utils, etc to also conform

Diffstat:
Mboot/boot.c | 25+++++--------------------
Mboot/boot.h | 12+-----------
Mboot/entry.S | 176+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Dhw/inc/hw/context-switch.h | 35-----------------------------------
Ahw/inc/hw/context.h | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mhw/inc/hw/debug.h | 3---
Mhw/src/context-switch.S | 7++++++-
Mhw/src/print-exception.c | 43++++++++++++++++++++++++++++++++-----------
Ahw/src/trap-entry-single-stack.S | 134+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dmisc/traps.c | 68--------------------------------------------------------------------
Dproject/traps.app.mk | 6------
11 files changed, 391 insertions(+), 236 deletions(-)

diff --git a/boot/boot.c b/boot/boot.c @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0 #include <hw/riscv.h> +#include <hw/context.h> #include <hw/intrinsics.h> #include <hw/debug.h> @@ -13,26 +14,9 @@ // we expect the supervisor program to be in memory after the end of the bootloader #define SVC_ENTRY (DRAM_BASE + BOOTLOADER_SIZE) -void mach_exception_handler(uint32_t regs[32]) { -#if EMULATE_MISSING_CSR_READS - uint32_t mcause = csr_read(CSR_MCAUSE); - uint32_t mtval = csr_read(CSR_MTVAL); - - // fragile: no mtval on qemu - if (mcause == 2) mtval = *((uint32_t*) regs[0]); - - if ((mcause == 2) && ((mtval & (~0xFFF00F80)) == 0x00002073)) { - uint32_t rd = (mtval >> 7) & 31; - xprintf("BAD CSR READ @%08x (%08x) -> x%u\n", regs[0], mtval, rd); - regs[rd] = 0xDEADBEEF; - regs[0] += 4; - return; - } -#endif - +void mach_exception_handler(eframe_t *ef) { xprintf("\n** MACHINE EXCEPTION **\n"); - xprint_exception(regs); - + xprint_m_exception(ef); xprintf("\nHALT\n"); for (;;) ; } @@ -69,6 +53,7 @@ void start(uint32_t hartid, uint32_t fdt) { xprintf("SVC ENTRY @0x%08x\n\n", SVC_ENTRY); - enter_mode_s(hartid, fdt, SVC_ENTRY, 0); + exit_mode_m(hartid, fdt, SVC_ENTRY, 0); + } diff --git a/boot/boot.h b/boot/boot.h @@ -1,20 +1,10 @@ #pragma once -// 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 - #ifndef __ASSEMBLY__ // entry.S void mach_exception_entry(void); -void enter_mode_s(uint32_t a0, uint32_t a1, uint32_t pc, uint32_t sp); +void exit_mode_m(uint32_t a0, uint32_t a1, uint32_t pc, uint32_t sp); #endif diff --git a/boot/entry.S b/boot/entry.S @@ -2,105 +2,119 @@ // Licensed under the Apache License, Version 2.0 #include <hw/riscv.h> -#include "boot.h" + +// This exception handler is conservative and stores *all* +// the general registers on the stack on exception entry. +// +// This allows the exception handler to easily inspect and +// modify the previous register state. +// +// A more efficient handler could only store the callee-save +// registers (that would otherwise be possibly clobbered by +// the C code it calls into), and trust that the others would +// be saved and restored as needed, further down the call chain. .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 + csrrw sp, mscratch, sp - // save previous registers to stack + // allocate space for eframe_t 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 the tframe_t + sw ra, 0x00(sp) + sw t0, 0x04(sp) + sw t1, 0x08(sp) + sw t2, 0x0C(sp) + sw t3, 0x10(sp) + sw t4, 0x14(sp) + sw t5, 0x18(sp) + sw t6, 0x1C(sp) + sw a0, 0x20(sp) + sw a1, 0x24(sp) + sw a2, 0x28(sp) + sw a3, 0x2C(sp) + sw a4, 0x30(sp) + sw a5, 0x34(sp) + sw a6, 0x38(sp) + sw a7, 0x3C(sp) - // save previous sp (we stashed it in MSCRATCH) - csrr t0, CSR_MSCRATCH - sw t0, 0x08(sp) + // save the cframe_t + csrr t0, mepc + csrr t1, mscratch + sw t0, 0x40(sp) // pc + sw t1, 0x44(sp) // sp + sw gp, 0x48(sp) + sw tp, 0x4C(sp) + sw s0, 0x50(sp) + sw s1, 0x54(sp) + sw s2, 0x58(sp) + sw s3, 0x5C(sp) + sw s4, 0x60(sp) + sw s5, 0x64(sp) + sw s6, 0x68(sp) + sw s7, 0x6C(sp) + sw s8, 0x70(sp) + sw s9, 0x74(sp) + sw s10, 0x78(sp) + sw s11, 0x7C(sp) + // call into C handler + mv a0, sp jal mach_exception_handler - // save machine sp back into SSCRATCH + // restore trap sp to mscratch addi t0, sp, (32 * 4) - csrw CSR_MSCRATCH, t0 + csrw mscratch, t0 - // return pc goes into MEPC for mret - lw t0, 0x00(sp) - csrw CSR_MEPC, t0 + // return pc goes into mepc for mret + lw t1, 0x40(sp) // pc + csrw mepc, t1 - // restore remaining registers - lw x1, 0x04(sp) - lw x3, 0x0C(sp) - lw x4, 0x10(sp) - lw x5, 0x14(sp) - lw x6, 0x18(sp) - lw x7, 0x1C(sp) - lw x8, 0x20(sp) - lw x9, 0x24(sp) - lw x10, 0x28(sp) - lw x11, 0x2C(sp) - lw x12, 0x30(sp) - lw x13, 0x34(sp) - lw x14, 0x38(sp) - lw x15, 0x3C(sp) - lw x16, 0x40(sp) - lw x17, 0x44(sp) - lw x18, 0x48(sp) - lw x19, 0x4C(sp) - lw x20, 0x50(sp) - lw x21, 0x54(sp) - lw x22, 0x58(sp) - lw x23, 0x5C(sp) - lw x24, 0x60(sp) - lw x25, 0x64(sp) - lw x26, 0x68(sp) - lw x27, 0x6C(sp) - lw x28, 0x70(sp) - lw x29, 0x74(sp) - lw x30, 0x78(sp) - lw x31, 0x7C(sp) + // restore registers from cframe_t + lw gp, 0x48(sp) + lw tp, 0x4C(sp) + lw s0, 0x50(sp) + lw s1, 0x54(sp) + lw s2, 0x58(sp) + lw s3, 0x5C(sp) + lw s4, 0x60(sp) + lw s5, 0x64(sp) + lw s6, 0x68(sp) + lw s7, 0x6C(sp) + lw s8, 0x70(sp) + lw s9, 0x74(sp) + lw s10, 0x78(sp) + lw s11, 0x7C(sp) - lw sp, 0x08(sp) + // restore registers from tframe_t + lw ra, 0x00(sp) + lw t0, 0x04(sp) + lw t1, 0x08(sp) + lw t2, 0x0C(sp) + lw t3, 0x10(sp) + lw t4, 0x14(sp) + lw t5, 0x18(sp) + lw t6, 0x1C(sp) + lw a0, 0x20(sp) + lw a1, 0x24(sp) + lw a2, 0x28(sp) + lw a3, 0x2C(sp) + lw a4, 0x30(sp) + lw a5, 0x34(sp) + lw a6, 0x38(sp) + lw a7, 0x3C(sp) + // restore previous sp last + lw sp, 0x44(sp) + + // return from exception mret -.globl enter_mode_s -enter_mode_s: // (a0, a1, svc_pc, svc_sp) - csrw CSR_MEPC, a2 +.globl exit_mode_m // a0, a1, pc, sp +exit_mode_m: + csrw mepc, a2 mv sp, a3 mret - diff --git a/hw/inc/hw/context-switch.h b/hw/inc/hw/context-switch.h @@ -1,35 +0,0 @@ -// Copyright 2022, Brian Swetland <swetland@frotz.net> -// Licensed under the Apache License, Version 2.0 - -#pragma once - -#include <stdint.h> - -// this layout must match the assembly in context-switch.S -typedef struct { - uint32_t pc; - uint32_t sp; - uint32_t gp; - uint32_t tp; - uint32_t s0; - uint32_t s1; - uint32_t s2; - uint32_t s3; - uint32_t s4; - uint32_t s5; - uint32_t s6; - uint32_t s7; - uint32_t s8; - uint32_t s9; - uint32_t s10; - uint32_t s11; -} rv32_ctxt_t; - -// store the current state into prev -// restore the new state from next -void context_switch(rv32_ctxt_t* prev, rv32_ctxt_t* next); - -// bootstrap for a new context -// will call s2(s0, s1) -// and call context_exit() should it return -void context_entry(void); diff --git a/hw/inc/hw/context.h b/hw/inc/hw/context.h @@ -0,0 +1,118 @@ +// Copyright 2022, Brian Swetland <swetland@frotz.net> +// Licensed under the Apache License, Version 2.0 + +#pragma once + +#include <stdint.h> + +// cframe - Context Frame +// contains the 16 callee-save and global registers +typedef struct cframe { + uint32_t pc; + uint32_t sp; + uint32_t gp; + uint32_t tp; + uint32_t s0; + uint32_t s1; + uint32_t s2; + uint32_t s3; + uint32_t s4; + uint32_t s5; + uint32_t s6; + uint32_t s7; + uint32_t s8; + uint32_t s9; + uint32_t s10; + uint32_t s11; +} cframe_t; + +// tframe - Trap Frame +// contains the 16 caller-save and temporary registers +// as well as the pc +typedef struct tframe { + uint32_t ra; + uint32_t t0; + uint32_t t1; + uint32_t t2; + uint32_t t3; + uint32_t t4; + uint32_t t5; + uint32_t t6; + uint32_t a0; + uint32_t a1; + uint32_t a2; + uint32_t a3; + uint32_t a4; + uint32_t a5; + uint32_t a6; + uint32_t a7; + + uint32_t pc; + uint32_t _0; + uint32_t _1; + uint32_t _2; +} tframe_t; + +// eframe - Exception Frame +// contains all general registers +// It stacks a cframe on an iframe +typedef struct eframe { + uint32_t ra; + uint32_t t0; + uint32_t t1; + uint32_t t2; + uint32_t t3; + uint32_t t4; + uint32_t t5; + uint32_t t6; + uint32_t a0; + uint32_t a1; + uint32_t a2; + uint32_t a3; + uint32_t a4; + uint32_t a5; + uint32_t a6; + uint32_t a7; + + uint32_t pc; + uint32_t sp; + uint32_t gp; + uint32_t tp; + uint32_t s0; + uint32_t s1; + uint32_t s2; + uint32_t s3; + uint32_t s4; + uint32_t s5; + uint32_t s6; + uint32_t s7; + uint32_t s8; + uint32_t s9; + uint32_t s10; + uint32_t s11; +} eframe_t; + +// save register state into from and restore it from to +void context_switch(cframe_t* from, cframe_t* to); + +// helper function which calls s2(s0, s1) +void context_entry(void); + +// trap vector +// saves register on stack in tframe_t or eframe_t +// calls interrupt_handler() or exception_handler() +void trap_entry(void); + +// restores tframe_t from stack and return from interrupt +void trap_exit(void); + +// restores eframe_t from stack and return from exception +void exception_exit(void); + +// debug helpers +void xprint_m_exception(eframe_t* ef); +void xprint_s_exception(eframe_t* ef); + +// called from trap_entry() to handle interrupts or exceptions +void interrupt_handler(void); +void exception_handler(eframe_t* ef); diff --git a/hw/inc/hw/debug.h b/hw/inc/hw/debug.h @@ -13,6 +13,3 @@ int xgetc(void); // debug-printf.c -- calls xputs() void xprintf(const char* fmt, ...); -// print-exception.c -- calls xprintf() -void xprint_exception(uint32_t regs[32]); - diff --git a/hw/src/context-switch.S b/hw/src/context-switch.S @@ -23,6 +23,7 @@ context_switch: sw s9, 0x34(a0) sw s10, 0x38(a0) sw s11, 0x3C(a0) + // load new context from next lw ra, 0x00(a1) lw sp, 0x04(a1) @@ -40,13 +41,17 @@ context_switch: lw s9, 0x34(a1) lw s10, 0x38(a1) lw s11, 0x3C(a1) + // return to new context ret +// startup helper +// calls routine in s2 with s0, s1 as arguments +// then calls thread_exit() if that routine returns .globl context_entry context_entry: mv a0, s0 mv a1, s1 jalr s2 - j context_exit + j thread_exit diff --git a/hw/src/print-exception.c b/hw/src/print-exception.c @@ -3,6 +3,7 @@ #include <hw/debug.h> #include <hw/riscv.h> +#include <hw/context.h> #include <hw/intrinsics.h> static const char* cause_name(uint32_t n) { @@ -38,20 +39,40 @@ static const char* mode_name(uint32_t n) { } } -void xprint_exception(uint32_t regs[32]) { - uint32_t mcause = csr_read(CSR_MCAUSE); +static void xprint_regs(eframe_t* ef, uint32_t xstatus, uint32_t xcause, uint32_t xtval) { + xprintf("pc %08x ra %08x sp %08x gp %08x xstatus %08x\n", + ef->pc, ef->ra, ef->sp, ef->gp, xstatus); + xprintf("tp %08x t0 %08x t1 %08x t2 %08x xcause %08x\n", + ef->tp, ef->t0, ef->t1, ef->t2, xcause); + xprintf("fp %08x s1 %08x a0 %08x a1 %08x xtval %08x\n", + ef->s0, ef->s1, ef->a0, ef->a1, xtval); + xprintf("a2 %08x a3 %08x a4 %08x a5 %08x\n", + ef->a2, ef->a3, ef->a4, ef->a5); + xprintf("a6 %08x a7 %08x s2 %08x s3 %08x\n", + ef->a6, ef->a7, ef->s2, ef->s3); + xprintf("s4 %08x s5 %08x s6 %08x s7 %08x\n", + ef->s4, ef->s5, ef->s6, ef->s7); + xprintf("s8 %08x s9 %08x 10 %08x 11 %08x\n", + ef->s8, ef->s9, ef->s10, ef->s11); + xprintf("t3 %08x t4 %08x t5 %08x t6 %08x\n", + ef->t3, ef->t4, ef->t5, ef->t6); +} + +void xprint_m_exception(eframe_t* ef) { uint32_t mstatus = csr_read(CSR_MSTATUS); + uint32_t mcause = csr_read(CSR_MCAUSE); uint32_t mtval = csr_read(CSR_MTVAL); - xprintf("** %s (in %s mode)\n\n", cause_name(mcause), mode_name((mstatus >> MSTATUS_MPP_SHIFT) & 3)); + xprint_regs(ef, mstatus, mcause, mtval); - xprintf("pc %08x ra %08x sp %08x gp %08x MSTATUS %08x\n", - regs[0], regs[1], regs[2], regs[3], mstatus); - xprintf("tp %08x t0 %08x t1 %08x t2 %08x MCAUSE %08x\n", - regs[4], regs[5], regs[6], regs[7], mcause); - xprintf("fp %08x s1 %08x a0 %08x a1 %08x MTVAL %08x\n", - regs[8], regs[9], regs[10], regs[11], mtval); - xprintf("a2 %08x a3 %08x a4 %08x a5 %08x\n", - regs[12], regs[13], regs[14], regs[15]); } +void xprint_s_exception(eframe_t* ef) { + uint32_t sstatus = csr_read(CSR_SSTATUS); + uint32_t scause = csr_read(CSR_SCAUSE); + uint32_t stval = csr_read(CSR_STVAL); + xprintf("** %s (in %s mode)\n\n", cause_name(scause), + mode_name((sstatus >> SSTATUS_SPP_SHIFT) & 1)); + xprint_regs(ef, sstatus, scause, stval); +} + diff --git a/hw/src/trap-entry-single-stack.S b/hw/src/trap-entry-single-stack.S @@ -0,0 +1,134 @@ +// Copyright 2022, Brian Swetland <swetland@frotz.net> +// Licensed under the Apache License, Version 2.0 + +// This file provides assembly glue for handling traps +// (interrupts or exceptions) and safely saving and +// restoring the processor state of the code running +// when the trap happened. + +// It assume a single stack setup -- when an interrupt +// or exception occurs, the state will be saved on the +// active stack that sp is pointing to. + +// It will call into interrupt_handler() or exception_handler() +// to process the interrupt or exception. + +// For interrupts, only the registers that must be saved +// are saved (the others are callee-save so the C code +// called into will save them if necessary). + +// For exceptions, ALL registers are saved so that the +// exception handler my inspect, display, or modify them +// as necesary. + +// hw/context.h defines structures tframe_t and eframe_t +// that correspond to how the registers are saved on the +// stack + +.global trap_entry +trap_entry: + // reserve stack space for a full eframe_t + addi sp, sp, - (32 * 4) + + // save caller-save registers (tframe_t) + sw ra, 0x00(sp) + sw t0, 0x04(sp) + sw t1, 0x08(sp) + sw t2, 0x0C(sp) + sw t3, 0x10(sp) + sw t4, 0x14(sp) + sw t5, 0x18(sp) + sw t6, 0x1C(sp) + sw a0, 0x20(sp) + sw a1, 0x24(sp) + sw a2, 0x28(sp) + sw a3, 0x2C(sp) + sw a4, 0x30(sp) + sw a5, 0x34(sp) + sw a6, 0x38(sp) + sw a7, 0x3C(sp) + + // save pc which hw stashed in SEPC + csrr t0, sepc + sw t0, 0x40(sp) + + // if the scause high bit is clear, it is an exception + csrr t1, scause + bge t1, zero, exception_entry + + // otherwise it is an interrupt, call interrupt_handler() + jal interrupt_handler + +.globl trap_exit +trap_exit: + // return pc goes into sepc for sret + lw t0, 0x40(sp) + csrw sepc, t0 + + // restore the caller-save registers + lw ra, 0x00(sp) + lw t0, 0x04(sp) + lw t1, 0x08(sp) + lw t2, 0x0C(sp) + lw t3, 0x10(sp) + lw t4, 0x14(sp) + lw t5, 0x18(sp) + lw t6, 0x1C(sp) + lw a0, 0x20(sp) + lw a1, 0x24(sp) + lw a2, 0x28(sp) + lw a3, 0x2C(sp) + lw a4, 0x30(sp) + lw a5, 0x34(sp) + lw a6, 0x38(sp) + lw a7, 0x3C(sp) + + // release the stack space + addi sp, sp, (32 * 4) + + // return from trap + sret + +exception_entry: + // save the callee-save registers (cframe_t) + // pc already stored at 0x40(sp) + addi t0, sp, (32 * 4) + sw t0, 0x44(sp) + sw gp, 0x48(sp) + sw tp, 0x4C(sp) + sw s0, 0x50(sp) + sw s1, 0x54(sp) + sw s2, 0x58(sp) + sw s3, 0x5C(sp) + sw s4, 0x60(sp) + sw s5, 0x64(sp) + sw s6, 0x68(sp) + sw s7, 0x6C(sp) + sw s8, 0x70(sp) + sw s9, 0x74(sp) + sw s10, 0x78(sp) + sw s11, 0x7C(sp) + + // call exception_handler() passing eframe_t* + // as the first argument + mv a0, sp + jal exception_handler + +.globl exception_exit +exception_exit: + lw gp, 0x48(sp) + lw tp, 0x4C(sp) + lw s0, 0x50(sp) + lw s1, 0x54(sp) + lw s2, 0x58(sp) + lw s3, 0x5C(sp) + lw s4, 0x60(sp) + lw s5, 0x64(sp) + lw s6, 0x68(sp) + lw s7, 0x6C(sp) + lw s8, 0x70(sp) + lw s9, 0x74(sp) + lw s10, 0x78(sp) + lw s11, 0x7C(sp) + + j trap_exit diff --git a/misc/traps.c b/misc/traps.c @@ -1,68 +0,0 @@ -// Copyright 2022, Brian Swetland <swetland@frotz.net> -// Licensed under the Apache License, Version 2.0 - -#include <hw/riscv.h> -#include <hw/debug.h> -#include <hw/platform.h> - -#define MEMORY_TOP (DRAM_BASE + DRAM_SIZE) - -#define SVC_SP (MEMORY_TOP - 8*1024) -#define USER_SP (MEMORY_TOP - 16*1024) - -extern void svc_exception_entry(void); -void enter_mode_u(uint32_t a0, uint32_t a1, uint32_t user_pc, uint32_t user_sp); - -void svc_exception_handler(uint32_t regs[32]) { - uint32_t cause = csr_read(CSR_SCAUSE); - uint32_t val = csr_read(CSR_STVAL); - xprintf("\nSUPERVISOR EXCEPTION %08x %08x %08x\n", - cause, val, (unsigned) regs); - - 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\n", - regs[12], regs[13], regs[14], regs[15]); - - if (cause == EXCn_ECALL_UMODE) { - // advance return address to next instr - regs[0] += 4; - xprintf("RETURNING FROM ECALL\n"); - return; - } - - xprintf("HALTED\n"); - for (;;) ; -} - -void user_start(uint32_t hartid, uint32_t fdt) { - xprintf("Hello, User Mode hartid=%08x fdt=%08x\n", hartid, fdt); - - // syscall - asm volatile ("ecall"); - - // illegal write from user mode - csr_write(CSR_MEPC, 0x42); - - xprintf("\nSTOP\n"); - for (;;) ; -} - -void start(uint32_t hartid, uint32_t fdt) { - xprintf("Hello, Trap Test %08x %08x\n", hartid, fdt); - - // set svc exception vector and stack pointer - csr_write(CSR_STVEC, (uintptr_t) svc_exception_entry); - csr_write(CSR_SSCRATCH, SVC_SP); - - //csr_set(CSR_SIE, INTb_SVC_SW); - - enter_mode_u(hartid, fdt, (uintptr_t)user_start, USER_SP); - - for (;;) ; -} - diff --git a/project/traps.app.mk b/project/traps.app.mk @@ -1,6 +0,0 @@ - -MOD_NAME := traps -MOD_SRC := hw/src/start.S misc/traps-entry.S misc/traps.c -MOD_SRC += hw/src/debug-printf.c hw/src/debug-io.c -MOD_LIB := c -include make/app.mk