rewrite trap.c
This commit is contained in:
parent
96cfda564c
commit
572545cb8f
1
Makefile
1
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 \
|
||||
|
@ -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()) };
|
||||
|
@ -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},
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -57,7 +57,7 @@ impl Spinlock {
|
||||
}
|
||||
|
||||
self.cpu = null_mut();
|
||||
|
||||
|
||||
self.locked.store(false, Ordering::Release);
|
||||
|
||||
pop_off();
|
||||
|
@ -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<T> {
|
||||
locked: AtomicBool,
|
||||
@ -15,7 +19,7 @@ impl<T> SpinMutex<T> {
|
||||
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> {
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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<u8> {
|
||||
/// 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.
|
||||
|
156
kernel/trap.c
156
kernel/trap.c
@ -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);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user