|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
| 2 | +/* |
| 3 | + * Copyright (C) 2015 - ARM Ltd |
| 4 | + * Author: Marc Zyngier <marc.zyngier@arm.com> |
| 5 | + */ |
| 6 | + |
| 7 | +#ifndef __ARM64_KVM_HYP_FAULT_H__ |
| 8 | +#define __ARM64_KVM_HYP_FAULT_H__ |
| 9 | + |
| 10 | +#include <asm/kvm_asm.h> |
| 11 | +#include <asm/kvm_emulate.h> |
| 12 | +#include <asm/kvm_hyp.h> |
| 13 | +#include <asm/kvm_mmu.h> |
| 14 | + |
| 15 | +static inline bool __translate_far_to_hpfar(u64 far, u64 *hpfar) |
| 16 | +{ |
| 17 | + u64 par, tmp; |
| 18 | + |
| 19 | + /* |
| 20 | + * Resolve the IPA the hard way using the guest VA. |
| 21 | + * |
| 22 | + * Stage-1 translation already validated the memory access |
| 23 | + * rights. As such, we can use the EL1 translation regime, and |
| 24 | + * don't have to distinguish between EL0 and EL1 access. |
| 25 | + * |
| 26 | + * We do need to save/restore PAR_EL1 though, as we haven't |
| 27 | + * saved the guest context yet, and we may return early... |
| 28 | + */ |
| 29 | + par = read_sysreg_par(); |
| 30 | + if (!__kvm_at("s1e1r", far)) |
| 31 | + tmp = read_sysreg_par(); |
| 32 | + else |
| 33 | + tmp = SYS_PAR_EL1_F; /* back to the guest */ |
| 34 | + write_sysreg(par, par_el1); |
| 35 | + |
| 36 | + if (unlikely(tmp & SYS_PAR_EL1_F)) |
| 37 | + return false; /* Translation failed, back to guest */ |
| 38 | + |
| 39 | + /* Convert PAR to HPFAR format */ |
| 40 | + *hpfar = PAR_TO_HPFAR(tmp); |
| 41 | + return true; |
| 42 | +} |
| 43 | + |
| 44 | +static inline bool __get_fault_info(u64 esr, struct kvm_vcpu_fault_info *fault) |
| 45 | +{ |
| 46 | + u64 hpfar, far; |
| 47 | + |
| 48 | + far = read_sysreg_el2(SYS_FAR); |
| 49 | + |
| 50 | + /* |
| 51 | + * The HPFAR can be invalid if the stage 2 fault did not |
| 52 | + * happen during a stage 1 page table walk (the ESR_EL2.S1PTW |
| 53 | + * bit is clear) and one of the two following cases are true: |
| 54 | + * 1. The fault was due to a permission fault |
| 55 | + * 2. The processor carries errata 834220 |
| 56 | + * |
| 57 | + * Therefore, for all non S1PTW faults where we either have a |
| 58 | + * permission fault or the errata workaround is enabled, we |
| 59 | + * resolve the IPA using the AT instruction. |
| 60 | + */ |
| 61 | + if (!(esr & ESR_ELx_S1PTW) && |
| 62 | + (cpus_have_final_cap(ARM64_WORKAROUND_834220) || |
| 63 | + (esr & ESR_ELx_FSC_TYPE) == FSC_PERM)) { |
| 64 | + if (!__translate_far_to_hpfar(far, &hpfar)) |
| 65 | + return false; |
| 66 | + } else { |
| 67 | + hpfar = read_sysreg(hpfar_el2); |
| 68 | + } |
| 69 | + |
| 70 | + fault->far_el2 = far; |
| 71 | + fault->hpfar_el2 = hpfar; |
| 72 | + return true; |
| 73 | +} |
| 74 | + |
| 75 | +#endif |
0 commit comments