event/message pages and to enable/disable SynIC messages/events processing
 in userspace.
 
+               /* KVM_EXIT_ARM_NISV */
+               struct {
+                       __u64 esr_iss;
+                       __u64 fault_ipa;
+               } arm_nisv;
+
+Used on arm and arm64 systems. If a guest accesses memory not in a memslot,
+KVM will typically return to userspace and ask it to do MMIO emulation on its
+behalf. However, for certain classes of instructions, no instruction decode
+(direction, length of memory access) is provided, and fetching and decoding
+the instruction from the VM is overly complicated to live in the kernel.
+
+Historically, when this situation occurred, KVM would print a warning and kill
+the VM. KVM assumed that if the guest accessed non-memslot memory, it was
+trying to do I/O, which just couldn't be emulated, and the warning message was
+phrased accordingly. However, what happened more often was that a guest bug
+caused access outside the guest memory areas which should lead to a more
+meaningful warning message and an external abort in the guest, if the access
+did not fall within an I/O window.
+
+Userspace implementations can query for KVM_CAP_ARM_NISV_TO_USER, and enable
+this capability at VM creation. Once this is done, these types of errors will
+instead return to userspace with KVM_EXIT_ARM_NISV, with the valid bits from
+the HSR (arm) and ESR_EL2 (arm64) in the esr_iss field, and the faulting IPA
+in the fault_ipa field. Userspace can either fix up the access if it's
+actually an I/O access by decoding the instruction from guest memory (if it's
+very brave) and continue executing the guest, or it can decide to suspend,
+dump, or restart the guest.
+
+Note that KVM does not skip the faulting instruction as it does for
+KVM_EXIT_MMIO, but userspace has to emulate any change to the processing state
+if it decides to decode and emulate the instruction.
+
                /* Fix the size of the union. */
                char padding[256];
        };
 
 #define HSR_ISV                (_AC(1, UL) << HSR_ISV_SHIFT)
 #define HSR_SRT_SHIFT  (16)
 #define HSR_SRT_MASK   (0xf << HSR_SRT_SHIFT)
+#define HSR_CM         (1 << 8)
 #define HSR_FSC                (0x3f)
 #define HSR_FSC_TYPE   (0x3c)
 #define HSR_SSE                (1 << 21)
 
        return kvm_vcpu_get_hsr(vcpu) & HSR_ISV;
 }
 
+static inline unsigned long kvm_vcpu_dabt_iss_nisv_sanitized(const struct kvm_vcpu *vcpu)
+{
+       return kvm_vcpu_get_hsr(vcpu) & (HSR_CM | HSR_WNR | HSR_FSC);
+}
+
 static inline bool kvm_vcpu_dabt_iswrite(struct kvm_vcpu *vcpu)
 {
        return kvm_vcpu_get_hsr(vcpu) & HSR_WNR;
 
 
        /* Mandated version of PSCI */
        u32 psci_version;
+
+       /*
+        * If we encounter a data abort without valid instruction syndrome
+        * information, report this to user space.  User space can (and
+        * should) opt in to this feature if KVM_CAP_ARM_NISV_TO_USER is
+        * supported.
+        */
+       bool return_nisv_io_abort_to_user;
 };
 
 #define KVM_NR_MEM_OBJS     40
 
        return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_ISV);
 }
 
+static inline unsigned long kvm_vcpu_dabt_iss_nisv_sanitized(const struct kvm_vcpu *vcpu)
+{
+       return kvm_vcpu_get_hsr(vcpu) & (ESR_ELx_CM | ESR_ELx_WNR | ESR_ELx_FSC);
+}
+
 static inline bool kvm_vcpu_dabt_issext(const struct kvm_vcpu *vcpu)
 {
        return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_SSE);
 
 
        /* Mandated version of PSCI */
        u32 psci_version;
+
+       /*
+        * If we encounter a data abort without valid instruction syndrome
+        * information, report this to user space.  User space can (and
+        * should) opt in to this feature if KVM_CAP_ARM_NISV_TO_USER is
+        * supported.
+        */
+       bool return_nisv_io_abort_to_user;
 };
 
 #define KVM_NR_MEM_OBJS     40
 
 #define KVM_EXIT_S390_STSI        25
 #define KVM_EXIT_IOAPIC_EOI       26
 #define KVM_EXIT_HYPERV           27
+#define KVM_EXIT_ARM_NISV         28
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 /* Emulate instruction failed. */
                } eoi;
                /* KVM_EXIT_HYPERV */
                struct kvm_hyperv_exit hyperv;
+               /* KVM_EXIT_ARM_NISV */
+               struct {
+                       __u64 esr_iss;
+                       __u64 fault_ipa;
+               } arm_nisv;
                /* Fix the size of the union. */
                char padding[256];
        };
 #define KVM_CAP_PMU_EVENT_FILTER 173
 #define KVM_CAP_ARM_IRQ_LINE_LAYOUT_2 174
 #define KVM_CAP_HYPERV_DIRECT_TLBFLUSH 175
+#define KVM_CAP_ARM_NISV_TO_USER 176
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
 
        return 0;
 }
 
+int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
+                           struct kvm_enable_cap *cap)
+{
+       int r;
+
+       if (cap->flags)
+               return -EINVAL;
+
+       switch (cap->cap) {
+       case KVM_CAP_ARM_NISV_TO_USER:
+               r = 0;
+               kvm->arch.return_nisv_io_abort_to_user = true;
+               break;
+       default:
+               r = -EINVAL;
+               break;
+       }
+
+       return r;
+}
 
 /**
  * kvm_arch_init_vm - initializes a VM data structure
        case KVM_CAP_IMMEDIATE_EXIT:
        case KVM_CAP_VCPU_EVENTS:
        case KVM_CAP_ARM_IRQ_LINE_LAYOUT_2:
+       case KVM_CAP_ARM_NISV_TO_USER:
                r = 1;
                break;
        case KVM_CAP_ARM_SET_DEVICE_ADDR:
 
                if (ret)
                        return ret;
        } else {
-               kvm_err("load/store instruction decoding not implemented\n");
+               if (vcpu->kvm->arch.return_nisv_io_abort_to_user) {
+                       run->exit_reason = KVM_EXIT_ARM_NISV;
+                       run->arm_nisv.esr_iss = kvm_vcpu_dabt_iss_nisv_sanitized(vcpu);
+                       run->arm_nisv.fault_ipa = fault_ipa;
+                       return 0;
+               }
+
+               kvm_pr_unimpl("Data abort outside memslots with no valid syndrome info\n");
                return -ENOSYS;
        }