kernel/drivers/pic/
clint.rs1use crate::{device::{manager::{DeviceManager, DriverPriority}, platform::{resource::PlatformDeviceResourceType, PlatformDeviceDriver, PlatformDeviceInfo}}, driver_initcall, interrupt::{
7 controllers::{LocalInterruptController, LocalInterruptType}, CpuId, InterruptError, InterruptManager, InterruptResult
8}};
9use alloc::{boxed::Box, vec};
10use core::ptr::{read_volatile, write_volatile};
11
12const CLINT_MSIP_OFFSET: usize = 0x0000; const CLINT_MTIMECMP_OFFSET: usize = 0x4000; const CLINT_MTIME_OFFSET: usize = 0xBFF8; const CLINT_MSIP_STRIDE: usize = 4;
19const CLINT_MTIMECMP_STRIDE: usize = 8;
20
21const MAX_CPUS: CpuId = 4095;
23
24pub struct Clint {
26 base_addr: usize,
28 max_cpus: CpuId,
30}
31
32impl Clint {
33 pub fn new(base_addr: usize, max_cpus: CpuId) -> Self {
43 Self {
44 base_addr,
45 max_cpus: max_cpus.min(MAX_CPUS),
46 }
47 }
48
49 fn msip_addr(&self, cpu_id: CpuId) -> usize {
51 self.base_addr + CLINT_MSIP_OFFSET + (cpu_id as usize * CLINT_MSIP_STRIDE)
52 }
53
54 fn mtimecmp_addr(&self, cpu_id: CpuId) -> usize {
56 self.base_addr + CLINT_MTIMECMP_OFFSET + (cpu_id as usize * CLINT_MTIMECMP_STRIDE)
57 }
58
59 fn mtime_addr(&self) -> usize {
61 self.base_addr + CLINT_MTIME_OFFSET
62 }
63
64 fn validate_cpu_id(&self, cpu_id: CpuId) -> InterruptResult<()> {
66 if cpu_id >= self.max_cpus {
67 Err(InterruptError::InvalidCpuId)
68 } else {
69 Ok(())
70 }
71 }
72}
73
74impl LocalInterruptController for Clint {
75 fn init(&mut self, cpu_id: CpuId) -> InterruptResult<()> {
77 self.validate_cpu_id(cpu_id)?;
78
79 self.clear_software_interrupt(cpu_id)?;
81
82 self.set_timer(cpu_id, u64::MAX)?;
84
85 Ok(())
86 }
87
88 fn enable_interrupt(&mut self, cpu_id: CpuId, interrupt_type: LocalInterruptType) -> InterruptResult<()> {
90 self.validate_cpu_id(cpu_id)?;
91
92 match interrupt_type {
93 LocalInterruptType::Timer => {
94 Ok(())
97 }
98 LocalInterruptType::Software => {
99 Ok(())
102 }
103 LocalInterruptType::External => {
104 Err(InterruptError::NotSupported)
106 }
107 }
108 }
109
110 fn disable_interrupt(&mut self, cpu_id: CpuId, interrupt_type: LocalInterruptType) -> InterruptResult<()> {
112 self.validate_cpu_id(cpu_id)?;
113
114 match interrupt_type {
115 LocalInterruptType::Timer => {
116 self.set_timer(cpu_id, u64::MAX)
118 }
119 LocalInterruptType::Software => {
120 self.clear_software_interrupt(cpu_id)
122 }
123 LocalInterruptType::External => {
124 Err(InterruptError::NotSupported)
126 }
127 }
128 }
129
130 fn is_pending(&self, cpu_id: CpuId, interrupt_type: LocalInterruptType) -> bool {
132 if self.validate_cpu_id(cpu_id).is_err() {
133 return false;
134 }
135
136 match interrupt_type {
137 LocalInterruptType::Timer => {
138 let current_time = self.get_time();
139 let compare_time = unsafe {
140 read_volatile(self.mtimecmp_addr(cpu_id) as *const u64)
141 };
142 current_time >= compare_time
143 }
144 LocalInterruptType::Software => {
145 let msip = unsafe {
146 read_volatile(self.msip_addr(cpu_id) as *const u32)
147 };
148 (msip & 1) != 0
149 }
150 LocalInterruptType::External => false, }
152 }
153
154 fn clear_interrupt(&mut self, cpu_id: CpuId, interrupt_type: LocalInterruptType) -> InterruptResult<()> {
156 self.validate_cpu_id(cpu_id)?;
157
158 match interrupt_type {
159 LocalInterruptType::Timer => {
160 let current_time = self.get_time();
162 self.set_timer(cpu_id, current_time + 1000000) }
164 LocalInterruptType::Software => {
165 self.clear_software_interrupt(cpu_id)
166 }
167 LocalInterruptType::External => {
168 Err(InterruptError::NotSupported)
169 }
170 }
171 }
172
173 fn send_software_interrupt(&mut self, target_cpu: CpuId) -> InterruptResult<()> {
175 self.validate_cpu_id(target_cpu)?;
176
177 let addr = self.msip_addr(target_cpu);
178 unsafe {
179 write_volatile(addr as *mut u32, 1);
180 }
181
182 Ok(())
183 }
184
185 fn clear_software_interrupt(&mut self, cpu_id: CpuId) -> InterruptResult<()> {
187 Ok(())
198 }
199
200 fn set_timer(&mut self, cpu_id: CpuId, time: u64) -> InterruptResult<()> {
202 self.validate_cpu_id(cpu_id)?;
203
204 crate::arch::riscv64::instruction::sbi::sbi_set_timer(time);
206
207 Ok(())
208 }
209
210 fn get_time(&self) -> u64 {
212 unsafe {
213 read_volatile(self.mtime_addr() as *const u64)
214 }
215 }
216}
217
218unsafe impl Send for Clint {}
219unsafe impl Sync for Clint {}
220
221fn probe_fn(device: &PlatformDeviceInfo) -> Result<(), &'static str> {
222 let res = device.get_resources();
223 if res.is_empty() {
224 return Err("No resources found");
225 }
226
227 let mem_res = res.iter()
229 .find(|r| r.res_type == PlatformDeviceResourceType::MEM)
230 .ok_or("Memory resource not found")?;
231
232 let base_addr = mem_res.start as usize;
233
234 let mut controller = Box::new(Clint::new(base_addr, 4)); if let Err(e) = controller.init(0) {
239 crate::early_println!("[interrupt] Failed to initialize CLINT for CPU {}: {}", 0, e);
240 return Err("Failed to initialize CLINT");
241 }
242
243 match InterruptManager::global().lock().register_local_controller_for_range(controller, 0..4) {
245 Ok(_) => {
246 crate::early_println!("[interrupt] CLINT registered at base address: {:#x}", base_addr);
247 },
248 Err(e) => {
249 crate::early_println!("[interrupt] Failed to register CLINT: {}", e);
250 return Err("Failed to register CLINT");
251 }
252 }
253
254 Ok(())
255}
256
257fn remove_fn(_device: &PlatformDeviceInfo) -> Result<(), &'static str> {
258 Ok(())
259}
260
261fn register_driver() {
262 let driver = PlatformDeviceDriver::new(
263 "riscv-clint",
264 probe_fn,
265 remove_fn,
266 vec!["sifive,clint0", "riscv,clint0"],
267 );
268 DeviceManager::get_mut_manager().register_driver(Box::new(driver), DriverPriority::Critical);
270}
271
272driver_initcall!(register_driver);
273
274
275#[cfg(test)]
276mod tests {
277 use super::*;
278
279 #[test_case]
280 fn test_clint_creation() {
281 let clint = Clint::new(0x200_0000, 4);
282 assert_eq!(clint.max_cpus, 4);
283 }
284
285 #[test_case]
286 fn test_address_calculation() {
287 let clint = Clint::new(0x200_0000, 4);
288
289 assert_eq!(clint.msip_addr(0), 0x200_0000);
291 assert_eq!(clint.msip_addr(1), 0x200_0004);
292 assert_eq!(clint.msip_addr(3), 0x200_000C);
293
294 assert_eq!(clint.mtimecmp_addr(0), 0x200_4000);
296 assert_eq!(clint.mtimecmp_addr(1), 0x200_4008);
297 assert_eq!(clint.mtimecmp_addr(3), 0x200_4018);
298
299 assert_eq!(clint.mtime_addr(), 0x200_BFF8);
301 }
302
303 #[test_case]
304 fn test_different_base_address() {
305 let clint = Clint::new(0x300_0000, 4);
307
308 assert_eq!(clint.msip_addr(0), 0x300_0000);
310 assert_eq!(clint.msip_addr(1), 0x300_0004);
311
312 assert_eq!(clint.mtimecmp_addr(0), 0x300_4000);
314 assert_eq!(clint.mtimecmp_addr(1), 0x300_4008);
315
316 assert_eq!(clint.mtime_addr(), 0x300_BFF8);
318 }
319
320 #[test_case]
321 fn test_validation() {
322 let clint = Clint::new(0x200_0000, 4);
323
324 assert!(clint.validate_cpu_id(0).is_ok());
326 assert!(clint.validate_cpu_id(3).is_ok());
327
328 assert!(clint.validate_cpu_id(4).is_err());
330 assert!(clint.validate_cpu_id(100).is_err());
331 }
332}