Browse Source

fix: (riscv/timer): 修复riscv下没有更新墙上时钟以及没有处理软中断的bug (#783)

LoGin 11 months ago
parent
commit
0722a06a09

+ 2 - 7
kernel/src/arch/x86_64/driver/hpet.rs

@@ -19,7 +19,6 @@ use crate::{
         irqdata::IrqHandlerData,
         irqdesc::{IrqHandleFlags, IrqHandler, IrqReturn},
         manage::irq_manager,
-        softirq::{softirq_vectors, SoftirqNumber},
         InterruptArch, IrqNumber,
     },
     kdebug, kerror, kinfo,
@@ -33,7 +32,7 @@ use crate::{
     },
     time::{
         jiffies::NSEC_PER_JIFFY,
-        timer::{clock, timer_get_first_expire, update_timer_jiffies},
+        timer::{try_raise_timer_softirq, update_timer_jiffies},
     },
 };
 
@@ -252,11 +251,7 @@ impl Hpet {
             assert!(!CurrentIrqArch::is_irq_enabled());
             update_timer_jiffies(1, Self::HPET0_INTERVAL_USEC as i64);
 
-            if let Ok(first_expire) = timer_get_first_expire() {
-                if first_expire <= clock() {
-                    softirq_vectors().raise_softirq(SoftirqNumber::TIMER);
-                }
-            }
+            try_raise_timer_softirq();
         }
     }
 }

+ 40 - 3
kernel/src/driver/clocksource/timer_riscv.rs

@@ -1,4 +1,4 @@
-use core::sync::atomic::{fence, Ordering};
+use core::sync::atomic::{compiler_fence, fence, Ordering};
 
 use alloc::{string::ToString, sync::Arc};
 use bitmap::{traits::BitMapOps, StaticBitmap};
@@ -19,7 +19,12 @@ use crate::{
     mm::percpu::PerCpu,
     process::ProcessManager,
     smp::core::smp_get_processor_id,
-    time::{clocksource::HZ, TimeArch},
+    time::{
+        clocksource::HZ,
+        jiffies::NSEC_PER_JIFFY,
+        timer::{try_raise_timer_softirq, update_timer_jiffies},
+        TimeArch,
+    },
 };
 
 pub struct RiscVSbiTimer;
@@ -29,6 +34,13 @@ static SBI_TIMER_INIT_BMP: SpinLock<StaticBitmap<{ PerCpu::MAX_CPU_NUM as usize
 
 static mut INTERVAL_CNT: usize = 0;
 
+/// 已经过去的纳秒数
+///
+/// 0号核心用这个值来更新墙上时钟,他只能被0号核心访问
+static mut HART0_NSEC_PASSED: usize = 0;
+/// hart0上一次更新墙上时钟的时间
+static mut HART0_LAST_UPDATED: u64 = 0;
+
 impl RiscVSbiTimer {
     pub const TIMER_IRQ: IrqNumber = IrqNumber::from(5);
 
@@ -39,8 +51,9 @@ impl RiscVSbiTimer {
         //     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());
+        Self::update_nsec_passed_and_walltime();
+        sbi_rt::set_timer(CurrentTimeArch::get_cycles() as u64 + unsafe { INTERVAL_CNT } as u64);
         Ok(())
     }
 
@@ -52,6 +65,30 @@ impl RiscVSbiTimer {
     fn disable() {
         unsafe { riscv::register::sie::clear_stimer() };
     }
+
+    fn update_nsec_passed_and_walltime() {
+        if smp_get_processor_id().data() != 0 {
+            return;
+        }
+
+        let cycles = CurrentTimeArch::get_cycles() as u64;
+        let nsec_passed =
+            CurrentTimeArch::cycles2ns((cycles - unsafe { HART0_LAST_UPDATED }) as usize);
+        unsafe {
+            HART0_LAST_UPDATED = cycles;
+            HART0_NSEC_PASSED += nsec_passed;
+        }
+
+        let jiffies = unsafe { HART0_NSEC_PASSED } / NSEC_PER_JIFFY as usize;
+        unsafe { HART0_NSEC_PASSED %= NSEC_PER_JIFFY as usize };
+
+        update_timer_jiffies(
+            jiffies as u64,
+            (jiffies * NSEC_PER_JIFFY as usize / 1000) as i64,
+        );
+        try_raise_timer_softirq();
+        compiler_fence(Ordering::SeqCst);
+    }
 }
 
 /// riscv 初始化本地调度时钟源

+ 2 - 0
kernel/src/driver/irqchip/riscv_intc.rs

@@ -10,6 +10,7 @@ use crate::{
         irqdata::IrqData,
         irqdesc::{irq_desc_manager, GenericIrqHandler},
         irqdomain::{irq_domain_manager, IrqDomain, IrqDomainOps},
+        softirq::do_softirq,
         HardwareIrqNumber, IrqNumber,
     },
     libs::spinlock::{SpinLock, SpinLockGuard},
@@ -165,6 +166,7 @@ pub fn riscv_intc_irq(trap_frame: &mut TrapFrame) {
     // kdebug!("riscv64_do_irq: interrupt {hwirq:?}");
     GenericIrqHandler::handle_domain_irq(riscv_intc_domain().clone().unwrap(), hwirq, trap_frame)
         .ok();
+    do_softirq();
     if hwirq.data() == RiscVSbiTimer::TIMER_IRQ.data() {
         __schedule(SchedMode::SM_PREEMPT);
     }

+ 9 - 0
kernel/src/time/timer.rs

@@ -357,6 +357,15 @@ pub fn timer_get_first_expire() -> Result<u64, SystemError> {
     return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
 }
 
+/// 检查是否需要触发定时器软中断,如果需要则触发
+pub fn try_raise_timer_softirq() {
+    if let Ok(first_expire) = timer_get_first_expire() {
+        if first_expire <= clock() {
+            softirq_vectors().raise_softirq(SoftirqNumber::TIMER);
+        }
+    }
+}
+
 /// 更新系统时间片
 pub fn update_timer_jiffies(add_jiffies: u64, time_us: i64) -> u64 {
     let prev = TIMER_JIFFIES.fetch_add(add_jiffies, Ordering::SeqCst);