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