|
1 | | -use core::arch::asm; |
| 1 | +// SPDX-License-Identifier: Apache-2.0 |
| 2 | +// Copyright 2025 KylinSoft Co., Ltd. <https://www.kylinos.cn/> |
| 3 | +// See LICENSES for license details. |
| 4 | + |
| 5 | +//! AArch64 exception level switching for early boot. |
2 | 6 |
|
3 | 7 | use aarch64_cpu::{asm::barrier, registers::*}; |
4 | | -use aarch64_cpu_ext::asm::tlb::{VAAE1IS, VMALLE1, tlbi}; |
5 | | -use page_table_generic::VirtAddr; |
6 | | -use crate::start_code; |
7 | | -use crate::mem::PageTable; |
8 | 8 |
|
| 9 | +/// Switch from EL3/EL2 down to EL1. |
| 10 | +/// |
| 11 | +/// Must be called before the MMU is enabled. All addresses are physical. |
| 12 | +/// |
| 13 | +/// # Safety |
| 14 | +/// |
| 15 | +/// Changes the CPU exception level. Must only be called once during early boot. |
9 | 16 | #[unsafe(link_section = ".idmap.text")] |
10 | | -pub fn switch_to_elx(bootargs: usize) { |
| 17 | +pub unsafe fn switch_to_el1() { |
11 | 18 | SPSel.write(SPSel::SP::ELx); |
12 | 19 | SP_EL0.set(0); |
13 | 20 | let current_el = CurrentEL.read(CurrentEL::EL); |
14 | | - let ret = sym_lma!(super::_start_secondary); |
15 | 21 | if current_el >= 2 { |
16 | 22 | if current_el == 3 { |
17 | | - // Set EL2 to 64bit and enable the HVC instruction. |
| 23 | + // Set EL2 to 64-bit and enable the HVC instruction. |
18 | 24 | SCR_EL3.write( |
19 | | - SCR_EL3::NS::NonSecure + SCR_EL3::HCE::HvcEnabled + SCR_EL3::RW::NextELIsAarch64, |
| 25 | + SCR_EL3::NS::NonSecure |
| 26 | + + SCR_EL3::HCE::HvcEnabled |
| 27 | + + SCR_EL3::RW::NextELIsAarch64, |
20 | 28 | ); |
21 | | - // Set the return address and exception level. |
| 29 | + // Return to EL1h. |
22 | 30 | SPSR_EL3.write( |
23 | 31 | SPSR_EL3::M::EL1h |
24 | 32 | + SPSR_EL3::D::Masked |
25 | 33 | + SPSR_EL3::A::Masked |
26 | 34 | + SPSR_EL3::I::Masked |
27 | 35 | + SPSR_EL3::F::Masked, |
28 | 36 | ); |
29 | | - |
30 | | - ELR_EL3.set(ret as _); |
31 | | - barrier::isb(barrier::SY); |
32 | | - unsafe { |
33 | | - asm!( |
34 | | - " |
35 | | - mov x0, {} |
36 | | - eret |
37 | | - ", |
38 | | - in(reg) bootargs, |
39 | | - options(nostack, noreturn), |
40 | | - ); |
41 | | - } |
| 37 | + ELR_EL3.set(LR.get()); |
42 | 38 | } |
43 | | - // Disable EL1 timer traps and the timer offset. |
| 39 | + // Disable EL1 timer traps and clear the timer offset. |
44 | 40 | CNTHCTL_EL2.modify(CNTHCTL_EL2::EL1PCEN::SET + CNTHCTL_EL2::EL1PCTEN::SET); |
45 | 41 | CNTVOFF_EL2.set(0); |
46 | | - // Set EL1 to 64bit. |
| 42 | + // Set EL1 to 64-bit. |
47 | 43 | HCR_EL2.write(HCR_EL2::RW::EL1IsAarch64); |
48 | | - // Set the return address and exception level. |
| 44 | + // Return to EL1h. |
49 | 45 | SPSR_EL2.write( |
50 | 46 | SPSR_EL2::M::EL1h |
51 | 47 | + SPSR_EL2::D::Masked |
52 | 48 | + SPSR_EL2::A::Masked |
53 | 49 | + SPSR_EL2::I::Masked |
54 | 50 | + SPSR_EL2::F::Masked, |
55 | 51 | ); |
56 | | - |
57 | | - unsafe { |
58 | | - ELR_EL2.set(ret as _); |
59 | | - barrier::isb(barrier::SY); |
60 | | - |
61 | | - asm!( |
62 | | - " |
63 | | - mov x0, {} |
64 | | - eret |
65 | | - ", |
66 | | - in(reg) bootargs, |
67 | | - options(nostack, noreturn), |
68 | | - ) |
69 | | - }; |
70 | | - } |
71 | | -} |
72 | | - |
73 | | -#[inline(always)] |
74 | | -pub(crate) fn flush_tlb(vaddr: Option<VirtAddr>) { |
75 | | - match vaddr { |
76 | | - Some(addr) => { |
77 | | - tlbi(VAAE1IS::new(addr.raw())); |
78 | | - } |
79 | | - None => { |
80 | | - tlbi(VMALLE1); |
81 | | - } |
| 52 | + SP_EL1.set(SP.get()); |
| 53 | + ELR_EL2.set(LR.get()); |
| 54 | + barrier::isb(barrier::SY); |
| 55 | + aarch64_cpu::asm::eret(); |
82 | 56 | } |
83 | | - barrier::dsb(barrier::SY); |
84 | | - barrier::isb(barrier::SY); |
85 | | -} |
86 | | - |
87 | | -pub fn get_kernal_table() -> PageTable { |
88 | | - let val = TTBR1_EL1.extract(); |
89 | | - PageTable { |
90 | | - id: val.read(TTBR1_EL1::ASID) as _, |
91 | | - addr: (val.read(TTBR1_EL1::BADDR) << 1) as _, |
92 | | - } |
93 | | -} |
94 | | - |
95 | | -pub fn set_kernal_table(tb: PageTable) { |
96 | | - TTBR1_EL1.set(TTBR1_EL1::ASID.val(tb.id as u64).value + tb.addr as u64); |
97 | | - tlbi(VMALLE1); |
98 | | - barrier::dsb(barrier::SY); |
99 | | - barrier::isb(barrier::SY); |
100 | 57 | } |
0 commit comments