kernel/drivers/pic/
sbi_clint.rs1use core::arch::asm;
6
7use alloc::boxed::Box;
8
9use crate::{
10 early_initcall,
11 interrupt::{
12 CpuId, InterruptError, InterruptManager, InterruptResult,
13 controllers::{LocalInterruptController, LocalInterruptType},
14 },
15};
16
17struct SbiClint {
18 max_cpus: usize,
19 timebase_frequency_hz: u64,
20}
21
22impl SbiClint {
23 fn validate_cpu_id(&self, cpu_id: CpuId) -> InterruptResult<()> {
25 if cpu_id as usize >= self.max_cpus {
26 Err(InterruptError::InvalidCpuId)
27 } else {
28 Ok(())
29 }
30 }
31}
32
33impl LocalInterruptController for SbiClint {
34 fn init(&mut self, cpu_id: CpuId) -> InterruptResult<()> {
36 self.validate_cpu_id(cpu_id)?;
37
38 self.clear_software_interrupt(cpu_id)?;
40
41 self.set_timer(cpu_id, u64::MAX)?;
43
44 Ok(())
45 }
46
47 fn enable_interrupt(
49 &mut self,
50 _cpu_id: CpuId,
51 interrupt_type: LocalInterruptType,
52 ) -> InterruptResult<()> {
53 match interrupt_type {
54 LocalInterruptType::Timer => {
55 Ok(())
58 }
59 LocalInterruptType::Software => {
60 Ok(())
63 }
64 LocalInterruptType::External => {
65 Err(InterruptError::NotSupported)
67 }
68 }
69 }
70
71 fn disable_interrupt(
73 &mut self,
74 cpu_id: CpuId,
75 interrupt_type: LocalInterruptType,
76 ) -> InterruptResult<()> {
77 match interrupt_type {
78 LocalInterruptType::Timer => {
79 self.set_timer(cpu_id, u64::MAX)
81 }
82 LocalInterruptType::Software => {
83 self.clear_software_interrupt(cpu_id)
85 }
86 LocalInterruptType::External => {
87 Err(InterruptError::NotSupported)
89 }
90 }
91 }
92
93 fn is_pending(&self, cpu_id: CpuId, interrupt_type: LocalInterruptType) -> bool {
95 if self.validate_cpu_id(cpu_id).is_err() {
96 return false;
97 }
98
99 match interrupt_type {
100 LocalInterruptType::Timer => false,
101 LocalInterruptType::Software => false,
102 LocalInterruptType::External => false, }
104 }
105
106 fn clear_interrupt(
108 &mut self,
109 cpu_id: CpuId,
110 interrupt_type: LocalInterruptType,
111 ) -> InterruptResult<()> {
112 self.validate_cpu_id(cpu_id)?;
113
114 match interrupt_type {
115 LocalInterruptType::Timer => {
116 let current_time = self.get_time();
118 self.set_timer(cpu_id, current_time + 1000000) }
120 LocalInterruptType::Software => self.clear_software_interrupt(cpu_id),
121 LocalInterruptType::External => Err(InterruptError::NotSupported),
122 }
123 }
124
125 fn send_software_interrupt(&mut self, _target_cpu: CpuId) -> InterruptResult<()> {
127 Ok(())
128 }
129
130 fn clear_software_interrupt(&mut self, _cpu_id: CpuId) -> InterruptResult<()> {
132 Ok(())
143 }
144
145 fn set_timer(&mut self, cpu_id: CpuId, time: u64) -> InterruptResult<()> {
147 self.validate_cpu_id(cpu_id)?;
148
149 crate::arch::riscv64::instruction::sbi::sbi_set_timer(time);
151
152 Ok(())
153 }
154
155 fn get_time(&self) -> u64 {
157 let time: u64;
158 unsafe {
159 asm!(
160 "rdtime {0}",
161 out(reg) time,
162 );
163 }
164 time
165 }
166
167 fn get_timer_frequency_hz(&self) -> u64 {
168 self.timebase_frequency_hz
169 }
170}
171
172unsafe impl Send for SbiClint {}
173unsafe impl Sync for SbiClint {}
174
175fn register_driver() {
176 let timebase_frequency_hz =
180 crate::arch::riscv64::fdt::timebase_frequency_hz_from_fdt().unwrap_or(10_000_000);
181
182 let mut controller = Box::new(SbiClint {
184 max_cpus: 4,
185 timebase_frequency_hz,
186 });
187
188 if let Err(e) = controller.init(0) {
189 crate::early_println!(
190 "[interrupt] Failed to initialize CLINT for CPU {}: {}",
191 0,
192 e
193 );
194 }
195
196 match InterruptManager::global()
198 .lock()
199 .register_local_controller_for_range(controller, 0..4)
200 {
201 Ok(_) => {}
202 Err(e) => {
203 crate::early_println!("[interrupt] Failed to register CLINT: {}", e);
204 }
205 }
206}
207
208early_initcall!(register_driver);