Skip to content
Merged
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
3 changes: 1 addition & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion modules/axhal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ riscv_goldfish = { version = "0.1", optional = true }
[target.'cfg(target_arch = "aarch64")'.dependencies]
aarch64-cpu = "9.4"
tock-registers = "0.8"
arm_gicv2 = { git = "https://github.com/arceos-hypervisor/arm_gicv2", rev = "7acc0dd" }
arm_gicv2 = { git = "https://github.com/arceos-hypervisor/arm_gicv2" }
crate_interface = { version = "0.1.3", optional = true }
arm_pl011 = "0.1"
arm_pl031 = { version = "0.2", optional = true }
Expand Down
10 changes: 9 additions & 1 deletion modules/axhal/src/irq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ use crate::trap::{register_trap_handler, IRQ};

pub use crate::platform::irq::{register_handler, set_enable};

#[cfg(target_arch = "aarch64")]
pub use crate::platform::irq::fetch_irq;

/// The type if an IRQ handler.
pub type IrqHandler = handler_table::Handler;

Expand Down Expand Up @@ -35,8 +38,13 @@ pub(crate) fn register_handler_common(irq_num: usize, handler: IrqHandler) -> bo
false
}

/// Core IRQ handling routine, registered at `axhal::trap::IRQ`,
/// which dispatches IRQs to registered handlers.
///
/// Note: this function is denoted as public here because it'll be called by the
/// hypervisor for hypervisor reserved IRQ handling.
#[register_trap_handler(IRQ)]
fn handler_irq(irq_num: usize) -> bool {
pub fn handler_irq(irq_num: usize) -> bool {
let guard = kernel_guard::NoPreempt::new();
dispatch_irq(irq_num);
drop(guard); // rescheduling may occur when preemption is re-enabled.
Expand Down
13 changes: 12 additions & 1 deletion modules/axhal/src/platform/aarch64_common/boot_el2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,18 @@ unsafe fn switch_to_el2() {

unsafe fn init_mmu_el2() {
// Set EL1 to 64bit.
HCR_EL2.write(HCR_EL2::RW::EL1IsAarch64);
// Enable `IMO` and `FMO` to make sure that:
// * Physical IRQ interrupts are taken to EL2;
// * Virtual IRQ interrupts are enabled;
// * Physical FIQ interrupts are taken to EL2;
// * Virtual FIQ interrupts are enabled.
HCR_EL2.modify(
HCR_EL2::VM::Enable
+ HCR_EL2::RW::EL1IsAarch64
+ HCR_EL2::IMO::EnableVirtualIRQ // Physical IRQ Routing.
+ HCR_EL2::FMO::EnableVirtualFIQ // Physical FIQ Routing.
+ HCR_EL2::TSC::EnableTrapEl1SmcToEl2,
);

// Device-nGnRE memory
let attr0 = MAIR_EL2::Attr0_Device::nonGathering_nonReordering_EarlyWriteAck;
Expand Down
10 changes: 5 additions & 5 deletions modules/axhal/src/platform/aarch64_common/generic_timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,12 @@ pub(crate) fn init_percpu() {
}
#[cfg(all(feature = "irq", feature = "hv"))]
{
// ENABLE, bit [0], Enables the timer.
let ctl = 1;
let tval = 0;
unsafe {
core::arch::asm!("msr CNTHP_CTL_EL2, {0:x}", in(reg) ctl);
core::arch::asm!("msr CNTHP_TVAL_EL2, {0:x}", in(reg) tval);
// ENABLE, bit [0], Enables the timer.
// * 0b0: Timer disabled.
// * 0b1: Timer enabled.
core::arch::asm!("msr CNTHP_CTL_EL2, {0:x}", in(reg) 0b1);
core::arch::asm!("msr CNTHP_TVAL_EL2, {0:x}", in(reg) 0);
}
}
#[cfg(feature = "irq")]
Expand Down
153 changes: 13 additions & 140 deletions modules/axhal/src/platform/aarch64_common/gic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,24 @@ pub fn register_handler(irq_num: usize, handler: IrqHandler) -> bool {
crate::irq::register_handler_common(irq_num, handler)
}

/// Fetches the IRQ number.
pub fn fetch_irq() -> usize {
GICC.iar() as usize
}

/// Dispatches the IRQ.
///
/// This function is called by the common interrupt handler. It looks
/// up in the IRQ handler table and calls the corresponding handler. If
/// necessary, it also acknowledges the interrupt controller after handling.
pub fn dispatch_irq(_unused: usize) {
GICC.handle_irq(|irq_num| crate::irq::dispatch_irq_common(irq_num as _));
pub fn dispatch_irq(irq_no: usize) {
if irq_no == 0 {
GICC.handle_irq(|irq_num| crate::irq::dispatch_irq_common(irq_num as _));
} else {
crate::irq::dispatch_irq_common(irq_no as _);
GICC.eoi(irq_no as _);
GICC.dir(irq_no as _);
}
}

/// Initializes GICD, GICC on the primary CPU.
Expand All @@ -62,141 +73,3 @@ pub(crate) fn init_primary() {
pub(crate) fn init_secondary() {
GICC.init();
}

#[cfg(feature = "hv")]
mod gic_if {

use super::{GICC, GICD};
use arm_gicv2::GicTrait;
struct GicIfImpl;

#[crate_interface::impl_interface]
impl GicTrait for GicIfImpl {
/// Sets the enable status of a specific interrupt in the GICD (Distributor).
///
/// # Parameters
/// - `vector`: The interrupt vector number, identifying the interrupt to be enabled or disabled.
/// - `enable`: A boolean value indicating whether to enable the interrupt. `true` enables the interrupt, `false` disables it.
///
/// This function locks and accesses the GICD controller, then sets the enable status of the specified interrupt vector based on the `enable` parameter.
/// It provides a mechanism for controlling whether interrupts can trigger CPU responses, used for interrupt management.
fn set_enable(vector: usize, enable: bool) {
GICD.lock().set_enable(vector, enable);
}

/// Retrieves the enable status of a specified interrupt vector from the GICD.
///
/// # Parameters
/// - `vector`: The index of the interrupt vector, used to identify a specific interrupt source.
///
/// # Returns
/// - `bool`: Indicates whether the specified interrupt vector is enabled. `true` means the interrupt vector is enabled, `false` means it is not enabled.
fn get_enable(vector: usize) -> bool {
GICD.lock().get_enable(vector)
}

/// Get the type of the GICD register
///
/// This function locks the GICD and calls its internal `get_typer` method to retrieve the type of the GICD register
///
/// # Returns
/// * `u32` - The type of the GICD register
fn get_typer() -> u32 {
GICD.lock().get_typer()
}

/// Get the Implementer ID Register (IIDR) of the interrupt controller
///
/// This function locks the GICD (interrupt controller) and calls its `get_iidr` method to retrieve the value of the Implementer ID Register.
/// This register can be used to identify the specific hardware implementer and version.
fn get_iidr() -> u32 {
GICD.lock().get_iidr()
}

/// Set the state of an interrupt source
///
/// This function updates the state of a specific interrupt source in the GICD (Interrupt Controller).
/// It first locks the GICD and then updates the interrupt source state using the provided interrupt ID (`int_id`),
/// new state value (`state`), and current CPU ID (`current_cpu_id`).
///
/// Parameters:
/// - `int_id`: The ID of the interrupt source.
/// - `state`: The new state value for the interrupt source.
/// - `current_cpu_id`: The ID of the current CPU.
fn set_state(int_id: usize, state: usize, current_cpu_id: usize) {
GICD.lock().set_state(int_id, state, current_cpu_id);
}

/// Get the state of an interrupt source
///
/// This function retrieves the current state of a specific interrupt source.
///
/// Parameters:
/// - `int_id`: The ID of the interrupt source.
///
/// Returns:
/// - The current state value.
fn get_state(int_id: usize) -> usize {
GICD.lock().get_state(int_id)
}

/// Set the ICFGR (Interrupt Configuration and Control Register)
///
/// This function sets the configuration of a specific interrupt source in the ICFGR.
///
/// Parameters:
/// - `int_id`: The ID of the interrupt source.
/// - `cfg`: The new configuration value.
fn set_icfgr(int_id: usize, cfg: u8) {
GICD.lock().set_icfgr(int_id, cfg);
}

/// Get the target CPU for an interrupt source
///
/// This function retrieves the target CPU for a specific interrupt source.
///
/// Parameters:
/// - `int_id`: The ID of the interrupt source.
///
/// Returns:
/// - The target CPU ID.
fn get_target_cpu(int_id: usize) -> usize {
GICD.lock().get_target_cpu(int_id)
}

/// Set the target CPU for an interrupt source
///
/// This function sets the target CPU for a specific interrupt source.
///
/// Parameters:
/// - `int_id`: The ID of the interrupt source.
/// - `target`: The new target CPU value.
fn set_target_cpu(int_id: usize, target: u8) {
GICD.lock().set_target_cpu(int_id, target);
}

/// Get the priority of an interrupt source
///
/// This function retrieves the priority of a specific interrupt source.
///
/// Parameters:
/// - `int_id`: The ID of the interrupt source.
///
/// Returns:
/// - The priority value.
fn get_priority(int_id: usize) -> usize {
GICD.lock().get_priority(int_id)
}

/// Set the priority of an interrupt source
///
/// This function sets the priority of a specific interrupt source.
///
/// Parameters:
/// - `int_id`: The ID of the interrupt source.
/// - `priority`: The new priority value.
fn set_priority(int_id: usize, priority: u8) {
GICD.lock().set_priority(int_id, priority);
}
}
}
1 change: 1 addition & 0 deletions modules/axhal/src/platform/aarch64_qemu_virt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pub(crate) unsafe extern "C" fn rust_entry(cpu_id: usize, dtb: usize) {
#[allow(dead_code)] // FIXME: temporariy allowd to bypass clippy warnings.
pub(crate) unsafe extern "C" fn rust_entry_secondary(cpu_id: usize) {
crate::arch::set_exception_vector_base(exception_vector_base as usize);
#[cfg(not(feature = "hv"))]
crate::arch::write_page_table_root0(0.into()); // disable low address access
crate::cpu::init_secondary(cpu_id);
rust_main_secondary(cpu_id);
Expand Down
5 changes: 5 additions & 0 deletions modules/axhal/src/platform/dummy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ pub mod irq {
/// up in the IRQ handler table and calls the corresponding handler. If
/// necessary, it also acknowledges the interrupt controller after handling.
pub fn dispatch_irq(irq_num: usize) {}

/// Fetches the IRQ number.
pub fn fetch_irq() -> usize {
0
}
}

/// Initializes the platform devices for the primary CPU.
Expand Down
Loading