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

KVM: MIPS/VZ: Trace guest mode changes

Create a trace event for guest mode changes, and enable VZ's
GuestCtl0.MC bit after the trace event is enabled to trap all guest mode
changes.

The MC bit causes Guest Hardware Field Change (GHFC) exceptions whenever
a guest mode change occurs (such as an exception entry or return from
exception), so we need to handle this exception now. The MC bit is only
enabled when restoring register state, so enabling the trace event won't
take immediate effect.

Tracing guest mode changes can be particularly handy when trying to work
out what a guest OS gets up to before something goes wrong, especially
if the problem occurs as a result of some previous guest userland
exception which would otherwise be invisible in the trace.

Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: "Radim Krčmář" <rkrcmar@redhat.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-mips@linux-mips.org
Cc: kvm@vger.kernel.org

+69 -2
+13
arch/mips/kvm/mips.c
··· 76 76 {NULL} 77 77 }; 78 78 79 + bool kvm_trace_guest_mode_change; 80 + 81 + int kvm_guest_mode_change_trace_reg(void) 82 + { 83 + kvm_trace_guest_mode_change = 1; 84 + return 0; 85 + } 86 + 87 + void kvm_guest_mode_change_trace_unreg(void) 88 + { 89 + kvm_trace_guest_mode_change = 0; 90 + } 91 + 79 92 /* 80 93 * XXXKYMA: We are simulatoring a processor that has the WII bit set in 81 94 * Config7, so we are "runnable" if interrupts are pending
+37
arch/mips/kvm/trace.h
··· 18 18 #define TRACE_INCLUDE_FILE trace 19 19 20 20 /* 21 + * arch/mips/kvm/mips.c 22 + */ 23 + extern bool kvm_trace_guest_mode_change; 24 + int kvm_guest_mode_change_trace_reg(void); 25 + void kvm_guest_mode_change_trace_unreg(void); 26 + 27 + /* 21 28 * Tracepoints for VM enters 22 29 */ 23 30 DECLARE_EVENT_CLASS(kvm_transition, ··· 308 301 309 302 TP_printk("GuestID: 0x%02x", 310 303 __entry->guestid) 304 + ); 305 + 306 + TRACE_EVENT_FN(kvm_guest_mode_change, 307 + TP_PROTO(struct kvm_vcpu *vcpu), 308 + TP_ARGS(vcpu), 309 + TP_STRUCT__entry( 310 + __field(unsigned long, epc) 311 + __field(unsigned long, pc) 312 + __field(unsigned long, badvaddr) 313 + __field(unsigned int, status) 314 + __field(unsigned int, cause) 315 + ), 316 + 317 + TP_fast_assign( 318 + __entry->epc = kvm_read_c0_guest_epc(vcpu->arch.cop0); 319 + __entry->pc = vcpu->arch.pc; 320 + __entry->badvaddr = kvm_read_c0_guest_badvaddr(vcpu->arch.cop0); 321 + __entry->status = kvm_read_c0_guest_status(vcpu->arch.cop0); 322 + __entry->cause = kvm_read_c0_guest_cause(vcpu->arch.cop0); 323 + ), 324 + 325 + TP_printk("EPC: 0x%08lx PC: 0x%08lx Status: 0x%08x Cause: 0x%08x BadVAddr: 0x%08lx", 326 + __entry->epc, 327 + __entry->pc, 328 + __entry->status, 329 + __entry->cause, 330 + __entry->badvaddr), 331 + 332 + kvm_guest_mode_change_trace_reg, 333 + kvm_guest_mode_change_trace_unreg 311 334 ); 312 335 313 336 #endif /* _TRACE_KVM_H */
+19 -2
arch/mips/kvm/vz.c
··· 1322 1322 return er; 1323 1323 } 1324 1324 1325 + static enum emulation_result kvm_trap_vz_handle_ghfc(u32 cause, u32 *opc, 1326 + struct kvm_vcpu *vcpu) 1327 + { 1328 + /* 1329 + * Presumably this is due to MC (guest mode change), so lets trace some 1330 + * relevant info. 1331 + */ 1332 + trace_kvm_guest_mode_change(vcpu); 1333 + 1334 + return EMULATE_DONE; 1335 + } 1336 + 1325 1337 static enum emulation_result kvm_trap_vz_handle_hc(u32 cause, u32 *opc, 1326 1338 struct kvm_vcpu *vcpu) 1327 1339 { ··· 1419 1407 break; 1420 1408 case MIPS_GCTL0_GEXC_GHFC: 1421 1409 ++vcpu->stat.vz_ghfc_exits; 1422 - er = kvm_trap_vz_no_handler_guest_exit(gexccode, cause, opc, 1423 - vcpu); 1410 + er = kvm_trap_vz_handle_ghfc(cause, opc, vcpu); 1424 1411 break; 1425 1412 case MIPS_GCTL0_GEXC_GPA: 1426 1413 ++vcpu->stat.vz_gpa_exits; ··· 2469 2458 * if left unmaintained. 2470 2459 */ 2471 2460 kvm_vz_restore_timer(vcpu); 2461 + 2462 + /* Set MC bit if we want to trace guest mode changes */ 2463 + if (kvm_trace_guest_mode_change) 2464 + set_c0_guestctl0(MIPS_GCTL0_MC); 2465 + else 2466 + clear_c0_guestctl0(MIPS_GCTL0_MC); 2472 2467 2473 2468 /* Don't bother restoring registers multiple times unless necessary */ 2474 2469 if (!all)