use core::{ffi::c_void, ptr::null_mut}; use alloc::boxed::Box; use crate::{ arch::interrupt::{cli, sti}, include::bindings::bindings::{verify_area, EBUSY, EEXIST, EPERM}, kBUG, libs::spinlock::RawSpinlock, }; const MAX_SOFTIRQ_NUM: u64 = 64; const MAX_LOCK_TRIAL_TIME: u64 = 50; pub static mut SOFTIRQ_HANDLER_PTR: *mut Softirq = null_mut(); /// 软中断向量号码 #[allow(dead_code)] #[repr(u8)] pub enum SoftirqNumber { TIMER = 0, //时钟软中断信号 VideoRefresh = 1, //帧缓冲区刷新软中断 } #[repr(C)] #[derive(Clone, Copy)] pub struct SoftirqVector { pub action: Option, //软中断处理函数 pub data: *mut c_void, } impl Default for SoftirqVector { fn default() -> Self { Self { action: None, data: null_mut(), } } } pub struct Softirq { modify_lock: RawSpinlock, pending: u64, running: u64, table: [SoftirqVector; MAX_SOFTIRQ_NUM as usize], } #[no_mangle] #[allow(dead_code)] /// @brief 提供给c的接口函数,用于初始化静态指针 pub extern "C" fn softirq_init() { if unsafe { SOFTIRQ_HANDLER_PTR.is_null() } { unsafe { SOFTIRQ_HANDLER_PTR = Box::leak(Box::new(Softirq::default())); } } else { kBUG!("Try to init SOFTIRQ_HANDLER_PTR twice."); panic!("Try to init SOFTIRQ_HANDLER_PTR twice."); } } /// @brief 将raw pointer转换为指针,减少unsafe块 #[inline] pub fn __get_softirq_handler_mut() -> &'static mut Softirq { return unsafe { SOFTIRQ_HANDLER_PTR.as_mut().unwrap() }; } #[no_mangle] #[allow(dead_code)] pub extern "C" fn raise_softirq(sirq_num: u64) { let softirq_handler = __get_softirq_handler_mut(); softirq_handler.set_softirq_pending(1 << sirq_num); } /// @brief 软中断注册函数 /// /// @param irq_num 软中断号 /// @param action 响应函数 /// @param data 响应数据结构体 #[no_mangle] #[allow(dead_code)] pub extern "C" fn register_softirq( irq_num: u32, action: Option, data: *mut c_void, ) { let softirq_handler = __get_softirq_handler_mut(); softirq_handler.register_softirq(irq_num, action, data); } /// @brief 卸载软中断 /// @param irq_num 软中断号 #[no_mangle] #[allow(dead_code)] pub extern "C" fn unregister_softirq(irq_num: u32) { let softirq_handler = __get_softirq_handler_mut(); softirq_handler.unregister_softirq(irq_num); } /// 设置软中断的运行状态(只应在do_softirq中调用此宏) #[no_mangle] #[allow(dead_code)] pub extern "C" fn set_softirq_pending(irq_num: u32) { let softirq_handler = __get_softirq_handler_mut(); softirq_handler.set_softirq_pending(irq_num); } /// @brief 设置软中断运行结束 /// /// @param softirq_num #[no_mangle] #[allow(dead_code)] pub extern "C" fn clear_softirq_pending(irq_num: u32) { let softirq_handler = __get_softirq_handler_mut(); softirq_handler.clear_softirq_pending(irq_num); } /// @brief 软中断处理程序 #[no_mangle] #[allow(dead_code)] pub extern "C" fn do_softirq() { let softirq_handler = __get_softirq_handler_mut(); softirq_handler.do_softirq(); } impl Default for Softirq { fn default() -> Self { Self { modify_lock: RawSpinlock::INIT, pending: (0), running: (0), table: [Default::default(); MAX_SOFTIRQ_NUM as usize], } } } impl Softirq { #[inline] #[allow(dead_code)] pub fn get_softirq_pending(&self) -> u64 { return self.pending; } #[inline] #[allow(dead_code)] pub fn get_softirq_running(&self) -> u64 { return self.running; } #[inline] pub fn set_softirq_pending(&mut self, softirq_num: u32) { self.pending |= 1 << softirq_num; } #[inline] pub fn set_softirq_running(&mut self, softirq_num: u32) { self.running |= 1 << softirq_num; } #[inline] pub fn clear_softirq_running(&mut self, softirq_num: u32) { self.running &= !(1 << softirq_num); } /// @brief 清除软中断pending标志位 #[inline] pub fn clear_softirq_pending(&mut self, softirq_num: u32) { self.pending &= !(1 << softirq_num); } /// @brief 判断对应running标志位是否为0 /// @return true: 标志位为1; false: 标志位为0 #[inline] pub fn is_running(&mut self, softirq_num: u32) -> bool { return (self.running & (1 << softirq_num)).ne(&0); } /// @brief 判断对应pending标志位是否为0 /// @return true: 标志位为1; false: 标志位为0 #[inline] pub fn is_pending(&mut self, softirq_num: u32) -> bool { return (self.pending & (1 << softirq_num)).ne(&0); } /// @brief 注册软中断向量 /// @param irq_num 中断向量号码 /// @param action 中断函数的入口地址 /// @param data 中断函数的操作数据 pub fn register_softirq( &mut self, irq_num: u32, action: Option, data: *mut c_void, ) -> i32 { if self.table[irq_num as usize].action.is_some() { return -(EEXIST as i32); } if unsafe { verify_area(action.unwrap() as u64, 1) } { return -(EPERM as i32); } self.modify_lock.lock(); self.table[irq_num as usize].action = action; self.table[irq_num as usize].data = data; self.modify_lock.unlock(); return 0; } /// @brief 解注册软中断向量 /// @param irq_num 中断向量号码 pub fn unregister_softirq(&mut self, irq_num: u32) -> i32 { for _trial_time in 0..MAX_LOCK_TRIAL_TIME { if self.is_running(irq_num) { continue; //running标志位为1 } if self.modify_lock.try_lock() { if self.is_running(irq_num) { self.modify_lock.unlock(); continue; } break; } } // 存在尝试加锁规定次数后仍加锁失败的情况,报告错误并退出 if !self.modify_lock.is_locked() { return -(EBUSY as i32); } self.clear_softirq_running(irq_num); self.clear_softirq_pending(irq_num); self.table[irq_num as usize].action = None; self.table[irq_num as usize].data = null_mut(); self.modify_lock.unlock(); return 0; } /// @brief 遍历执行软中断 pub fn do_softirq(&mut self) { sti(); let mut softirq_index: u32 = 0; //软中断向量号码 while (softirq_index as u64) < MAX_SOFTIRQ_NUM && self.pending != 0 { if self.is_pending(softirq_index) && self.table[softirq_index as usize].action.is_some() && !self.is_running(softirq_index) { if self.modify_lock.try_lock() { if self.is_running(softirq_index) || self.table[softirq_index as usize].action.is_none() { self.modify_lock.unlock(); continue; } self.clear_softirq_pending(softirq_index); self.set_softirq_running(softirq_index); self.modify_lock.unlock(); unsafe { (self.table[softirq_index as usize].action.unwrap())( self.table[softirq_index as usize].data, ); } self.clear_softirq_running(softirq_index); } } softirq_index += 1; } cli(); } }