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
17 changes: 17 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 All @@ -39,3 +55,4 @@ pub fn translate_kernel_address(vpn: address::VirtPageNum) -> Option<page_table:
None
}
}

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
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 interrupt_controller;
mod kernel_main;
226 changes: 220 additions & 6 deletions kernel/src/arch/rv64/boot.S
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,28 @@
.attribute arch, "rv64gc"

_start:
# Read hart ID from mhartid CSR (M-mode)
csrr a0, mhartid
mv tp, a0 # save hartid to thread pointer for later use

# Preserve DTB pointer that QEMU/firmware passes in a1
la t0, dtb_ptr
sd a1, 0(t0)

# set up a simple trap handler for M-mode
la t0, early_trap_handler
csrw mtvec, t0

# Initialize mscratch to 0 (will be set properly later if needed)
csrw mscratch, zero

# set up the 8MB initial stack for each cpu.
li sp, 0x80800000
li a0, 0x00800000
csrr a1, mhartid
addi a1, a1, 1
mul a0, a0, a1
add sp, sp, a0
li t0, 0x00800000
mv t1, a0 # use hartid
addi t1, t1, 1
mul t0, t0, t1
add sp, sp, t0
# clear the BSS
la t0, __bss_start
la t1, __bss_end
Expand All @@ -24,4 +39,203 @@ _start:
# jump to kernel_main
jal ra, kernel_main
2:
j 2b
j 2b

# M-mode trap handler - handles interrupts and exceptions
.align 4
early_trap_handler:
# Check if this is an interrupt or exception
csrr t0, mcause
blt t0, zero, handle_interrupt # If MSB is set, it's an interrupt

# This is an exception - print debug info and halt
j unhandled_trap

handle_interrupt:
# Get interrupt code (lower bits of mcause)
li t1, 0x7FFFFFFFFFFFFFFF
and t0, t0, t1

# Check interrupt type
li t1, 7 # M-mode timer interrupt
beq t0, t1, handle_timer_interrupt

li t1, 3 # M-mode software interrupt (IPI)
beq t0, t1, handle_software_interrupt

# Unknown interrupt - just return
mret

handle_timer_interrupt:
# Save all registers that might be clobbered by the Rust handler
addi sp, sp, -256
sd ra, 0(sp)
sd t0, 8(sp)
sd t1, 16(sp)
sd t2, 24(sp)
sd a0, 32(sp)
sd a1, 40(sp)
sd a2, 48(sp)
sd a3, 56(sp)
sd a4, 64(sp)
sd a5, 72(sp)
sd a6, 80(sp)
sd a7, 88(sp)
sd t3, 96(sp)
sd t4, 104(sp)
sd t5, 112(sp)
sd t6, 120(sp)

# Disable timer interrupt temporarily by setting mtimecmp to max
# MTIMECMP base is 0x02004000, each hart has 8-byte register
csrr t0, mhartid
slli t0, t0, 3 # Multiply by 8
li t1, 0x02004000
add t0, t0, t1
li t1, -1
sd t1, 0(t0)

# Call the Rust timer handler
call riscv_handle_timer

# Restore registers
ld ra, 0(sp)
ld t0, 8(sp)
ld t1, 16(sp)
ld t2, 24(sp)
ld a0, 32(sp)
ld a1, 40(sp)
ld a2, 48(sp)
ld a3, 56(sp)
ld a4, 64(sp)
ld a5, 72(sp)
ld a6, 80(sp)
ld a7, 88(sp)
ld t3, 96(sp)
ld t4, 104(sp)
ld t5, 112(sp)
ld t6, 120(sp)
addi sp, sp, 256

# Return from interrupt
mret

handle_software_interrupt:
# Save all registers that might be clobbered by the Rust handler
addi sp, sp, -256
sd ra, 0(sp)
sd t0, 8(sp)
sd t1, 16(sp)
sd t2, 24(sp)
sd a0, 32(sp)
sd a1, 40(sp)
sd a2, 48(sp)
sd a3, 56(sp)
sd a4, 64(sp)
sd a5, 72(sp)
sd a6, 80(sp)
sd a7, 88(sp)
sd t3, 96(sp)
sd t4, 104(sp)
sd t5, 112(sp)
sd t6, 120(sp)

# Clear the software interrupt by writing 0 to MSIP
# MSIP base is 0x02000000, each hart has 4-byte register
csrr t0, mhartid
slli t0, t0, 2 # Multiply by 4
li t1, 0x02000000
add t0, t0, t1
sw zero, 0(t0) # Clear MSIP

# Call the Rust IPI handler
call riscv_handle_ipi

# Restore registers
ld ra, 0(sp)
ld t0, 8(sp)
ld t1, 16(sp)
ld t2, 24(sp)
ld a0, 32(sp)
ld a1, 40(sp)
ld a2, 48(sp)
ld a3, 56(sp)
ld a4, 64(sp)
ld a5, 72(sp)
ld a6, 80(sp)
ld a7, 88(sp)
ld t3, 96(sp)
ld t4, 104(sp)
ld t5, 112(sp)
ld t6, 120(sp)
addi sp, sp, 256

# Return from interrupt
mret

unhandled_trap:
# Write 'TRAP!' to UART
li t0, 0x10000000
li t1, 'T'
sb t1, 0(t0)
li t1, 'R'
sb t1, 0(t0)
li t1, 'A'
sb t1, 0(t0)
li t1, 'P'
sb t1, 0(t0)
li t1, '!'
sb t1, 0(t0)
li t1, '\r'
sb t1, 0(t0)
li t1, '\n'
sb t1, 0(t0)

# Print mcause
csrr a0, mcause
call print_hex

# Print mepc
csrr a0, mepc
call print_hex

# Print mtval
csrr a0, mtval
call print_hex

# Infinite loop
1:
j 1b

# Helper function to print a hex value
print_hex:
li t0, 0x10000000
li t2, 60 # shift amount: 60, 56, 52, ..., 0
li t3, 16 # counter
1:
srl t1, a0, t2
andi t1, t1, 0xF
li t4, 10
blt t1, t4, 2f
addi t1, t1, 'A'-10
j 3f
2:
addi t1, t1, '0'
3:
sb t1, 0(t0)
addi t2, t2, -4
addi t3, t3, -1
bnez t3, 1b

# Print newline
li t1, '\r'
sb t1, 0(t0)
li t1, '\n'
sb t1, 0(t0)
ret

.section .data
.align 3
.global dtb_ptr
dtb_ptr:
.dword 0
2 changes: 0 additions & 2 deletions kernel/src/arch/rv64/config.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
pub const HEAP_START: usize = 0x0008_8000_0000;

pub const PREEMPT_IRQ: u16 = 0;
pub const WAKEUP_IRQ: u16 = 1;
Loading
Loading