{
        u32 inst;
        enum emulation_result emulated = EMULATE_FAIL;
-       int advance = 1;
        struct instruction_op op;
 
        /* this default type might be overwritten by subcategories */
                int type = op.type & INSTR_TYPE_MASK;
                int size = GETSIZE(op.type);
 
+               vcpu->mmio_is_write = OP_IS_STORE(type);
+
                switch (type) {
                case LOAD:  {
                        int instr_byte_swap = op.type & BYTEREV;
                }
        }
 
-       if (emulated == EMULATE_FAIL) {
-               advance = 0;
-               kvmppc_core_queue_program(vcpu, 0);
-       }
-
        trace_kvm_ppc_instr(inst, kvmppc_get_pc(vcpu), emulated);
 
        /* Advance past emulated instruction. */
-       if (advance)
+       if (emulated != EMULATE_FAIL)
                kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) + 4);
 
        return emulated;
 
                kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst);
                kvm_debug_ratelimited("Guest access to device memory using unsupported instruction (opcode: %#08x)\n",
                                      last_inst);
+
+               /*
+                * Injecting a Data Storage here is a bit more
+                * accurate since the instruction that caused the
+                * access could still be a valid one.
+                */
+               if (!IS_ENABLED(CONFIG_BOOKE)) {
+                       ulong dsisr = DSISR_BADACCESS;
+
+                       if (vcpu->mmio_is_write)
+                               dsisr |= DSISR_ISSTORE;
+
+                       kvmppc_core_queue_data_storage(vcpu, vcpu->arch.vaddr_accessed, dsisr);
+               } else {
+                       /*
+                        * BookE does not send a SIGBUS on a bad
+                        * fault, so use a Program interrupt instead
+                        * to avoid a fault loop.
+                        */
+                       kvmppc_core_queue_program(vcpu, 0);
+               }
+
                r = RESUME_GUEST;
                break;
        }