/
plic.rs
107 lines (99 loc) · 3.5 KB
/
plic.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
use crate::trace::{push_trace, S_EXT_INTR_ENTER, S_EXT_INTR_EXIT};
use crate::trap::{push_trap_record, UserTrapRecord, USER_EXT_INT_MAP};
use crate::uart;
use rv_plic::{Priority, PLIC};
#[cfg(any(feature = "board_qemu", feature = "board_lrv"))]
pub const PLIC_BASE: usize = 0xc00_0000;
#[cfg(any(feature = "board_qemu", feature = "board_lrv"))]
pub const PLIC_PRIORITY_BIT: usize = 3;
pub type Plic = PLIC<{ PLIC_BASE }, { PLIC_PRIORITY_BIT }>;
pub fn get_context(hart_id: usize, mode: char) -> usize {
const MODE_PER_HART: usize = 3;
hart_id * MODE_PER_HART
+ match mode {
'M' => 0,
'S' => 1,
'U' => 2,
_ => panic!("Wrong Mode"),
}
}
#[cfg(feature = "board_qemu")]
pub fn init() {
Plic::set_priority(12, Priority::lowest());
Plic::set_priority(13, Priority::lowest());
Plic::set_priority(14, Priority::lowest());
Plic::set_priority(15, Priority::lowest());
}
#[cfg(feature = "board_lrv")]
pub fn init() {
Plic::set_priority(4, Priority::lowest());
Plic::set_priority(5, Priority::lowest());
Plic::set_priority(6, Priority::lowest());
Plic::set_priority(7, Priority::lowest());
}
#[cfg(feature = "board_qemu")]
pub fn init_hart(hart_id: usize) {
let context = get_context(hart_id, 'S');
Plic::enable(context, 12);
Plic::enable(context, 13);
Plic::enable(context, 14);
Plic::enable(context, 15);
Plic::set_threshold(context, Priority::any());
}
#[cfg(feature = "board_lrv")]
pub fn init_hart(hart_id: usize) {
let context = get_context(hart_id, 'S');
Plic::clear_enable(context, 0);
Plic::clear_enable(get_context(hart_id, 'U'), 0);
Plic::enable(context, 4);
Plic::enable(context, 5);
Plic::enable(context, 6);
Plic::enable(context, 7);
Plic::set_threshold(context, Priority::any());
Plic::set_threshold(get_context(hart_id, 'U'), Priority::any());
Plic::set_threshold(get_context(hart_id, 'M'), Priority::never());
}
pub fn handle_external_interrupt(hart_id: usize) {
let context = get_context(hart_id, 'S');
while let Some(irq) = Plic::claim(context) {
push_trace(S_EXT_INTR_ENTER + irq as usize);
let mut can_user_handle = false;
let uei_map = USER_EXT_INT_MAP.lock();
if let Some(pid) = uei_map.get(&irq).cloned() {
trace!("[PLIC] irq {:?} mapped to pid {:?}", irq, pid);
drop(uei_map); // avoid deadlock with sys_set_ext_int_enable
if push_trap_record(
pid,
UserTrapRecord {
// User External Interrupt
cause: 8,
message: irq as usize,
},
)
.is_ok()
{
can_user_handle = true;
}
// prioritize_task(*pid);
}
if !can_user_handle {
match irq {
#[cfg(feature = "board_qemu")]
12 | 13 | 14 | 15 => {
uart::handle_interrupt(irq);
trace!("[PLIC] irq {:?} handled by kenel", irq);
}
#[cfg(feature = "board_lrv")]
4 | 5 | 6 | 7 => {
uart::handle_interrupt(irq);
// trace!("[PLIC] irq {:?} handled by kenel", irq);
}
_ => {
warn!("[PLIC]: irq {:?} not supported!", irq);
}
}
Plic::complete(context, irq);
}
push_trace(S_EXT_INTR_EXIT + irq as usize);
}
}