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
#[allow(clippy::upper_case_acronyms)]
pub struct PLIC {
base_addr: usize,
}
#[derive(Copy, Clone)]
pub enum IntrTargetPriority {
Machine = 0,
Supervisor = 1,
}
impl IntrTargetPriority {
pub fn supported_number() -> usize {
2
}
}
impl PLIC {
fn priority_ptr(&self, intr_source_id: usize) -> *mut u32 {
assert!(intr_source_id > 0 && intr_source_id <= 132);
(self.base_addr + intr_source_id * 4) as *mut u32
}
fn hart_id_with_priority(hart_id: usize, target_priority: IntrTargetPriority) -> usize {
let priority_num = IntrTargetPriority::supported_number();
hart_id * priority_num + target_priority as usize
}
fn enable_ptr(
&self,
hart_id: usize,
target_priority: IntrTargetPriority,
intr_source_id: usize,
) -> (*mut u32, usize) {
let id = Self::hart_id_with_priority(hart_id, target_priority);
let (reg_id, reg_shift) = (intr_source_id / 32, intr_source_id % 32);
(
(self.base_addr + 0x2000 + 0x80 * id + 0x4 * reg_id) as *mut u32,
reg_shift,
)
}
fn threshold_ptr_of_hart_with_priority(
&self,
hart_id: usize,
target_priority: IntrTargetPriority,
) -> *mut u32 {
let id = Self::hart_id_with_priority(hart_id, target_priority);
(self.base_addr + 0x20_0000 + 0x1000 * id) as *mut u32
}
fn claim_comp_ptr_of_hart_with_priority(
&self,
hart_id: usize,
target_priority: IntrTargetPriority,
) -> *mut u32 {
let id = Self::hart_id_with_priority(hart_id, target_priority);
(self.base_addr + 0x20_0004 + 0x1000 * id) as *mut u32
}
pub unsafe fn new(base_addr: usize) -> Self {
Self { base_addr }
}
pub fn set_priority(&mut self, intr_source_id: usize, priority: u32) {
assert!(priority < 8);
unsafe {
self.priority_ptr(intr_source_id).write_volatile(priority);
}
}
#[allow(unused)]
pub fn get_priority(&mut self, intr_source_id: usize) -> u32 {
unsafe { self.priority_ptr(intr_source_id).read_volatile() & 7 }
}
pub fn enable(
&mut self,
hart_id: usize,
target_priority: IntrTargetPriority,
intr_source_id: usize,
) {
let (reg_ptr, shift) = self.enable_ptr(hart_id, target_priority, intr_source_id);
unsafe {
reg_ptr.write_volatile(reg_ptr.read_volatile() | 1 << shift);
}
}
#[allow(unused)]
pub fn disable(
&mut self,
hart_id: usize,
target_priority: IntrTargetPriority,
intr_source_id: usize,
) {
let (reg_ptr, shift) = self.enable_ptr(hart_id, target_priority, intr_source_id);
unsafe {
reg_ptr.write_volatile(reg_ptr.read_volatile() & (!(1u32 << shift)));
}
}
pub fn set_threshold(
&mut self,
hart_id: usize,
target_priority: IntrTargetPriority,
threshold: u32,
) {
assert!(threshold < 8);
let threshold_ptr = self.threshold_ptr_of_hart_with_priority(hart_id, target_priority);
unsafe {
threshold_ptr.write_volatile(threshold);
}
}
#[allow(unused)]
pub fn get_threshold(&mut self, hart_id: usize, target_priority: IntrTargetPriority) -> u32 {
let threshold_ptr = self.threshold_ptr_of_hart_with_priority(hart_id, target_priority);
unsafe { threshold_ptr.read_volatile() & 7 }
}
pub fn claim(&mut self, hart_id: usize, target_priority: IntrTargetPriority) -> u32 {
let claim_comp_ptr = self.claim_comp_ptr_of_hart_with_priority(hart_id, target_priority);
unsafe { claim_comp_ptr.read_volatile() }
}
pub fn complete(
&mut self,
hart_id: usize,
target_priority: IntrTargetPriority,
completion: u32,
) {
let claim_comp_ptr = self.claim_comp_ptr_of_hart_with_priority(hart_id, target_priority);
unsafe {
claim_comp_ptr.write_volatile(completion);
}
}
}