@@ -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;
}
@@ -810,6 +821,42 @@ 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)
+{
+ /*
+ * 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 */
+ return kvm_vcpu_ioctl(cs, KVM_SET_VCPU_EVENTS, &events);
+ } 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 +867,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);