Skip to content

Commit

Permalink
初始化riscv-sbi-timer (#716)
Browse files Browse the repository at this point in the history
  • Loading branch information
fslongjin authored Apr 12, 2024
1 parent 3959e94 commit f049d1a
Show file tree
Hide file tree
Showing 13 changed files with 340 additions and 41 deletions.
12 changes: 6 additions & 6 deletions kernel/src/arch/riscv64/interrupt/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
}

/// 处理异常
Expand Down
6 changes: 5 additions & 1 deletion kernel/src/arch/riscv64/process/idle.rs
Original file line number Diff line number Diff line change
@@ -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进程
Expand All @@ -14,6 +16,8 @@ impl ProcessManager {
kBUG!("Idle process should not be scheduled with IRQs disabled.");
spin_loop();
}

kdebug!("idle loop");
}
}
}
19 changes: 17 additions & 2 deletions kernel/src/arch/riscv64/process/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::{
CurrentIrqArch,
},
exception::InterruptArch,
kerror,
kdebug, kerror,
libs::spinlock::SpinLockGuard,
mm::VirtAddr,
process::{
Expand Down Expand Up @@ -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);

Expand All @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down
14 changes: 9 additions & 5 deletions kernel/src/arch/riscv64/sched.rs
Original file line number Diff line number Diff line change
@@ -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]
Expand All @@ -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 changes: 4 additions & 0 deletions kernel/src/arch/riscv64/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,7 @@ impl TimeArch for RiscV64TimeArch {
cycles * 1000000000 / unsafe { TIME_FREQ }
}
}

pub fn riscv_time_base_freq() -> usize {
unsafe { TIME_FREQ }
}
2 changes: 2 additions & 0 deletions kernel/src/driver/clocksource/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#[cfg(target_arch = "riscv64")]
pub mod timer_riscv;
131 changes: 131 additions & 0 deletions kernel/src/driver/clocksource/timer_riscv.rs
Original file line number Diff line number Diff line change
@@ -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)
}
}
65 changes: 51 additions & 14 deletions kernel/src/driver/irqchip/riscv_intc.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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 {
Expand All @@ -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
Expand Down Expand Up @@ -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;

Expand All @@ -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);
Expand All @@ -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 change: 1 addition & 0 deletions kernel/src/driver/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Loading

0 comments on commit f049d1a

Please sign in to comment.