linux/arch/arm64/kvm/inject_fault.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Fault injection for both 32 and 64bit guests.
   4 *
   5 * Copyright (C) 2012,2013 - ARM Ltd
   6 * Author: Marc Zyngier <marc.zyngier@arm.com>
   7 *
   8 * Based on arch/arm/kvm/emulate.c
   9 * Copyright (C) 2012 - Virtual Open Systems and Columbia University
  10 * Author: Christoffer Dall <c.dall@virtualopensystems.com>
  11 */
  12
  13#include <linux/kvm_host.h>
  14#include <asm/kvm_emulate.h>
  15#include <asm/esr.h>
  16
  17static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
  18{
  19        unsigned long cpsr = *vcpu_cpsr(vcpu);
  20        bool is_aarch32 = vcpu_mode_is_32bit(vcpu);
  21        u32 esr = 0;
  22
  23        vcpu->arch.flags |= (KVM_ARM64_EXCEPT_AA64_EL1          |
  24                             KVM_ARM64_EXCEPT_AA64_ELx_SYNC     |
  25                             KVM_ARM64_PENDING_EXCEPTION);
  26
  27        vcpu_write_sys_reg(vcpu, addr, FAR_EL1);
  28
  29        /*
  30         * Build an {i,d}abort, depending on the level and the
  31         * instruction set. Report an external synchronous abort.
  32         */
  33        if (kvm_vcpu_trap_il_is32bit(vcpu))
  34                esr |= ESR_ELx_IL;
  35
  36        /*
  37         * Here, the guest runs in AArch64 mode when in EL1. If we get
  38         * an AArch32 fault, it means we managed to trap an EL0 fault.
  39         */
  40        if (is_aarch32 || (cpsr & PSR_MODE_MASK) == PSR_MODE_EL0t)
  41                esr |= (ESR_ELx_EC_IABT_LOW << ESR_ELx_EC_SHIFT);
  42        else
  43                esr |= (ESR_ELx_EC_IABT_CUR << ESR_ELx_EC_SHIFT);
  44
  45        if (!is_iabt)
  46                esr |= ESR_ELx_EC_DABT_LOW << ESR_ELx_EC_SHIFT;
  47
  48        vcpu_write_sys_reg(vcpu, esr | ESR_ELx_FSC_EXTABT, ESR_EL1);
  49}
  50
  51static void inject_undef64(struct kvm_vcpu *vcpu)
  52{
  53        u32 esr = (ESR_ELx_EC_UNKNOWN << ESR_ELx_EC_SHIFT);
  54
  55        vcpu->arch.flags |= (KVM_ARM64_EXCEPT_AA64_EL1          |
  56                             KVM_ARM64_EXCEPT_AA64_ELx_SYNC     |
  57                             KVM_ARM64_PENDING_EXCEPTION);
  58
  59        /*
  60         * Build an unknown exception, depending on the instruction
  61         * set.
  62         */
  63        if (kvm_vcpu_trap_il_is32bit(vcpu))
  64                esr |= ESR_ELx_IL;
  65
  66        vcpu_write_sys_reg(vcpu, esr, ESR_EL1);
  67}
  68
  69#define DFSR_FSC_EXTABT_LPAE    0x10
  70#define DFSR_FSC_EXTABT_nLPAE   0x08
  71#define DFSR_LPAE               BIT(9)
  72#define TTBCR_EAE               BIT(31)
  73
  74static void inject_undef32(struct kvm_vcpu *vcpu)
  75{
  76        vcpu->arch.flags |= (KVM_ARM64_EXCEPT_AA32_UND |
  77                             KVM_ARM64_PENDING_EXCEPTION);
  78}
  79
  80/*
  81 * Modelled after TakeDataAbortException() and TakePrefetchAbortException
  82 * pseudocode.
  83 */
  84static void inject_abt32(struct kvm_vcpu *vcpu, bool is_pabt, u32 addr)
  85{
  86        u64 far;
  87        u32 fsr;
  88
  89        /* Give the guest an IMPLEMENTATION DEFINED exception */
  90        if (vcpu_read_sys_reg(vcpu, TCR_EL1) & TTBCR_EAE) {
  91                fsr = DFSR_LPAE | DFSR_FSC_EXTABT_LPAE;
  92        } else {
  93                /* no need to shuffle FS[4] into DFSR[10] as its 0 */
  94                fsr = DFSR_FSC_EXTABT_nLPAE;
  95        }
  96
  97        far = vcpu_read_sys_reg(vcpu, FAR_EL1);
  98
  99        if (is_pabt) {
 100                vcpu->arch.flags |= (KVM_ARM64_EXCEPT_AA32_IABT |
 101                                     KVM_ARM64_PENDING_EXCEPTION);
 102                far &= GENMASK(31, 0);
 103                far |= (u64)addr << 32;
 104                vcpu_write_sys_reg(vcpu, fsr, IFSR32_EL2);
 105        } else { /* !iabt */
 106                vcpu->arch.flags |= (KVM_ARM64_EXCEPT_AA32_DABT |
 107                                     KVM_ARM64_PENDING_EXCEPTION);
 108                far &= GENMASK(63, 32);
 109                far |= addr;
 110                vcpu_write_sys_reg(vcpu, fsr, ESR_EL1);
 111        }
 112
 113        vcpu_write_sys_reg(vcpu, far, FAR_EL1);
 114}
 115
 116/**
 117 * kvm_inject_dabt - inject a data abort into the guest
 118 * @vcpu: The VCPU to receive the data abort
 119 * @addr: The address to report in the DFAR
 120 *
 121 * It is assumed that this code is called from the VCPU thread and that the
 122 * VCPU therefore is not currently executing guest code.
 123 */
 124void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr)
 125{
 126        if (vcpu_el1_is_32bit(vcpu))
 127                inject_abt32(vcpu, false, addr);
 128        else
 129                inject_abt64(vcpu, false, addr);
 130}
 131
 132/**
 133 * kvm_inject_pabt - inject a prefetch abort into the guest
 134 * @vcpu: The VCPU to receive the prefetch abort
 135 * @addr: The address to report in the DFAR
 136 *
 137 * It is assumed that this code is called from the VCPU thread and that the
 138 * VCPU therefore is not currently executing guest code.
 139 */
 140void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
 141{
 142        if (vcpu_el1_is_32bit(vcpu))
 143                inject_abt32(vcpu, true, addr);
 144        else
 145                inject_abt64(vcpu, true, addr);
 146}
 147
 148/**
 149 * kvm_inject_undefined - inject an undefined instruction into the guest
 150 * @vcpu: The vCPU in which to inject the exception
 151 *
 152 * It is assumed that this code is called from the VCPU thread and that the
 153 * VCPU therefore is not currently executing guest code.
 154 */
 155void kvm_inject_undefined(struct kvm_vcpu *vcpu)
 156{
 157        if (vcpu_el1_is_32bit(vcpu))
 158                inject_undef32(vcpu);
 159        else
 160                inject_undef64(vcpu);
 161}
 162
 163void kvm_set_sei_esr(struct kvm_vcpu *vcpu, u64 esr)
 164{
 165        vcpu_set_vsesr(vcpu, esr & ESR_ELx_ISS_MASK);
 166        *vcpu_hcr(vcpu) |= HCR_VSE;
 167}
 168
 169/**
 170 * kvm_inject_vabt - inject an async abort / SError into the guest
 171 * @vcpu: The VCPU to receive the exception
 172 *
 173 * It is assumed that this code is called from the VCPU thread and that the
 174 * VCPU therefore is not currently executing guest code.
 175 *
 176 * Systems with the RAS Extensions specify an imp-def ESR (ISV/IDS = 1) with
 177 * the remaining ISS all-zeros so that this error is not interpreted as an
 178 * uncategorized RAS error. Without the RAS Extensions we can't specify an ESR
 179 * value, so the CPU generates an imp-def value.
 180 */
 181void kvm_inject_vabt(struct kvm_vcpu *vcpu)
 182{
 183        kvm_set_sei_esr(vcpu, ESR_ELx_ISV);
 184}
 185