Skip to content

Commit

Permalink
[platforms] add axplat-aarch64-qemu-virt and axplat-aarch64-common
Browse files Browse the repository at this point in the history
  • Loading branch information
equation314 committed Feb 17, 2025
1 parent 5f3b383 commit 870bc01
Show file tree
Hide file tree
Showing 23 changed files with 1,165 additions and 17 deletions.
8 changes: 7 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ jobs:
platform:
- name: axplat-x86-pc
target: x86_64-unknown-none
- name: axplat-aarch64-common
target: aarch64-unknown-none
- name: axplat-aarch64-qemu-virt
target: aarch64-unknown-none
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
Expand All @@ -76,7 +80,9 @@ jobs:
- uses: dtolnay/rust-toolchain@nightly
- name: Build docs
continue-on-error: ${{ github.ref != env.default-branch && github.event_name != 'pull_request' }}
run: cargo doc --no-deps --all-features --workspace --exclude "axplat-*"
run: |
cargo doc --no-deps --all-features --workspace --exclude "axplat-*"
cargo doc --no-deps --all-features -p axplat-aarch64-common
- name: Deploy to Github Pages
if: ${{ github.ref == env.default-branch }}
uses: JamesIves/github-pages-deploy-action@v4
Expand Down
86 changes: 84 additions & 2 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ members = [
"axhal_plat_macros",
"axplat-cli",
"platforms/axplat-x86-pc",
"platforms/axplat-aarch64-common",
"platforms/axplat-aarch64-qemu-virt",
]

[workspace.package]
Expand Down
101 changes: 100 additions & 1 deletion axhal_cpu/src/aarch64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod trap;

use core::arch::asm;

use aarch64_cpu::registers::{DAIF, TPIDR_EL0, TTBR0_EL1, TTBR1_EL1, VBAR_EL1};
use aarch64_cpu::{asm::barrier, registers::*};
use memory_addr::{PhysAddr, VirtAddr};
use tock_registers::interfaces::{Readable, Writeable};

Expand Down Expand Up @@ -137,3 +137,102 @@ pub fn read_thread_pointer() -> usize {
pub unsafe fn write_thread_pointer(tpidr_el0: usize) {
TPIDR_EL0.set(tpidr_el0 as _)
}

/// Swtich current exception level to EL1.
///
/// It usually used in the kernel booting process, where the kernel starts at
/// EL2 or EL3. At that time, the MMU is not enable and the kernel is using
/// physical address.
///
/// # Safety
///
/// This function is unsafe as it changes the CPU mode.
pub unsafe fn switch_to_el1() {
SPSel.write(SPSel::SP::ELx);
SP_EL0.set(0);
let current_el = CurrentEL.read(CurrentEL::EL);
if current_el >= 2 {
if current_el == 3 {
// Set EL2 to 64bit and enable the HVC instruction.
SCR_EL3.write(
SCR_EL3::NS::NonSecure + SCR_EL3::HCE::HvcEnabled + SCR_EL3::RW::NextELIsAarch64,
);
// Set the return address and exception level.
SPSR_EL3.write(
SPSR_EL3::M::EL1h
+ SPSR_EL3::D::Masked
+ SPSR_EL3::A::Masked
+ SPSR_EL3::I::Masked
+ SPSR_EL3::F::Masked,
);
ELR_EL3.set(LR.get());
}
// Disable EL1 timer traps and the timer offset.
CNTHCTL_EL2.modify(CNTHCTL_EL2::EL1PCEN::SET + CNTHCTL_EL2::EL1PCTEN::SET);
CNTVOFF_EL2.set(0);
// Set EL1 to 64bit.
HCR_EL2.write(HCR_EL2::RW::EL1IsAarch64);
// Set the return address and exception level.
SPSR_EL2.write(
SPSR_EL2::M::EL1h
+ SPSR_EL2::D::Masked
+ SPSR_EL2::A::Masked
+ SPSR_EL2::I::Masked
+ SPSR_EL2::F::Masked,
);
SP_EL1.set(SP.get());
ELR_EL2.set(LR.get());
aarch64_cpu::asm::eret();
}
}

/// Enable EL1 MMU with the given page table root.
///
/// It usually used in the kernel booting process.
///
/// # Safety
///
/// This function is unsafe as it changes the address translation configuration.
pub unsafe fn enable_mmu(root_paddr: PhysAddr) {
use page_table_entry::aarch64::MemAttr;

MAIR_EL1.set(MemAttr::MAIR_VALUE);

// Enable TTBR0 and TTBR1 walks, page size = 4K, vaddr size = 48 bits, paddr size = 48 bits.
let tcr_flags0 = TCR_EL1::EPD0::EnableTTBR0Walks
+ TCR_EL1::TG0::KiB_4
+ TCR_EL1::SH0::Inner
+ TCR_EL1::ORGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable
+ TCR_EL1::IRGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable
+ TCR_EL1::T0SZ.val(16);
let tcr_flags1 = TCR_EL1::EPD1::EnableTTBR1Walks
+ TCR_EL1::TG1::KiB_4
+ TCR_EL1::SH1::Inner
+ TCR_EL1::ORGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable
+ TCR_EL1::IRGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable
+ TCR_EL1::T1SZ.val(16);
TCR_EL1.write(TCR_EL1::IPS::Bits_48 + tcr_flags0 + tcr_flags1);
barrier::isb(barrier::SY);

// Set both TTBR0 and TTBR1
let root_paddr = root_paddr.as_usize() as u64;
TTBR0_EL1.set(root_paddr);
TTBR1_EL1.set(root_paddr);

// Flush the entire TLB
flush_tlb(None);

// Enable the MMU and turn on I-cache and D-cache
SCTLR_EL1.modify(SCTLR_EL1::M::Enable + SCTLR_EL1::C::Cacheable + SCTLR_EL1::I::Cacheable);
barrier::isb(barrier::SY);
}

/// Enable FP and SIMD instructions.
///
/// It usually used in the kernel booting process.
pub fn enable_fp() {
if cfg!(feature = "fp_simd") {
CPACR_EL1.write(CPACR_EL1::FPEN::TrapNothing);
barrier::isb(barrier::SY);
}
}
8 changes: 4 additions & 4 deletions axhal_plat/src/irq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,24 @@ pub type IrqHandler = handler_table::Handler;
#[def_plat_interface]
pub trait IrqIf {
/// Enables or disables the given IRQ.
fn set_enable(vector: usize, enabled: bool);
fn set_enable(irq: usize, enabled: bool);

/// Registers an IRQ handler for the given IRQ.
///
/// It also enables the IRQ if the registration succeeds. It returns `false`
/// if the registration failed.
fn register(vector: usize, handler: IrqHandler) -> bool;
fn register(irq: usize, handler: IrqHandler) -> bool;

/// Unregisters the IRQ handler for the given IRQ.
///
/// It also disables the IRQ if the unregistration succeeds. It returns the
/// existing handler if it is registered, `None` otherwise.
fn unregister(vector: usize) -> Option<IrqHandler>;
fn unregister(irq: usize) -> Option<IrqHandler>;

/// Handles the IRQ.
///
/// It is called by the common interrupt handler. It should look up in the
/// IRQ handler table and calls the corresponding handler. If necessary, it
/// also acknowledges the interrupt controller after handling.
fn handle(vector: usize);
fn handle(irq: usize);
}
4 changes: 2 additions & 2 deletions axhal_plat/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ pub mod __priv {
pub use crate_interface::{call_interface, def_interface};
}

/// Call the function decorated by [`crate::main`] for the primary core.
/// Call the function decorated by [`axhal_plat::main`][main] for the primary core.
pub fn call_main(cpu_id: usize, dtb: usize) -> ! {
unsafe { __axhal_plat_main(cpu_id, dtb) }
}

/// Call the function decorated by [`crate::secondary_main`] for secondary cores.
/// Call the function decorated by [`axhal_plat::secondary_main`][secondary_main] for secondary cores.
pub fn call_secondary_main(cpu_id: usize) -> ! {
unsafe { __axhal_plat_secondary_main(cpu_id) }
}
Expand Down
8 changes: 4 additions & 4 deletions axplat-cli/template/src/irq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@ struct IrqIfImpl;
#[impl_plat_interface]
impl IrqIf for IrqIfImpl {
/// Enables or disables the given IRQ.
fn set_enable(vector: usize, enabled: bool) {
fn set_enable(irq: usize, enabled: bool) {
todo!()
}

/// Registers an IRQ handler for the given IRQ.
///
/// It also enables the IRQ if the registration succeeds. It returns `false`
/// if the registration failed.
fn register(vector: usize, handler: IrqHandler) -> bool {
fn register(irq: usize, handler: IrqHandler) -> bool {
todo!()
}

/// Unregisters the IRQ handler for the given IRQ.
///
/// It also disables the IRQ if the unregistration succeeds. It returns the
/// existing handler if it is registered, `None` otherwise.
fn unregister(vector: usize) -> Option<IrqHandler> {
fn unregister(irq: usize) -> Option<IrqHandler> {
todo!()
}

Expand All @@ -30,7 +30,7 @@ impl IrqIf for IrqIfImpl {
/// It is called by the common interrupt handler. It should look up in the
/// IRQ handler table and calls the corresponding handler. If necessary, it
/// also acknowledges the interrupt controller after handling.
fn handle(vector: usize) {
fn handle(irq: usize) {
todo!()
}
}
24 changes: 24 additions & 0 deletions platforms/axplat-aarch64-common/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "axplat-aarch64-common"
version = "0.1.0"
edition.workspace = true
authors.workspace = true
license.workspace = true
homepage.workspace = true
documentation.workspace = true
repository.workspace = true

[dependencies]
kspin = "0.1"
log = "=0.4.21"
int_ratio = "0.1"
lazyinit = "0.2"
memory_addr = "0.3"
page_table_entry = "0.5"
aarch64-cpu = "10.0"
tock-registers = "0.9"
arm_pl011 = "0.1"
arm_gicv2 = { version = "0.1" }
arm_pl031 = { version = "0.2" }
axhal_cpu = { version = "0.1", path = "../../axhal_cpu" }
axhal_plat = { version = "0.1", path = "../../axhal_plat" }
Loading

0 comments on commit 870bc01

Please sign in to comment.