diff --git a/Makefile b/Makefile index fa22aa4..cb32d70 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,6 @@ OBJS = \ $K/proc.o \ $K/swtch.o \ $K/trampoline.o \ - $K/trap.o \ $K/bio.o \ $K/fs.o \ $K/log.o \ diff --git a/kernel/rustkernel/src/console.rs b/kernel/rustkernel/src/console.rs index 1ae61a0..f05787c 100644 --- a/kernel/rustkernel/src/console.rs +++ b/kernel/rustkernel/src/console.rs @@ -10,14 +10,11 @@ use crate::{ file::{devsw, CONSOLE}, - proc::{killed, myproc, sleep_mutex, wakeup, procdump}, + proc::{killed, myproc, procdump, sleep_mutex, wakeup}, sync::spinmutex::SpinMutex, - uart::{uartinit, uartputc, uartputc_sync}, -}; -use core::{ - ffi::c_void, - ptr::addr_of_mut, + uart::{uartinit, uartputc, Uart}, }; +use core::{ffi::c_void, ptr::addr_of_mut}; extern "C" { fn either_copyin(dst: *mut c_void, user_src: i32, src: u64, len: u64) -> i32; @@ -65,15 +62,13 @@ const fn ctrl_x(x: u8) -> u8 { /// Called by printf(), and to echo input /// characters but not from write(). pub fn consputc(c: u8) { - unsafe { - if c == BACKSPACE { - // If the user typed backspace, overwrite with a space. - uartputc_sync(0x08); - uartputc_sync(b' '); - uartputc_sync(0x08); - } else { - uartputc_sync(c); - } + if c == BACKSPACE { + // If the user typed backspace, overwrite with a space. + Uart::write_byte_sync(0x08); + Uart::write_byte_sync(b' '); + Uart::write_byte_sync(0x08); + } else { + Uart::write_byte_sync(c); } } @@ -114,12 +109,9 @@ pub unsafe extern "C" fn consoleread(user_dst: i32, mut dst: u64, mut n: i32) -> // cons.lock.unlock(); return -1; } - sleep_mutex( - addr_of_mut!(console.read_index).cast(), - &mut console, - ); + sleep_mutex(addr_of_mut!(console.read_index).cast(), &mut console); } - + c = *console.read_byte(); console.read_index += 1; @@ -177,7 +169,9 @@ pub fn consoleintr(mut c: u8) { unsafe { procdump() }; } else if c == ctrl_x(b'U') { // Kill line. - while console.edit_index != console.write_index && console.buffer[(console.edit_index - 1) % INPUT_BUF_SIZE] != b'\n' { + while console.edit_index != console.write_index + && console.buffer[(console.edit_index - 1) % INPUT_BUF_SIZE] != b'\n' + { console.edit_index -= 1; consputc(BACKSPACE); } @@ -197,7 +191,10 @@ pub fn consoleintr(mut c: u8) { *console.edit_byte() = c; console.edit_index += 1; - if c == b'\n' || c == ctrl_x(b'D') || console.edit_index - console.read_index == INPUT_BUF_SIZE { + if c == b'\n' + || c == ctrl_x(b'D') + || console.edit_index - console.read_index == INPUT_BUF_SIZE + { // Wake up consoleread() if a whole line (or EOF) has arrived. console.write_index = console.edit_index; unsafe { wakeup(addr_of_mut!(console.read_index).cast()) }; diff --git a/kernel/rustkernel/src/kalloc.rs b/kernel/rustkernel/src/kalloc.rs index 1ce5892..b07b329 100644 --- a/kernel/rustkernel/src/kalloc.rs +++ b/kernel/rustkernel/src/kalloc.rs @@ -4,8 +4,8 @@ use crate::{ riscv::{memlayout::PHYSTOP, pg_round_up, PGSIZE}, - sync::spinlock::Spinlock, string::memset, + sync::spinlock::Spinlock, }; use core::{ ffi::{c_char, CStr}, diff --git a/kernel/rustkernel/src/lib.rs b/kernel/rustkernel/src/lib.rs index 7d8b0ed..7300d48 100644 --- a/kernel/rustkernel/src/lib.rs +++ b/kernel/rustkernel/src/lib.rs @@ -16,9 +16,9 @@ pub(crate) mod param; pub mod printf; pub mod proc; pub(crate) mod riscv; -pub mod sync; pub mod start; pub mod string; +pub mod sync; pub mod syscall; pub mod sysproc; pub mod trap; @@ -85,7 +85,7 @@ fn panic_wrapper(panic_info: &core::panic::PanicInfo) -> ! { } unsafe { crate::PANICKED = true }; - + loop { core::hint::spin_loop(); } diff --git a/kernel/rustkernel/src/proc.rs b/kernel/rustkernel/src/proc.rs index b5b5ca7..1d27d6f 100644 --- a/kernel/rustkernel/src/proc.rs +++ b/kernel/rustkernel/src/proc.rs @@ -90,7 +90,7 @@ impl Context { #[derive(Copy, Clone)] pub struct Cpu { pub proc: *mut Proc, - /// swtch() here to enter scheduler() + /// swtch() here to enter scheduler() pub context: Context, /// Depth of push_off() nesting. pub interrupt_disable_layers: i32, @@ -239,10 +239,9 @@ pub unsafe extern "C" fn mycpu() -> *mut Cpu { /// Return the current struct proc *, or zero if none. #[no_mangle] pub unsafe extern "C" fn myproc() -> *mut Proc { - push_off(); + let _ = crate::trap::InterruptBlocker::new(); let c = mycpu(); let p = (*c).proc; - pop_off(); p } @@ -499,4 +498,3 @@ pub unsafe extern "C" fn killed(p: *mut Proc) -> i32 { (*p).lock.unlock(); k } - \ No newline at end of file diff --git a/kernel/rustkernel/src/riscv/memlayout.rs b/kernel/rustkernel/src/riscv/memlayout.rs index d0ba291..4f4d26b 100644 --- a/kernel/rustkernel/src/riscv/memlayout.rs +++ b/kernel/rustkernel/src/riscv/memlayout.rs @@ -67,7 +67,7 @@ pub const PHYSTOP: u64 = KERNBASE + 128 * 1024 * 1024; pub const TRAMPOLINE: u64 = MAXVA - PGSIZE; // Map kernel stacks beneath the trampoline, -// each surrouned by invalid guard pages. +// each surrounded by invalid guard pages. pub fn kstack(p: u64) -> u64 { TRAMPOLINE - (p + 1) * 2 * PGSIZE } diff --git a/kernel/rustkernel/src/riscv/mod.rs b/kernel/rustkernel/src/riscv/mod.rs index ceea72c..0a633c1 100644 --- a/kernel/rustkernel/src/riscv/mod.rs +++ b/kernel/rustkernel/src/riscv/mod.rs @@ -43,6 +43,10 @@ pub const MIE_MSIE: u64 = 1 << 3; pub const SATP_SV39: u64 = 8 << 60; +pub fn make_satp(pagetable: u64) -> u64 { + SATP_SV39 | (pagetable >> 12) +} + /// Bytes per page pub const PGSIZE: u64 = 4096; /// Bits of offset within a page diff --git a/kernel/rustkernel/src/sync/spinlock.rs b/kernel/rustkernel/src/sync/spinlock.rs index 63ffea4..02c8d6f 100644 --- a/kernel/rustkernel/src/sync/spinlock.rs +++ b/kernel/rustkernel/src/sync/spinlock.rs @@ -57,7 +57,7 @@ impl Spinlock { } self.cpu = null_mut(); - + self.locked.store(false, Ordering::Release); pop_off(); diff --git a/kernel/rustkernel/src/sync/spinmutex.rs b/kernel/rustkernel/src/sync/spinmutex.rs index ffd0f15..fe99ec4 100644 --- a/kernel/rustkernel/src/sync/spinmutex.rs +++ b/kernel/rustkernel/src/sync/spinmutex.rs @@ -1,4 +1,8 @@ -use core::{cell::UnsafeCell, ops::{Deref, DerefMut, Drop}, sync::atomic::{AtomicBool, Ordering}}; +use core::{ + cell::UnsafeCell, + ops::{Deref, DerefMut, Drop}, + sync::atomic::{AtomicBool, Ordering}, +}; pub struct SpinMutex { locked: AtomicBool, @@ -15,7 +19,7 @@ impl SpinMutex { while self.locked.swap(true, Ordering::Acquire) { core::hint::spin_loop(); } - SpinMutexGuard { mutex: &self } + SpinMutexGuard { mutex: self } } pub unsafe fn unlock(&self) { self.locked.store(false, Ordering::Release); @@ -30,7 +34,7 @@ impl<'m, T> Deref for SpinMutexGuard<'m, T> { type Target = T; fn deref(&self) -> &Self::Target { - unsafe { & *self.mutex.inner.get() } + unsafe { &*self.mutex.inner.get() } } } impl<'m, T> DerefMut for SpinMutexGuard<'m, T> { diff --git a/kernel/rustkernel/src/trap.rs b/kernel/rustkernel/src/trap.rs index 68d3f8e..05d2b60 100644 --- a/kernel/rustkernel/src/trap.rs +++ b/kernel/rustkernel/src/trap.rs @@ -1,17 +1,25 @@ use crate::{ printf::print, - proc::{cpuid, wakeup, mycpu}, + proc::{cpuid, exit, killed, mycpu, myproc, r#yield, setkilled, wakeup, ProcState}, riscv::*, sync::spinlock::Spinlock, + syscall::syscall, +}; +use core::{ + ffi::{c_char, CStr}, + ptr::{addr_of, addr_of_mut}, }; -use core::{ffi::CStr, ptr::addr_of_mut}; extern "C" { pub fn kernelvec(); - pub fn usertrap(); - pub fn usertrapret(); - fn syscall(); + // pub fn usertrap(); + // pub fn usertrapret(); + // fn syscall(); + // pub fn userret(satp: u64); fn virtio_disk_intr(); + pub static mut trampoline: [c_char; 0]; + pub static mut uservec: [c_char; 0]; + pub static mut userret: [c_char; 0]; } #[no_mangle] @@ -43,59 +51,6 @@ pub unsafe extern "C" fn clockintr() { tickslock.unlock(); } -// /// Handle an interrupt, exception, or syscall from user space. -// /// Called from trampoline.S. -// #[no_mangle] -// pub unsafe extern "C" fn usertrap() { -// if r_sstatus() & SSTATUS_SPP != 0 { -// panic!("usertrap: not from user mode"); -// } -// -// // Send interrupts and exceptions to kerneltrap(), -// // since we're now in the kernel. -// w_stvec(kernelvec as usize as u64); -// -// let p = myproc(); -// -// // Save user program counter. -// (*(*p).trapframe).epc = r_sepc(); -// -// if r_scause() == 8 { -// // Syscall -// -// if killed(p) > 0 { -// exit(-1); -// } -// -// // sepc points to the ecall instruction, -// // but we want to return to the next instruction. -// (*(*p).trapframe).epc += 4; -// -// // An interrupt will change sepc, scause, and sstatus, -// // so enable only now that we're done with those registers. -// intr_on(); -// -// syscall(); -// } else { -// let which_dev = devintr(); -// if which_dev == 0 { -// print!("usertrap(): unexpected scause {:#018x} pid={}\n", r_scause(), (*p).pid); -// print!(" sepc={:#018x} stval={:#018x}\n", r_sepc(), r_stval()); -// setkilled(p); -// } -// if killed(p) > 0 { -// exit(-1); -// } -// -// // Give up the CPU if this is a timer interrupt. -// if which_dev == 2 { -// r#yield(); -// } -// -// usertrapret(); -// } -// } - /// Check if it's an external interrupt or software interrupt and handle it. /// /// Returns 2 if timer interrupt, 1 if other device, 0 if not recognized. @@ -143,13 +98,14 @@ pub unsafe extern "C" fn devintr() -> i32 { } } +#[derive(Default)] pub struct InterruptBlocker; impl InterruptBlocker { - pub fn new() { + pub fn new() -> InterruptBlocker { unsafe { let interrupts_before = intr_get(); let cpu = mycpu(); - + intr_off(); if (*cpu).interrupt_disable_layers == 0 { @@ -158,6 +114,7 @@ impl InterruptBlocker { (*cpu).interrupt_disable_layers += 1; // crate::sync::spinlock::push_off(); } + InterruptBlocker } } impl core::ops::Drop for InterruptBlocker { @@ -180,3 +137,145 @@ impl core::ops::Drop for InterruptBlocker { } } impl !Send for InterruptBlocker {} + +/// Return to user space +#[no_mangle] +pub unsafe extern "C" fn usertrapret() { + let p = myproc(); + + // We're about to switch the destination of traps from + // kerneltrap() to usertrap(), so turn off interrupts until + // we're back in user space, where usertrap() is correct. + intr_off(); + + // Send syscalls, interrupts, and exceptions to uservec in trampoline.S + let trampoline_uservec = + TRAMPOLINE + (addr_of!(uservec) as usize as u64) - (addr_of!(trampoline) as usize as u64); + w_stvec(trampoline_uservec); + + // Set up trapframe values that uservec will need when + // the process next traps into the kernel. + // kernel page table + (*(*p).trapframe).kernel_satp = r_satp(); + // process's kernel stack + (*(*p).trapframe).kernel_sp = (*p).kstack + PGSIZE; + (*(*p).trapframe).kernel_trap = usertrap as usize as u64; + // hartid for cpuid() + (*(*p).trapframe).kernel_hartid = r_tp(); + + // Set up the registers that trampoline.S's + // sret will use to get to user space. + + // Set S Previous Privelege mode to User. + let mut x = r_sstatus(); + // Clear SPP to 0 for user mode. + x &= !SSTATUS_SPP; + // Enable interrupts in user mode. + x |= SSTATUS_SPIE; + w_sstatus(x); + + // Set S Exception Program Counter to the saved user pc. + w_sepc((*(*p).trapframe).epc); + + // Tell trampoline.S the user page table to switch to. + let satp = make_satp((*p).pagetable as usize as u64); + + // Jump to userret in trampoline.S at the top of memory, which + // switches to the user page table, restores user registers, + // and switches to user mode with sret. + let trampoline_userret = (TRAMPOLINE + (addr_of!(userret) as usize as u64) + - (addr_of!(trampoline) as usize as u64)) as usize; + let trampoline_userret = trampoline_userret as *const (); + // Rust's most dangerous function: core::mem::transmute + let trampoline_userret = core::mem::transmute::<*const (), fn(u64)>(trampoline_userret); + trampoline_userret(satp) +} + +/// Interrupts and exceptions from kernel code go here via kernelvec, +/// on whatever the current kernel stack is. +#[no_mangle] +pub unsafe extern "C" fn kerneltrap() { + let sepc = r_sepc(); + let sstatus = r_sstatus(); + let scause = r_scause(); + + if sstatus & SSTATUS_SPP == 0 { + panic!("kerneltrap: not from supervisor mode"); + } else if intr_get() != 0 { + panic!("kerneltrap: interrupts enabled"); + } + + let which_dev = devintr(); + if which_dev == 0 { + print!("scause {}\nsepc={} stval={}\n", scause, r_sepc(), r_stval()); + panic!("kerneltrap"); + } else if which_dev == 2 && !myproc().is_null() && (*myproc()).state == ProcState::Running { + // Give up the CPU if this is a timer interrupt. + r#yield(); + } + + // The yield() may have caused some traps to occur, + // so restore trap registers for use by kernelvec.S's sepc instruction. + w_sepc(sepc); + w_sstatus(sstatus); +} + +/// Handle an interrupt, exception, or system call from userspace. +/// +/// Called from trampoline.S +#[no_mangle] +pub unsafe extern "C" fn usertrap() { + if r_sstatus() & SSTATUS_SPP != 0 { + panic!("usertrap: not from user mode"); + } + + // Send interrupts and exceptions to kerneltrap(), + // since we're now in the kernel. + w_stvec(kernelvec as usize as u64); + + let p = myproc(); + + // Save user program counter. + (*(*p).trapframe).epc = r_sepc(); + + if r_scause() == 8 { + // System call + + if killed(p) > 0 { + exit(-1); + } + + // sepc points to the ecall instruction, but + // we want to return to the next instruction. + (*(*p).trapframe).epc += 4; + + // An interrupt will change sepc, scause, and sstatus, + // so enable only now that we're done with those registers. + intr_on(); + + syscall(); + } + + let which_dev = devintr(); + if r_scause() != 8 && which_dev == 0 { + print!( + "usertrap(): unexpected scause {} {}\n\tsepc={} stval={}", + r_scause(), + (*p).pid, + r_sepc(), + r_stval() + ); + setkilled(p); + } + + if killed(p) > 0 { + exit(-1); + } + + // Give up the CPU if this is a timer interrupt. + if which_dev == 2 { + r#yield(); + } + + usertrapret(); +} diff --git a/kernel/rustkernel/src/uart.rs b/kernel/rustkernel/src/uart.rs index 6a97f58..d061f12 100644 --- a/kernel/rustkernel/src/uart.rs +++ b/kernel/rustkernel/src/uart.rs @@ -5,7 +5,7 @@ use crate::{ console::consoleintr, proc::{sleep, sleep_mutex, wakeup}, riscv::memlayout::UART0, - sync::spinlock::{pop_off, push_off, Spinlock}, + sync::spinlock::Spinlock, sync::spinmutex::SpinMutex, trap::InterruptBlocker, }; @@ -22,15 +22,16 @@ enum Register { } impl Register { pub fn as_ptr(&self) -> *mut u8 { - let addr = UART0 + match self { - Register::ReceiveHolding => 0, - Register::TransmitHolding => 0, - Register::InterruptEnable => 1, - Register::FIFOControl => 2, - Register::InterruptStatus => 2, - Register::LineControl => 2, - Register::LineStatus => 5, - }; + let addr = UART0 + + match self { + Register::ReceiveHolding => 0, + Register::TransmitHolding => 0, + Register::InterruptEnable => 1, + Register::FIFOControl => 2, + Register::InterruptStatus => 2, + Register::LineControl => 2, + Register::LineStatus => 5, + }; addr as *mut u8 } pub fn read(&self) -> u8 { @@ -53,9 +54,12 @@ pub struct Uart { pub read_index: usize, } impl Uart { + /// Alternate version of Uart::write_byte() that doesn't + /// use interrupts, for use by kernel printf() and + /// to echo characters. It spins waiting for the UART's + /// output register to be empty. pub fn write_byte_sync(x: u8) { - // let _ = InterruptBlocker::new(); - unsafe { push_off(); } + let _ = InterruptBlocker::new(); if unsafe { crate::PANICKED } { loop { @@ -69,8 +73,6 @@ impl Uart { } Register::TransmitHolding.write(x); - - unsafe { pop_off(); } } /// If the UART is idle, and a character is /// waiting in the transmit buffer, send it. @@ -175,36 +177,12 @@ pub(crate) unsafe fn uartputc(c: u8) { ); } - uart_tx_buf[(uart_tx_w % UART_TX_BUF_SIZE) as usize] = c; + uart_tx_buf[uart_tx_w % UART_TX_BUF_SIZE] = c; uart_tx_w += 1; uartstart(); uart_tx_lock.unlock(); } -/// Alternate version of uartputc() that doesn't -/// use interrupts, for use by kernel printf() and -/// to echo characters. It spins waiting for the UART's -/// output register to be empty. -pub(crate) unsafe fn uartputc_sync(c: u8) { - push_off(); - Uart::write_byte_sync(c); - - // if crate::PANICKED { - // loop { - // core::hint::spin_loop(); - // } - // } - - // // Wait for Transmit Holding Empty to be set in LSR. - // while Register::LineStatus.read() & LSR_TX_IDLE == 0 { - // core::hint::spin_loop(); - // } - - // Register::TransmitHolding.write(c); - - pop_off(); -} - /// If the UART is idle, and a character is waiting /// in the transmit buffer, send it. /// Caller must hold uart_tx_lock. @@ -223,7 +201,7 @@ unsafe fn uartstart() { } // let buf = uart_tx_buf.lock(); - let c = uart_tx_buf[(uart_tx_r % UART_TX_BUF_SIZE) as usize]; + let c = uart_tx_buf[uart_tx_r % UART_TX_BUF_SIZE]; uart_tx_r += 1; // Maybe uartputc() is waiting for space in the buffer. @@ -248,12 +226,8 @@ pub(crate) fn uartgetc() -> Option { /// both. Called from devintr(). pub(crate) unsafe fn uartintr() { // Read and process incoming characters. - loop { - if let Some(c) = uartgetc() { - consoleintr(c); - } else { - break; - } + while let Some(c) = uartgetc() { + consoleintr(c); } // Send buffered characters. diff --git a/kernel/trap.c b/kernel/trap.c deleted file mode 100644 index 8bae29c..0000000 --- a/kernel/trap.c +++ /dev/null @@ -1,156 +0,0 @@ -#include "types.h" -#include "param.h" -#include "memlayout.h" -#include "riscv.h" -#include "spinlock.h" -#include "proc.h" -#include "defs.h" - -extern char trampoline[], uservec[], userret[]; - -// in kernelvec.S, calls kerneltrap(). -void kernelvec(); - -extern int devintr(); - -// -// handle an interrupt, exception, or system call from user space. -// called from trampoline.S -// -void usertrap(void) -{ - int which_dev = 0; - - if((r_sstatus() & SSTATUS_SPP) != 0) - panic("usertrap: not from user mode"); - - // send interrupts and exceptions to kerneltrap(), - // since we're now in the kernel. - w_stvec((uint64)kernelvec); - - struct proc *p = myproc(); - - // save user program counter. - p->trapframe->epc = r_sepc(); - - if(r_scause() == 8){ - // system call - - if(killed(p)) - exit(-1); - - // sepc points to the ecall instruction, - // but we want to return to the next instruction. - p->trapframe->epc += 4; - - // an interrupt will change sepc, scause, and sstatus, - // so enable only now that we're done with those registers. - intr_on(); - - syscall(); - } else if((which_dev = devintr()) != 0){ - // ok - } else { - printstr("usertrap(): unexepected scause "); - printptr(r_scause()); - printstr(" pid="); - printint(p->pid); - printstr(" sepc="); - printptr(r_sepc()); - printstr(" stval="); - printptr(r_stval()); - printstr("\n"); - setkilled(p); - } - - if(killed(p)) - exit(-1); - - // give up the CPU if this is a timer interrupt. - if(which_dev == 2) - yield(); - - usertrapret(); -} - -// -// return to user space -// -void -usertrapret(void) -{ - struct proc *p = myproc(); - - // we're about to switch the destination of traps from - // kerneltrap() to usertrap(), so turn off interrupts until - // we're back in user space, where usertrap() is correct. - intr_off(); - - // send syscalls, interrupts, and exceptions to uservec in trampoline.S - uint64 trampoline_uservec = TRAMPOLINE + (uservec - trampoline); - w_stvec(trampoline_uservec); - - // set up trapframe values that uservec will need when - // the process next traps into the kernel. - p->trapframe->kernel_satp = r_satp(); // kernel page table - p->trapframe->kernel_sp = p->kstack + PGSIZE; // process's kernel stack - p->trapframe->kernel_trap = (uint64)usertrap; - p->trapframe->kernel_hartid = r_tp(); // hartid for cpuid() - - // set up the registers that trampoline.S's sret will use - // to get to user space. - - // set S Previous Privilege mode to User. - unsigned long x = r_sstatus(); - x &= ~SSTATUS_SPP; // clear SPP to 0 for user mode - x |= SSTATUS_SPIE; // enable interrupts in user mode - w_sstatus(x); - - // set S Exception Program Counter to the saved user pc. - w_sepc(p->trapframe->epc); - - // tell trampoline.S the user page table to switch to. - uint64 satp = MAKE_SATP(p->pagetable); - - // jump to userret in trampoline.S at the top of memory, which - // switches to the user page table, restores user registers, - // and switches to user mode with sret. - uint64 trampoline_userret = TRAMPOLINE + (userret - trampoline); - ((void (*)(uint64))trampoline_userret)(satp); -} - -// interrupts and exceptions from kernel code go here via kernelvec, -// on whatever the current kernel stack is. -void -kerneltrap() -{ - int which_dev = 0; - uint64 sepc = r_sepc(); - uint64 sstatus = r_sstatus(); - uint64 scause = r_scause(); - - if((sstatus & SSTATUS_SPP) == 0) - panic("kerneltrap: not from supervisor mode"); - if(intr_get() != 0) - panic("kerneltrap: interrupts enabled"); - - if((which_dev = devintr()) == 0){ - printstr("scause "); - printptr(scause); - printstr("\nsepc="); - printptr(r_sepc()); - printstr(" stval="); - printptr(r_stval()); - printstr("\n"); - panic("kerneltrap"); - } - - // give up the CPU if this is a timer interrupt. - if(which_dev == 2 && myproc() != 0 && myproc()->state == RUNNING) - yield(); - - // the yield() may have caused some traps to occur, - // so restore trap registers for use by kernelvec.S's sepc instruction. - w_sepc(sepc); - w_sstatus(sstatus); -}