Skip to content

Commit 051cb8a

Browse files
fslongjinBrahmaMantra
authored andcommitted
fix: (riscv/timer): 修复riscv下没有更新墙上时钟以及没有处理软中断的bug (DragonOS-Community#783)
1 parent b5baeae commit 051cb8a

File tree

4 files changed

+53
-10
lines changed

4 files changed

+53
-10
lines changed

kernel/src/arch/x86_64/driver/hpet.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ use crate::{
1919
irqdata::IrqHandlerData,
2020
irqdesc::{IrqHandleFlags, IrqHandler, IrqReturn},
2121
manage::irq_manager,
22-
softirq::{softirq_vectors, SoftirqNumber},
2322
InterruptArch, IrqNumber,
2423
},
2524
kdebug, kerror, kinfo,
@@ -33,7 +32,7 @@ use crate::{
3332
},
3433
time::{
3534
jiffies::NSEC_PER_JIFFY,
36-
timer::{clock, timer_get_first_expire, update_timer_jiffies},
35+
timer::{try_raise_timer_softirq, update_timer_jiffies},
3736
},
3837
};
3938

@@ -252,11 +251,7 @@ impl Hpet {
252251
assert!(!CurrentIrqArch::is_irq_enabled());
253252
update_timer_jiffies(1, Self::HPET0_INTERVAL_USEC as i64);
254253

255-
if let Ok(first_expire) = timer_get_first_expire() {
256-
if first_expire <= clock() {
257-
softirq_vectors().raise_softirq(SoftirqNumber::TIMER);
258-
}
259-
}
254+
try_raise_timer_softirq();
260255
}
261256
}
262257
}

kernel/src/driver/clocksource/timer_riscv.rs

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use core::sync::atomic::{fence, Ordering};
1+
use core::sync::atomic::{compiler_fence, fence, Ordering};
22

33
use alloc::{string::ToString, sync::Arc};
44
use bitmap::{traits::BitMapOps, StaticBitmap};
@@ -19,7 +19,12 @@ use crate::{
1919
mm::percpu::PerCpu,
2020
process::ProcessManager,
2121
smp::core::smp_get_processor_id,
22-
time::{clocksource::HZ, TimeArch},
22+
time::{
23+
clocksource::HZ,
24+
jiffies::NSEC_PER_JIFFY,
25+
timer::{try_raise_timer_softirq, update_timer_jiffies},
26+
TimeArch,
27+
},
2328
};
2429

2530
pub struct RiscVSbiTimer;
@@ -29,6 +34,13 @@ static SBI_TIMER_INIT_BMP: SpinLock<StaticBitmap<{ PerCpu::MAX_CPU_NUM as usize
2934

3035
static mut INTERVAL_CNT: usize = 0;
3136

37+
/// 已经过去的纳秒数
38+
///
39+
/// 0号核心用这个值来更新墙上时钟,他只能被0号核心访问
40+
static mut HART0_NSEC_PASSED: usize = 0;
41+
/// hart0上一次更新墙上时钟的时间
42+
static mut HART0_LAST_UPDATED: u64 = 0;
43+
3244
impl RiscVSbiTimer {
3345
pub const TIMER_IRQ: IrqNumber = IrqNumber::from(5);
3446

@@ -39,8 +51,9 @@ impl RiscVSbiTimer {
3951
// smp_get_processor_id().data(),
4052
// CurrentTimeArch::get_cycles() as u64
4153
// );
42-
sbi_rt::set_timer(CurrentTimeArch::get_cycles() as u64 + unsafe { INTERVAL_CNT } as u64);
4354
ProcessManager::update_process_times(trap_frame.is_from_user());
55+
Self::update_nsec_passed_and_walltime();
56+
sbi_rt::set_timer(CurrentTimeArch::get_cycles() as u64 + unsafe { INTERVAL_CNT } as u64);
4457
Ok(())
4558
}
4659

@@ -52,6 +65,30 @@ impl RiscVSbiTimer {
5265
fn disable() {
5366
unsafe { riscv::register::sie::clear_stimer() };
5467
}
68+
69+
fn update_nsec_passed_and_walltime() {
70+
if smp_get_processor_id().data() != 0 {
71+
return;
72+
}
73+
74+
let cycles = CurrentTimeArch::get_cycles() as u64;
75+
let nsec_passed =
76+
CurrentTimeArch::cycles2ns((cycles - unsafe { HART0_LAST_UPDATED }) as usize);
77+
unsafe {
78+
HART0_LAST_UPDATED = cycles;
79+
HART0_NSEC_PASSED += nsec_passed;
80+
}
81+
82+
let jiffies = unsafe { HART0_NSEC_PASSED } / NSEC_PER_JIFFY as usize;
83+
unsafe { HART0_NSEC_PASSED %= NSEC_PER_JIFFY as usize };
84+
85+
update_timer_jiffies(
86+
jiffies as u64,
87+
(jiffies * NSEC_PER_JIFFY as usize / 1000) as i64,
88+
);
89+
try_raise_timer_softirq();
90+
compiler_fence(Ordering::SeqCst);
91+
}
5592
}
5693

5794
/// riscv 初始化本地调度时钟源

kernel/src/driver/irqchip/riscv_intc.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::{
1010
irqdata::IrqData,
1111
irqdesc::{irq_desc_manager, GenericIrqHandler},
1212
irqdomain::{irq_domain_manager, IrqDomain, IrqDomainOps},
13+
softirq::do_softirq,
1314
HardwareIrqNumber, IrqNumber,
1415
},
1516
libs::spinlock::{SpinLock, SpinLockGuard},
@@ -165,6 +166,7 @@ pub fn riscv_intc_irq(trap_frame: &mut TrapFrame) {
165166
// kdebug!("riscv64_do_irq: interrupt {hwirq:?}");
166167
GenericIrqHandler::handle_domain_irq(riscv_intc_domain().clone().unwrap(), hwirq, trap_frame)
167168
.ok();
169+
do_softirq();
168170
if hwirq.data() == RiscVSbiTimer::TIMER_IRQ.data() {
169171
__schedule(SchedMode::SM_PREEMPT);
170172
}

kernel/src/time/timer.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,15 @@ pub fn timer_get_first_expire() -> Result<u64, SystemError> {
357357
return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
358358
}
359359

360+
/// 检查是否需要触发定时器软中断,如果需要则触发
361+
pub fn try_raise_timer_softirq() {
362+
if let Ok(first_expire) = timer_get_first_expire() {
363+
if first_expire <= clock() {
364+
softirq_vectors().raise_softirq(SoftirqNumber::TIMER);
365+
}
366+
}
367+
}
368+
360369
/// 更新系统时间片
361370
pub fn update_timer_jiffies(add_jiffies: u64, time_us: i64) -> u64 {
362371
let prev = TIMER_JIFFIES.fetch_add(add_jiffies, Ordering::SeqCst);

0 commit comments

Comments
 (0)