-
Notifications
You must be signed in to change notification settings - Fork 377
/
Copy pathmod.rs
138 lines (121 loc) · 3.62 KB
/
mod.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use crate::arch::interrupt::consts::SupervisorExternal;
use crate::drivers::IRQ_MANAGER;
use crate::process::thread::Thread;
use alloc::sync::Arc;
use log::*;
use riscv::register::*;
use riscv::register::{scause::Scause, sscratch, stvec};
use trapframe::{TrapFrame, UserContext};
pub mod consts;
/// Enable interrupt
#[inline]
pub unsafe fn enable() {
sstatus::set_sie();
}
/// Disable interrupt and return current interrupt status
#[inline]
pub unsafe fn disable_and_store() -> usize {
let e = sstatus::read().sie() as usize;
sstatus::clear_sie();
e
}
/// Enable interrupt if `flags` != 0
#[inline]
pub unsafe fn restore(flags: usize) {
if flags != 0 {
enable();
}
}
/// Dispatch and handle interrupt.
///
/// This function is called from `trap.asm`.
#[no_mangle]
pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
trap_handler_no_frame(tf);
}
use crate::memory::AccessType;
#[inline]
pub fn trap_handler_no_frame(tf: &mut TrapFrame) {
use self::scause::{Exception as E, Interrupt as I, Trap};
let scause = scause::read();
let stval = stval::read();
let is_user = false;
trace!("Interrupt @ CPU{}: {:?} ", super::cpu::id(), scause.cause());
match scause.cause() {
Trap::Interrupt(I::SupervisorExternal) => external(),
Trap::Interrupt(I::SupervisorSoft) => ipi(),
Trap::Interrupt(I::SupervisorTimer) => timer(),
Trap::Exception(E::LoadPageFault) => page_fault(stval, &mut tf.sepc, AccessType::read(is_user)),
Trap::Exception(E::StorePageFault) => page_fault(stval, &mut tf.sepc, AccessType::write(is_user)),
Trap::Exception(E::InstructionPageFault) => {
page_fault(stval, &mut tf.sepc, AccessType::execute(is_user))
}
Trap::Exception(E::Breakpoint) => rkprobes::kprobes_trap_handler(tf),
_ => {
let bits = scause.bits();
panic!("unhandled trap {:?} ({})", scause.cause(), bits);
}
}
trace!("Interrupt end");
}
fn external() {
#[cfg(feature = "board_u540")]
unsafe {
super::board::handle_external_interrupt();
}
IRQ_MANAGER
.read()
.try_handle_interrupt(Some(SupervisorExternal));
}
fn ipi() {
debug!("IPI");
super::sbi::clear_ipi();
}
pub fn timer() {
super::timer::set_next();
crate::trap::timer();
}
fn page_fault(stval: usize, sepc: &mut usize, access: AccessType) {
let addr = stval;
info!("\nEXCEPTION: Page Fault @ {:#x}", addr);
if crate::memory::handle_page_fault_ext(addr, access) {
return;
}
extern "C" {
fn _copy_user_start();
fn _copy_user_end();
}
if *sepc >= _copy_user_start as usize && *sepc < _copy_user_end as usize {
info!("fixup for addr {:x?}", addr);
*sepc = crate::memory::read_user_fixup as usize;
return;
}
error!("unhandled page fault {:#x} from {:#x}", addr, sepc);
panic!("unhandled page fault");
}
pub fn ack(irq: usize) {
// Handled in PLIC driver
}
pub fn enable_irq(irq: usize) {
// Handled in PLIC driver
}
pub fn get_trap_num(_context: &UserContext) -> usize {
scause::read().bits()
}
pub fn wait_for_interrupt() {
unsafe {
// enable interrupt and disable
let sie = riscv::register::sstatus::read().sie();
riscv::register::sstatus::set_sie();
riscv::asm::wfi();
if !sie {
riscv::register::sstatus::clear_sie();
}
}
}
pub fn handle_user_page_fault_ext(thread: &Arc<Thread>, addr: usize, access: AccessType) -> bool {
thread.vm.lock().handle_page_fault_ext(addr, access)
}
pub fn handle_reserved_inst(tf: &mut UserContext) -> bool {
false
}