18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Fault injection for both 32 and 64bit guests. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2012,2013 - ARM Ltd 68c2ecf20Sopenharmony_ci * Author: Marc Zyngier <marc.zyngier@arm.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Based on arch/arm/kvm/emulate.c 98c2ecf20Sopenharmony_ci * Copyright (C) 2012 - Virtual Open Systems and Columbia University 108c2ecf20Sopenharmony_ci * Author: Christoffer Dall <c.dall@virtualopensystems.com> 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/kvm_host.h> 148c2ecf20Sopenharmony_ci#include <asm/kvm_emulate.h> 158c2ecf20Sopenharmony_ci#include <asm/esr.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define CURRENT_EL_SP_EL0_VECTOR 0x0 188c2ecf20Sopenharmony_ci#define CURRENT_EL_SP_ELx_VECTOR 0x200 198c2ecf20Sopenharmony_ci#define LOWER_EL_AArch64_VECTOR 0x400 208c2ecf20Sopenharmony_ci#define LOWER_EL_AArch32_VECTOR 0x600 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cienum exception_type { 238c2ecf20Sopenharmony_ci except_type_sync = 0, 248c2ecf20Sopenharmony_ci except_type_irq = 0x80, 258c2ecf20Sopenharmony_ci except_type_fiq = 0x100, 268c2ecf20Sopenharmony_ci except_type_serror = 0x180, 278c2ecf20Sopenharmony_ci}; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* 308c2ecf20Sopenharmony_ci * This performs the exception entry at a given EL (@target_mode), stashing PC 318c2ecf20Sopenharmony_ci * and PSTATE into ELR and SPSR respectively, and compute the new PC/PSTATE. 328c2ecf20Sopenharmony_ci * The EL passed to this function *must* be a non-secure, privileged mode with 338c2ecf20Sopenharmony_ci * bit 0 being set (PSTATE.SP == 1). 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * When an exception is taken, most PSTATE fields are left unchanged in the 368c2ecf20Sopenharmony_ci * handler. However, some are explicitly overridden (e.g. M[4:0]). Luckily all 378c2ecf20Sopenharmony_ci * of the inherited bits have the same position in the AArch64/AArch32 SPSR_ELx 388c2ecf20Sopenharmony_ci * layouts, so we don't need to shuffle these for exceptions from AArch32 EL0. 398c2ecf20Sopenharmony_ci * 408c2ecf20Sopenharmony_ci * For the SPSR_ELx layout for AArch64, see ARM DDI 0487E.a page C5-429. 418c2ecf20Sopenharmony_ci * For the SPSR_ELx layout for AArch32, see ARM DDI 0487E.a page C5-426. 428c2ecf20Sopenharmony_ci * 438c2ecf20Sopenharmony_ci * Here we manipulate the fields in order of the AArch64 SPSR_ELx layout, from 448c2ecf20Sopenharmony_ci * MSB to LSB. 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_cistatic void enter_exception64(struct kvm_vcpu *vcpu, unsigned long target_mode, 478c2ecf20Sopenharmony_ci enum exception_type type) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci unsigned long sctlr, vbar, old, new, mode; 508c2ecf20Sopenharmony_ci u64 exc_offset; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci mode = *vcpu_cpsr(vcpu) & (PSR_MODE_MASK | PSR_MODE32_BIT); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (mode == target_mode) 558c2ecf20Sopenharmony_ci exc_offset = CURRENT_EL_SP_ELx_VECTOR; 568c2ecf20Sopenharmony_ci else if ((mode | PSR_MODE_THREAD_BIT) == target_mode) 578c2ecf20Sopenharmony_ci exc_offset = CURRENT_EL_SP_EL0_VECTOR; 588c2ecf20Sopenharmony_ci else if (!(mode & PSR_MODE32_BIT)) 598c2ecf20Sopenharmony_ci exc_offset = LOWER_EL_AArch64_VECTOR; 608c2ecf20Sopenharmony_ci else 618c2ecf20Sopenharmony_ci exc_offset = LOWER_EL_AArch32_VECTOR; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci switch (target_mode) { 648c2ecf20Sopenharmony_ci case PSR_MODE_EL1h: 658c2ecf20Sopenharmony_ci vbar = vcpu_read_sys_reg(vcpu, VBAR_EL1); 668c2ecf20Sopenharmony_ci sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1); 678c2ecf20Sopenharmony_ci vcpu_write_sys_reg(vcpu, *vcpu_pc(vcpu), ELR_EL1); 688c2ecf20Sopenharmony_ci break; 698c2ecf20Sopenharmony_ci default: 708c2ecf20Sopenharmony_ci /* Don't do that */ 718c2ecf20Sopenharmony_ci BUG(); 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci *vcpu_pc(vcpu) = vbar + exc_offset + type; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci old = *vcpu_cpsr(vcpu); 778c2ecf20Sopenharmony_ci new = 0; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci new |= (old & PSR_N_BIT); 808c2ecf20Sopenharmony_ci new |= (old & PSR_Z_BIT); 818c2ecf20Sopenharmony_ci new |= (old & PSR_C_BIT); 828c2ecf20Sopenharmony_ci new |= (old & PSR_V_BIT); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci // TODO: TCO (if/when ARMv8.5-MemTag is exposed to guests) 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci new |= (old & PSR_DIT_BIT); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci // PSTATE.UAO is set to zero upon any exception to AArch64 898c2ecf20Sopenharmony_ci // See ARM DDI 0487E.a, page D5-2579. 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci // PSTATE.PAN is unchanged unless SCTLR_ELx.SPAN == 0b0 928c2ecf20Sopenharmony_ci // SCTLR_ELx.SPAN is RES1 when ARMv8.1-PAN is not implemented 938c2ecf20Sopenharmony_ci // See ARM DDI 0487E.a, page D5-2578. 948c2ecf20Sopenharmony_ci new |= (old & PSR_PAN_BIT); 958c2ecf20Sopenharmony_ci if (!(sctlr & SCTLR_EL1_SPAN)) 968c2ecf20Sopenharmony_ci new |= PSR_PAN_BIT; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci // PSTATE.SS is set to zero upon any exception to AArch64 998c2ecf20Sopenharmony_ci // See ARM DDI 0487E.a, page D2-2452. 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci // PSTATE.IL is set to zero upon any exception to AArch64 1028c2ecf20Sopenharmony_ci // See ARM DDI 0487E.a, page D1-2306. 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci // PSTATE.SSBS is set to SCTLR_ELx.DSSBS upon any exception to AArch64 1058c2ecf20Sopenharmony_ci // See ARM DDI 0487E.a, page D13-3258 1068c2ecf20Sopenharmony_ci if (sctlr & SCTLR_ELx_DSSBS) 1078c2ecf20Sopenharmony_ci new |= PSR_SSBS_BIT; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci // PSTATE.BTYPE is set to zero upon any exception to AArch64 1108c2ecf20Sopenharmony_ci // See ARM DDI 0487E.a, pages D1-2293 to D1-2294. 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci new |= PSR_D_BIT; 1138c2ecf20Sopenharmony_ci new |= PSR_A_BIT; 1148c2ecf20Sopenharmony_ci new |= PSR_I_BIT; 1158c2ecf20Sopenharmony_ci new |= PSR_F_BIT; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci new |= target_mode; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci *vcpu_cpsr(vcpu) = new; 1208c2ecf20Sopenharmony_ci vcpu_write_spsr(vcpu, old); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci unsigned long cpsr = *vcpu_cpsr(vcpu); 1268c2ecf20Sopenharmony_ci bool is_aarch32 = vcpu_mode_is_32bit(vcpu); 1278c2ecf20Sopenharmony_ci u32 esr = 0; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci enter_exception64(vcpu, PSR_MODE_EL1h, except_type_sync); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci vcpu_write_sys_reg(vcpu, addr, FAR_EL1); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci /* 1348c2ecf20Sopenharmony_ci * Build an {i,d}abort, depending on the level and the 1358c2ecf20Sopenharmony_ci * instruction set. Report an external synchronous abort. 1368c2ecf20Sopenharmony_ci */ 1378c2ecf20Sopenharmony_ci if (kvm_vcpu_trap_il_is32bit(vcpu)) 1388c2ecf20Sopenharmony_ci esr |= ESR_ELx_IL; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci /* 1418c2ecf20Sopenharmony_ci * Here, the guest runs in AArch64 mode when in EL1. If we get 1428c2ecf20Sopenharmony_ci * an AArch32 fault, it means we managed to trap an EL0 fault. 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_ci if (is_aarch32 || (cpsr & PSR_MODE_MASK) == PSR_MODE_EL0t) 1458c2ecf20Sopenharmony_ci esr |= (ESR_ELx_EC_IABT_LOW << ESR_ELx_EC_SHIFT); 1468c2ecf20Sopenharmony_ci else 1478c2ecf20Sopenharmony_ci esr |= (ESR_ELx_EC_IABT_CUR << ESR_ELx_EC_SHIFT); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (!is_iabt) 1508c2ecf20Sopenharmony_ci esr |= ESR_ELx_EC_DABT_LOW << ESR_ELx_EC_SHIFT; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci vcpu_write_sys_reg(vcpu, esr | ESR_ELx_FSC_EXTABT, ESR_EL1); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic void inject_undef64(struct kvm_vcpu *vcpu) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci u32 esr = (ESR_ELx_EC_UNKNOWN << ESR_ELx_EC_SHIFT); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci enter_exception64(vcpu, PSR_MODE_EL1h, except_type_sync); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* 1628c2ecf20Sopenharmony_ci * Build an unknown exception, depending on the instruction 1638c2ecf20Sopenharmony_ci * set. 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_ci if (kvm_vcpu_trap_il_is32bit(vcpu)) 1668c2ecf20Sopenharmony_ci esr |= ESR_ELx_IL; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci vcpu_write_sys_reg(vcpu, esr, ESR_EL1); 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/** 1728c2ecf20Sopenharmony_ci * kvm_inject_dabt - inject a data abort into the guest 1738c2ecf20Sopenharmony_ci * @vcpu: The VCPU to receive the data abort 1748c2ecf20Sopenharmony_ci * @addr: The address to report in the DFAR 1758c2ecf20Sopenharmony_ci * 1768c2ecf20Sopenharmony_ci * It is assumed that this code is called from the VCPU thread and that the 1778c2ecf20Sopenharmony_ci * VCPU therefore is not currently executing guest code. 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_civoid kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci if (vcpu_el1_is_32bit(vcpu)) 1828c2ecf20Sopenharmony_ci kvm_inject_dabt32(vcpu, addr); 1838c2ecf20Sopenharmony_ci else 1848c2ecf20Sopenharmony_ci inject_abt64(vcpu, false, addr); 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci/** 1888c2ecf20Sopenharmony_ci * kvm_inject_pabt - inject a prefetch abort into the guest 1898c2ecf20Sopenharmony_ci * @vcpu: The VCPU to receive the prefetch abort 1908c2ecf20Sopenharmony_ci * @addr: The address to report in the DFAR 1918c2ecf20Sopenharmony_ci * 1928c2ecf20Sopenharmony_ci * It is assumed that this code is called from the VCPU thread and that the 1938c2ecf20Sopenharmony_ci * VCPU therefore is not currently executing guest code. 1948c2ecf20Sopenharmony_ci */ 1958c2ecf20Sopenharmony_civoid kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci if (vcpu_el1_is_32bit(vcpu)) 1988c2ecf20Sopenharmony_ci kvm_inject_pabt32(vcpu, addr); 1998c2ecf20Sopenharmony_ci else 2008c2ecf20Sopenharmony_ci inject_abt64(vcpu, true, addr); 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci/** 2048c2ecf20Sopenharmony_ci * kvm_inject_undefined - inject an undefined instruction into the guest 2058c2ecf20Sopenharmony_ci * @vcpu: The vCPU in which to inject the exception 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci * It is assumed that this code is called from the VCPU thread and that the 2088c2ecf20Sopenharmony_ci * VCPU therefore is not currently executing guest code. 2098c2ecf20Sopenharmony_ci */ 2108c2ecf20Sopenharmony_civoid kvm_inject_undefined(struct kvm_vcpu *vcpu) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci if (vcpu_el1_is_32bit(vcpu)) 2138c2ecf20Sopenharmony_ci kvm_inject_undef32(vcpu); 2148c2ecf20Sopenharmony_ci else 2158c2ecf20Sopenharmony_ci inject_undef64(vcpu); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_civoid kvm_set_sei_esr(struct kvm_vcpu *vcpu, u64 esr) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci vcpu_set_vsesr(vcpu, esr & ESR_ELx_ISS_MASK); 2218c2ecf20Sopenharmony_ci *vcpu_hcr(vcpu) |= HCR_VSE; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci/** 2258c2ecf20Sopenharmony_ci * kvm_inject_vabt - inject an async abort / SError into the guest 2268c2ecf20Sopenharmony_ci * @vcpu: The VCPU to receive the exception 2278c2ecf20Sopenharmony_ci * 2288c2ecf20Sopenharmony_ci * It is assumed that this code is called from the VCPU thread and that the 2298c2ecf20Sopenharmony_ci * VCPU therefore is not currently executing guest code. 2308c2ecf20Sopenharmony_ci * 2318c2ecf20Sopenharmony_ci * Systems with the RAS Extensions specify an imp-def ESR (ISV/IDS = 1) with 2328c2ecf20Sopenharmony_ci * the remaining ISS all-zeros so that this error is not interpreted as an 2338c2ecf20Sopenharmony_ci * uncategorized RAS error. Without the RAS Extensions we can't specify an ESR 2348c2ecf20Sopenharmony_ci * value, so the CPU generates an imp-def value. 2358c2ecf20Sopenharmony_ci */ 2368c2ecf20Sopenharmony_civoid kvm_inject_vabt(struct kvm_vcpu *vcpu) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci kvm_set_sei_esr(vcpu, ESR_ELx_ISV); 2398c2ecf20Sopenharmony_ci} 240