Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: PPC: Book3s: mmio: Deliver DSI after emulation failure

MMIO emulation can fail if the guest uses an instruction that we are
not prepared to emulate. Since these instructions can be and most
likely are valid ones, this is (slightly) closer to an access fault
than to an illegal instruction, so deliver a Data Storage interrupt
instead of a Program interrupt.

BookE ignores bad faults, so it will keep using a Program interrupt
because a DSI would cause a fault loop in the guest.

Suggested-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20220125215655.1026224-6-farosas@linux.ibm.com

authored by

Fabiano Rosas and committed by
Michael Ellerman
c1c8a663 349fbfe9

+25 -7
+3 -7
arch/powerpc/kvm/emulate_loadstore.c
··· 73 73 { 74 74 u32 inst; 75 75 enum emulation_result emulated = EMULATE_FAIL; 76 - int advance = 1; 77 76 struct instruction_op op; 78 77 79 78 /* this default type might be overwritten by subcategories */ ··· 96 97 if (analyse_instr(&op, &vcpu->arch.regs, ppc_inst(inst)) == 0) { 97 98 int type = op.type & INSTR_TYPE_MASK; 98 99 int size = GETSIZE(op.type); 100 + 101 + vcpu->mmio_is_write = OP_IS_STORE(type); 99 102 100 103 switch (type) { 101 104 case LOAD: { ··· 356 355 } 357 356 } 358 357 359 - if (emulated == EMULATE_FAIL) { 360 - advance = 0; 361 - kvmppc_core_queue_program(vcpu, 0); 362 - } 363 - 364 358 trace_kvm_ppc_instr(inst, kvmppc_get_pc(vcpu), emulated); 365 359 366 360 /* Advance past emulated instruction. */ 367 - if (advance) 361 + if (emulated != EMULATE_FAIL) 368 362 kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) + 4); 369 363 370 364 return emulated;
+22
arch/powerpc/kvm/powerpc.c
··· 309 309 kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst); 310 310 kvm_debug_ratelimited("Guest access to device memory using unsupported instruction (opcode: %#08x)\n", 311 311 last_inst); 312 + 313 + /* 314 + * Injecting a Data Storage here is a bit more 315 + * accurate since the instruction that caused the 316 + * access could still be a valid one. 317 + */ 318 + if (!IS_ENABLED(CONFIG_BOOKE)) { 319 + ulong dsisr = DSISR_BADACCESS; 320 + 321 + if (vcpu->mmio_is_write) 322 + dsisr |= DSISR_ISSTORE; 323 + 324 + kvmppc_core_queue_data_storage(vcpu, vcpu->arch.vaddr_accessed, dsisr); 325 + } else { 326 + /* 327 + * BookE does not send a SIGBUS on a bad 328 + * fault, so use a Program interrupt instead 329 + * to avoid a fault loop. 330 + */ 331 + kvmppc_core_queue_program(vcpu, 0); 332 + } 333 + 312 334 r = RESUME_GUEST; 313 335 break; 314 336 }