Browse Source

初始化riscv-sbi-timer (#716)

LoGin 11 months ago
parent
commit
f049d1af01

+ 6 - 6
kernel/src/arch/riscv64/interrupt/handle.rs

@@ -5,7 +5,10 @@ use core::hint::spin_loop;
 
 use system_error::SystemError;
 
-use crate::{arch::syscall::syscall_handler, kdebug, kerror};
+use crate::{
+    arch::syscall::syscall_handler, driver::irqchip::riscv_intc::riscv_intc_irq,
+    exception::HardwareIrqNumber, kdebug, kerror,
+};
 
 use super::TrapFrame;
 
@@ -40,11 +43,8 @@ unsafe extern "C" fn riscv64_do_irq(trap_frame: &mut TrapFrame) {
 }
 
 /// 处理中断
-fn riscv64_do_interrupt(_trap_frame: &mut TrapFrame) {
-    kdebug!("todo: riscv64_do_irq: interrupt");
-    loop {
-        spin_loop();
-    }
+fn riscv64_do_interrupt(trap_frame: &mut TrapFrame) {
+    riscv_intc_irq(trap_frame);
 }
 
 /// 处理异常

+ 5 - 1
kernel/src/arch/riscv64/process/idle.rs

@@ -1,6 +1,8 @@
 use core::hint::spin_loop;
 
-use crate::{arch::CurrentIrqArch, exception::InterruptArch, kBUG, process::ProcessManager};
+use crate::{
+    arch::CurrentIrqArch, exception::InterruptArch, kBUG, kdebug, process::ProcessManager,
+};
 
 impl ProcessManager {
     /// 每个核的idle进程
@@ -14,6 +16,8 @@ impl ProcessManager {
                 kBUG!("Idle process should not be scheduled with IRQs disabled.");
                 spin_loop();
             }
+
+            kdebug!("idle loop");
         }
     }
 }

+ 17 - 2
kernel/src/arch/riscv64/process/mod.rs

@@ -18,7 +18,7 @@ use crate::{
         CurrentIrqArch,
     },
     exception::InterruptArch,
-    kerror,
+    kdebug, kerror,
     libs::spinlock::SpinLockGuard,
     mm::VirtAddr,
     process::{
@@ -127,14 +127,22 @@ impl ProcessManager {
     /// 参考: https://code.dragonos.org.cn/xref/linux-6.6.21/arch/riscv/include/asm/switch_to.h#76
     pub unsafe fn switch_process(prev: Arc<ProcessControlBlock>, next: Arc<ProcessControlBlock>) {
         assert!(!CurrentIrqArch::is_irq_enabled());
+        kdebug!(
+            "riscv switch process: prev: {:?}, next: {:?}",
+            prev.pid(),
+            next.pid()
+        );
         Self::switch_process_fpu(&prev, &next);
+        kdebug!("riscv switch process: after switch_process_fpu");
         Self::switch_local_context(&prev, &next);
+        kdebug!("riscv switch process: after switch_local_context");
 
         // 切换地址空间
         let next_addr_space = next.basic().user_vm().as_ref().unwrap().clone();
         compiler_fence(Ordering::SeqCst);
 
         next_addr_space.read().user_mapper.utable.make_current();
+        kdebug!("riscv switch process: after switch addr space");
         drop(next_addr_space);
         compiler_fence(Ordering::SeqCst);
 
@@ -147,7 +155,7 @@ impl ProcessManager {
         ProcessManager::current_pcb().preempt_enable();
         PROCESS_SWITCH_RESULT.as_mut().unwrap().get_mut().prev_pcb = Some(prev);
         PROCESS_SWITCH_RESULT.as_mut().unwrap().get_mut().next_pcb = Some(next);
-        // kdebug!("switch tss ok");
+        kdebug!("riscv switch process: before to inner");
         compiler_fence(Ordering::SeqCst);
         // 正式切换上下文
         switch_to_inner(prev_arch, next_arch);
@@ -244,7 +252,14 @@ unsafe extern "C" fn switch_to_inner(prev: *mut ArchPCBInfo, next: *mut ArchPCBI
 
 /// 在切换上下文完成后的钩子函数(必须在这里加一个跳转函数,否则会出现relocation truncated to fit: R_RISCV_JAL错误)
 unsafe extern "C" fn before_switch_finish_hook() {
+    let pcb = ProcessManager::current_pcb();
+    kdebug!(
+        "before_switch_finish_hook, pid: {:?}, name: {:?}",
+        pcb.pid(),
+        pcb.basic().name()
+    );
     switch_finish_hook();
+    kdebug!("after switch_finish_hook");
 }
 
 impl ProcessControlBlock {

+ 9 - 5
kernel/src/arch/riscv64/sched.rs

@@ -1,4 +1,9 @@
-use crate::sched::SchedArch;
+use crate::{
+    driver::clocksource::timer_riscv::riscv_sbi_timer_init_local, exception::InterruptArch,
+    sched::SchedArch,
+};
+
+use super::CurrentIrqArch;
 
 /// 发起调度
 #[no_mangle]
@@ -10,14 +15,13 @@ pub struct RiscV64SchedArch;
 
 impl SchedArch for RiscV64SchedArch {
     fn enable_sched_local() {
-        todo!()
+        riscv_sbi_timer_init_local();
+        unsafe { CurrentIrqArch::interrupt_enable() };
     }
 
     fn disable_sched_local() {
         todo!()
     }
 
-    fn initial_setup_sched_local() {
-        todo!()
-    }
+    fn initial_setup_sched_local() {}
 }

+ 4 - 0
kernel/src/arch/riscv64/time.rs

@@ -64,3 +64,7 @@ impl TimeArch for RiscV64TimeArch {
         cycles * 1000000000 / unsafe { TIME_FREQ }
     }
 }
+
+pub fn riscv_time_base_freq() -> usize {
+    unsafe { TIME_FREQ }
+}

+ 2 - 0
kernel/src/driver/clocksource/mod.rs

@@ -0,0 +1,2 @@
+#[cfg(target_arch = "riscv64")]
+pub mod timer_riscv;

+ 131 - 0
kernel/src/driver/clocksource/timer_riscv.rs

@@ -0,0 +1,131 @@
+use core::sync::atomic::{fence, Ordering};
+
+use alloc::{string::ToString, sync::Arc};
+use bitmap::{traits::BitMapOps, StaticBitmap};
+use system_error::SystemError;
+
+use crate::{
+    arch::{interrupt::TrapFrame, time::riscv_time_base_freq, CurrentIrqArch, CurrentTimeArch},
+    driver::base::device::DeviceId,
+    exception::{
+        irqdata::{IrqHandlerData, IrqLineStatus},
+        irqdesc::{
+            irq_desc_manager, IrqDesc, IrqFlowHandler, IrqHandleFlags, IrqHandler, IrqReturn,
+        },
+        manage::irq_manager,
+        InterruptArch, IrqNumber,
+    },
+    libs::spinlock::SpinLock,
+    mm::percpu::PerCpu,
+    process::ProcessManager,
+    smp::core::smp_get_processor_id,
+    time::TimeArch,
+};
+
+pub struct RiscVSbiTimer;
+
+static SBI_TIMER_INIT_BMP: SpinLock<StaticBitmap<{ PerCpu::MAX_CPU_NUM as usize }>> =
+    SpinLock::new(StaticBitmap::new());
+
+static mut INTERVAL_CNT: usize = 0;
+
+impl RiscVSbiTimer {
+    pub const TIMER_IRQ: IrqNumber = IrqNumber::from(5);
+
+    fn handle_irq(trap_frame: &mut TrapFrame) -> Result<(), SystemError> {
+        // 更新下一次中断时间
+        kdebug!(
+            "riscv_sbi_timer: handle_irq: cpu_id: {}, time: {}",
+            smp_get_processor_id().data(),
+            CurrentTimeArch::get_cycles() as u64
+        );
+        sbi_rt::set_timer(CurrentTimeArch::get_cycles() as u64 + unsafe { INTERVAL_CNT } as u64);
+        ProcessManager::update_process_times(trap_frame.is_from_user());
+        Ok(())
+    }
+
+    fn enable() {
+        unsafe { riscv::register::sie::set_stimer() };
+    }
+
+    fn disable() {
+        unsafe { riscv::register::sie::clear_stimer() };
+    }
+}
+
+/// riscv 初始化本地调度时钟源
+#[inline(never)]
+pub fn riscv_sbi_timer_init_local() {
+    assert_eq!(CurrentIrqArch::is_irq_enabled(), false);
+
+    if unsafe { INTERVAL_CNT } == 0 {
+        // todo: 将来正式实现时,需要除以HZ
+        let new = riscv_time_base_freq();
+        if new == 0 {
+            panic!("riscv_sbi_timer_init: failed to get timebase-frequency");
+        }
+        unsafe {
+            INTERVAL_CNT = new;
+        }
+    }
+
+    let mut guard = SBI_TIMER_INIT_BMP.lock();
+    // 如果已经初始化过了,直接返回。或者cpu id不存在
+    if guard
+        .get(smp_get_processor_id().data() as usize)
+        .unwrap_or(true)
+    {
+        return;
+    }
+
+    irq_manager()
+        .request_irq(
+            RiscVSbiTimer::TIMER_IRQ,
+            "riscv_clocksource".to_string(),
+            &RiscvSbiTimerHandler,
+            IrqHandleFlags::IRQF_SHARED | IrqHandleFlags::IRQF_PERCPU,
+            Some(DeviceId::new(Some("riscv sbi timer"), None).unwrap()),
+        )
+        .expect("Apic timer init failed");
+
+    // 设置第一次中断
+    sbi_rt::set_timer(CurrentTimeArch::get_cycles() as u64);
+
+    RiscVSbiTimer::enable();
+    guard
+        .set(smp_get_processor_id().data() as usize, true)
+        .unwrap();
+}
+
+#[inline(never)]
+pub fn riscv_sbi_timer_irq_desc_init() {
+    let desc = irq_desc_manager().lookup(RiscVSbiTimer::TIMER_IRQ).unwrap();
+
+    desc.modify_status(IrqLineStatus::IRQ_LEVEL, IrqLineStatus::empty());
+    desc.set_handler(&RiscvSbiTimerIrqFlowHandler);
+}
+
+#[derive(Debug)]
+struct RiscvSbiTimerHandler;
+
+impl IrqHandler for RiscvSbiTimerHandler {
+    fn handle(
+        &self,
+        _irq: IrqNumber,
+        _static_data: Option<&dyn IrqHandlerData>,
+        _dynamic_data: Option<Arc<dyn IrqHandlerData>>,
+    ) -> Result<IrqReturn, SystemError> {
+        // empty (只是为了让编译通过,不会被调用到。真正的处理函数在 RiscvSbiTimerIrqFlowHandler 中)
+        Ok(IrqReturn::NotHandled)
+    }
+}
+
+#[derive(Debug)]
+struct RiscvSbiTimerIrqFlowHandler;
+
+impl IrqFlowHandler for RiscvSbiTimerIrqFlowHandler {
+    fn handle(&self, _irq_desc: &Arc<IrqDesc>, trap_frame: &mut TrapFrame) {
+        RiscVSbiTimer::handle_irq(trap_frame).unwrap();
+        fence(Ordering::SeqCst)
+    }
+}

+ 51 - 14
kernel/src/driver/irqchip/riscv_intc.rs

@@ -1,13 +1,19 @@
 use alloc::{string::ToString, sync::Arc};
 use system_error::SystemError;
 
-use crate::exception::{
-    handle::PerCpuDevIdIrqHandler,
-    irqchip::{IrqChip, IrqChipFlags},
-    irqdata::IrqData,
-    irqdesc::irq_desc_manager,
-    irqdomain::{irq_domain_manager, IrqDomain, IrqDomainOps},
-    HardwareIrqNumber, IrqNumber,
+use crate::{
+    arch::interrupt::TrapFrame,
+    driver::clocksource::timer_riscv::{riscv_sbi_timer_irq_desc_init, RiscVSbiTimer},
+    exception::{
+        handle::PerCpuDevIdIrqHandler,
+        irqchip::{IrqChip, IrqChipFlags},
+        irqdata::IrqData,
+        irqdesc::{irq_desc_manager, GenericIrqHandler},
+        irqdomain::{irq_domain_manager, IrqDomain, IrqDomainOps},
+        HardwareIrqNumber, IrqNumber,
+    },
+    libs::spinlock::{SpinLock, SpinLockGuard},
+    sched::{SchedMode, __schedule},
 };
 
 static mut RISCV_INTC_DOMAIN: Option<Arc<IrqDomain>> = None;
@@ -24,7 +30,9 @@ fn riscv_intc_chip() -> Option<&'static Arc<RiscvIntcChip>> {
 }
 
 #[derive(Debug)]
-struct RiscvIntcChip;
+struct RiscvIntcChip {
+    inner: SpinLock<InnerIrqChip>,
+}
 
 impl IrqChip for RiscvIntcChip {
     fn name(&self) -> &'static str {
@@ -43,9 +51,7 @@ impl IrqChip for RiscvIntcChip {
         Ok(())
     }
 
-    fn irq_ack(&self, irq: &Arc<IrqData>) {
-        todo!()
-    }
+    fn irq_ack(&self, _irq: &Arc<IrqData>) {}
 
     fn can_mask_ack(&self) -> bool {
         false
@@ -75,10 +81,28 @@ impl IrqChip for RiscvIntcChip {
     }
 
     fn flags(&self) -> IrqChipFlags {
-        todo!()
+        self.inner().flags
+    }
+}
+
+impl RiscvIntcChip {
+    fn new() -> Self {
+        Self {
+            inner: SpinLock::new(InnerIrqChip {
+                flags: IrqChipFlags::empty(),
+            }),
+        }
+    }
+    fn inner(&self) -> SpinLockGuard<InnerIrqChip> {
+        self.inner.lock_irqsave()
     }
 }
 
+#[derive(Debug)]
+struct InnerIrqChip {
+    flags: IrqChipFlags,
+}
+
 #[derive(Debug)]
 struct RiscvIntcDomainOps;
 
@@ -104,14 +128,14 @@ impl IrqDomainOps for RiscvIntcDomainOps {
         return Ok(());
     }
 
-    fn unmap(&self, irq_domain: &Arc<IrqDomain>, virq: IrqNumber) {
+    fn unmap(&self, _irq_domain: &Arc<IrqDomain>, _virq: IrqNumber) {
         todo!("riscv_intc_domain_ops::unmap");
     }
 }
 
 #[inline(never)]
 pub unsafe fn riscv_intc_init() -> Result<(), SystemError> {
-    let intc_chip = Arc::new(RiscvIntcChip);
+    let intc_chip = Arc::new(RiscvIntcChip::new());
 
     unsafe {
         RISCV_INTC_CHIP = Some(intc_chip);
@@ -130,5 +154,18 @@ pub unsafe fn riscv_intc_init() -> Result<(), SystemError> {
         RISCV_INTC_DOMAIN = Some(intc_domain);
     }
 
+    riscv_sbi_timer_irq_desc_init();
+
     return Ok(());
 }
+
+/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-riscv-intc.c#23
+pub fn riscv_intc_irq(trap_frame: &mut TrapFrame) {
+    let hwirq = HardwareIrqNumber::new(trap_frame.cause.code() as u32);
+    kdebug!("riscv64_do_irq: interrupt {hwirq:?}");
+    GenericIrqHandler::handle_domain_irq(riscv_intc_domain().clone().unwrap(), hwirq, trap_frame)
+        .ok();
+    if hwirq.data() == RiscVSbiTimer::TIMER_IRQ.data() {
+        __schedule(SchedMode::SM_PREEMPT);
+    }
+}

+ 1 - 0
kernel/src/driver/mod.rs

@@ -1,6 +1,7 @@
 pub mod acpi;
 pub mod base;
 pub mod block;
+pub mod clocksource;
 pub mod disk;
 pub mod firmware;
 pub mod input;

+ 17 - 1
kernel/src/exception/irqdata.rs

@@ -11,6 +11,7 @@ use crate::libs::{
 
 use super::{
     irqchip::{IrqChip, IrqChipData},
+    irqdesc::IrqDesc,
     irqdomain::IrqDomain,
     msi::MsiDesc,
     HardwareIrqNumber, IrqNumber,
@@ -43,7 +44,7 @@ impl IrqData {
             inner: SpinLock::new(InnerIrqData {
                 hwirq,
                 common_data,
-
+                desc: Weak::new(),
                 domain: None,
                 parent_data: None,
             }),
@@ -71,6 +72,18 @@ impl IrqData {
         self.irq
     }
 
+    pub fn irq_desc(&self) -> Option<Arc<IrqDesc>> {
+        self.inner.lock_irqsave().desc.upgrade()
+    }
+
+    pub fn set_irq_desc(&self, desc: Weak<IrqDesc>) {
+        self.inner.lock_irqsave().desc = desc;
+    }
+
+    pub fn clear_irq_desc(&self) {
+        self.inner.lock_irqsave().desc = Weak::new();
+    }
+
     pub fn hardware_irq(&self) -> HardwareIrqNumber {
         self.inner.lock_irqsave().hwirq
     }
@@ -133,6 +146,8 @@ pub struct InnerIrqData {
     /// 涉及的所有irqchip之间共享的数据
     common_data: Arc<IrqCommonData>,
 
+    desc: Weak<IrqDesc>,
+
     /// 中断域
     domain: Option<Arc<IrqDomain>>,
     /// 中断的父中断(如果具有中断域继承的话)
@@ -409,6 +424,7 @@ impl IrqLineStatus {
     ///
     /// - 如果不是电平触发类型,则返回None
     /// - 如果是电平触发类型,则返回Some(bool),当为true时表示高电平触发
+    #[allow(dead_code)]
     pub fn is_level_high(&self) -> Option<bool> {
         if !self.is_level_type() {
             return None;

+ 36 - 2
kernel/src/exception/irqdesc.rs

@@ -37,6 +37,7 @@ use super::{
     handle::bad_irq_handler,
     irqchip::IrqChip,
     irqdata::{IrqCommonData, IrqData, IrqHandlerData, IrqLineStatus, IrqStatus},
+    irqdomain::{irq_domain_manager, IrqDomain},
     sysfs::{irq_sysfs_del, IrqKObjType},
     HardwareIrqNumber, InterruptArch, IrqNumber,
 };
@@ -119,11 +120,12 @@ impl IrqDesc {
             kobj_state: LockedKObjectState::new(Some(KObjectState::INITIALIZED)),
             threads_active: AtomicI64::new(0),
         };
-
+        let irq_desc = Arc::new(irq_desc);
+        irq_desc.irq_data().set_irq_desc(Arc::downgrade(&irq_desc));
         irq_desc.set_handler(bad_irq_handler());
         irq_desc.inner().irq_data.irqd_set(irqd_flags);
 
-        return Arc::new(irq_desc);
+        return irq_desc;
     }
 
     /// 返回当前活跃的中断线程数量
@@ -988,3 +990,35 @@ impl IrqDescManager {
         return Ok(());
     }
 }
+
+pub struct GenericIrqHandler;
+
+#[allow(dead_code)]
+impl GenericIrqHandler {
+    /// `handle_domain_irq` - 调用属于某个中断域的硬件中断的处理程序
+    ///
+    /// # 参数
+    ///
+    /// * `domain`: 执行查找的域
+    /// * `hwirq`: 要转换为逻辑中断的硬件中断号
+    ///
+    /// # 返回
+    ///
+    /// 成功时返回 `Ok(())`,如果转换失败则返回 `Err(SystemError)`
+    ///
+    /// 此函数必须在初始化了中断寄存器的中断上下文中调用
+    ///
+    /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/kernel/irq/irqdesc.c?fi=generic_handle_domain_irq#726
+    pub fn handle_domain_irq(
+        domain: Arc<IrqDomain>,
+        hwirq: HardwareIrqNumber,
+        trap_frame: &mut TrapFrame,
+    ) -> Result<(), SystemError> {
+        let (irq_desc, _) =
+            irq_domain_manager().resolve_irq_mapping(Some(domain.clone()), hwirq)?;
+
+        irq_desc.handler().unwrap().handle(&irq_desc, trap_frame);
+
+        return Ok(());
+    }
+}

+ 59 - 4
kernel/src/exception/irqdomain.rs

@@ -11,14 +11,17 @@ use system_error::SystemError;
 use crate::{
     driver::{base::device::Device, open_firmware::device_node::DeviceNode},
     exception::{irqdata::IrqLineStatus, irqdesc::irq_desc_manager, manage::irq_manager},
-    libs::{rwlock::RwLock, spinlock::SpinLock},
+    libs::{
+        rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
+        spinlock::SpinLock,
+    },
 };
 
 use super::{
     dummychip::no_irq_chip,
     irqchip::{IrqChip, IrqChipData, IrqChipGeneric, IrqGcFlags},
     irqdata::{IrqData, IrqHandlerData},
-    irqdesc::IrqFlowHandler,
+    irqdesc::{IrqDesc, IrqFlowHandler},
     HardwareIrqNumber, IrqNumber,
 };
 
@@ -389,6 +392,48 @@ impl IrqDomainManager {
 
         return None;
     }
+
+    /// `resolve_irq_mapping` - 从硬件中断号找到中断号。
+    ///
+    /// ## 参数
+    ///
+    /// - `domain`: 拥有此硬件中断的域
+    /// - `hwirq`: 该域空间中的硬件中断号
+    /// - `irq`: 如果需要,可选的指针以返回Linux中断
+    ///
+    /// ## 返回
+    ///
+    /// 返回一个元组,包含中断描述符和中断号
+    pub fn resolve_irq_mapping(
+        &self,
+        mut domain: Option<Arc<IrqDomain>>,
+        hwirq: HardwareIrqNumber,
+    ) -> Result<(Arc<IrqDesc>, IrqNumber), SystemError> {
+        if domain.is_none() {
+            domain = Some(self.default_domain().ok_or(SystemError::EINVAL)?);
+        }
+
+        let domain = domain.unwrap();
+
+        if domain.no_map() {
+            if hwirq < domain.revmap_read_irqsave().hwirq_max {
+                let irq_desc = irq_desc_manager()
+                    .lookup(IrqNumber::new(hwirq.data()))
+                    .ok_or(SystemError::EINVAL)?;
+                if irq_desc.irq_data().hardware_irq() == hwirq {
+                    let irq = irq_desc.irq_data().irq();
+                    return Ok((irq_desc, irq));
+                }
+            }
+
+            return Err(SystemError::EINVAL);
+        }
+
+        let revmap = domain.revmap_read_irqsave();
+        let irq_data = revmap.lookup(hwirq).ok_or(SystemError::EINVAL)?;
+        let irq_desc = irq_data.irq_desc().unwrap();
+        return Ok((irq_desc, irq_data.irq()));
+    }
 }
 
 struct InnerIrqDomainManager {
@@ -480,9 +525,19 @@ impl IrqDomain {
             .contains(IrqDomainFlags::NO_MAP)
     }
 
+    #[allow(dead_code)]
+    fn revmap_read_irqsave(&self) -> RwLockReadGuard<IrqDomainRevMap> {
+        self.revmap.read_irqsave()
+    }
+
+    #[allow(dead_code)]
+    fn revmap_write_irqsave(&self) -> RwLockWriteGuard<IrqDomainRevMap> {
+        self.revmap.write_irqsave()
+    }
+
     #[allow(dead_code)]
     fn set_hwirq_max(&self, hwirq_max: HardwareIrqNumber) {
-        self.revmap.write_irqsave().hwirq_max = hwirq_max;
+        self.revmap_write_irqsave().hwirq_max = hwirq_max;
     }
 
     pub fn name(&self) -> Option<String> {
@@ -498,7 +553,7 @@ impl IrqDomain {
 
     /// The number of mapped interrupts
     pub fn map_count(&self) -> u32 {
-        self.revmap.read().map.len() as u32
+        self.revmap_read_irqsave().map.len() as u32
     }
 
     pub fn host_data(&self) -> Option<Arc<dyn IrqChipData>> {

+ 2 - 6
kernel/src/sched/mod.rs

@@ -911,12 +911,8 @@ pub fn __schedule(sched_mod: SchedMode) {
 
         // CurrentApic.send_eoi();
         compiler_fence(Ordering::SeqCst);
-        #[cfg(target_arch = "x86_64")]
-        unsafe {
-            ProcessManager::switch_process(prev, next)
-        };
-        #[cfg(target_arch = "riscv64")]
-        todo!()
+
+        unsafe { ProcessManager::switch_process(prev, next) };
     } else {
         kwarn!(
             "!!!switch_process {} {:?} to self ",