1 use core::{ 2 fmt::Debug, 3 intrinsics::unlikely, 4 mem::{self, MaybeUninit}, 5 ptr::null_mut, 6 sync::atomic::{compiler_fence, AtomicI16, Ordering}, 7 }; 8 9 use alloc::{boxed::Box, sync::Arc, vec::Vec}; 10 use num_traits::FromPrimitive; 11 use system_error::SystemError; 12 13 use crate::{ 14 arch::CurrentIrqArch, 15 exception::InterruptArch, 16 kdebug, kinfo, 17 libs::rwlock::RwLock, 18 mm::percpu::{PerCpu, PerCpuVar}, 19 process::ProcessManager, 20 smp::{core::smp_get_processor_id, cpu::ProcessorId}, 21 time::timer::clock, 22 }; 23 24 const MAX_SOFTIRQ_NUM: u64 = 64; 25 const MAX_SOFTIRQ_RESTART: i32 = 20; 26 27 static mut __CPU_PENDING: Option<Box<[VecStatus; PerCpu::MAX_CPU_NUM as usize]>> = None; 28 static mut __SORTIRQ_VECTORS: *mut Softirq = null_mut(); 29 30 #[no_mangle] 31 pub extern "C" fn rs_softirq_init() { 32 softirq_init().expect("softirq_init failed"); 33 } 34 35 #[inline(never)] 36 pub fn softirq_init() -> Result<(), SystemError> { 37 kinfo!("Initializing softirq..."); 38 unsafe { 39 __SORTIRQ_VECTORS = Box::leak(Box::new(Softirq::new())); 40 __CPU_PENDING = Some(Box::new( 41 [VecStatus::default(); PerCpu::MAX_CPU_NUM as usize], 42 )); 43 let cpu_pending = __CPU_PENDING.as_mut().unwrap(); 44 for i in 0..PerCpu::MAX_CPU_NUM { 45 cpu_pending[i as usize] = VecStatus::default(); 46 } 47 } 48 kinfo!("Softirq initialized."); 49 return Ok(()); 50 } 51 52 #[inline(always)] 53 pub fn softirq_vectors() -> &'static mut Softirq { 54 unsafe { 55 return __SORTIRQ_VECTORS.as_mut().unwrap(); 56 } 57 } 58 59 #[inline(always)] 60 fn cpu_pending(cpu_id: ProcessorId) -> &'static mut VecStatus { 61 unsafe { 62 return &mut __CPU_PENDING.as_mut().unwrap()[cpu_id.data() as usize]; 63 } 64 } 65 66 /// 软中断向量号码 67 #[allow(dead_code)] 68 #[repr(u8)] 69 #[derive(FromPrimitive, Copy, Clone, Debug, PartialEq, Eq)] 70 pub enum SoftirqNumber { 71 /// 时钟软中断信号 72 TIMER = 0, 73 VideoRefresh = 1, //帧缓冲区刷新软中断 74 } 75 76 impl From<u64> for SoftirqNumber { 77 fn from(value: u64) -> Self { 78 return <Self as FromPrimitive>::from_u64(value).unwrap(); 79 } 80 } 81 82 bitflags! { 83 #[derive(Default)] 84 pub struct VecStatus: u64 { 85 const TIMER = 1 << 0; 86 const VIDEO_REFRESH = 1 << 1; 87 } 88 } 89 90 impl From<SoftirqNumber> for VecStatus { 91 fn from(value: SoftirqNumber) -> Self { 92 return Self::from_bits_truncate(1 << (value as u64)); 93 } 94 } 95 96 pub trait SoftirqVec: Send + Sync + Debug { 97 fn run(&self); 98 } 99 100 #[derive(Debug)] 101 pub struct Softirq { 102 table: RwLock<[Option<Arc<dyn SoftirqVec>>; MAX_SOFTIRQ_NUM as usize]>, 103 /// 软中断嵌套层数(per cpu) 104 cpu_running_count: PerCpuVar<AtomicI16>, 105 } 106 impl Softirq { 107 /// 每个CPU最大嵌套的软中断数量 108 const MAX_RUNNING_PER_CPU: i16 = 3; 109 fn new() -> Softirq { 110 let mut data: [MaybeUninit<Option<Arc<dyn SoftirqVec>>>; MAX_SOFTIRQ_NUM as usize] = 111 unsafe { MaybeUninit::uninit().assume_init() }; 112 113 for i in 0..MAX_SOFTIRQ_NUM { 114 data[i as usize] = MaybeUninit::new(None); 115 } 116 117 let data: [Option<Arc<dyn SoftirqVec>>; MAX_SOFTIRQ_NUM as usize] = unsafe { 118 mem::transmute::<_, [Option<Arc<dyn SoftirqVec>>; MAX_SOFTIRQ_NUM as usize]>(data) 119 }; 120 121 let mut percpu_count = Vec::with_capacity(PerCpu::MAX_CPU_NUM as usize); 122 percpu_count.resize_with(PerCpu::MAX_CPU_NUM as usize, || AtomicI16::new(0)); 123 let cpu_running_count = PerCpuVar::new(percpu_count).unwrap(); 124 125 return Softirq { 126 table: RwLock::new(data), 127 cpu_running_count, 128 }; 129 } 130 131 fn cpu_running_count(&self) -> &PerCpuVar<AtomicI16> { 132 return &self.cpu_running_count; 133 } 134 135 /// @brief 注册软中断向量 136 /// 137 /// @param softirq_num 中断向量号 138 /// 139 /// @param hanlder 中断函数对应的结构体 140 pub fn register_softirq( 141 &self, 142 softirq_num: SoftirqNumber, 143 handler: Arc<dyn SoftirqVec>, 144 ) -> Result<i32, SystemError> { 145 // kdebug!("register_softirq softirq_num = {:?}", softirq_num as u64); 146 147 // let self = &mut SOFTIRQ_VECTORS.lock(); 148 // 判断该软中断向量是否已经被注册 149 let mut table_guard = self.table.write_irqsave(); 150 if table_guard[softirq_num as usize].is_some() { 151 // kdebug!("register_softirq failed"); 152 153 return Err(SystemError::EINVAL); 154 } 155 table_guard[softirq_num as usize] = Some(handler); 156 drop(table_guard); 157 158 // kdebug!( 159 // "register_softirq successfully, softirq_num = {:?}", 160 // softirq_num as u64 161 // ); 162 compiler_fence(Ordering::SeqCst); 163 return Ok(0); 164 } 165 166 /// @brief 解注册软中断向量 167 /// 168 /// @param irq_num 中断向量号码 169 #[allow(dead_code)] 170 pub fn unregister_softirq(&self, softirq_num: SoftirqNumber) { 171 // kdebug!("unregister_softirq softirq_num = {:?}", softirq_num as u64); 172 let mut table_guard = self.table.write_irqsave(); 173 // 将软中断向量清空 174 table_guard[softirq_num as usize] = None; 175 drop(table_guard); 176 // 将对应位置的pending和runing都置0 177 // self.running.lock().set(VecStatus::from(softirq_num), false); 178 // 将对应CPU的pending置0 179 compiler_fence(Ordering::SeqCst); 180 cpu_pending(smp_get_processor_id()).set(VecStatus::from(softirq_num), false); 181 compiler_fence(Ordering::SeqCst); 182 } 183 184 #[inline(never)] 185 pub fn do_softirq(&self) { 186 if self.cpu_running_count().get().load(Ordering::SeqCst) >= Self::MAX_RUNNING_PER_CPU { 187 // 当前CPU的软中断嵌套层数已经达到最大值,不再执行 188 return; 189 } 190 // 创建一个RunningCountGuard,当退出作用域时,会自动将cpu_running_count减1 191 let _count_guard = RunningCountGuard::new(self.cpu_running_count()); 192 193 // TODO pcb的flags未修改 194 let end = clock() + 500 * 2; 195 let cpu_id = smp_get_processor_id(); 196 let mut max_restart = MAX_SOFTIRQ_RESTART; 197 loop { 198 compiler_fence(Ordering::SeqCst); 199 let pending = cpu_pending(cpu_id).bits; 200 cpu_pending(cpu_id).bits = 0; 201 compiler_fence(Ordering::SeqCst); 202 203 unsafe { CurrentIrqArch::interrupt_enable() }; 204 if pending != 0 { 205 for i in 0..MAX_SOFTIRQ_NUM { 206 if pending & (1 << i) == 0 { 207 continue; 208 } 209 210 let table_guard = self.table.read_irqsave(); 211 let softirq_func = table_guard[i as usize].clone(); 212 drop(table_guard); 213 if softirq_func.is_none() { 214 continue; 215 } 216 217 let prev_count: usize = ProcessManager::current_pcb().preempt_count(); 218 219 softirq_func.as_ref().unwrap().run(); 220 if unlikely(prev_count != ProcessManager::current_pcb().preempt_count()) { 221 kdebug!( 222 "entered softirq {:?} with preempt_count {:?},exited with {:?}", 223 i, 224 prev_count, 225 ProcessManager::current_pcb().preempt_count() 226 ); 227 unsafe { ProcessManager::current_pcb().set_preempt_count(prev_count) }; 228 } 229 } 230 } 231 unsafe { CurrentIrqArch::interrupt_disable() }; 232 max_restart -= 1; 233 compiler_fence(Ordering::SeqCst); 234 if cpu_pending(cpu_id).is_empty() { 235 compiler_fence(Ordering::SeqCst); 236 if clock() < end && max_restart > 0 { 237 continue; 238 } else { 239 break; 240 } 241 } else { 242 // TODO:当有softirqd时 唤醒它 243 break; 244 } 245 } 246 } 247 248 pub fn raise_softirq(&self, softirq_num: SoftirqNumber) { 249 let guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; 250 let processor_id = smp_get_processor_id(); 251 252 cpu_pending(processor_id).insert(VecStatus::from(softirq_num)); 253 254 compiler_fence(Ordering::SeqCst); 255 256 drop(guard); 257 // kdebug!("raise_softirq exited"); 258 } 259 260 #[allow(dead_code)] 261 pub unsafe fn clear_softirq_pending(&self, softirq_num: SoftirqNumber) { 262 compiler_fence(Ordering::SeqCst); 263 cpu_pending(smp_get_processor_id()).remove(VecStatus::from(softirq_num)); 264 compiler_fence(Ordering::SeqCst); 265 } 266 } 267 268 /// 当前CPU的软中断嵌套层数的计数器守卫 269 /// 270 /// 当进入作用域时,会自动将cpu_running_count加1, 271 /// 当退出作用域时,会自动将cpu_running_count减1 272 struct RunningCountGuard<'a> { 273 cpu_running_count: &'a PerCpuVar<AtomicI16>, 274 } 275 276 impl<'a> RunningCountGuard<'a> { 277 fn new(cpu_running_count: &'a PerCpuVar<AtomicI16>) -> RunningCountGuard { 278 cpu_running_count.get().fetch_add(1, Ordering::SeqCst); 279 return RunningCountGuard { cpu_running_count }; 280 } 281 } 282 283 impl<'a> Drop for RunningCountGuard<'a> { 284 fn drop(&mut self) { 285 self.cpu_running_count.get().fetch_sub(1, Ordering::SeqCst); 286 } 287 } 288 289 pub fn do_softirq() { 290 softirq_vectors().do_softirq(); 291 } 292