-
Notifications
You must be signed in to change notification settings - Fork 68
Expand file tree
/
Copy pathhandler.rs
More file actions
112 lines (102 loc) · 3.78 KB
/
Copy pathhandler.rs
File metadata and controls
112 lines (102 loc) · 3.78 KB
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
use super::context::Context;
use super::timer;
use crate::fs::STDIN;
use crate::kernel::syscall_handler;
use crate::memory::*;
use crate::process::PROCESSOR;
use crate::sbi::console_getchar;
use riscv::register::{
scause::{Exception, Interrupt, Scause, Trap},
sie, stvec,
};
global_asm!(include_str!("./interrupt.asm"));
/// 初始化中断处理
///
/// 把中断入口 `__interrupt` 写入 `stvec` 中,并且开启中断使能
pub fn init() {
unsafe {
extern "C" {
/// `interrupt.asm` 中的中断入口
fn __interrupt();
}
// 使用 Direct 模式,将中断入口设置为 `__interrupt`
stvec::write(__interrupt as usize, stvec::TrapMode::Direct);
// 开启外部中断使能
sie::set_sext();
// 在 OpenSBI 中开启外部中断
*PhysicalAddress(0x0c00_2080).deref_kernel() = 1u32 << 10;
// 在 OpenSBI 中开启串口
*PhysicalAddress(0x1000_0004).deref_kernel() = 0x0bu8;
*PhysicalAddress(0x1000_0001).deref_kernel() = 0x01u8;
// 其他一些外部中断相关魔数
*PhysicalAddress(0x0C00_0028).deref_kernel() = 0x07u32;
*PhysicalAddress(0x0C20_1000).deref_kernel() = 0u32;
}
}
/// 中断的处理入口
///
/// `interrupt.asm` 首先保存寄存器至 Context,其作为参数和 scause 以及 stval 一并传入此函数
/// 具体的中断类型需要根据 scause 来推断,然后分别处理
#[no_mangle]
pub fn handle_interrupt(context: &mut Context, scause: Scause, stval: usize) -> *mut Context {
// 首先检查线程是否已经结束(内核线程会自己设置标记来结束自己)
{
let mut processor = PROCESSOR.lock();
let current_thread = processor.current_thread();
if current_thread.as_ref().inner().dead {
println!("thread {} exit", current_thread.id);
processor.kill_current_thread();
return processor.prepare_next_thread();
}
}
// 根据中断类型来处理,返回的 Context 必须位于放在中断栈顶
match scause.cause() {
// 断点中断(ebreak)
Trap::Exception(Exception::Breakpoint) => breakpoint(context),
// 系统调用
Trap::Exception(Exception::UserEnvCall) => syscall_handler(context),
// 时钟中断
Trap::Interrupt(Interrupt::SupervisorTimer) => supervisor_timer(context),
// 外部中断(键盘输入)
Trap::Interrupt(Interrupt::SupervisorExternal) => supervisor_external(context),
// 其他情况,无法处理
_ => fault("unimplemented interrupt type", scause, stval),
}
}
/// 处理 ebreak 断点
///
/// 继续执行,其中 `sepc` 增加 2 字节,以跳过当前这条 `ebreak` 指令
fn breakpoint(context: &mut Context) -> *mut Context {
println!("Breakpoint at 0x{:x}", context.sepc);
context.sepc += 2;
context
}
/// 处理时钟中断
fn supervisor_timer(context: &mut Context) -> *mut Context {
timer::tick();
PROCESSOR.lock().park_current_thread(context);
PROCESSOR.lock().prepare_next_thread()
}
/// 处理外部中断,只实现了键盘输入
fn supervisor_external(context: &mut Context) -> *mut Context {
let mut c = console_getchar();
if c <= 255 {
if c == '\r' as usize {
c = '\n' as usize;
}
STDIN.push(c as u8);
}
context
}
/// 出现未能解决的异常,终止当前线程
fn fault(msg: &str, scause: Scause, stval: usize) -> *mut Context {
println!(
"{:#x?} terminated: {}",
PROCESSOR.lock().current_thread(),
msg
);
println!("cause: {:?}, stval: {:x}", scause.cause(), stval);
PROCESSOR.lock().kill_current_thread();
// 跳转到 PROCESSOR 调度的下一个线程
PROCESSOR.lock().prepare_next_thread()
}