Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion awkernel_lib/src/arch/rv32/delay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl Delay for super::RV32 {
while {
let test: u32;
core::arch::asm!(
"rdcycleh {0}; rdcycle {1}; rdcycleh {2}",
"rdcycleh {0:x}; rdcycle {1:x}; rdcycleh {2:x}",
out(reg) cycleh,
out(reg) cycle,
out(reg) test
Expand Down
16 changes: 16 additions & 0 deletions awkernel_lib/src/arch/rv64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,22 @@ pub struct RV64;

impl super::Arch for RV64 {}

/// # Safety
///
/// This function must be called at initialization,
/// and called by the primary CPU.
pub unsafe fn init_primary() {
delay::init_primary();
}

/// # Safety
///
/// This function must be called at initialization,
/// and called by non-primary CPUs.
pub unsafe fn init_non_primary() {
delay::init_non_primary();
}

pub fn init_page_allocator() {
frame_allocator::init_page_allocator();
}
Expand Down
4 changes: 3 additions & 1 deletion awkernel_lib/src/arch/rv64/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ impl CPU for super::RV64 {
fn cpu_id() -> usize {
let hartid: usize;
unsafe {
core::arch::asm!("csrr {}, mhartid", out(reg) hartid);
// In M-mode, read from tp register (set during boot)
// This avoids repeatedly accessing mhartid CSR
core::arch::asm!("mv {}, tp", out(reg) hartid);
}
hartid
}
Expand Down
33 changes: 23 additions & 10 deletions awkernel_lib/src/arch/rv64/delay.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use crate::delay::Delay;
use core::sync::atomic::{AtomicU64, Ordering};

// we should get this info from device tree
const ACLINT_MTIME_BASE: u32 = 0x0200_0000 + 0x0000bff8;
const RISCV_TIMEBASE_FREQ: u64 = 10_000_000;

static COUNT_START: AtomicU64 = AtomicU64::new(0);

impl Delay for super::RV64 {
fn wait_interrupt() {
unsafe { core::arch::asm!("wfi") };
Expand All @@ -16,19 +19,19 @@ impl Delay for super::RV64 {
}

fn uptime() -> u64 {
// as microsec
unsafe {
let mtime = ACLINT_MTIME_BASE as *const u64;
*mtime * 1_000_000 / RISCV_TIMEBASE_FREQ
}
let start = COUNT_START.load(Ordering::Acquire);
let mtime = ACLINT_MTIME_BASE as *const u64;
let now = unsafe { core::ptr::read_volatile(mtime) };
let diff = now - start;
diff * 1_000_000 / RISCV_TIMEBASE_FREQ
}

fn uptime_nano() -> u128 {
// as microsec
unsafe {
let mtime = ACLINT_MTIME_BASE as *const u128;
*mtime * 1_000_000_000 / RISCV_TIMEBASE_FREQ as u128
}
let start = COUNT_START.load(Ordering::Acquire);
let mtime = ACLINT_MTIME_BASE as *const u64;
let now = unsafe { core::ptr::read_volatile(mtime) };
let diff = now - start;
diff as u128 * 1_000_000_000 / RISCV_TIMEBASE_FREQ as u128
}

fn cpu_counter() -> u64 {
Expand All @@ -39,3 +42,13 @@ impl Delay for super::RV64 {
cycle
}
}

pub(super) unsafe fn init_primary() {
let mtime = ACLINT_MTIME_BASE as *const u64;
let count = core::ptr::read_volatile(mtime);
COUNT_START.store(count, Ordering::Release);
}

pub(super) unsafe fn init_non_primary() {
// No additional initialization needed for non-primary CPUs
}
2 changes: 2 additions & 0 deletions awkernel_lib/src/arch/rv64/interrupt.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::interrupt::Interrupt;

// RV64 runs in M-mode without OpenSBI, so we use mstatus
// MIE (Machine Interrupt Enable) is bit 3 (0x08) in mstatus
impl Interrupt for super::RV64 {
fn get_flag() -> usize {
let x: usize;
Expand Down
51 changes: 51 additions & 0 deletions awkernel_lib/src/interrupt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,57 @@ pub fn handle_preemption() {
preemption();
}

/// Handle all pending interrupt requests for RISC-V.
/// This is called from the M-mode interrupt handler.
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
pub fn handle_irqs(is_task: bool) {
use crate::{heap, unwind::catch_unwind};
use core::mem::transmute;

let handlers = IRQ_HANDLERS.read();
let mut need_preemption = false;

let controller = INTERRUPT_CONTROLLER.read();
if let Some(ctrl) = controller.as_ref() {
let iter = ctrl.pending_irqs();
drop(controller); // unlock

// Use the primary allocator.
#[cfg(not(feature = "std"))]
let _guard = {
let g = heap::TALLOC.save();
unsafe { heap::TALLOC.use_primary() };
g
};

for irq in iter {
if irq == PREEMPT_IRQ.load(Ordering::Relaxed) {
need_preemption = true;
continue;
}

if let Some((_, handler)) = handlers.get(&irq) {
if let Err(err) = catch_unwind(|| {
handler(irq);
}) {
log::warn!("an interrupt handler has been panicked\n{err:?}");
}
}
}
}

if need_preemption && is_task {
let ptr = PREEMPT_FN.load(Ordering::Relaxed);
let preemption = unsafe { transmute::<*mut (), fn()>(ptr) };
preemption();
}

// Because IPIs are edge-trigger,
// IPI sent during interrupt handlers will be ignored.
// To notify the interrupt again, we setup a timer.
crate::cpu::reset_wakeup_timer();
}

/// Disable interrupts and automatically restored the configuration.
///
/// ```
Expand Down
5 changes: 3 additions & 2 deletions kernel/ld/rv64-link.lds
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ ENTRY(_start)

SECTIONS
{
. = 0x80200000;
/* Boot code at DRAM start for -bios none */
. = 0x80000000;
PROVIDE (__executable_start = .);
__ram_start = .;

PROVIDE (stext = .);
.init : { KEEP(*(.init)) }
.text : { *(.text .text.* .gnu.linkonce.t*) }
Expand Down
1 change: 1 addition & 0 deletions kernel/src/arch/rv64.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod config;
mod console;
mod kernel_main;
mod timer;
Loading
Loading