xref: /haiku/src/system/boot/platform/efi/arch/arm64/aarch64.h (revision df59dfec3b5a60258b73a8f437533746ee689020)
1f9412d9fSurnenfeld /*
2f9412d9fSurnenfeld  * Copyright 2021-2022, Oliver Ruiz Dorantes. All rights reserved.
3f9412d9fSurnenfeld  * Distributed under the terms of the MIT License.
4f9412d9fSurnenfeld  */
5f9412d9fSurnenfeld 
6f9412d9fSurnenfeld #include <efi/types.h>
7f9412d9fSurnenfeld 
8f9412d9fSurnenfeld #include <kernel/arch/arm64/arm_registers.h>
9f9412d9fSurnenfeld #include <kernel/arch/arm64/arch_pte.h>
10f9412d9fSurnenfeld 
11f9412d9fSurnenfeld #include <arch_kernel.h>
12f9412d9fSurnenfeld 
13f9412d9fSurnenfeld 
14f9412d9fSurnenfeld extern "C" void _arch_exception_loop(void);
15f9412d9fSurnenfeld extern "C" void _arch_exception_panic(const char* someString, uint64 someValue);
16f9412d9fSurnenfeld 
17f9412d9fSurnenfeld extern "C" uint64 _arch_transition_EL2_EL1(void);
18f9412d9fSurnenfeld 
19f9412d9fSurnenfeld extern "C" void arch_cache_disable(void);
20f9412d9fSurnenfeld extern "C" void arch_cache_enable(void);
21f9412d9fSurnenfeld extern "C" void _arch_cache_flush_invalidate_all(void);
22f9412d9fSurnenfeld extern "C" void _arch_mmu_invalidate_tlb_all(uint8 el);
23f9412d9fSurnenfeld 
24f9412d9fSurnenfeld extern "C" void _arch_cache_clean_poc(void);
25f9412d9fSurnenfeld 
26f9412d9fSurnenfeld 
27f9412d9fSurnenfeld static const uint8 kInvalidExceptionLevel = 0xFFu;
28f9412d9fSurnenfeld 
29f9412d9fSurnenfeld 
30f9412d9fSurnenfeld #define	AARCH64_CHECK_ACCESS(operand, address)						\
31f9412d9fSurnenfeld 	__asm __volatile("at	" #operand ", %0" : : "r"((uint64_t)address))
32f9412d9fSurnenfeld 
33f9412d9fSurnenfeld #define	AARCH64_BREAK(id)						\
34f9412d9fSurnenfeld 	__asm __volatile("brk	" #id)
35f9412d9fSurnenfeld 
36f9412d9fSurnenfeld 
arch_exception_level()37f9412d9fSurnenfeld static inline uint64 arch_exception_level()
38f9412d9fSurnenfeld {
39f9412d9fSurnenfeld 	return (READ_SPECIALREG(CurrentEL) >> 2);
40f9412d9fSurnenfeld }
41f9412d9fSurnenfeld 
42f9412d9fSurnenfeld 
43f9412d9fSurnenfeld // Check arch_cpu.h macro ADDRESS_TRANSLATE_FUNC(stage) for alternative implementation
arch_mmu_read_access(addr_t address)44f9412d9fSurnenfeld static inline bool arch_mmu_read_access(addr_t address) {
45f9412d9fSurnenfeld 
46f9412d9fSurnenfeld 	switch (arch_exception_level())
47f9412d9fSurnenfeld 	{
48f9412d9fSurnenfeld 		case 0:
49f9412d9fSurnenfeld 			AARCH64_CHECK_ACCESS(S1E0R, address);
50f9412d9fSurnenfeld 			break;
51f9412d9fSurnenfeld 		case 1:
52f9412d9fSurnenfeld 			AARCH64_CHECK_ACCESS(S1E1R, address);
53f9412d9fSurnenfeld 			break;
54f9412d9fSurnenfeld 		case 2:
55f9412d9fSurnenfeld 			AARCH64_CHECK_ACCESS(S1E2R, address);
56f9412d9fSurnenfeld 			break;
57f9412d9fSurnenfeld 		case 3:
58f9412d9fSurnenfeld 			AARCH64_CHECK_ACCESS(S1E3R, address);
59f9412d9fSurnenfeld 			break;
60f9412d9fSurnenfeld 		default:
61f9412d9fSurnenfeld 			return false;
62f9412d9fSurnenfeld 	}
63f9412d9fSurnenfeld 	return !(READ_SPECIALREG(PAR_EL1) & PAR_F);
64f9412d9fSurnenfeld }
65f9412d9fSurnenfeld 
66f9412d9fSurnenfeld 
arch_mmu_write_access(addr_t address)67f9412d9fSurnenfeld static inline bool arch_mmu_write_access(addr_t address) {
68f9412d9fSurnenfeld 
69f9412d9fSurnenfeld 	switch (arch_exception_level())
70f9412d9fSurnenfeld 	{
71f9412d9fSurnenfeld 		case 0:
72f9412d9fSurnenfeld 			AARCH64_CHECK_ACCESS(S1E0W, address);
73f9412d9fSurnenfeld 			break;
74f9412d9fSurnenfeld 		case 1:
75f9412d9fSurnenfeld 			AARCH64_CHECK_ACCESS(S1E1W, address);
76f9412d9fSurnenfeld 			break;
77f9412d9fSurnenfeld 		case 2:
78f9412d9fSurnenfeld 			AARCH64_CHECK_ACCESS(S1E2W, address);
79f9412d9fSurnenfeld 			break;
80f9412d9fSurnenfeld 		case 3:
81f9412d9fSurnenfeld 			AARCH64_CHECK_ACCESS(S1E3W, address);
82f9412d9fSurnenfeld 			break;
83f9412d9fSurnenfeld 		default:
84f9412d9fSurnenfeld 			return false;
85f9412d9fSurnenfeld 	}
86f9412d9fSurnenfeld 	return !(READ_SPECIALREG(PAR_EL1) & PAR_F);
87f9412d9fSurnenfeld }
88f9412d9fSurnenfeld 
89f9412d9fSurnenfeld 
90f9412d9fSurnenfeld static inline uint64 arch_mmu_base_register(bool kernel = false)
91f9412d9fSurnenfeld {
92f9412d9fSurnenfeld 	switch (arch_exception_level())
93f9412d9fSurnenfeld 	{
94f9412d9fSurnenfeld 		case 1:
95f9412d9fSurnenfeld 			if (kernel) {
96f9412d9fSurnenfeld 				return READ_SPECIALREG(TTBR1_EL1);
97f9412d9fSurnenfeld 			} else {
98f9412d9fSurnenfeld 				return READ_SPECIALREG(TTBR0_EL1);
99f9412d9fSurnenfeld 			}
100f9412d9fSurnenfeld 		case 2:
101f9412d9fSurnenfeld 			if (kernel) {
102f9412d9fSurnenfeld 				/* This register is present only when
103f9412d9fSurnenfeld 				 * FEAT_VHE is implemented. Otherwise,
104f9412d9fSurnenfeld 				 * direct accesses to TTBR1_EL2 are UNDEFINED.
105f9412d9fSurnenfeld 				 */
106f9412d9fSurnenfeld 				return READ_SPECIALREG(TTBR0_EL2); // TTBR1_EL2
107f9412d9fSurnenfeld 			} else {
108f9412d9fSurnenfeld 				return READ_SPECIALREG(TTBR0_EL2);
109f9412d9fSurnenfeld 			}
110f9412d9fSurnenfeld 		case 3:
111f9412d9fSurnenfeld 			return READ_SPECIALREG(TTBR0_EL3);
112f9412d9fSurnenfeld 		default:
113f9412d9fSurnenfeld 			return false;
114f9412d9fSurnenfeld 	}
115f9412d9fSurnenfeld }
116f9412d9fSurnenfeld 
117f9412d9fSurnenfeld 
_arch_mmu_get_sctlr()118f9412d9fSurnenfeld static inline uint64 _arch_mmu_get_sctlr()
119f9412d9fSurnenfeld {
120f9412d9fSurnenfeld 	switch (arch_exception_level())
121f9412d9fSurnenfeld 	{
122f9412d9fSurnenfeld 		case 1:
123f9412d9fSurnenfeld 			return READ_SPECIALREG(SCTLR_EL1);
124f9412d9fSurnenfeld 		case 2:
125f9412d9fSurnenfeld 			return READ_SPECIALREG(SCTLR_EL2);
126f9412d9fSurnenfeld 		case 3:
127f9412d9fSurnenfeld 			return READ_SPECIALREG(SCTLR_EL3);
128f9412d9fSurnenfeld 		default:
129f9412d9fSurnenfeld 			return false;
130f9412d9fSurnenfeld 	}
131f9412d9fSurnenfeld }
132f9412d9fSurnenfeld 
133f9412d9fSurnenfeld 
_arch_mmu_set_sctlr(uint64 sctlr)134f9412d9fSurnenfeld static inline void _arch_mmu_set_sctlr(uint64 sctlr)
135f9412d9fSurnenfeld {
136f9412d9fSurnenfeld 	switch (arch_exception_level())
137f9412d9fSurnenfeld 	{
138f9412d9fSurnenfeld 		case 1:
139f9412d9fSurnenfeld 			WRITE_SPECIALREG(SCTLR_EL1, sctlr);
140f9412d9fSurnenfeld 			break;
141f9412d9fSurnenfeld 		case 2:
142f9412d9fSurnenfeld 			WRITE_SPECIALREG(SCTLR_EL2, sctlr);
143f9412d9fSurnenfeld 			break;
144f9412d9fSurnenfeld 		case 3:
145f9412d9fSurnenfeld 			WRITE_SPECIALREG(SCTLR_EL3, sctlr);
146f9412d9fSurnenfeld 			break;
147f9412d9fSurnenfeld 	}
148f9412d9fSurnenfeld }
149f9412d9fSurnenfeld 
150f9412d9fSurnenfeld 
arch_mmu_enabled()151f9412d9fSurnenfeld static inline bool arch_mmu_enabled()
152f9412d9fSurnenfeld {
153f9412d9fSurnenfeld 	return _arch_mmu_get_sctlr() & SCTLR_M;
154f9412d9fSurnenfeld }
155f9412d9fSurnenfeld 
156f9412d9fSurnenfeld 
arch_mmu_cache_enabled()157f9412d9fSurnenfeld static inline bool arch_mmu_cache_enabled()
158f9412d9fSurnenfeld {
159f9412d9fSurnenfeld 	return _arch_mmu_get_sctlr() & SCTLR_C;
160f9412d9fSurnenfeld }
161f9412d9fSurnenfeld 
162f9412d9fSurnenfeld 
163f9412d9fSurnenfeld static inline uint64 _arch_mmu_get_tcr(int el = kInvalidExceptionLevel) {
164f9412d9fSurnenfeld 
165f9412d9fSurnenfeld 	if (el == kInvalidExceptionLevel)
166f9412d9fSurnenfeld 		el = arch_exception_level();
167f9412d9fSurnenfeld 
168f9412d9fSurnenfeld 	switch (el)
169f9412d9fSurnenfeld 	{
170f9412d9fSurnenfeld 		case 1:
171f9412d9fSurnenfeld 			return READ_SPECIALREG(TCR_EL1);
172f9412d9fSurnenfeld 		case 2:
173f9412d9fSurnenfeld 			return READ_SPECIALREG(TCR_EL2);
174f9412d9fSurnenfeld 		case 3:
175f9412d9fSurnenfeld 			return READ_SPECIALREG(TCR_EL3);
176f9412d9fSurnenfeld 		default:
177f9412d9fSurnenfeld 			return 0;
178f9412d9fSurnenfeld 	}
179f9412d9fSurnenfeld }
180f9412d9fSurnenfeld 
181f9412d9fSurnenfeld // TODO: move to arm_registers.h
182f9412d9fSurnenfeld static constexpr uint64 TG_MASK = 0x3u;
183f9412d9fSurnenfeld static constexpr uint64 TG_4KB = 0x0u;
184f9412d9fSurnenfeld static constexpr uint64 TG_16KB = 0x2u;
185f9412d9fSurnenfeld static constexpr uint64 TG_64KB = 0x1u;
186f9412d9fSurnenfeld 
187f9412d9fSurnenfeld static constexpr uint64 TxSZ_MASK = (1 << 6) - 1;
188f9412d9fSurnenfeld 
189f9412d9fSurnenfeld static constexpr uint64 T0SZ_MASK = TxSZ_MASK;
190f9412d9fSurnenfeld static constexpr uint64 T1SZ_MASK = TxSZ_MASK << TCR_T1SZ_SHIFT;
191f9412d9fSurnenfeld 
192*add4a0b6SOwen Anderson static constexpr uint64 IPS_MASK = 0x7UL << TCR_IPS_SHIFT;
193*add4a0b6SOwen Anderson 
194f9412d9fSurnenfeld static constexpr uint64 TCR_EPD1_DISABLE = (1 << 23);
195f9412d9fSurnenfeld 
arch_mmu_user_address_bits()196f9412d9fSurnenfeld static inline uint32 arch_mmu_user_address_bits()
197f9412d9fSurnenfeld {
198f9412d9fSurnenfeld 
199f9412d9fSurnenfeld 	uint64 reg = _arch_mmu_get_tcr();
200f9412d9fSurnenfeld 
201f9412d9fSurnenfeld 	return 64 - (reg & T0SZ_MASK);
202f9412d9fSurnenfeld }
203f9412d9fSurnenfeld 
204f9412d9fSurnenfeld 
arch_mmu_user_granule()205f9412d9fSurnenfeld static inline uint32 arch_mmu_user_granule()
206f9412d9fSurnenfeld {
207f9412d9fSurnenfeld 	uint64 reg = _arch_mmu_get_tcr();
208f9412d9fSurnenfeld 	return ((reg >> TCR_TG0_SHIFT) & TG_MASK);
209f9412d9fSurnenfeld }
210f9412d9fSurnenfeld 
211f9412d9fSurnenfeld 
212f9412d9fSurnenfeld /*
213f9412d9fSurnenfeld  * Given that "EL2 and EL3 have a TTBR0, but no TTBR1. This means
214f9412d9fSurnenfeld  * that is either EL2 or EL3 is using AArch64, they can only use
215f9412d9fSurnenfeld  * virtual addresses in the range 0x0 to 0x0000FFFF_FFFFFFFF."
216f9412d9fSurnenfeld  *
217f9412d9fSurnenfeld  * Following calls might only have sense under EL1
218f9412d9fSurnenfeld  */
arch_mmu_kernel_address_bits()219f9412d9fSurnenfeld static inline uint32 arch_mmu_kernel_address_bits()
220f9412d9fSurnenfeld {
221f9412d9fSurnenfeld 	uint64 reg = _arch_mmu_get_tcr();
222f9412d9fSurnenfeld 	return 64 - ((reg & T1SZ_MASK) >> TCR_T1SZ_SHIFT);
223f9412d9fSurnenfeld }
224f9412d9fSurnenfeld 
225f9412d9fSurnenfeld 
arch_mmu_kernel_granule()226f9412d9fSurnenfeld static inline uint32 arch_mmu_kernel_granule()
227f9412d9fSurnenfeld {
228f9412d9fSurnenfeld 	uint64 reg = _arch_mmu_get_tcr();
229f9412d9fSurnenfeld 	return ((reg >> TCR_TG1_SHIFT) & TG_MASK);
230f9412d9fSurnenfeld }
231f9412d9fSurnenfeld 
232f9412d9fSurnenfeld 
233f9412d9fSurnenfeld /*
234f9412d9fSurnenfeld  * Distinguish between kernel(TTBR1) and user(TTBR0) addressing
235f9412d9fSurnenfeld  */
arch_mmu_is_kernel_address(uint64 address)236f9412d9fSurnenfeld static inline bool arch_mmu_is_kernel_address(uint64 address)
237f9412d9fSurnenfeld {
238f9412d9fSurnenfeld 	return address > KERNEL_BASE;
239f9412d9fSurnenfeld }
240f9412d9fSurnenfeld 
241f9412d9fSurnenfeld 
arch_mmu_entries_per_granularity(uint32 granularity)242f9412d9fSurnenfeld static inline constexpr uint32 arch_mmu_entries_per_granularity(uint32 granularity)
243f9412d9fSurnenfeld {
244f9412d9fSurnenfeld 	return (granularity / 8);
245f9412d9fSurnenfeld }
246