AArch64 EL2 hypervisor for QEMU virt that boots at EL2
1

Configure Feed

Select the types of activity you want to include in your feed.

ariel / arch / aarch64 / arch.c
6.8 kB 271 lines
1#include "hv/arch.h" 2#include "hv/config.h" 3#include "hv/mmio.h" 4#include "hv/panic.h" 5#include "hv/uart.h" 6#include "hv/vcpu.h" 7 8uint64_t arch_current_el(void) 9{ 10 uint64_t v; 11 __asm__ volatile("mrs %0, CurrentEL" : "=r"(v)); 12 return (v >> 2u) & 0x3u; 13} 14 15uint64_t arch_mpidr_el1(void) 16{ 17 uint64_t v; 18 __asm__ volatile("mrs %0, mpidr_el1" : "=r"(v)); 19 return v; 20} 21 22uint64_t arch_cntpct_el0(void) 23{ 24 uint64_t v; 25 __asm__ volatile("mrs %0, cntpct_el0" : "=r"(v)); 26 return v; 27} 28 29uint64_t arch_cntfrq_el0(void) 30{ 31 uint64_t v; 32 __asm__ volatile("mrs %0, cntfrq_el0" : "=r"(v)); 33 return v; 34} 35 36uint64_t arch_vectors_base(void) 37{ 38 return (uint64_t)(uintptr_t)__vectors_el2; 39} 40 41bool arch_vectors_aligned(void) 42{ 43 return hv_is_aligned_u64(arch_vectors_base(), 2048u); 44} 45 46uint64_t arch_irq_save(void) 47{ 48 uint64_t flags; 49 __asm__ volatile("mrs %0, daif\nmsr daifset, #0xf\nisb" : "=r"(flags) :: "memory"); 50 return flags; 51} 52 53void arch_irq_restore(uint64_t flags) 54{ 55 __asm__ volatile("msr daif, %0\nisb" :: "r"(flags) : "memory"); 56} 57 58void arch_dump_el2_state(void) 59{ 60 uint64_t current_el; 61 uint64_t hcr; 62 uint64_t vtcr; 63 uint64_t vttbr; 64 uint64_t vbar; 65 uint64_t sctlr; 66 uint64_t mair; 67 uint64_t sp; 68 69 __asm__ volatile( 70 "mrs %0, CurrentEL\n" 71 "mrs %1, hcr_el2\n" 72 "mrs %2, vtcr_el2\n" 73 "mrs %3, vttbr_el2\n" 74 "mrs %4, vbar_el2\n" 75 "mrs %5, sctlr_el2\n" 76 "mrs %6, mair_el2\n" 77 "mov %7, sp\n" 78 : "=r"(current_el), "=r"(hcr), "=r"(vtcr), "=r"(vttbr), 79 "=r"(vbar), "=r"(sctlr), "=r"(mair), "=r"(sp)); 80 81 uart_puts("cpu current_el="); 82 uart_put_hex64(current_el); 83 uart_puts(" hcr_el2="); 84 uart_put_hex64(hcr); 85 uart_puts(" vtcr_el2="); 86 uart_put_hex64(vtcr); 87 uart_puts(" vttbr_el2="); 88 uart_put_hex64(vttbr); 89 uart_puts("\n"); 90 uart_puts("cpu vbar_el2="); 91 uart_put_hex64(vbar); 92 uart_puts(" sctlr_el2="); 93 uart_put_hex64(sctlr); 94 uart_puts(" mair_el2="); 95 uart_put_hex64(mair); 96 uart_puts(" sp="); 97 uart_put_hex64(sp); 98 uart_puts("\n"); 99} 100 101void arch_install_vectors(void) 102{ 103 if (!arch_vectors_aligned()) { 104 panic("VBAR_EL2 vector table is not 2KB aligned"); 105 } 106 __asm__ volatile("msr vbar_el2, %0\nisb" :: "r"(arch_vectors_base()) : "memory"); 107} 108 109void arch_tlbi_vmalle1is(void) 110{ 111 __asm__ volatile("dsb ish\n tlbi vmalle1is\n dsb ish\n isb" ::: "memory"); 112} 113 114void arch_enable_el2_mmu(uint64_t ttbr0, uint64_t tcr, uint64_t mair) 115{ 116 uint64_t sctlr; 117 118 __asm__ volatile( 119 "dsb sy\n" 120 "msr ttbr0_el2, %0\n" 121 "msr tcr_el2, %1\n" 122 "msr mair_el2, %2\n" 123 "isb\n" 124 "tlbi alle2\n" 125 "dsb sy\n" 126 "isb\n" 127 :: "r"(ttbr0), "r"(tcr), "r"(mair) 128 : "memory"); 129 130 __asm__ volatile("mrs %0, sctlr_el2" : "=r"(sctlr)); 131 sctlr |= HV_BIT(0) | HV_BIT(2) | HV_BIT(12); 132 __asm__ volatile( 133 "msr sctlr_el2, %0\n" 134 "isb\n" 135 :: "r"(sctlr) 136 : "memory"); 137} 138 139void arch_el2_configure(uint64_t vttbr, uint64_t vtcr) 140{ 141 const uint64_t mair = 0x000000000000ff00ull | 0x0000000000000004ull; 142 uint64_t hcr = 0; 143 144 hcr |= HV_BIT(31); 145 hcr |= HV_BIT(0); 146#if !CONFIG_BOOT_LINUX 147 hcr |= HV_BIT(26); 148#endif 149 hcr |= HV_BIT(22); 150 hcr |= HV_BIT(21); 151 hcr |= HV_BIT(19); 152#if !CONFIG_BOOT_LINUX 153 hcr |= HV_BIT(20); 154 hcr |= HV_BIT(18) | HV_BIT(17) | HV_BIT(16) | HV_BIT(15); 155#endif 156#if CONFIG_ENABLE_WFI_TRAPS 157 hcr |= HV_BIT(14) | HV_BIT(13); 158#endif 159 160 __asm__ volatile( 161 "msr mair_el2, %0\n" 162 "msr vtcr_el2, %1\n" 163 "msr vttbr_el2, %2\n" 164 "msr mdcr_el2, %3\n" 165 "msr cptr_el2, %4\n" 166 "msr cnthctl_el2, %5\n" 167 "msr hcr_el2, %6\n" 168 "isb\n" 169 :: "r"(mair), "r"(vtcr), "r"(vttbr), 170 "r"(0ull), "r"(0x33ffull), "r"(3ull), "r"(hcr) 171 : "memory"); 172} 173 174void arch_prepare_guest_entry(struct vcpu *vcpu) 175{ 176 BUG_ON(vcpu == (struct vcpu *)0); 177 __asm__ volatile( 178 "msr sctlr_el1, %0\n" 179 "msr ttbr0_el1, %1\n" 180 "msr ttbr1_el1, %2\n" 181 "msr tcr_el1, %3\n" 182 "msr mair_el1, %4\n" 183 "msr vbar_el1, %5\n" 184 "msr cntkctl_el1, %6\n" 185 "isb\n" 186 :: "r"(vcpu->sysregs.sctlr_el1), "r"(vcpu->sysregs.ttbr0_el1), 187 "r"(vcpu->sysregs.ttbr1_el1), "r"(vcpu->sysregs.tcr_el1), 188 "r"(vcpu->sysregs.mair_el1), "r"(vcpu->sysregs.vbar_el1), 189 "r"(vcpu->sysregs.cntkctl_el1) 190 : "memory"); 191} 192 193void arch_capture_el1_sysregs(struct vcpu *vcpu) 194{ 195 BUG_ON(vcpu == (struct vcpu *)0); 196 __asm__ volatile( 197 "mrs %0, vbar_el1\n" 198 "mrs %1, elr_el1\n" 199 "mrs %2, spsr_el1\n" 200 "mrs %3, esr_el1\n" 201 "mrs %4, far_el1\n" 202 : "=r"(vcpu->sysregs.vbar_el1), "=r"(vcpu->sysregs.elr_el1), 203 "=r"(vcpu->sysregs.spsr_el1), "=r"(vcpu->sysregs.esr_el1), 204 "=r"(vcpu->sysregs.far_el1)); 205} 206 207void arch_sync_el1_sysregs(const struct vcpu *vcpu) 208{ 209 BUG_ON(vcpu == (const struct vcpu *)0); 210 __asm__ volatile( 211 "dsb sy\n" 212 "msr mair_el1, %0\n" 213 "msr tcr_el1, %1\n" 214 "msr ttbr0_el1, %2\n" 215 "msr ttbr1_el1, %3\n" 216 "msr vbar_el1, %4\n" 217 "msr cntkctl_el1, %5\n" 218 "msr cpacr_el1, %6\n" 219 "isb\n" 220 "msr sctlr_el1, %7\n" 221 "isb\n" 222 :: "r"(vcpu->sysregs.mair_el1), "r"(vcpu->sysregs.tcr_el1), 223 "r"(vcpu->sysregs.ttbr0_el1), "r"(vcpu->sysregs.ttbr1_el1), 224 "r"(vcpu->sysregs.vbar_el1), "r"(vcpu->sysregs.cntkctl_el1), 225 "r"(vcpu->sysregs.cpacr_el1), "r"(vcpu->sysregs.sctlr_el1) 226 : "memory"); 227} 228 229void arch_advance_guest_pc(struct vcpu *vcpu) 230{ 231 BUG_ON(vcpu == (struct vcpu *)0); 232 vcpu->pc += 4u; 233} 234 235void arch_inject_guest_undef(struct vcpu *vcpu) 236{ 237 const uint64_t current_el_spx_sync = 0x200u; 238 const uint64_t pstate_el1h_daif = 0x3c5u; 239 240 BUG_ON(vcpu == (struct vcpu *)0); 241 arch_capture_el1_sysregs(vcpu); 242 if (!hv_is_aligned_u64(vcpu->sysregs.vbar_el1, 2048u)) { 243 vcpu->state = VCPU_PAUSED; 244 return; 245 } 246 247 vcpu->sysregs.elr_el1 = vcpu->pc; 248 vcpu->sysregs.spsr_el1 = vcpu->pstate; 249 vcpu->sysregs.esr_el1 = 0u; 250 vcpu->sysregs.far_el1 = 0u; 251 vcpu->pc = vcpu->sysregs.vbar_el1 + current_el_spx_sync; 252 vcpu->pstate = pstate_el1h_daif; 253 vcpu->stats.injected_undefs++; 254 255 __asm__ volatile( 256 "msr elr_el1, %0\n" 257 "msr spsr_el1, %1\n" 258 "msr esr_el1, %2\n" 259 "msr far_el1, %3\n" 260 "isb\n" 261 :: "r"(vcpu->sysregs.elr_el1), "r"(vcpu->sysregs.spsr_el1), 262 "r"(vcpu->sysregs.esr_el1), "r"(vcpu->sysregs.far_el1) 263 : "memory"); 264} 265 266void arch_halt(void) 267{ 268 for (;;) { 269 __asm__ volatile("wfe"); 270 } 271}