kernel/drivers/pic/
plic.rs

1//! RISC-V Platform-Level Interrupt Controller (PLIC) Implementation
2//!
3//! The PLIC is responsible for managing external interrupts from devices and
4//! routing them to different CPUs with priority support.
5
6use 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
12/// PLIC register offsets
13const 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
19/// PLIC context stride for enable registers (per context)
20const PLIC_ENABLE_CONTEXT_STRIDE: usize = 0x80;
21/// PLIC context stride for threshold/claim registers (per context)
22const PLIC_CONTEXT_STRIDE: usize = 0x1000;
23
24/// Maximum number of interrupts supported by this PLIC implementation
25const MAX_INTERRUPTS: InterruptId = 1024;
26
27/// Maximum number of CPUs supported by this PLIC implementation
28const MAX_CPUS: CpuId = 15872; // RISC-V spec allows up to 15872 contexts
29
30/// RISC-V PLIC Implementation
31pub struct Plic {
32    /// Base address of the PLIC
33    base_addr: usize,
34    /// Maximum number of interrupts this PLIC supports
35    max_interrupts: InterruptId,
36    /// Maximum number of CPUs this PLIC supports
37    max_cpus: CpuId,
38}
39
40impl Plic {
41    /// Create a new PLIC instance
42    /// 
43    /// # Arguments
44    /// 
45    /// * `base_addr` - Physical base address of the PLIC
46    /// * `max_interrupts` - Maximum interrupt ID supported (1-based)
47    /// * `max_cpus` - Maximum number of CPUs supported
48    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    /// Convert CPU ID to PLIC context ID for Supervisor mode.
57    /// Hart 0 S-Mode -> Context 1, Hart 1 S-Mode -> Context 3, etc.
58    fn context_id_for_cpu(&self, cpu_id: CpuId) -> usize {
59        (cpu_id as usize * 2) + 1
60    }
61
62    /// Get the address of a priority register for an interrupt
63    fn priority_addr(&self, interrupt_id: InterruptId) -> usize {
64        self.base_addr + PLIC_PRIORITY_BASE + (interrupt_id as usize * 4)
65    }
66
67    /// Get the address of a pending register for an interrupt
68    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    /// Get the address of an enable register for a CPU and interrupt
74    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    /// Get the address of a threshold register for a CPU
82    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    /// Get the address of a claim register for a CPU
89    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    /// Validate interrupt ID
96    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    /// Validate CPU ID
105    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    /// Initialize the PLIC
116    fn init(&mut self) -> InterruptResult<()> {
117        // Disable all interrupts for all CPUs initially
118        for cpu_id in 0..self.max_cpus {
119            // Disable all interrupts for this CPU's context
120            for word in 0..=(self.max_interrupts / 32) {
121                let interrupt_id_base = word * 32;
122                if interrupt_id_base > 0 { // Interrupt ID 0 is not used
123                    let addr = self.enable_addr(cpu_id, interrupt_id_base);
124                    unsafe { write_volatile(addr as *mut u32, 0); }
125                }
126            }
127            // Set threshold to 0 (allow all priorities)
128            let _ = self.set_threshold(cpu_id, 0);
129        }
130
131        // Set all interrupt priorities to 1 (lowest non-zero priority)
132        for interrupt_id in 1..=self.max_interrupts {
133            let _ = self.set_priority(interrupt_id, 1);
134        }
135
136        Ok(())
137    }
138
139    /// Enable a specific interrupt for a CPU
140    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    /// Disable a specific interrupt for a CPU
157    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    /// Set priority for a specific interrupt
174    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    /// Get priority for a specific interrupt
190    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    /// Set priority threshold for a CPU
200    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    /// Get priority threshold for a CPU
216    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    /// Claim an interrupt (acknowledge and get the interrupt ID)
226    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    /// Complete an interrupt (signal that handling is finished)
240    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    /// Check if a specific interrupt is pending
253    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    /// Get the maximum number of interrupts supported
268    fn max_interrupts(&self) -> InterruptId {
269        self.max_interrupts
270    }
271
272    /// Get the number of CPUs supported
273    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    // Get memory region resource (res_type == PlatformDeviceResourceType::MEM)
288    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)); // Example values for max interrupts and CPUs
295
296    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    // Register the driver with the kernel
321    DeviceManager::get_mut_manager().register_driver(Box::new(driver), DriverPriority::Critical)
322}
323
324// driver_initcall!(register_driver);
325early_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        // Test priority address
343        assert_eq!(plic.priority_addr(1), 0x1000_0004);
344        assert_eq!(plic.priority_addr(10), 0x1000_0028);
345        
346        // Test enable address for S-Mode
347        // CPU 0 -> Context 1
348        assert_eq!(plic.enable_addr(0, 10), 0x1000_2080);
349        // CPU 1 -> Context 3
350        assert_eq!(plic.enable_addr(1, 40), 0x1000_2184);
351        
352        // Test threshold address for S-Mode
353        // CPU 0 -> Context 1
354        assert_eq!(plic.threshold_addr(0), 0x1020_1000);
355        // CPU 1 -> Context 3
356        assert_eq!(plic.threshold_addr(1), 0x1020_3000);
357        
358        // Test claim address for S-Mode
359        // CPU 0 -> Context 1
360        assert_eq!(plic.claim_addr(0), 0x1020_1004);
361        // CPU 1 -> Context 3
362        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        // Valid IDs should pass
370        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        // Invalid IDs should fail
376        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}