@@ -233,9 +233,13 @@ enum arm_exception_class {
#define ARM_EL_EC_SHIFT 26
#define ARM_EL_IL_SHIFT 25
#define ARM_EL_ISV_SHIFT 24
+#define ARM_EL_AET_SHIFT 10
#define ARM_EL_IL (1 << ARM_EL_IL_SHIFT)
#define ARM_EL_ISV (1 << ARM_EL_ISV_SHIFT)
+/* Asynchronous Error Type */
+#define KVM_SEI_SEV_RECOVERABLE 1
+
/* Utility functions for constructing various kinds of syndrome value.
* Note that in general we follow the AArch64 syndrome values; in a
* few cases the value in HSR for exceptions taken to AArch32 Hyp
@@ -593,6 +593,9 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
ret = EXCP_DEBUG;
} /* otherwise return to guest */
break;
+ case KVM_EXIT_EXCEPTION:
+ kvm_arm_handle_exception(cs, run);
+ break;
default:
qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n",
__func__, run->exit_reason);
@@ -493,6 +493,12 @@ bool kvm_arm_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit)
return false;
}
+bool kvm_arm_handle_exception(CPUState *cs, struct kvm_run *run)
+{
+ qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
+ return false;
+}
+
int kvm_arch_insert_hw_breakpoint(target_ulong addr,
target_ulong len, int type)
{
@@ -986,3 +986,37 @@ static bool kvm_can_set_vcpu_esr(struct KVMState *state)
int ret = kvm_check_extension(state, KVM_CAP_ARM_INJECT_SERROR_ESR);
return (ret) ? true : false;
}
+
+static bool kvm_inject_arm_sei(CPUState *cs, unsigned int error_code)
+{
+ int ret;
+ /* IMPLEMENTATION DEFINED syndrome by default */
+ uint32_t syndrome = ARM_EL_ISV;
+
+ if (kvm_can_set_vcpu_esr(cs->kvm_state)) {
+ if (error_code == KVM_SEI_SEV_RECOVERABLE) {
+ /* Set Recoverable Asynchronous SError interrupt Type */
+ syndrome = (3 << ARM_EL_AET_SHIFT) | 0x11;
+ }
+ ret = kvm_vcpu_ioctl(cs, KVM_ARM_INJECT_SERROR_ESR, &syndrome);
+ if (ret < 0) {
+ fprintf(stderr, "KVM_ARM_SET_SERROR_ESR failed: %s\n",
+ strerror(-ret));
+ abort();
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool kvm_arm_handle_exception(CPUState *cs, struct kvm_run *run)
+{
+ int exception = run->ex.exception;
+ unsigned int error_code = run->ex.error_code;
+ if (exception == EC_SERROR) {
+ return kvm_inject_arm_sei(cs, error_code);
+ }
+ return false;
+}
@@ -288,4 +288,12 @@ static inline const char *its_class_name(void)
}
}
+/**
+ * kvm_arm_handle_exception:
+ * @cs: CPUState
+ * @run: KVM RUN structure
+ *
+ * Returns: TRUE if the SError exception was successfully handled
+ */
+bool kvm_arm_handle_exception(CPUState *cs, struct kvm_run *run);
#endif