aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2020-07-04 16:08:41 +0100
committerPeter Maydell <peter.maydell@linaro.org>2020-07-04 16:08:41 +0100
commiteb6490f544388dd24c0d054a96dd304bc7284450 (patch)
tree7c2be83ea21a30a14306eb18f482488003196271 /target
parent0b100c8e72c54bcd6f865d6570ffe838dafe7105 (diff)
parent0f10bf84a9d489259a5b11c6aa1b05c1175b76ea (diff)
downloadqemu-eb6490f544388dd24c0d054a96dd304bc7284450.zip
qemu-eb6490f544388dd24c0d054a96dd304bc7284450.tar.gz
qemu-eb6490f544388dd24c0d054a96dd304bc7284450.tar.bz2
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20200703' into staging
target-arm queue: * i.MX6UL EVK board: put PHYs in the correct places * hw/arm/virt: Let the virtio-iommu bypass MSIs * target/arm: kvm: Handle DABT with no valid ISS * hw/arm/virt-acpi-build: Only expose flash on older machine types * target/arm: Fix temp double-free in sve ldr/str * hw/display/bcm2835_fb.c: Initialize all fields of struct * hw/arm/spitz: Code cleanup to fix Coverity-detected memory leak * Deprecate TileGX port # gpg: Signature made Fri 03 Jul 2020 17:53:05 BST # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20200703: (34 commits) Deprecate TileGX port Replace uses of FROM_SSI_SLAVE() macro with QOM casts hw/arm/spitz: Provide usual QOM macros for corgi-ssp and spitz-lcdtg hw/arm/pxa2xx_pic: Use LOG_GUEST_ERROR for bad guest register accesses hw/arm/spitz: Use LOG_GUEST_ERROR for bad guest register accesses hw/gpio/zaurus.c: Use LOG_GUEST_ERROR for bad guest register accesses hw/arm/spitz: Encapsulate misc GPIO handling in a device hw/misc/max111x: Create header file for documentation, TYPE_ macros hw/misc/max111x: Use GPIO lines rather than max111x_set_input() hw/arm/spitz: Use max111x properties to set initial values ssi: Add ssi_realize_and_unref() hw/misc/max111x: Don't use vmstate_register() hw/misc/max111x: provide QOM properties for setting initial values hw/arm/spitz: Implement inbound GPIO lines for bit5 and power signals hw/arm/spitz: Keep pointers to scp0, scp1 in SpitzMachineState hw/arm/spitz: Keep pointers to MPU and SSI devices in SpitzMachineState hw/arm/spitz: Create SpitzMachineClass abstract base class hw/arm/spitz: Detabify hw/display/bcm2835_fb.c: Initialize all fields of struct target/arm: Fix temp double-free in sve ldr/str ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target')
-rw-r--r--target/arm/cpu.h2
-rw-r--r--target/arm/kvm.c80
-rw-r--r--target/arm/kvm32.c34
-rw-r--r--target/arm/kvm64.c49
-rw-r--r--target/arm/kvm_arm.h10
-rw-r--r--target/arm/translate-a64.c6
-rw-r--r--target/arm/translate-a64.h1
-rw-r--r--target/arm/translate-sve.c8
8 files changed, 184 insertions, 6 deletions
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index cf99dcc..9e8ed42 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -573,6 +573,8 @@ typedef struct CPUARMState {
uint64_t esr;
} serror;
+ uint8_t ext_dabt_raised; /* Tracking/verifying injection of ext DABT */
+
/* State of our input IRQ/FIQ/VIRQ/VFIQ lines */
uint32_t irq_line_state;
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 7c672c7..8bb7318 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -39,6 +39,7 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
static bool cap_has_mp_state;
static bool cap_has_inject_serror_esr;
+static bool cap_has_inject_ext_dabt;
static ARMHostCPUFeatures arm_host_cpu_features;
@@ -245,6 +246,16 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
ret = -EINVAL;
}
+ if (kvm_check_extension(s, KVM_CAP_ARM_NISV_TO_USER)) {
+ if (kvm_vm_enable_cap(s, KVM_CAP_ARM_NISV_TO_USER, 0)) {
+ error_report("Failed to enable KVM_CAP_ARM_NISV_TO_USER cap");
+ } else {
+ /* Set status for supporting the external dabt injection */
+ cap_has_inject_ext_dabt = kvm_check_extension(s,
+ KVM_CAP_ARM_INJECT_EXT_DABT);
+ }
+ }
+
return ret;
}
@@ -738,6 +749,29 @@ int kvm_get_vcpu_events(ARMCPU *cpu)
void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+
+ if (unlikely(env->ext_dabt_raised)) {
+ /*
+ * Verifying that the ext DABT has been properly injected,
+ * otherwise risking indefinitely re-running the faulting instruction
+ * Covering a very narrow case for kernels 5.5..5.5.4
+ * when injected abort was misconfigured to be
+ * an IMPLEMENTATION DEFINED exception (for 32-bit EL1)
+ */
+ if (!arm_feature(env, ARM_FEATURE_AARCH64) &&
+ unlikely(!kvm_arm_verify_ext_dabt_pending(cs))) {
+
+ error_report("Data abort exception with no valid ISS generated by "
+ "guest memory access. KVM unable to emulate faulting "
+ "instruction. Failed to inject an external data abort "
+ "into the guest.");
+ abort();
+ }
+ /* Clear the status */
+ env->ext_dabt_raised = 0;
+ }
}
MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
@@ -810,6 +844,47 @@ void kvm_arm_vm_state_change(void *opaque, int running, RunState state)
}
}
+/**
+ * kvm_arm_handle_dabt_nisv:
+ * @cs: CPUState
+ * @esr_iss: ISS encoding (limited) for the exception from Data Abort
+ * ISV bit set to '0b0' -> no valid instruction syndrome
+ * @fault_ipa: faulting address for the synchronous data abort
+ *
+ * Returns: 0 if the exception has been handled, < 0 otherwise
+ */
+static int kvm_arm_handle_dabt_nisv(CPUState *cs, uint64_t esr_iss,
+ uint64_t fault_ipa)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ /*
+ * Request KVM to inject the external data abort into the guest
+ */
+ if (cap_has_inject_ext_dabt) {
+ struct kvm_vcpu_events events = { };
+ /*
+ * The external data abort event will be handled immediately by KVM
+ * using the address fault that triggered the exit on given VCPU.
+ * Requesting injection of the external data abort does not rely
+ * on any other VCPU state. Therefore, in this particular case, the VCPU
+ * synchronization can be exceptionally skipped.
+ */
+ events.exception.ext_dabt_pending = 1;
+ /* KVM_CAP_ARM_INJECT_EXT_DABT implies KVM_CAP_VCPU_EVENTS */
+ if (!kvm_vcpu_ioctl(cs, KVM_SET_VCPU_EVENTS, &events)) {
+ env->ext_dabt_raised = 1;
+ return 0;
+ }
+ } else {
+ error_report("Data abort exception triggered by guest memory access "
+ "at physical address: 0x" TARGET_FMT_lx,
+ (target_ulong)fault_ipa);
+ error_printf("KVM unable to emulate faulting instruction.\n");
+ }
+ return -1;
+}
+
int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
{
int ret = 0;
@@ -820,6 +895,11 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
ret = EXCP_DEBUG;
} /* otherwise return to guest */
break;
+ case KVM_EXIT_ARM_NISV:
+ /* External DABT with no valid iss to decode */
+ ret = kvm_arm_handle_dabt_nisv(cs, run->arm_nisv.esr_iss,
+ run->arm_nisv.fault_ipa);
+ break;
default:
qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n",
__func__, run->exit_reason);
diff --git a/target/arm/kvm32.c b/target/arm/kvm32.c
index 7b3a19e..0af46b4 100644
--- a/target/arm/kvm32.c
+++ b/target/arm/kvm32.c
@@ -559,3 +559,37 @@ void kvm_arm_pmu_init(CPUState *cs)
{
qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
}
+
+#define ARM_REG_DFSR ARM_CP15_REG32(0, 5, 0, 0)
+#define ARM_REG_TTBCR ARM_CP15_REG32(0, 2, 0, 2)
+/*
+ *DFSR:
+ * TTBCR.EAE == 0
+ * FS[4] - DFSR[10]
+ * FS[3:0] - DFSR[3:0]
+ * TTBCR.EAE == 1
+ * FS, bits [5:0]
+ */
+#define DFSR_FSC(lpae, v) \
+ ((lpae) ? ((v) & 0x3F) : (((v) >> 6) | ((v) & 0x1F)))
+
+#define DFSC_EXTABT(lpae) ((lpae) ? 0x10 : 0x08)
+
+bool kvm_arm_verify_ext_dabt_pending(CPUState *cs)
+{
+ uint32_t dfsr_val;
+
+ if (!kvm_get_one_reg(cs, ARM_REG_DFSR, &dfsr_val)) {
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ uint32_t ttbcr;
+ int lpae = 0;
+
+ if (!kvm_get_one_reg(cs, ARM_REG_TTBCR, &ttbcr)) {
+ lpae = arm_feature(env, ARM_FEATURE_LPAE) && (ttbcr & TTBCR_EAE);
+ }
+ /* The verification is based on FS filed of the DFSR reg only*/
+ return (DFSR_FSC(lpae, dfsr_val) == DFSC_EXTABT(lpae));
+ }
+ return false;
+}
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index 3dc494a..1169237 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -1493,3 +1493,52 @@ bool kvm_arm_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit)
return false;
}
+
+#define ARM64_REG_ESR_EL1 ARM64_SYS_REG(3, 0, 5, 2, 0)
+#define ARM64_REG_TCR_EL1 ARM64_SYS_REG(3, 0, 2, 0, 2)
+
+/*
+ * ESR_EL1
+ * ISS encoding
+ * AARCH64: DFSC, bits [5:0]
+ * AARCH32:
+ * TTBCR.EAE == 0
+ * FS[4] - DFSR[10]
+ * FS[3:0] - DFSR[3:0]
+ * TTBCR.EAE == 1
+ * FS, bits [5:0]
+ */
+#define ESR_DFSC(aarch64, lpae, v) \
+ ((aarch64 || (lpae)) ? ((v) & 0x3F) \
+ : (((v) >> 6) | ((v) & 0x1F)))
+
+#define ESR_DFSC_EXTABT(aarch64, lpae) \
+ ((aarch64) ? 0x10 : (lpae) ? 0x10 : 0x8)
+
+bool kvm_arm_verify_ext_dabt_pending(CPUState *cs)
+{
+ uint64_t dfsr_val;
+
+ if (!kvm_get_one_reg(cs, ARM64_REG_ESR_EL1, &dfsr_val)) {
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ int aarch64_mode = arm_feature(env, ARM_FEATURE_AARCH64);
+ int lpae = 0;
+
+ if (!aarch64_mode) {
+ uint64_t ttbcr;
+
+ if (!kvm_get_one_reg(cs, ARM64_REG_TCR_EL1, &ttbcr)) {
+ lpae = arm_feature(env, ARM_FEATURE_LPAE)
+ && (ttbcr & TTBCR_EAE);
+ }
+ }
+ /*
+ * The verification here is based on the DFSC bits
+ * of the ESR_EL1 reg only
+ */
+ return (ESR_DFSC(aarch64_mode, lpae, dfsr_val) ==
+ ESR_DFSC_EXTABT(aarch64_mode, lpae));
+ }
+ return false;
+}
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index a4ce4fd..adb3851 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -450,6 +450,16 @@ struct kvm_guest_debug_arch;
void kvm_arm_copy_hw_debug_data(struct kvm_guest_debug_arch *ptr);
/**
+ * kvm_arm_verify_ext_dabt_pending:
+ * @cs: CPUState
+ *
+ * Verify the fault status code wrt the Ext DABT injection
+ *
+ * Returns: true if the fault status code is as expected, false otherwise
+ */
+bool kvm_arm_verify_ext_dabt_pending(CPUState *cs);
+
+/**
* its_class_name:
*
* Return the ITS class name to use depending on whether KVM acceleration
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 73d753f..8c07649 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -461,6 +461,12 @@ TCGv_i64 new_tmp_a64(DisasContext *s)
return s->tmp_a64[s->tmp_a64_count++] = tcg_temp_new_i64();
}
+TCGv_i64 new_tmp_a64_local(DisasContext *s)
+{
+ assert(s->tmp_a64_count < TMP_A64_MAX);
+ return s->tmp_a64[s->tmp_a64_count++] = tcg_temp_local_new_i64();
+}
+
TCGv_i64 new_tmp_a64_zero(DisasContext *s)
{
TCGv_i64 t = new_tmp_a64(s);
diff --git a/target/arm/translate-a64.h b/target/arm/translate-a64.h
index 49e4865..647f0c7 100644
--- a/target/arm/translate-a64.h
+++ b/target/arm/translate-a64.h
@@ -30,6 +30,7 @@ void unallocated_encoding(DisasContext *s);
} while (0)
TCGv_i64 new_tmp_a64(DisasContext *s);
+TCGv_i64 new_tmp_a64_local(DisasContext *s);
TCGv_i64 new_tmp_a64_zero(DisasContext *s);
TCGv_i64 cpu_reg(DisasContext *s, int reg);
TCGv_i64 cpu_reg_sp(DisasContext *s, int reg);
diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c
index f318ca2..08f0fd1 100644
--- a/target/arm/translate-sve.c
+++ b/target/arm/translate-sve.c
@@ -4372,9 +4372,8 @@ static void do_ldr(DisasContext *s, uint32_t vofs, int len, int rn, int imm)
/* Copy the clean address into a local temp, live across the loop. */
t0 = clean_addr;
- clean_addr = tcg_temp_local_new_i64();
+ clean_addr = new_tmp_a64_local(s);
tcg_gen_mov_i64(clean_addr, t0);
- tcg_temp_free_i64(t0);
gen_set_label(loop);
@@ -4422,7 +4421,6 @@ static void do_ldr(DisasContext *s, uint32_t vofs, int len, int rn, int imm)
tcg_gen_st_i64(t0, cpu_env, vofs + len_align);
tcg_temp_free_i64(t0);
}
- tcg_temp_free_i64(clean_addr);
}
/* Similarly for stores. */
@@ -4463,9 +4461,8 @@ static void do_str(DisasContext *s, uint32_t vofs, int len, int rn, int imm)
/* Copy the clean address into a local temp, live across the loop. */
t0 = clean_addr;
- clean_addr = tcg_temp_local_new_i64();
+ clean_addr = new_tmp_a64_local(s);
tcg_gen_mov_i64(clean_addr, t0);
- tcg_temp_free_i64(t0);
gen_set_label(loop);
@@ -4509,7 +4506,6 @@ static void do_str(DisasContext *s, uint32_t vofs, int len, int rn, int imm)
}
tcg_temp_free_i64(t0);
}
- tcg_temp_free_i64(clean_addr);
}
static bool trans_LDR_zri(DisasContext *s, arg_rri *a)