ax_cpu/arch/aarch64/
mmu.rs1#[derive(Clone, Copy, Debug, Default)]
8pub struct El1;
9
10#[derive(Clone, Copy, Debug, Default)]
13pub struct El2;
14
15impl El1 {
16 pub fn flush_tlb(address: Option<crate::VirtAddr>) {
18 unsafe {
21 if let Some(address) = address {
22 let operand = (address.as_usize() >> 12) & ((1usize << 44) - 1);
23 core::arch::asm!("dsb nshst; tlbi vaae1, {}; dsb nsh; isb", in(reg) operand);
24 } else {
25 core::arch::asm!("dsb nshst; tlbi vmalle1; dsb nsh; isb");
26 }
27 }
28 }
29}
30
31impl El2 {
32 pub fn flush_tlb(address: Option<crate::VirtAddr>) {
35 unsafe {
38 if let Some(address) = address {
39 let operand = (address.as_usize() >> 12) & ((1usize << 44) - 1);
40 core::arch::asm!("dsb nshst; tlbi vae2, {}; dsb nsh; isb", in(reg) operand);
41 } else {
42 core::arch::asm!("dsb nshst; tlbi alle2; dsb nsh; isb");
43 }
44 }
45 }
46}
47
48impl El1 {
49 pub fn read_kernel_page_table() -> crate::PhysAddr {
51 use aarch64_cpu::registers::{Readable, TTBR1_EL1};
52 crate::PhysAddr::from_usize((TTBR1_EL1.get() & 0x0000_ffff_ffff_f000) as usize)
53 }
54 pub unsafe fn write_kernel_page_table(root: crate::PhysAddr) {
60 use aarch64_cpu::registers::{TTBR1_EL1, Writeable};
61 TTBR1_EL1.set(root.as_usize() as u64);
62 }
63 pub fn address_space_tag_capacity() -> u32 {
65 super::asm::address_space_tag_capacity()
66 }
67 pub fn flush_tlb_range(start: crate::VirtAddr, size: usize) {
69 crate::mmu::flush_range_with(start, size, Self::flush_tlb);
70 }
71}
72
73impl El2 {
74 pub fn read_kernel_page_table() -> crate::PhysAddr {
76 use aarch64_cpu::registers::{Readable, TTBR0_EL2};
77 crate::PhysAddr::from_usize((TTBR0_EL2.get() & 0x0000_ffff_ffff_f000) as usize)
78 }
79 pub unsafe fn write_kernel_page_table(root: crate::PhysAddr) {
85 use aarch64_cpu::registers::{TTBR0_EL2, Writeable};
86 TTBR0_EL2.set(root.as_usize() as u64);
87 }
88 pub const fn address_space_tag_capacity() -> u32 {
90 1
91 }
92 pub fn flush_tlb_range(start: crate::VirtAddr, size: usize) {
94 crate::mmu::flush_range_with(start, size, Self::flush_tlb);
95 }
96}
97
98impl El1 {
99 pub unsafe fn configure_stage1(mair: u64) {
106 use aarch64_cpu::{asm::barrier, registers::*};
107 MAIR_EL1.set(mair);
108 const VADDR_SIZE: u64 = 48;
110 const T0SZ: u64 = 64 - VADDR_SIZE;
111
112 let tcr_flags0 = TCR_EL1::EPD0::EnableTTBR0Walks
113 + TCR_EL1::TG0::KiB_4
114 + TCR_EL1::SH0::Inner
115 + TCR_EL1::ORGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable
116 + TCR_EL1::IRGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable
117 + TCR_EL1::T0SZ.val(T0SZ);
118 let tcr_flags1 = TCR_EL1::EPD1::EnableTTBR1Walks
119 + TCR_EL1::TG1::KiB_4
120 + TCR_EL1::SH1::Inner
121 + TCR_EL1::ORGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable
122 + TCR_EL1::IRGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable
123 + TCR_EL1::T1SZ.val(T0SZ);
124 let asid_size = if ID_AA64MMFR0_EL1.read(ID_AA64MMFR0_EL1::ASIDBits) == 2 {
128 TCR_EL1::AS::ASID16Bits
129 } else {
130 TCR_EL1::AS::ASID8Bits
131 };
132 let physical_range = (ID_AA64MMFR0_EL1.get() & 15).min(5);
135 TCR_EL1.write(TCR_EL1::IPS.val(physical_range) + asid_size + tcr_flags0 + tcr_flags1);
136
137 Self::flush_tlb(None);
138 barrier::dsb(barrier::SY);
139 barrier::isb(barrier::SY);
140 }
141}
142
143impl El1 {
144 pub fn is_mmu_enabled() -> bool {
146 use aarch64_cpu::registers::*;
147 SCTLR_EL1.is_set(SCTLR_EL1::M)
148 }
149 pub unsafe fn enable_mmu_and_caches() {
155 use aarch64_cpu::{asm::barrier, registers::*};
156
157 SCTLR_EL1.modify(
158 SCTLR_EL1::M::Enable
159 + SCTLR_EL1::C::Cacheable
160 + SCTLR_EL1::I::Cacheable
161 + SCTLR_EL1::UCT::DontTrap
162 + SCTLR_EL1::DZE::DontTrap
163 + SCTLR_EL1::UCI::DontTrap,
164 );
165 SCTLR_EL1.set(SCTLR_EL1.get() | (1 << 23));
166 Self::flush_tlb(None);
167 barrier::dsb(barrier::SY);
168 barrier::isb(barrier::SY);
169 }
170}
171
172impl El2 {
173 pub unsafe fn configure_stage1(mair: u64) {
180 use aarch64_cpu::{asm::barrier, registers::*};
181 MAIR_EL2.set(mair);
182 const VADDR_SIZE: u64 = 48;
184 const T0SZ: u64 = 64 - VADDR_SIZE;
185
186 let tcr_flags0 = TCR_EL2::T0SZ.val(T0SZ)
189 + TCR_EL2::TG0::KiB_4
190 + TCR_EL2::SH0::Inner
191 + TCR_EL2::ORGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable
192 + TCR_EL2::IRGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable;
193
194 let physical_range = (ID_AA64MMFR0_EL1.get() & 15).min(5);
195 TCR_EL2.write(TCR_EL2::PS.val(physical_range) + tcr_flags0);
196
197 Self::flush_tlb_inner_shareable(None);
198 barrier::dsb(barrier::SY);
199 barrier::isb(barrier::SY);
200 }
201}
202
203impl El2 {
204 pub fn is_mmu_enabled() -> bool {
206 use aarch64_cpu::registers::*;
207 SCTLR_EL2.is_set(SCTLR_EL2::M)
208 }
209 pub unsafe fn enable_mmu_and_caches() {
215 use aarch64_cpu::{asm::barrier, registers::*};
216
217 SCTLR_EL2.modify(SCTLR_EL2::M::Enable + SCTLR_EL2::C::Cacheable + SCTLR_EL2::I::Cacheable);
218 Self::flush_tlb(None);
219 barrier::dsb(barrier::SY);
220 barrier::isb(barrier::SY);
221 }
222}
223
224impl El1 {
225 pub fn flush_tlb_inner_shareable(address: Option<crate::VirtAddr>) {
227 unsafe {
230 if let Some(address) = address {
231 let operand = (address.as_usize() >> 12) & ((1usize << 44) - 1);
232 core::arch::asm!("dsb ishst; tlbi vaae1is, {}; dsb ish; isb", in(reg) operand);
233 } else {
234 core::arch::asm!("dsb ishst; tlbi vmalle1is; dsb ish; isb");
235 }
236 }
237 }
238}
239
240impl El2 {
241 pub fn flush_tlb_inner_shareable(address: Option<crate::VirtAddr>) {
243 unsafe {
246 if let Some(address) = address {
247 let operand = (address.as_usize() >> 12) & ((1usize << 44) - 1);
248 core::arch::asm!("dsb ishst; tlbi vae2is, {}; dsb ish; isb", in(reg) operand);
249 } else {
250 core::arch::asm!("dsb ishst; tlbi alle2is; dsb ish; isb");
251 }
252 }
253 }
254}
255
256fn decode_ttbr(value: u64) -> crate::mmu::HardwareAddressSpace {
257 crate::mmu::HardwareAddressSpace::new(
258 crate::PhysAddr::from_usize((value & 0x0000_ffff_ffff_f000) as usize),
259 (value >> 48) as u16,
260 )
261}
262
263fn encode_ttbr(space: crate::mmu::HardwareAddressSpace) -> u64 {
264 space.root().as_usize() as u64 | (u64::from(space.hardware_tag()) << 48)
265}
266
267impl El1 {
268 pub fn read_kernel_address_space() -> crate::mmu::HardwareAddressSpace {
270 use aarch64_cpu::registers::*;
271 decode_ttbr(TTBR1_EL1.get())
272 }
273 pub fn read_user_address_space() -> crate::mmu::HardwareAddressSpace {
275 use aarch64_cpu::registers::*;
276 decode_ttbr(TTBR0_EL1.get())
277 }
278 pub unsafe fn write_kernel_address_space(space: crate::mmu::HardwareAddressSpace) {
284 use aarch64_cpu::registers::*;
285 TTBR1_EL1.set(encode_ttbr(space));
286 }
287 pub unsafe fn write_user_address_space(space: crate::mmu::HardwareAddressSpace) {
293 use aarch64_cpu::registers::*;
294 TTBR0_EL1.set(encode_ttbr(space));
295 }
296}