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/kvm/handle_exit.c: 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#include <linux/kvm.h> 1262306a36Sopenharmony_ci#include <linux/kvm_host.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <asm/esr.h> 1562306a36Sopenharmony_ci#include <asm/exception.h> 1662306a36Sopenharmony_ci#include <asm/kvm_asm.h> 1762306a36Sopenharmony_ci#include <asm/kvm_emulate.h> 1862306a36Sopenharmony_ci#include <asm/kvm_mmu.h> 1962306a36Sopenharmony_ci#include <asm/kvm_nested.h> 2062306a36Sopenharmony_ci#include <asm/debug-monitors.h> 2162306a36Sopenharmony_ci#include <asm/stacktrace/nvhe.h> 2262306a36Sopenharmony_ci#include <asm/traps.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <kvm/arm_hypercalls.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define CREATE_TRACE_POINTS 2762306a36Sopenharmony_ci#include "trace_handle_exit.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_citypedef int (*exit_handle_fn)(struct kvm_vcpu *); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic void kvm_handle_guest_serror(struct kvm_vcpu *vcpu, u64 esr) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci if (!arm64_is_ras_serror(esr) || arm64_is_fatal_ras_serror(NULL, esr)) 3462306a36Sopenharmony_ci kvm_inject_vabt(vcpu); 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic int handle_hvc(struct kvm_vcpu *vcpu) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci trace_kvm_hvc_arm64(*vcpu_pc(vcpu), vcpu_get_reg(vcpu, 0), 4062306a36Sopenharmony_ci kvm_vcpu_hvc_get_imm(vcpu)); 4162306a36Sopenharmony_ci vcpu->stat.hvc_exit_stat++; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci /* Forward hvc instructions to the virtual EL2 if the guest has EL2. */ 4462306a36Sopenharmony_ci if (vcpu_has_nv(vcpu)) { 4562306a36Sopenharmony_ci if (vcpu_read_sys_reg(vcpu, HCR_EL2) & HCR_HCD) 4662306a36Sopenharmony_ci kvm_inject_undefined(vcpu); 4762306a36Sopenharmony_ci else 4862306a36Sopenharmony_ci kvm_inject_nested_sync(vcpu, kvm_vcpu_get_esr(vcpu)); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci return 1; 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci return kvm_smccc_call_handler(vcpu); 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic int handle_smc(struct kvm_vcpu *vcpu) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci /* 5962306a36Sopenharmony_ci * "If an SMC instruction executed at Non-secure EL1 is 6062306a36Sopenharmony_ci * trapped to EL2 because HCR_EL2.TSC is 1, the exception is a 6162306a36Sopenharmony_ci * Trap exception, not a Secure Monitor Call exception [...]" 6262306a36Sopenharmony_ci * 6362306a36Sopenharmony_ci * We need to advance the PC after the trap, as it would 6462306a36Sopenharmony_ci * otherwise return to the same address. Furthermore, pre-incrementing 6562306a36Sopenharmony_ci * the PC before potentially exiting to userspace maintains the same 6662306a36Sopenharmony_ci * abstraction for both SMCs and HVCs. 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_ci kvm_incr_pc(vcpu); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* 7162306a36Sopenharmony_ci * SMCs with a nonzero immediate are reserved according to DEN0028E 2.9 7262306a36Sopenharmony_ci * "SMC and HVC immediate value". 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_ci if (kvm_vcpu_hvc_get_imm(vcpu)) { 7562306a36Sopenharmony_ci vcpu_set_reg(vcpu, 0, ~0UL); 7662306a36Sopenharmony_ci return 1; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci /* 8062306a36Sopenharmony_ci * If imm is zero then it is likely an SMCCC call. 8162306a36Sopenharmony_ci * 8262306a36Sopenharmony_ci * Note that on ARMv8.3, even if EL3 is not implemented, SMC executed 8362306a36Sopenharmony_ci * at Non-secure EL1 is trapped to EL2 if HCR_EL2.TSC==1, rather than 8462306a36Sopenharmony_ci * being treated as UNDEFINED. 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_ci return kvm_smccc_call_handler(vcpu); 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* 9062306a36Sopenharmony_ci * Guest access to FP/ASIMD registers are routed to this handler only 9162306a36Sopenharmony_ci * when the system doesn't support FP/ASIMD. 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_cistatic int handle_no_fpsimd(struct kvm_vcpu *vcpu) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci kvm_inject_undefined(vcpu); 9662306a36Sopenharmony_ci return 1; 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/** 10062306a36Sopenharmony_ci * kvm_handle_wfx - handle a wait-for-interrupts or wait-for-event 10162306a36Sopenharmony_ci * instruction executed by a guest 10262306a36Sopenharmony_ci * 10362306a36Sopenharmony_ci * @vcpu: the vcpu pointer 10462306a36Sopenharmony_ci * 10562306a36Sopenharmony_ci * WFE[T]: Yield the CPU and come back to this vcpu when the scheduler 10662306a36Sopenharmony_ci * decides to. 10762306a36Sopenharmony_ci * WFI: Simply call kvm_vcpu_halt(), which will halt execution of 10862306a36Sopenharmony_ci * world-switches and schedule other host processes until there is an 10962306a36Sopenharmony_ci * incoming IRQ or FIQ to the VM. 11062306a36Sopenharmony_ci * WFIT: Same as WFI, with a timed wakeup implemented as a background timer 11162306a36Sopenharmony_ci * 11262306a36Sopenharmony_ci * WF{I,E}T can immediately return if the deadline has already expired. 11362306a36Sopenharmony_ci */ 11462306a36Sopenharmony_cistatic int kvm_handle_wfx(struct kvm_vcpu *vcpu) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci u64 esr = kvm_vcpu_get_esr(vcpu); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if (esr & ESR_ELx_WFx_ISS_WFE) { 11962306a36Sopenharmony_ci trace_kvm_wfx_arm64(*vcpu_pc(vcpu), true); 12062306a36Sopenharmony_ci vcpu->stat.wfe_exit_stat++; 12162306a36Sopenharmony_ci } else { 12262306a36Sopenharmony_ci trace_kvm_wfx_arm64(*vcpu_pc(vcpu), false); 12362306a36Sopenharmony_ci vcpu->stat.wfi_exit_stat++; 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (esr & ESR_ELx_WFx_ISS_WFxT) { 12762306a36Sopenharmony_ci if (esr & ESR_ELx_WFx_ISS_RV) { 12862306a36Sopenharmony_ci u64 val, now; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci now = kvm_arm_timer_get_reg(vcpu, KVM_REG_ARM_TIMER_CNT); 13162306a36Sopenharmony_ci val = vcpu_get_reg(vcpu, kvm_vcpu_sys_get_rt(vcpu)); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (now >= val) 13462306a36Sopenharmony_ci goto out; 13562306a36Sopenharmony_ci } else { 13662306a36Sopenharmony_ci /* Treat WFxT as WFx if RN is invalid */ 13762306a36Sopenharmony_ci esr &= ~ESR_ELx_WFx_ISS_WFxT; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (esr & ESR_ELx_WFx_ISS_WFE) { 14262306a36Sopenharmony_ci kvm_vcpu_on_spin(vcpu, vcpu_mode_priv(vcpu)); 14362306a36Sopenharmony_ci } else { 14462306a36Sopenharmony_ci if (esr & ESR_ELx_WFx_ISS_WFxT) 14562306a36Sopenharmony_ci vcpu_set_flag(vcpu, IN_WFIT); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci kvm_vcpu_wfi(vcpu); 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ciout: 15062306a36Sopenharmony_ci kvm_incr_pc(vcpu); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci return 1; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/** 15662306a36Sopenharmony_ci * kvm_handle_guest_debug - handle a debug exception instruction 15762306a36Sopenharmony_ci * 15862306a36Sopenharmony_ci * @vcpu: the vcpu pointer 15962306a36Sopenharmony_ci * 16062306a36Sopenharmony_ci * We route all debug exceptions through the same handler. If both the 16162306a36Sopenharmony_ci * guest and host are using the same debug facilities it will be up to 16262306a36Sopenharmony_ci * userspace to re-inject the correct exception for guest delivery. 16362306a36Sopenharmony_ci * 16462306a36Sopenharmony_ci * @return: 0 (while setting vcpu->run->exit_reason) 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_cistatic int kvm_handle_guest_debug(struct kvm_vcpu *vcpu) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct kvm_run *run = vcpu->run; 16962306a36Sopenharmony_ci u64 esr = kvm_vcpu_get_esr(vcpu); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci run->exit_reason = KVM_EXIT_DEBUG; 17262306a36Sopenharmony_ci run->debug.arch.hsr = lower_32_bits(esr); 17362306a36Sopenharmony_ci run->debug.arch.hsr_high = upper_32_bits(esr); 17462306a36Sopenharmony_ci run->flags = KVM_DEBUG_ARCH_HSR_HIGH_VALID; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci switch (ESR_ELx_EC(esr)) { 17762306a36Sopenharmony_ci case ESR_ELx_EC_WATCHPT_LOW: 17862306a36Sopenharmony_ci run->debug.arch.far = vcpu->arch.fault.far_el2; 17962306a36Sopenharmony_ci break; 18062306a36Sopenharmony_ci case ESR_ELx_EC_SOFTSTP_LOW: 18162306a36Sopenharmony_ci vcpu_clear_flag(vcpu, DBG_SS_ACTIVE_PENDING); 18262306a36Sopenharmony_ci break; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci return 0; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci u64 esr = kvm_vcpu_get_esr(vcpu); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci kvm_pr_unimpl("Unknown exception class: esr: %#016llx -- %s\n", 19362306a36Sopenharmony_ci esr, esr_get_class_string(esr)); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci kvm_inject_undefined(vcpu); 19662306a36Sopenharmony_ci return 1; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci/* 20062306a36Sopenharmony_ci * Guest access to SVE registers should be routed to this handler only 20162306a36Sopenharmony_ci * when the system doesn't support SVE. 20262306a36Sopenharmony_ci */ 20362306a36Sopenharmony_cistatic int handle_sve(struct kvm_vcpu *vcpu) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci kvm_inject_undefined(vcpu); 20662306a36Sopenharmony_ci return 1; 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci/* 21062306a36Sopenharmony_ci * Guest usage of a ptrauth instruction (which the guest EL1 did not turn into 21162306a36Sopenharmony_ci * a NOP). If we get here, it is that we didn't fixup ptrauth on exit, and all 21262306a36Sopenharmony_ci * that we can do is give the guest an UNDEF. 21362306a36Sopenharmony_ci */ 21462306a36Sopenharmony_cistatic int kvm_handle_ptrauth(struct kvm_vcpu *vcpu) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci kvm_inject_undefined(vcpu); 21762306a36Sopenharmony_ci return 1; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic int kvm_handle_eret(struct kvm_vcpu *vcpu) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci if (kvm_vcpu_get_esr(vcpu) & ESR_ELx_ERET_ISS_ERET) 22362306a36Sopenharmony_ci return kvm_handle_ptrauth(vcpu); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* 22662306a36Sopenharmony_ci * If we got here, two possibilities: 22762306a36Sopenharmony_ci * 22862306a36Sopenharmony_ci * - the guest is in EL2, and we need to fully emulate ERET 22962306a36Sopenharmony_ci * 23062306a36Sopenharmony_ci * - the guest is in EL1, and we need to reinject the 23162306a36Sopenharmony_ci * exception into the L1 hypervisor. 23262306a36Sopenharmony_ci * 23362306a36Sopenharmony_ci * If KVM ever traps ERET for its own use, we'll have to 23462306a36Sopenharmony_ci * revisit this. 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_ci if (is_hyp_ctxt(vcpu)) 23762306a36Sopenharmony_ci kvm_emulate_nested_eret(vcpu); 23862306a36Sopenharmony_ci else 23962306a36Sopenharmony_ci kvm_inject_nested_sync(vcpu, kvm_vcpu_get_esr(vcpu)); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci return 1; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic int handle_svc(struct kvm_vcpu *vcpu) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci /* 24762306a36Sopenharmony_ci * So far, SVC traps only for NV via HFGITR_EL2. A SVC from a 24862306a36Sopenharmony_ci * 32bit guest would be caught by vpcu_mode_is_bad_32bit(), so 24962306a36Sopenharmony_ci * we should only have to deal with a 64 bit exception. 25062306a36Sopenharmony_ci */ 25162306a36Sopenharmony_ci kvm_inject_nested_sync(vcpu, kvm_vcpu_get_esr(vcpu)); 25262306a36Sopenharmony_ci return 1; 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cistatic exit_handle_fn arm_exit_handlers[] = { 25662306a36Sopenharmony_ci [0 ... ESR_ELx_EC_MAX] = kvm_handle_unknown_ec, 25762306a36Sopenharmony_ci [ESR_ELx_EC_WFx] = kvm_handle_wfx, 25862306a36Sopenharmony_ci [ESR_ELx_EC_CP15_32] = kvm_handle_cp15_32, 25962306a36Sopenharmony_ci [ESR_ELx_EC_CP15_64] = kvm_handle_cp15_64, 26062306a36Sopenharmony_ci [ESR_ELx_EC_CP14_MR] = kvm_handle_cp14_32, 26162306a36Sopenharmony_ci [ESR_ELx_EC_CP14_LS] = kvm_handle_cp14_load_store, 26262306a36Sopenharmony_ci [ESR_ELx_EC_CP10_ID] = kvm_handle_cp10_id, 26362306a36Sopenharmony_ci [ESR_ELx_EC_CP14_64] = kvm_handle_cp14_64, 26462306a36Sopenharmony_ci [ESR_ELx_EC_HVC32] = handle_hvc, 26562306a36Sopenharmony_ci [ESR_ELx_EC_SMC32] = handle_smc, 26662306a36Sopenharmony_ci [ESR_ELx_EC_HVC64] = handle_hvc, 26762306a36Sopenharmony_ci [ESR_ELx_EC_SMC64] = handle_smc, 26862306a36Sopenharmony_ci [ESR_ELx_EC_SVC64] = handle_svc, 26962306a36Sopenharmony_ci [ESR_ELx_EC_SYS64] = kvm_handle_sys_reg, 27062306a36Sopenharmony_ci [ESR_ELx_EC_SVE] = handle_sve, 27162306a36Sopenharmony_ci [ESR_ELx_EC_ERET] = kvm_handle_eret, 27262306a36Sopenharmony_ci [ESR_ELx_EC_IABT_LOW] = kvm_handle_guest_abort, 27362306a36Sopenharmony_ci [ESR_ELx_EC_DABT_LOW] = kvm_handle_guest_abort, 27462306a36Sopenharmony_ci [ESR_ELx_EC_SOFTSTP_LOW]= kvm_handle_guest_debug, 27562306a36Sopenharmony_ci [ESR_ELx_EC_WATCHPT_LOW]= kvm_handle_guest_debug, 27662306a36Sopenharmony_ci [ESR_ELx_EC_BREAKPT_LOW]= kvm_handle_guest_debug, 27762306a36Sopenharmony_ci [ESR_ELx_EC_BKPT32] = kvm_handle_guest_debug, 27862306a36Sopenharmony_ci [ESR_ELx_EC_BRK64] = kvm_handle_guest_debug, 27962306a36Sopenharmony_ci [ESR_ELx_EC_FP_ASIMD] = handle_no_fpsimd, 28062306a36Sopenharmony_ci [ESR_ELx_EC_PAC] = kvm_handle_ptrauth, 28162306a36Sopenharmony_ci}; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci u64 esr = kvm_vcpu_get_esr(vcpu); 28662306a36Sopenharmony_ci u8 esr_ec = ESR_ELx_EC(esr); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci return arm_exit_handlers[esr_ec]; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci/* 29262306a36Sopenharmony_ci * We may be single-stepping an emulated instruction. If the emulation 29362306a36Sopenharmony_ci * has been completed in the kernel, we can return to userspace with a 29462306a36Sopenharmony_ci * KVM_EXIT_DEBUG, otherwise userspace needs to complete its 29562306a36Sopenharmony_ci * emulation first. 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_cistatic int handle_trap_exceptions(struct kvm_vcpu *vcpu) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci int handled; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* 30262306a36Sopenharmony_ci * See ARM ARM B1.14.1: "Hyp traps on instructions 30362306a36Sopenharmony_ci * that fail their condition code check" 30462306a36Sopenharmony_ci */ 30562306a36Sopenharmony_ci if (!kvm_condition_valid(vcpu)) { 30662306a36Sopenharmony_ci kvm_incr_pc(vcpu); 30762306a36Sopenharmony_ci handled = 1; 30862306a36Sopenharmony_ci } else { 30962306a36Sopenharmony_ci exit_handle_fn exit_handler; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci exit_handler = kvm_get_exit_handler(vcpu); 31262306a36Sopenharmony_ci handled = exit_handler(vcpu); 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci return handled; 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci/* 31962306a36Sopenharmony_ci * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on 32062306a36Sopenharmony_ci * proper exit to userspace. 32162306a36Sopenharmony_ci */ 32262306a36Sopenharmony_ciint handle_exit(struct kvm_vcpu *vcpu, int exception_index) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct kvm_run *run = vcpu->run; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (ARM_SERROR_PENDING(exception_index)) { 32762306a36Sopenharmony_ci /* 32862306a36Sopenharmony_ci * The SError is handled by handle_exit_early(). If the guest 32962306a36Sopenharmony_ci * survives it will re-execute the original instruction. 33062306a36Sopenharmony_ci */ 33162306a36Sopenharmony_ci return 1; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci exception_index = ARM_EXCEPTION_CODE(exception_index); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci switch (exception_index) { 33762306a36Sopenharmony_ci case ARM_EXCEPTION_IRQ: 33862306a36Sopenharmony_ci return 1; 33962306a36Sopenharmony_ci case ARM_EXCEPTION_EL1_SERROR: 34062306a36Sopenharmony_ci return 1; 34162306a36Sopenharmony_ci case ARM_EXCEPTION_TRAP: 34262306a36Sopenharmony_ci return handle_trap_exceptions(vcpu); 34362306a36Sopenharmony_ci case ARM_EXCEPTION_HYP_GONE: 34462306a36Sopenharmony_ci /* 34562306a36Sopenharmony_ci * EL2 has been reset to the hyp-stub. This happens when a guest 34662306a36Sopenharmony_ci * is pre-emptied by kvm_reboot()'s shutdown call. 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_ci run->exit_reason = KVM_EXIT_FAIL_ENTRY; 34962306a36Sopenharmony_ci return 0; 35062306a36Sopenharmony_ci case ARM_EXCEPTION_IL: 35162306a36Sopenharmony_ci /* 35262306a36Sopenharmony_ci * We attempted an illegal exception return. Guest state must 35362306a36Sopenharmony_ci * have been corrupted somehow. Give up. 35462306a36Sopenharmony_ci */ 35562306a36Sopenharmony_ci run->exit_reason = KVM_EXIT_FAIL_ENTRY; 35662306a36Sopenharmony_ci return -EINVAL; 35762306a36Sopenharmony_ci default: 35862306a36Sopenharmony_ci kvm_pr_unimpl("Unsupported exception type: %d", 35962306a36Sopenharmony_ci exception_index); 36062306a36Sopenharmony_ci run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 36162306a36Sopenharmony_ci return 0; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci/* For exit types that need handling before we can be preempted */ 36662306a36Sopenharmony_civoid handle_exit_early(struct kvm_vcpu *vcpu, int exception_index) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci if (ARM_SERROR_PENDING(exception_index)) { 36962306a36Sopenharmony_ci if (this_cpu_has_cap(ARM64_HAS_RAS_EXTN)) { 37062306a36Sopenharmony_ci u64 disr = kvm_vcpu_get_disr(vcpu); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci kvm_handle_guest_serror(vcpu, disr_to_esr(disr)); 37362306a36Sopenharmony_ci } else { 37462306a36Sopenharmony_ci kvm_inject_vabt(vcpu); 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci return; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci exception_index = ARM_EXCEPTION_CODE(exception_index); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci if (exception_index == ARM_EXCEPTION_EL1_SERROR) 38362306a36Sopenharmony_ci kvm_handle_guest_serror(vcpu, kvm_vcpu_get_esr(vcpu)); 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_civoid __noreturn __cold nvhe_hyp_panic_handler(u64 esr, u64 spsr, 38762306a36Sopenharmony_ci u64 elr_virt, u64 elr_phys, 38862306a36Sopenharmony_ci u64 par, uintptr_t vcpu, 38962306a36Sopenharmony_ci u64 far, u64 hpfar) { 39062306a36Sopenharmony_ci u64 elr_in_kimg = __phys_to_kimg(elr_phys); 39162306a36Sopenharmony_ci u64 hyp_offset = elr_in_kimg - kaslr_offset() - elr_virt; 39262306a36Sopenharmony_ci u64 mode = spsr & PSR_MODE_MASK; 39362306a36Sopenharmony_ci u64 panic_addr = elr_virt + hyp_offset; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (mode != PSR_MODE_EL2t && mode != PSR_MODE_EL2h) { 39662306a36Sopenharmony_ci kvm_err("Invalid host exception to nVHE hyp!\n"); 39762306a36Sopenharmony_ci } else if (ESR_ELx_EC(esr) == ESR_ELx_EC_BRK64 && 39862306a36Sopenharmony_ci (esr & ESR_ELx_BRK64_ISS_COMMENT_MASK) == BUG_BRK_IMM) { 39962306a36Sopenharmony_ci const char *file = NULL; 40062306a36Sopenharmony_ci unsigned int line = 0; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci /* All hyp bugs, including warnings, are treated as fatal. */ 40362306a36Sopenharmony_ci if (!is_protected_kvm_enabled() || 40462306a36Sopenharmony_ci IS_ENABLED(CONFIG_NVHE_EL2_DEBUG)) { 40562306a36Sopenharmony_ci struct bug_entry *bug = find_bug(elr_in_kimg); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if (bug) 40862306a36Sopenharmony_ci bug_get_file_line(bug, &file, &line); 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (file) 41262306a36Sopenharmony_ci kvm_err("nVHE hyp BUG at: %s:%u!\n", file, line); 41362306a36Sopenharmony_ci else 41462306a36Sopenharmony_ci kvm_err("nVHE hyp BUG at: [<%016llx>] %pB!\n", panic_addr, 41562306a36Sopenharmony_ci (void *)(panic_addr + kaslr_offset())); 41662306a36Sopenharmony_ci } else { 41762306a36Sopenharmony_ci kvm_err("nVHE hyp panic at: [<%016llx>] %pB!\n", panic_addr, 41862306a36Sopenharmony_ci (void *)(panic_addr + kaslr_offset())); 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci /* Dump the nVHE hypervisor backtrace */ 42262306a36Sopenharmony_ci kvm_nvhe_dump_backtrace(hyp_offset); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci /* 42562306a36Sopenharmony_ci * Hyp has panicked and we're going to handle that by panicking the 42662306a36Sopenharmony_ci * kernel. The kernel offset will be revealed in the panic so we're 42762306a36Sopenharmony_ci * also safe to reveal the hyp offset as a debugging aid for translating 42862306a36Sopenharmony_ci * hyp VAs to vmlinux addresses. 42962306a36Sopenharmony_ci */ 43062306a36Sopenharmony_ci kvm_err("Hyp Offset: 0x%llx\n", hyp_offset); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci panic("HYP panic:\nPS:%08llx PC:%016llx ESR:%016llx\nFAR:%016llx HPFAR:%016llx PAR:%016llx\nVCPU:%016lx\n", 43362306a36Sopenharmony_ci spsr, elr_virt, esr, far, hpfar, par, vcpu); 43462306a36Sopenharmony_ci} 435