Skip to main content

ax_cpu/aarch64/
init.rs

1//! Helper functions to initialize the CPU states on systems bootstrapping.
2
3use aarch64_cpu::{asm::barrier, registers::*};
4use ax_memory_addr::PhysAddr;
5
6/// Swtich current exception level to EL1.
7///
8/// It usually used in the system booting process, where the startup code is
9/// running in EL2 or EL3. Besides, the stack is not available and the MMU is
10/// not enabled.
11///
12/// # Safety
13///
14/// This function is unsafe as it changes the CPU mode.
15pub unsafe fn switch_to_el1() {
16    SPSel.write(SPSel::SP::ELx);
17    SP_EL0.set(0);
18    let current_el = CurrentEL.read(CurrentEL::EL);
19    if current_el >= 2 {
20        if current_el == 3 {
21            // Set EL2 to 64bit and enable the HVC instruction.
22            SCR_EL3.write(
23                SCR_EL3::NS::NonSecure + SCR_EL3::HCE::HvcEnabled + SCR_EL3::RW::NextELIsAarch64,
24            );
25            // Set the return address and exception level.
26            SPSR_EL3.write(
27                SPSR_EL3::M::EL1h
28                    + SPSR_EL3::D::Masked
29                    + SPSR_EL3::A::Masked
30                    + SPSR_EL3::I::Masked
31                    + SPSR_EL3::F::Masked,
32            );
33            ELR_EL3.set(LR.get());
34        }
35        // Disable EL1 timer traps and the timer offset.
36        CNTHCTL_EL2.modify(CNTHCTL_EL2::EL1PCEN::SET + CNTHCTL_EL2::EL1PCTEN::SET);
37        CNTVOFF_EL2.set(0);
38        // Set EL1 to 64bit.
39        HCR_EL2.write(HCR_EL2::RW::EL1IsAarch64);
40        // Set the return address and exception level.
41        SPSR_EL2.write(
42            SPSR_EL2::M::EL1h
43                + SPSR_EL2::D::Masked
44                + SPSR_EL2::A::Masked
45                + SPSR_EL2::I::Masked
46                + SPSR_EL2::F::Masked,
47        );
48        SP_EL1.set(SP.get());
49        ELR_EL2.set(LR.get());
50        aarch64_cpu::asm::eret();
51    }
52}
53
54/// Configures and enables the MMU on the current CPU.
55///
56/// It first sets `MAIR_EL1`, `TCR_EL1`, `TTBR0_EL1`, `TTBR1_EL1` registers to
57/// the conventional values, and then enables the MMU and caches by setting
58/// `SCTLR_EL1`.
59///
60/// # Safety
61///
62/// This function is unsafe as it changes the address translation configuration.
63pub unsafe fn init_mmu(root_paddr: PhysAddr) {
64    use ax_page_table_entry::aarch64::MemAttr;
65
66    MAIR_EL1.set(MemAttr::MAIR_VALUE);
67
68    // Enable TTBR0 and TTBR1 walks, page size = 4K, vaddr size = 48 bits, paddr size = 48 bits.
69    let tcr_flags0 = TCR_EL1::EPD0::EnableTTBR0Walks
70        + TCR_EL1::TG0::KiB_4
71        + TCR_EL1::SH0::Inner
72        + TCR_EL1::ORGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable
73        + TCR_EL1::IRGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable
74        + TCR_EL1::T0SZ.val(16);
75    let tcr_flags1 = TCR_EL1::EPD1::EnableTTBR1Walks
76        + TCR_EL1::TG1::KiB_4
77        + TCR_EL1::SH1::Inner
78        + TCR_EL1::ORGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable
79        + TCR_EL1::IRGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable
80        + TCR_EL1::T1SZ.val(16);
81    TCR_EL1.write(TCR_EL1::IPS::Bits_48 + tcr_flags0 + tcr_flags1);
82    barrier::isb(barrier::SY);
83
84    // Set both TTBR0 and TTBR1
85    let root_paddr = root_paddr.as_usize() as u64;
86    TTBR0_EL1.set(root_paddr);
87    TTBR1_EL1.set(root_paddr);
88
89    // Flush the entire TLB
90    crate::asm::flush_tlb(None);
91
92    // Enable the MMU and turn on I-cache and D-cache
93    SCTLR_EL1.modify(SCTLR_EL1::M::Enable + SCTLR_EL1::C::Cacheable + SCTLR_EL1::I::Cacheable);
94    // Disable SPAN
95    SCTLR_EL1.set(SCTLR_EL1.get() | (1 << 23));
96    barrier::isb(barrier::SY);
97}
98
99/// Initializes trap handling on the current CPU.
100///
101/// In detail, it initializes the exception vector, and sets `TTBR0_EL1` to 0 to
102/// block low address access.
103pub fn init_trap() {
104    #[cfg(feature = "uspace")]
105    crate::uspace_common::init_exception_table();
106    unsafe extern "C" {
107        fn exception_vector_base();
108    }
109    unsafe {
110        crate::asm::write_exception_vector_base(exception_vector_base as *const () as usize);
111        crate::asm::write_user_page_table(0.into());
112    }
113}