1use crate::{device::{manager::{DeviceManager, DriverPriority}, platform::{resource::PlatformDeviceResourceType, PlatformDeviceDriver, PlatformDeviceInfo}}, driver_initcall, early_initcall, interrupt::{
7 controllers::{ExternalInterruptController, LocalInterruptType}, CpuId, InterruptError, InterruptId, InterruptManager, InterruptResult, Priority
8}};
9use alloc::{boxed::Box, vec};
10use core::ptr::{read_volatile, write_volatile};
11
12const PLIC_PRIORITY_BASE: usize = 0x0000_0000;
14const PLIC_PENDING_BASE: usize = 0x0000_1000;
15const PLIC_ENABLE_BASE: usize = 0x0000_2000;
16const PLIC_THRESHOLD_BASE: usize = 0x0020_0000;
17const PLIC_CLAIM_BASE: usize = 0x0020_0004;
18
19const PLIC_ENABLE_CONTEXT_STRIDE: usize = 0x80;
21const PLIC_CONTEXT_STRIDE: usize = 0x1000;
23
24const MAX_INTERRUPTS: InterruptId = 1024;
26
27const MAX_CPUS: CpuId = 15872; pub struct Plic {
32 base_addr: usize,
34 max_interrupts: InterruptId,
36 max_cpus: CpuId,
38}
39
40impl Plic {
41 pub fn new(base_addr: usize, max_interrupts: InterruptId, max_cpus: CpuId) -> Self {
49 Self {
50 base_addr,
51 max_interrupts: max_interrupts.min(MAX_INTERRUPTS),
52 max_cpus: max_cpus.min(MAX_CPUS),
53 }
54 }
55
56 fn context_id_for_cpu(&self, cpu_id: CpuId) -> usize {
59 (cpu_id as usize * 2) + 1
60 }
61
62 fn priority_addr(&self, interrupt_id: InterruptId) -> usize {
64 self.base_addr + PLIC_PRIORITY_BASE + (interrupt_id as usize * 4)
65 }
66
67 fn pending_addr(&self, interrupt_id: InterruptId) -> usize {
69 let word_offset = interrupt_id / 32;
70 self.base_addr + PLIC_PENDING_BASE + (word_offset as usize * 4)
71 }
72
73 fn enable_addr(&self, cpu_id: CpuId, interrupt_id: InterruptId) -> usize {
75 let word_offset = interrupt_id / 32;
76 let context_id = self.context_id_for_cpu(cpu_id);
77 let context_offset = context_id * PLIC_ENABLE_CONTEXT_STRIDE;
78 self.base_addr + PLIC_ENABLE_BASE + context_offset + (word_offset as usize * 4)
79 }
80
81 fn threshold_addr(&self, cpu_id: CpuId) -> usize {
83 let context_id = self.context_id_for_cpu(cpu_id);
84 let context_offset = context_id * PLIC_CONTEXT_STRIDE;
85 self.base_addr + PLIC_THRESHOLD_BASE + context_offset
86 }
87
88 fn claim_addr(&self, cpu_id: CpuId) -> usize {
90 let context_id = self.context_id_for_cpu(cpu_id);
91 let context_offset = context_id * PLIC_CONTEXT_STRIDE;
92 self.base_addr + PLIC_CLAIM_BASE + context_offset
93 }
94
95 fn validate_interrupt_id(&self, interrupt_id: InterruptId) -> InterruptResult<()> {
97 if interrupt_id == 0 || interrupt_id > self.max_interrupts {
98 Err(InterruptError::InvalidInterruptId)
99 } else {
100 Ok(())
101 }
102 }
103
104 fn validate_cpu_id(&self, cpu_id: CpuId) -> InterruptResult<()> {
106 if cpu_id >= self.max_cpus {
107 Err(InterruptError::InvalidCpuId)
108 } else {
109 Ok(())
110 }
111 }
112}
113
114impl ExternalInterruptController for Plic {
115 fn init(&mut self) -> InterruptResult<()> {
117 for cpu_id in 0..self.max_cpus {
119 for word in 0..=(self.max_interrupts / 32) {
121 let interrupt_id_base = word * 32;
122 if interrupt_id_base > 0 { let addr = self.enable_addr(cpu_id, interrupt_id_base);
124 unsafe { write_volatile(addr as *mut u32, 0); }
125 }
126 }
127 let _ = self.set_threshold(cpu_id, 0);
129 }
130
131 for interrupt_id in 1..=self.max_interrupts {
133 let _ = self.set_priority(interrupt_id, 1);
134 }
135
136 Ok(())
137 }
138
139 fn enable_interrupt(&mut self, interrupt_id: InterruptId, cpu_id: CpuId) -> InterruptResult<()> {
141 self.validate_interrupt_id(interrupt_id)?;
142 self.validate_cpu_id(cpu_id)?;
143
144 let addr = self.enable_addr(cpu_id, interrupt_id);
145 let bit_offset = interrupt_id % 32;
146
147 unsafe {
148 let current = read_volatile(addr as *const u32);
149 let new_value = current | (1 << bit_offset);
150 write_volatile(addr as *mut u32, new_value);
151 }
152
153 Ok(())
154 }
155
156 fn disable_interrupt(&mut self, interrupt_id: InterruptId, cpu_id: CpuId) -> InterruptResult<()> {
158 self.validate_interrupt_id(interrupt_id)?;
159 self.validate_cpu_id(cpu_id)?;
160
161 let addr = self.enable_addr(cpu_id, interrupt_id);
162 let bit_offset = interrupt_id % 32;
163
164 unsafe {
165 let current = read_volatile(addr as *const u32);
166 let new_value = current & !(1 << bit_offset);
167 write_volatile(addr as *mut u32, new_value);
168 }
169
170 Ok(())
171 }
172
173 fn set_priority(&mut self, interrupt_id: InterruptId, priority: Priority) -> InterruptResult<()> {
175 self.validate_interrupt_id(interrupt_id)?;
176
177 if priority > 7 {
178 return Err(InterruptError::InvalidPriority);
179 }
180
181 let addr = self.priority_addr(interrupt_id);
182 unsafe {
183 write_volatile(addr as *mut u32, priority);
184 }
185
186 Ok(())
187 }
188
189 fn get_priority(&self, interrupt_id: InterruptId) -> InterruptResult<Priority> {
191 self.validate_interrupt_id(interrupt_id)?;
192
193 let addr = self.priority_addr(interrupt_id);
194 let priority = unsafe { read_volatile(addr as *const u32) };
195
196 Ok(priority)
197 }
198
199 fn set_threshold(&mut self, cpu_id: CpuId, threshold: Priority) -> InterruptResult<()> {
201 self.validate_cpu_id(cpu_id)?;
202
203 if threshold > 7 {
204 return Err(InterruptError::InvalidPriority);
205 }
206
207 let addr = self.threshold_addr(cpu_id);
208 unsafe {
209 write_volatile(addr as *mut u32, threshold);
210 }
211
212 Ok(())
213 }
214
215 fn get_threshold(&self, cpu_id: CpuId) -> InterruptResult<Priority> {
217 self.validate_cpu_id(cpu_id)?;
218
219 let addr = self.threshold_addr(cpu_id);
220 let threshold = unsafe { read_volatile(addr as *const u32) };
221
222 Ok(threshold)
223 }
224
225 fn claim_interrupt(&mut self, cpu_id: CpuId) -> InterruptResult<Option<InterruptId>> {
227 self.validate_cpu_id(cpu_id)?;
228
229 let addr = self.claim_addr(cpu_id);
230 let interrupt_id = unsafe { read_volatile(addr as *const u32) };
231
232 if interrupt_id == 0 {
233 Ok(None)
234 } else {
235 Ok(Some(interrupt_id))
236 }
237 }
238
239 fn complete_interrupt(&mut self, cpu_id: CpuId, interrupt_id: InterruptId) -> InterruptResult<()> {
241 self.validate_cpu_id(cpu_id)?;
242 self.validate_interrupt_id(interrupt_id)?;
243
244 let addr = self.claim_addr(cpu_id);
245 unsafe {
246 write_volatile(addr as *mut u32, interrupt_id);
247 }
248
249 Ok(())
250 }
251
252 fn is_pending(&self, interrupt_id: InterruptId) -> bool {
254 if self.validate_interrupt_id(interrupt_id).is_err() {
255 return false;
256 }
257
258 let addr = self.pending_addr(interrupt_id);
259 let bit_offset = interrupt_id % 32;
260
261 unsafe {
262 let pending_word = read_volatile(addr as *const u32);
263 (pending_word & (1 << bit_offset)) != 0
264 }
265 }
266
267 fn max_interrupts(&self) -> InterruptId {
269 self.max_interrupts
270 }
271
272 fn max_cpus(&self) -> CpuId {
274 self.max_cpus
275 }
276}
277
278unsafe impl Send for Plic {}
279unsafe impl Sync for Plic {}
280
281fn probe_fn(device: &PlatformDeviceInfo) -> Result<(), &'static str> {
282 let res = device.get_resources();
283 if res.is_empty() {
284 return Err("No resources found");
285 }
286
287 let mem_res = res.iter()
289 .find(|r| r.res_type == PlatformDeviceResourceType::MEM)
290 .ok_or("Memory resource not found")?;
291
292 let base_addr = mem_res.start as usize;
293
294 let controller = Box::new(Plic::new(base_addr, 1023, 4)); match InterruptManager::global().lock().register_external_controller(controller) {
297 Ok(_) => {
298 crate::early_println!("[interrupt] PLIC registered at base address: {:#x}", base_addr);
299 },
300 Err(e) => {
301 crate::early_println!("[interrupt] Failed to register PLIC: {}", e);
302 return Err("Failed to register PLIC");
303 }
304 }
305
306 Ok(())
307}
308
309fn remove_fn(_device: &PlatformDeviceInfo) -> Result<(), &'static str> {
310 Ok(())
311}
312
313fn register_driver() {
314 let driver = PlatformDeviceDriver::new(
315 "riscv-plic",
316 probe_fn,
317 remove_fn,
318 vec!["sifive,plic-1.0.0", "riscv,plic0"],
319 );
320 DeviceManager::get_mut_manager().register_driver(Box::new(driver), DriverPriority::Critical)
322}
323
324early_initcall!(register_driver);
326
327#[cfg(test)]
328mod tests {
329 use super::*;
330
331 #[test_case]
332 fn test_plic_creation() {
333 let plic = Plic::new(0x1000_0000, 100, 8);
334 assert_eq!(plic.max_interrupts(), 100);
335 assert_eq!(plic.max_cpus(), 8);
336 }
337
338 #[test_case]
339 fn test_address_calculation() {
340 let plic = Plic::new(0x1000_0000, 100, 8);
341
342 assert_eq!(plic.priority_addr(1), 0x1000_0004);
344 assert_eq!(plic.priority_addr(10), 0x1000_0028);
345
346 assert_eq!(plic.enable_addr(0, 10), 0x1000_2080);
349 assert_eq!(plic.enable_addr(1, 40), 0x1000_2184);
351
352 assert_eq!(plic.threshold_addr(0), 0x1020_1000);
355 assert_eq!(plic.threshold_addr(1), 0x1020_3000);
357
358 assert_eq!(plic.claim_addr(0), 0x1020_1004);
361 assert_eq!(plic.claim_addr(1), 0x1020_3004);
363 }
364
365 #[test_case]
366 fn test_validation() {
367 let plic = Plic::new(0x1000_0000, 100, 8);
368
369 assert!(plic.validate_interrupt_id(1).is_ok());
371 assert!(plic.validate_interrupt_id(100).is_ok());
372 assert!(plic.validate_cpu_id(0).is_ok());
373 assert!(plic.validate_cpu_id(7).is_ok());
374
375 assert!(plic.validate_interrupt_id(0).is_err());
377 assert!(plic.validate_interrupt_id(101).is_err());
378 assert!(plic.validate_cpu_id(8).is_err());
379 }
380}