Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arm64: KVM: Move most of the fault decoding to C

The fault decoding process (including computing the IPA in the case
of a permission fault) would be much better done in C code, as we
have a reasonable infrastructure to deal with the VHE/non-VHE
differences.

Let's move the whole thing to C, including the workaround for
erratum 834220, and just patch the odd ESR_EL2 access remaining
in hyp-entry.S.

Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

+90 -67
-3
arch/arm64/kernel/asm-offsets.c
··· 110 110 DEFINE(CPU_USER_PT_REGS, offsetof(struct kvm_regs, regs)); 111 111 DEFINE(CPU_FP_REGS, offsetof(struct kvm_regs, fp_regs)); 112 112 DEFINE(VCPU_FPEXC32_EL2, offsetof(struct kvm_vcpu, arch.ctxt.sys_regs[FPEXC32_EL2])); 113 - DEFINE(VCPU_ESR_EL2, offsetof(struct kvm_vcpu, arch.fault.esr_el2)); 114 - DEFINE(VCPU_FAR_EL2, offsetof(struct kvm_vcpu, arch.fault.far_el2)); 115 - DEFINE(VCPU_HPFAR_EL2, offsetof(struct kvm_vcpu, arch.fault.hpfar_el2)); 116 113 DEFINE(VCPU_HOST_CONTEXT, offsetof(struct kvm_vcpu, arch.host_cpu_context)); 117 114 #endif 118 115 #ifdef CONFIG_CPU_PM
+5 -64
arch/arm64/kvm/hyp/hyp-entry.S
··· 19 19 20 20 #include <asm/alternative.h> 21 21 #include <asm/assembler.h> 22 - #include <asm/asm-offsets.h> 23 22 #include <asm/cpufeature.h> 24 23 #include <asm/kvm_arm.h> 25 24 #include <asm/kvm_asm.h> ··· 68 69 el1_sync: // Guest trapped into EL2 69 70 save_x0_to_x3 70 71 72 + alternative_if_not ARM64_HAS_VIRT_HOST_EXTN 71 73 mrs x1, esr_el2 74 + alternative_else 75 + mrs x1, esr_el1 76 + alternative_endif 72 77 lsr x2, x1, #ESR_ELx_EC_SHIFT 73 78 74 79 cmp x2, #ESR_ELx_EC_HVC64 ··· 108 105 cmp x2, #ESR_ELx_EC_FP_ASIMD 109 106 b.eq __fpsimd_guest_restore 110 107 111 - cmp x2, #ESR_ELx_EC_DABT_LOW 112 - mov x0, #ESR_ELx_EC_IABT_LOW 113 - ccmp x2, x0, #4, ne 114 - b.ne 1f // Not an abort we care about 115 - 116 - /* This is an abort. Check for permission fault */ 117 - alternative_if_not ARM64_WORKAROUND_834220 118 - and x2, x1, #ESR_ELx_FSC_TYPE 119 - cmp x2, #FSC_PERM 120 - b.ne 1f // Not a permission fault 121 - alternative_else 122 - nop // Use the permission fault path to 123 - nop // check for a valid S1 translation, 124 - nop // regardless of the ESR value. 125 - alternative_endif 126 - 127 - /* 128 - * Check for Stage-1 page table walk, which is guaranteed 129 - * to give a valid HPFAR_EL2. 130 - */ 131 - tbnz x1, #7, 1f // S1PTW is set 132 - 133 - /* Preserve PAR_EL1 */ 134 - mrs x3, par_el1 135 - stp x3, xzr, [sp, #-16]! 136 - 137 - /* 138 - * Permission fault, HPFAR_EL2 is invalid. 139 - * Resolve the IPA the hard way using the guest VA. 140 - * Stage-1 translation already validated the memory access rights. 141 - * As such, we can use the EL1 translation regime, and don't have 142 - * to distinguish between EL0 and EL1 access. 143 - */ 144 - mrs x2, far_el2 145 - at s1e1r, x2 146 - isb 147 - 148 - /* Read result */ 149 - mrs x3, par_el1 150 - ldp x0, xzr, [sp], #16 // Restore PAR_EL1 from the stack 151 - msr par_el1, x0 152 - tbnz x3, #0, 3f // Bail out if we failed the translation 153 - ubfx x3, x3, #12, #36 // Extract IPA 154 - lsl x3, x3, #4 // and present it like HPFAR 155 - b 2f 156 - 157 - 1: mrs x3, hpfar_el2 158 - mrs x2, far_el2 159 - 160 - 2: mrs x0, tpidr_el2 161 - str w1, [x0, #VCPU_ESR_EL2] 162 - str x2, [x0, #VCPU_FAR_EL2] 163 - str x3, [x0, #VCPU_HPFAR_EL2] 164 - 108 + mrs x0, tpidr_el2 165 109 mov x1, #ARM_EXCEPTION_TRAP 166 110 b __guest_exit 167 - 168 - /* 169 - * Translation failed. Just return to the guest and 170 - * let it fault again. Another CPU is probably playing 171 - * behind our back. 172 - */ 173 - 3: restore_x0_to_x3 174 - 175 - eret 176 111 177 112 el1_irq: 178 113 save_x0_to_x3
+85
arch/arm64/kvm/hyp/switch.c
··· 15 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 16 */ 17 17 18 + #include <linux/types.h> 18 19 #include <asm/kvm_asm.h> 19 20 20 21 #include "hyp.h" ··· 150 149 __vgic_call_restore_state()(vcpu); 151 150 } 152 151 152 + static bool __hyp_text __true_value(void) 153 + { 154 + return true; 155 + } 156 + 157 + static bool __hyp_text __false_value(void) 158 + { 159 + return false; 160 + } 161 + 162 + static hyp_alternate_select(__check_arm_834220, 163 + __false_value, __true_value, 164 + ARM64_WORKAROUND_834220); 165 + 166 + static bool __hyp_text __translate_far_to_hpfar(u64 far, u64 *hpfar) 167 + { 168 + u64 par, tmp; 169 + 170 + /* 171 + * Resolve the IPA the hard way using the guest VA. 172 + * 173 + * Stage-1 translation already validated the memory access 174 + * rights. As such, we can use the EL1 translation regime, and 175 + * don't have to distinguish between EL0 and EL1 access. 176 + * 177 + * We do need to save/restore PAR_EL1 though, as we haven't 178 + * saved the guest context yet, and we may return early... 179 + */ 180 + par = read_sysreg(par_el1); 181 + asm volatile("at s1e1r, %0" : : "r" (far)); 182 + isb(); 183 + 184 + tmp = read_sysreg(par_el1); 185 + write_sysreg(par, par_el1); 186 + 187 + if (unlikely(tmp & 1)) 188 + return false; /* Translation failed, back to guest */ 189 + 190 + /* Convert PAR to HPFAR format */ 191 + *hpfar = ((tmp >> 12) & ((1UL << 36) - 1)) << 4; 192 + return true; 193 + } 194 + 195 + static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu) 196 + { 197 + u64 esr = read_sysreg_el2(esr); 198 + u8 ec = esr >> ESR_ELx_EC_SHIFT; 199 + u64 hpfar, far; 200 + 201 + vcpu->arch.fault.esr_el2 = esr; 202 + 203 + if (ec != ESR_ELx_EC_DABT_LOW && ec != ESR_ELx_EC_IABT_LOW) 204 + return true; 205 + 206 + far = read_sysreg_el2(far); 207 + 208 + /* 209 + * The HPFAR can be invalid if the stage 2 fault did not 210 + * happen during a stage 1 page table walk (the ESR_EL2.S1PTW 211 + * bit is clear) and one of the two following cases are true: 212 + * 1. The fault was due to a permission fault 213 + * 2. The processor carries errata 834220 214 + * 215 + * Therefore, for all non S1PTW faults where we either have a 216 + * permission fault or the errata workaround is enabled, we 217 + * resolve the IPA using the AT instruction. 218 + */ 219 + if (!(esr & ESR_ELx_S1PTW) && 220 + (__check_arm_834220()() || (esr & ESR_ELx_FSC_TYPE) == FSC_PERM)) { 221 + if (!__translate_far_to_hpfar(far, &hpfar)) 222 + return false; 223 + } else { 224 + hpfar = read_sysreg(hpfar_el2); 225 + } 226 + 227 + vcpu->arch.fault.far_el2 = far; 228 + vcpu->arch.fault.hpfar_el2 = hpfar; 229 + return true; 230 + } 231 + 153 232 static int __hyp_text __guest_run(struct kvm_vcpu *vcpu) 154 233 { 155 234 struct kvm_cpu_context *host_ctxt; ··· 261 180 __debug_restore_state(vcpu, kern_hyp_va(vcpu->arch.debug_ptr), guest_ctxt); 262 181 263 182 /* Jump in the fire! */ 183 + again: 264 184 exit_code = __guest_enter(vcpu, host_ctxt); 265 185 /* And we're baaack! */ 186 + 187 + if (exit_code == ARM_EXCEPTION_TRAP && !__populate_fault_info(vcpu)) 188 + goto again; 266 189 267 190 fp_enabled = __fpsimd_enabled(); 268 191