162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2012,2013 - ARM Ltd 462306a36Sopenharmony_ci * Author: Marc Zyngier <marc.zyngier@arm.com> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Derived from arch/arm/include/kvm_emulate.h 762306a36Sopenharmony_ci * Copyright (C) 2012 - Virtual Open Systems and Columbia University 862306a36Sopenharmony_ci * Author: Christoffer Dall <c.dall@virtualopensystems.com> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#ifndef __ARM64_KVM_EMULATE_H__ 1262306a36Sopenharmony_ci#define __ARM64_KVM_EMULATE_H__ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/kvm_host.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <asm/debug-monitors.h> 1762306a36Sopenharmony_ci#include <asm/esr.h> 1862306a36Sopenharmony_ci#include <asm/kvm_arm.h> 1962306a36Sopenharmony_ci#include <asm/kvm_hyp.h> 2062306a36Sopenharmony_ci#include <asm/ptrace.h> 2162306a36Sopenharmony_ci#include <asm/cputype.h> 2262306a36Sopenharmony_ci#include <asm/virt.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define CURRENT_EL_SP_EL0_VECTOR 0x0 2562306a36Sopenharmony_ci#define CURRENT_EL_SP_ELx_VECTOR 0x200 2662306a36Sopenharmony_ci#define LOWER_EL_AArch64_VECTOR 0x400 2762306a36Sopenharmony_ci#define LOWER_EL_AArch32_VECTOR 0x600 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cienum exception_type { 3062306a36Sopenharmony_ci except_type_sync = 0, 3162306a36Sopenharmony_ci except_type_irq = 0x80, 3262306a36Sopenharmony_ci except_type_fiq = 0x100, 3362306a36Sopenharmony_ci except_type_serror = 0x180, 3462306a36Sopenharmony_ci}; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define kvm_exception_type_names \ 3762306a36Sopenharmony_ci { except_type_sync, "SYNC" }, \ 3862306a36Sopenharmony_ci { except_type_irq, "IRQ" }, \ 3962306a36Sopenharmony_ci { except_type_fiq, "FIQ" }, \ 4062306a36Sopenharmony_ci { except_type_serror, "SERROR" } 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cibool kvm_condition_valid32(const struct kvm_vcpu *vcpu); 4362306a36Sopenharmony_civoid kvm_skip_instr32(struct kvm_vcpu *vcpu); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_civoid kvm_inject_undefined(struct kvm_vcpu *vcpu); 4662306a36Sopenharmony_civoid kvm_inject_vabt(struct kvm_vcpu *vcpu); 4762306a36Sopenharmony_civoid kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr); 4862306a36Sopenharmony_civoid kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr); 4962306a36Sopenharmony_civoid kvm_inject_size_fault(struct kvm_vcpu *vcpu); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_civoid kvm_vcpu_wfi(struct kvm_vcpu *vcpu); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_civoid kvm_emulate_nested_eret(struct kvm_vcpu *vcpu); 5462306a36Sopenharmony_ciint kvm_inject_nested_sync(struct kvm_vcpu *vcpu, u64 esr_el2); 5562306a36Sopenharmony_ciint kvm_inject_nested_irq(struct kvm_vcpu *vcpu); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#if defined(__KVM_VHE_HYPERVISOR__) || defined(__KVM_NVHE_HYPERVISOR__) 5862306a36Sopenharmony_cistatic __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci return !(vcpu->arch.hcr_el2 & HCR_RW); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci#else 6362306a36Sopenharmony_cistatic __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci return test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features); 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci#endif 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS; 7262306a36Sopenharmony_ci if (has_vhe() || has_hvhe()) 7362306a36Sopenharmony_ci vcpu->arch.hcr_el2 |= HCR_E2H; 7462306a36Sopenharmony_ci if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN)) { 7562306a36Sopenharmony_ci /* route synchronous external abort exceptions to EL2 */ 7662306a36Sopenharmony_ci vcpu->arch.hcr_el2 |= HCR_TEA; 7762306a36Sopenharmony_ci /* trap error record accesses */ 7862306a36Sopenharmony_ci vcpu->arch.hcr_el2 |= HCR_TERR; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (cpus_have_const_cap(ARM64_HAS_STAGE2_FWB)) { 8262306a36Sopenharmony_ci vcpu->arch.hcr_el2 |= HCR_FWB; 8362306a36Sopenharmony_ci } else { 8462306a36Sopenharmony_ci /* 8562306a36Sopenharmony_ci * For non-FWB CPUs, we trap VM ops (HCR_EL2.TVM) until M+C 8662306a36Sopenharmony_ci * get set in SCTLR_EL1 such that we can detect when the guest 8762306a36Sopenharmony_ci * MMU gets turned on and do the necessary cache maintenance 8862306a36Sopenharmony_ci * then. 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci vcpu->arch.hcr_el2 |= HCR_TVM; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (cpus_have_final_cap(ARM64_HAS_EVT) && 9462306a36Sopenharmony_ci !cpus_have_final_cap(ARM64_MISMATCHED_CACHE_TYPE)) 9562306a36Sopenharmony_ci vcpu->arch.hcr_el2 |= HCR_TID4; 9662306a36Sopenharmony_ci else 9762306a36Sopenharmony_ci vcpu->arch.hcr_el2 |= HCR_TID2; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (vcpu_el1_is_32bit(vcpu)) 10062306a36Sopenharmony_ci vcpu->arch.hcr_el2 &= ~HCR_RW; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci if (kvm_has_mte(vcpu->kvm)) 10362306a36Sopenharmony_ci vcpu->arch.hcr_el2 |= HCR_ATA; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic inline unsigned long *vcpu_hcr(struct kvm_vcpu *vcpu) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci return (unsigned long *)&vcpu->arch.hcr_el2; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic inline void vcpu_clear_wfx_traps(struct kvm_vcpu *vcpu) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci vcpu->arch.hcr_el2 &= ~HCR_TWE; 11462306a36Sopenharmony_ci if (atomic_read(&vcpu->arch.vgic_cpu.vgic_v3.its_vpe.vlpi_count) || 11562306a36Sopenharmony_ci vcpu->kvm->arch.vgic.nassgireq) 11662306a36Sopenharmony_ci vcpu->arch.hcr_el2 &= ~HCR_TWI; 11762306a36Sopenharmony_ci else 11862306a36Sopenharmony_ci vcpu->arch.hcr_el2 |= HCR_TWI; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic inline void vcpu_set_wfx_traps(struct kvm_vcpu *vcpu) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci vcpu->arch.hcr_el2 |= HCR_TWE; 12462306a36Sopenharmony_ci vcpu->arch.hcr_el2 |= HCR_TWI; 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic inline void vcpu_ptrauth_enable(struct kvm_vcpu *vcpu) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci vcpu->arch.hcr_el2 |= (HCR_API | HCR_APK); 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic inline void vcpu_ptrauth_disable(struct kvm_vcpu *vcpu) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci vcpu->arch.hcr_el2 &= ~(HCR_API | HCR_APK); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic inline unsigned long vcpu_get_vsesr(struct kvm_vcpu *vcpu) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci return vcpu->arch.vsesr_el2; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic inline void vcpu_set_vsesr(struct kvm_vcpu *vcpu, u64 vsesr) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci vcpu->arch.vsesr_el2 = vsesr; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic __always_inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci return (unsigned long *)&vcpu_gp_regs(vcpu)->pc; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic __always_inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci return (unsigned long *)&vcpu_gp_regs(vcpu)->pstate; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic __always_inline bool vcpu_mode_is_32bit(const struct kvm_vcpu *vcpu) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci return !!(*vcpu_cpsr(vcpu) & PSR_MODE32_BIT); 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic __always_inline bool kvm_condition_valid(const struct kvm_vcpu *vcpu) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci if (vcpu_mode_is_32bit(vcpu)) 16562306a36Sopenharmony_ci return kvm_condition_valid32(vcpu); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci return true; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic inline void vcpu_set_thumb(struct kvm_vcpu *vcpu) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci *vcpu_cpsr(vcpu) |= PSR_AA32_T_BIT; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci/* 17662306a36Sopenharmony_ci * vcpu_get_reg and vcpu_set_reg should always be passed a register number 17762306a36Sopenharmony_ci * coming from a read of ESR_EL2. Otherwise, it may give the wrong result on 17862306a36Sopenharmony_ci * AArch32 with banked registers. 17962306a36Sopenharmony_ci */ 18062306a36Sopenharmony_cistatic __always_inline unsigned long vcpu_get_reg(const struct kvm_vcpu *vcpu, 18162306a36Sopenharmony_ci u8 reg_num) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci return (reg_num == 31) ? 0 : vcpu_gp_regs(vcpu)->regs[reg_num]; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic __always_inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num, 18762306a36Sopenharmony_ci unsigned long val) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci if (reg_num != 31) 19062306a36Sopenharmony_ci vcpu_gp_regs(vcpu)->regs[reg_num] = val; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic inline bool vcpu_is_el2_ctxt(const struct kvm_cpu_context *ctxt) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci switch (ctxt->regs.pstate & (PSR_MODE32_BIT | PSR_MODE_MASK)) { 19662306a36Sopenharmony_ci case PSR_MODE_EL2h: 19762306a36Sopenharmony_ci case PSR_MODE_EL2t: 19862306a36Sopenharmony_ci return true; 19962306a36Sopenharmony_ci default: 20062306a36Sopenharmony_ci return false; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic inline bool vcpu_is_el2(const struct kvm_vcpu *vcpu) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci return vcpu_is_el2_ctxt(&vcpu->arch.ctxt); 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic inline bool __vcpu_el2_e2h_is_set(const struct kvm_cpu_context *ctxt) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci return ctxt_sys_reg(ctxt, HCR_EL2) & HCR_E2H; 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic inline bool vcpu_el2_e2h_is_set(const struct kvm_vcpu *vcpu) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci return __vcpu_el2_e2h_is_set(&vcpu->arch.ctxt); 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic inline bool __vcpu_el2_tge_is_set(const struct kvm_cpu_context *ctxt) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci return ctxt_sys_reg(ctxt, HCR_EL2) & HCR_TGE; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic inline bool vcpu_el2_tge_is_set(const struct kvm_vcpu *vcpu) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci return __vcpu_el2_tge_is_set(&vcpu->arch.ctxt); 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic inline bool __is_hyp_ctxt(const struct kvm_cpu_context *ctxt) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci /* 23262306a36Sopenharmony_ci * We are in a hypervisor context if the vcpu mode is EL2 or 23362306a36Sopenharmony_ci * E2H and TGE bits are set. The latter means we are in the user space 23462306a36Sopenharmony_ci * of the VHE kernel. ARMv8.1 ARM describes this as 'InHost' 23562306a36Sopenharmony_ci * 23662306a36Sopenharmony_ci * Note that the HCR_EL2.{E2H,TGE}={0,1} isn't really handled in the 23762306a36Sopenharmony_ci * rest of the KVM code, and will result in a misbehaving guest. 23862306a36Sopenharmony_ci */ 23962306a36Sopenharmony_ci return vcpu_is_el2_ctxt(ctxt) || 24062306a36Sopenharmony_ci (__vcpu_el2_e2h_is_set(ctxt) && __vcpu_el2_tge_is_set(ctxt)) || 24162306a36Sopenharmony_ci __vcpu_el2_tge_is_set(ctxt); 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic inline bool is_hyp_ctxt(const struct kvm_vcpu *vcpu) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci return __is_hyp_ctxt(&vcpu->arch.ctxt); 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci/* 25062306a36Sopenharmony_ci * The layout of SPSR for an AArch32 state is different when observed from an 25162306a36Sopenharmony_ci * AArch64 SPSR_ELx or an AArch32 SPSR_*. This function generates the AArch32 25262306a36Sopenharmony_ci * view given an AArch64 view. 25362306a36Sopenharmony_ci * 25462306a36Sopenharmony_ci * In ARM DDI 0487E.a see: 25562306a36Sopenharmony_ci * 25662306a36Sopenharmony_ci * - The AArch64 view (SPSR_EL2) in section C5.2.18, page C5-426 25762306a36Sopenharmony_ci * - The AArch32 view (SPSR_abt) in section G8.2.126, page G8-6256 25862306a36Sopenharmony_ci * - The AArch32 view (SPSR_und) in section G8.2.132, page G8-6280 25962306a36Sopenharmony_ci * 26062306a36Sopenharmony_ci * Which show the following differences: 26162306a36Sopenharmony_ci * 26262306a36Sopenharmony_ci * | Bit | AA64 | AA32 | Notes | 26362306a36Sopenharmony_ci * +-----+------+------+-----------------------------| 26462306a36Sopenharmony_ci * | 24 | DIT | J | J is RES0 in ARMv8 | 26562306a36Sopenharmony_ci * | 21 | SS | DIT | SS doesn't exist in AArch32 | 26662306a36Sopenharmony_ci * 26762306a36Sopenharmony_ci * ... and all other bits are (currently) common. 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_cistatic inline unsigned long host_spsr_to_spsr32(unsigned long spsr) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci const unsigned long overlap = BIT(24) | BIT(21); 27262306a36Sopenharmony_ci unsigned long dit = !!(spsr & PSR_AA32_DIT_BIT); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci spsr &= ~overlap; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci spsr |= dit << 21; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci return spsr; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci u32 mode; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (vcpu_mode_is_32bit(vcpu)) { 28662306a36Sopenharmony_ci mode = *vcpu_cpsr(vcpu) & PSR_AA32_MODE_MASK; 28762306a36Sopenharmony_ci return mode > PSR_AA32_MODE_USR; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci mode = *vcpu_cpsr(vcpu) & PSR_MODE_MASK; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return mode != PSR_MODE_EL0t; 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic __always_inline u64 kvm_vcpu_get_esr(const struct kvm_vcpu *vcpu) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci return vcpu->arch.fault.esr_el2; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic __always_inline int kvm_vcpu_get_condition(const struct kvm_vcpu *vcpu) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci u64 esr = kvm_vcpu_get_esr(vcpu); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (esr & ESR_ELx_CV) 30562306a36Sopenharmony_ci return (esr & ESR_ELx_COND_MASK) >> ESR_ELx_COND_SHIFT; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci return -1; 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic __always_inline unsigned long kvm_vcpu_get_hfar(const struct kvm_vcpu *vcpu) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci return vcpu->arch.fault.far_el2; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic __always_inline phys_addr_t kvm_vcpu_get_fault_ipa(const struct kvm_vcpu *vcpu) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci return ((phys_addr_t)vcpu->arch.fault.hpfar_el2 & HPFAR_MASK) << 8; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic inline u64 kvm_vcpu_get_disr(const struct kvm_vcpu *vcpu) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci return vcpu->arch.fault.disr_el1; 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic inline u32 kvm_vcpu_hvc_get_imm(const struct kvm_vcpu *vcpu) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci return kvm_vcpu_get_esr(vcpu) & ESR_ELx_xVC_IMM_MASK; 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic __always_inline bool kvm_vcpu_dabt_isvalid(const struct kvm_vcpu *vcpu) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_ISV); 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic inline unsigned long kvm_vcpu_dabt_iss_nisv_sanitized(const struct kvm_vcpu *vcpu) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci return kvm_vcpu_get_esr(vcpu) & (ESR_ELx_CM | ESR_ELx_WNR | ESR_ELx_FSC); 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic inline bool kvm_vcpu_dabt_issext(const struct kvm_vcpu *vcpu) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_SSE); 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic inline bool kvm_vcpu_dabt_issf(const struct kvm_vcpu *vcpu) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_SF); 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cistatic __always_inline int kvm_vcpu_dabt_get_rd(const struct kvm_vcpu *vcpu) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci return (kvm_vcpu_get_esr(vcpu) & ESR_ELx_SRT_MASK) >> ESR_ELx_SRT_SHIFT; 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic __always_inline bool kvm_vcpu_abt_iss1tw(const struct kvm_vcpu *vcpu) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_S1PTW); 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci/* Always check for S1PTW *before* using this. */ 36162306a36Sopenharmony_cistatic __always_inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *vcpu) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci return kvm_vcpu_get_esr(vcpu) & ESR_ELx_WNR; 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic inline bool kvm_vcpu_dabt_is_cm(const struct kvm_vcpu *vcpu) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_CM); 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic __always_inline unsigned int kvm_vcpu_dabt_get_as(const struct kvm_vcpu *vcpu) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci return 1 << ((kvm_vcpu_get_esr(vcpu) & ESR_ELx_SAS) >> ESR_ELx_SAS_SHIFT); 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci/* This one is not specific to Data Abort */ 37762306a36Sopenharmony_cistatic __always_inline bool kvm_vcpu_trap_il_is32bit(const struct kvm_vcpu *vcpu) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_IL); 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic __always_inline u8 kvm_vcpu_trap_get_class(const struct kvm_vcpu *vcpu) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci return ESR_ELx_EC(kvm_vcpu_get_esr(vcpu)); 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic inline bool kvm_vcpu_trap_is_iabt(const struct kvm_vcpu *vcpu) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci return kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_IABT_LOW; 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic inline bool kvm_vcpu_trap_is_exec_fault(const struct kvm_vcpu *vcpu) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci return kvm_vcpu_trap_is_iabt(vcpu) && !kvm_vcpu_abt_iss1tw(vcpu); 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cistatic __always_inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC; 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic __always_inline u8 kvm_vcpu_trap_get_fault_type(const struct kvm_vcpu *vcpu) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_TYPE; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic __always_inline u8 kvm_vcpu_trap_get_fault_level(const struct kvm_vcpu *vcpu) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_LEVEL; 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic __always_inline bool kvm_vcpu_abt_issea(const struct kvm_vcpu *vcpu) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci switch (kvm_vcpu_trap_get_fault(vcpu)) { 41562306a36Sopenharmony_ci case ESR_ELx_FSC_EXTABT: 41662306a36Sopenharmony_ci case ESR_ELx_FSC_SEA_TTW0: 41762306a36Sopenharmony_ci case ESR_ELx_FSC_SEA_TTW1: 41862306a36Sopenharmony_ci case ESR_ELx_FSC_SEA_TTW2: 41962306a36Sopenharmony_ci case ESR_ELx_FSC_SEA_TTW3: 42062306a36Sopenharmony_ci case ESR_ELx_FSC_SECC: 42162306a36Sopenharmony_ci case ESR_ELx_FSC_SECC_TTW0: 42262306a36Sopenharmony_ci case ESR_ELx_FSC_SECC_TTW1: 42362306a36Sopenharmony_ci case ESR_ELx_FSC_SECC_TTW2: 42462306a36Sopenharmony_ci case ESR_ELx_FSC_SECC_TTW3: 42562306a36Sopenharmony_ci return true; 42662306a36Sopenharmony_ci default: 42762306a36Sopenharmony_ci return false; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic __always_inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci u64 esr = kvm_vcpu_get_esr(vcpu); 43462306a36Sopenharmony_ci return ESR_ELx_SYS64_ISS_RT(esr); 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci if (kvm_vcpu_abt_iss1tw(vcpu)) { 44062306a36Sopenharmony_ci /* 44162306a36Sopenharmony_ci * Only a permission fault on a S1PTW should be 44262306a36Sopenharmony_ci * considered as a write. Otherwise, page tables baked 44362306a36Sopenharmony_ci * in a read-only memslot will result in an exception 44462306a36Sopenharmony_ci * being delivered in the guest. 44562306a36Sopenharmony_ci * 44662306a36Sopenharmony_ci * The drawback is that we end-up faulting twice if the 44762306a36Sopenharmony_ci * guest is using any of HW AF/DB: a translation fault 44862306a36Sopenharmony_ci * to map the page containing the PT (read only at 44962306a36Sopenharmony_ci * first), then a permission fault to allow the flags 45062306a36Sopenharmony_ci * to be set. 45162306a36Sopenharmony_ci */ 45262306a36Sopenharmony_ci switch (kvm_vcpu_trap_get_fault_type(vcpu)) { 45362306a36Sopenharmony_ci case ESR_ELx_FSC_PERM: 45462306a36Sopenharmony_ci return true; 45562306a36Sopenharmony_ci default: 45662306a36Sopenharmony_ci return false; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci if (kvm_vcpu_trap_is_iabt(vcpu)) 46162306a36Sopenharmony_ci return false; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci return kvm_vcpu_dabt_iswrite(vcpu); 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK; 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_cistatic inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci if (vcpu_mode_is_32bit(vcpu)) { 47462306a36Sopenharmony_ci *vcpu_cpsr(vcpu) |= PSR_AA32_E_BIT; 47562306a36Sopenharmony_ci } else { 47662306a36Sopenharmony_ci u64 sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1); 47762306a36Sopenharmony_ci sctlr |= SCTLR_ELx_EE; 47862306a36Sopenharmony_ci vcpu_write_sys_reg(vcpu, sctlr, SCTLR_EL1); 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistatic inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci if (vcpu_mode_is_32bit(vcpu)) 48562306a36Sopenharmony_ci return !!(*vcpu_cpsr(vcpu) & PSR_AA32_E_BIT); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if (vcpu_mode_priv(vcpu)) 48862306a36Sopenharmony_ci return !!(vcpu_read_sys_reg(vcpu, SCTLR_EL1) & SCTLR_ELx_EE); 48962306a36Sopenharmony_ci else 49062306a36Sopenharmony_ci return !!(vcpu_read_sys_reg(vcpu, SCTLR_EL1) & SCTLR_EL1_E0E); 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu, 49462306a36Sopenharmony_ci unsigned long data, 49562306a36Sopenharmony_ci unsigned int len) 49662306a36Sopenharmony_ci{ 49762306a36Sopenharmony_ci if (kvm_vcpu_is_be(vcpu)) { 49862306a36Sopenharmony_ci switch (len) { 49962306a36Sopenharmony_ci case 1: 50062306a36Sopenharmony_ci return data & 0xff; 50162306a36Sopenharmony_ci case 2: 50262306a36Sopenharmony_ci return be16_to_cpu(data & 0xffff); 50362306a36Sopenharmony_ci case 4: 50462306a36Sopenharmony_ci return be32_to_cpu(data & 0xffffffff); 50562306a36Sopenharmony_ci default: 50662306a36Sopenharmony_ci return be64_to_cpu(data); 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci } else { 50962306a36Sopenharmony_ci switch (len) { 51062306a36Sopenharmony_ci case 1: 51162306a36Sopenharmony_ci return data & 0xff; 51262306a36Sopenharmony_ci case 2: 51362306a36Sopenharmony_ci return le16_to_cpu(data & 0xffff); 51462306a36Sopenharmony_ci case 4: 51562306a36Sopenharmony_ci return le32_to_cpu(data & 0xffffffff); 51662306a36Sopenharmony_ci default: 51762306a36Sopenharmony_ci return le64_to_cpu(data); 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci return data; /* Leave LE untouched */ 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_cistatic inline unsigned long vcpu_data_host_to_guest(struct kvm_vcpu *vcpu, 52562306a36Sopenharmony_ci unsigned long data, 52662306a36Sopenharmony_ci unsigned int len) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci if (kvm_vcpu_is_be(vcpu)) { 52962306a36Sopenharmony_ci switch (len) { 53062306a36Sopenharmony_ci case 1: 53162306a36Sopenharmony_ci return data & 0xff; 53262306a36Sopenharmony_ci case 2: 53362306a36Sopenharmony_ci return cpu_to_be16(data & 0xffff); 53462306a36Sopenharmony_ci case 4: 53562306a36Sopenharmony_ci return cpu_to_be32(data & 0xffffffff); 53662306a36Sopenharmony_ci default: 53762306a36Sopenharmony_ci return cpu_to_be64(data); 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci } else { 54062306a36Sopenharmony_ci switch (len) { 54162306a36Sopenharmony_ci case 1: 54262306a36Sopenharmony_ci return data & 0xff; 54362306a36Sopenharmony_ci case 2: 54462306a36Sopenharmony_ci return cpu_to_le16(data & 0xffff); 54562306a36Sopenharmony_ci case 4: 54662306a36Sopenharmony_ci return cpu_to_le32(data & 0xffffffff); 54762306a36Sopenharmony_ci default: 54862306a36Sopenharmony_ci return cpu_to_le64(data); 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci return data; /* Leave LE untouched */ 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic __always_inline void kvm_incr_pc(struct kvm_vcpu *vcpu) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci WARN_ON(vcpu_get_flag(vcpu, PENDING_EXCEPTION)); 55862306a36Sopenharmony_ci vcpu_set_flag(vcpu, INCREMENT_PC); 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci#define kvm_pend_exception(v, e) \ 56262306a36Sopenharmony_ci do { \ 56362306a36Sopenharmony_ci WARN_ON(vcpu_get_flag((v), INCREMENT_PC)); \ 56462306a36Sopenharmony_ci vcpu_set_flag((v), PENDING_EXCEPTION); \ 56562306a36Sopenharmony_ci vcpu_set_flag((v), e); \ 56662306a36Sopenharmony_ci } while (0) 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_cistatic inline bool vcpu_has_feature(struct kvm_vcpu *vcpu, int feature) 57062306a36Sopenharmony_ci{ 57162306a36Sopenharmony_ci return test_bit(feature, vcpu->arch.features); 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_cistatic __always_inline void kvm_write_cptr_el2(u64 val) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci if (has_vhe() || has_hvhe()) 57762306a36Sopenharmony_ci write_sysreg(val, cpacr_el1); 57862306a36Sopenharmony_ci else 57962306a36Sopenharmony_ci write_sysreg(val, cptr_el2); 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_cistatic __always_inline u64 kvm_get_reset_cptr_el2(struct kvm_vcpu *vcpu) 58362306a36Sopenharmony_ci{ 58462306a36Sopenharmony_ci u64 val; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci if (has_vhe()) { 58762306a36Sopenharmony_ci val = (CPACR_EL1_FPEN_EL0EN | CPACR_EL1_FPEN_EL1EN | 58862306a36Sopenharmony_ci CPACR_EL1_ZEN_EL1EN); 58962306a36Sopenharmony_ci if (cpus_have_final_cap(ARM64_SME)) 59062306a36Sopenharmony_ci val |= CPACR_EL1_SMEN_EL1EN; 59162306a36Sopenharmony_ci } else if (has_hvhe()) { 59262306a36Sopenharmony_ci val = (CPACR_EL1_FPEN_EL0EN | CPACR_EL1_FPEN_EL1EN); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (!vcpu_has_sve(vcpu) || 59562306a36Sopenharmony_ci (vcpu->arch.fp_state != FP_STATE_GUEST_OWNED)) 59662306a36Sopenharmony_ci val |= CPACR_EL1_ZEN_EL1EN | CPACR_EL1_ZEN_EL0EN; 59762306a36Sopenharmony_ci if (cpus_have_final_cap(ARM64_SME)) 59862306a36Sopenharmony_ci val |= CPACR_EL1_SMEN_EL1EN | CPACR_EL1_SMEN_EL0EN; 59962306a36Sopenharmony_ci } else { 60062306a36Sopenharmony_ci val = CPTR_NVHE_EL2_RES1; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci if (vcpu_has_sve(vcpu) && 60362306a36Sopenharmony_ci (vcpu->arch.fp_state == FP_STATE_GUEST_OWNED)) 60462306a36Sopenharmony_ci val |= CPTR_EL2_TZ; 60562306a36Sopenharmony_ci if (cpus_have_final_cap(ARM64_SME)) 60662306a36Sopenharmony_ci val &= ~CPTR_EL2_TSM; 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci return val; 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic __always_inline void kvm_reset_cptr_el2(struct kvm_vcpu *vcpu) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci u64 val = kvm_get_reset_cptr_el2(vcpu); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci kvm_write_cptr_el2(val); 61762306a36Sopenharmony_ci} 61862306a36Sopenharmony_ci#endif /* __ARM64_KVM_EMULATE_H__ */ 619