KVM: Improved guest debugging / debug register emulation
v3 cover KVM: Improved guest debugging / debug register emulation
This is the kernel part of the guest debugging / debug register emulation patch series.
Changes since last round (was v1, skipped v2 to remain in sync with user space series):
- Reworked patch 3 (single-stepping over STI / MOV SS on VMX)
- Rebased over latest git
Meanwhile basic tests on a SVM host indicate that this platform is fine the series as well.
Find the patches also at git://git.kiszka.org/linux-kvm.git gdb-queue
Jan
--
Siemens AG, Corporate Technology, CT SE 26
Corporate Competence Center Embedded Linux
PATCH v3 1/5 KVM: VMX: Support for injecting software exceptions
VMX differentiates between processor and software generated exceptions when injecting them into the guest. Extend vmx_queue_exception accordingly (and refactor related constants) so that we can use this service reliably for the new guest debugging framework.
---
arch/x86/include/asm/vmx.h | 3 ++- arch/x86/kvm/vmx.c | 35 ++++++++++++++++++++--------------- 2 files changed, 22 insertions(+), 16 deletions(-)
arch/x86/include/asm/vmx.h +2 -1
@@ -270,8 +270,9 @@ enum vmcs_field {#define INTR_TYPE_EXT_INTR (0 << 8)/* external interrupt */ #define INTR_TYPE_NMI_INTR (2 << 8)/* NMI */ -#define INTR_TYPE_EXCEPTION (3 << 8)/* processor exception */ +#define INTR_TYPE_HARD_EXCEPTION (3 << 8)/* processor exception */ #define INTR_TYPE_SOFT_INTR (4 << 8)/* software interrupt */ +#define INTR_TYPE_SOFT_EXCEPTION (6 << 8)/* software exception */ /* GUEST_INTERRUPTIBILITY_INFO flags. */ #define GUEST_INTR_STATE_STI 0x00000001
arch/x86/kvm/vmx.c +20 -15
@@ -189,21 +189,21 @@ static inline int is_page_fault(u32 intr_info) {return (intr_info & (INTR_INFO_INTR_TYPE_MASK |INTR_INFO_VECTOR_MASK |INTR_INFO_VALID_MASK )) == - (INTR_TYPE_EXCEPTION |PF_VECTOR |INTR_INFO_VALID_MASK ); + (INTR_TYPE_HARD_EXCEPTION |PF_VECTOR |INTR_INFO_VALID_MASK ); }static inline int is_no_device (u32 intr_info) {return (intr_info & (INTR_INFO_INTR_TYPE_MASK |INTR_INFO_VECTOR_MASK |INTR_INFO_VALID_MASK )) == - (INTR_TYPE_EXCEPTION |NM_VECTOR |INTR_INFO_VALID_MASK ); + (INTR_TYPE_HARD_EXCEPTION |NM_VECTOR |INTR_INFO_VALID_MASK ); }static inline int is_invalid_opcode (u32 intr_info) {return (intr_info & (INTR_INFO_INTR_TYPE_MASK |INTR_INFO_VECTOR_MASK |INTR_INFO_VALID_MASK )) == - (INTR_TYPE_EXCEPTION |UD_VECTOR |INTR_INFO_VALID_MASK ); + (INTR_TYPE_HARD_EXCEPTION |UD_VECTOR |INTR_INFO_VALID_MASK ); }static inline int is_external_interrupt (u32 intr_info)
@@ -747,29 +747,33 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, bool has_error_code, u32 error_code) {struct vcpu_vmx *vmx =to_vmx (vcpu); +u32 intr_info = nr |INTR_INFO_VALID_MASK ; -if (has_error_code) +if (has_error_code) {vmcs_write32 (VM_ENTRY_EXCEPTION_ERROR_CODE , error_code); + intr_info |=INTR_INFO_DELIVER_CODE_MASK ; + }if (vcpu->arch.rmode.active) { vmx->rmode.irq.pending = true; vmx->rmode.irq.vector = nr; vmx->rmode.irq.rip =kvm_rip_read (vcpu); -if (nr ==BP_VECTOR ) +if (nr ==BP_VECTOR || nr ==OF_VECTOR ) vmx->rmode.irq.rip++; -vmcs_write32 (VM_ENTRY_INTR_INFO_FIELD , - nr |INTR_TYPE_SOFT_INTR - | (has_error_code ?INTR_INFO_DELIVER_CODE_MASK :0 ) - |INTR_INFO_VALID_MASK ); + intr_info |=INTR_TYPE_SOFT_INTR ; +vmcs_write32 (VM_ENTRY_INTR_INFO_FIELD , intr_info);vmcs_write32 (VM_ENTRY_INSTRUCTION_LEN ,1 );kvm_rip_write (vcpu, vmx->rmode.irq.rip -1 );return ; } -vmcs_write32 (VM_ENTRY_INTR_INFO_FIELD , - nr |INTR_TYPE_EXCEPTION - | (has_error_code ?INTR_INFO_DELIVER_CODE_MASK :0 ) - |INTR_INFO_VALID_MASK ); +if (nr ==BP_VECTOR || nr ==OF_VECTOR ) { +vmcs_write32 (VM_ENTRY_INSTRUCTION_LEN ,1 ); + intr_info |=INTR_TYPE_SOFT_EXCEPTION ; + }else + intr_info |=INTR_TYPE_HARD_EXCEPTION ; + +vmcs_write32 (VM_ENTRY_INTR_INFO_FIELD , intr_info); }static bool vmx_exception_injected (struct kvm_vcpu *vcpu)
@@ -2649,7 +2653,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) }if ((intr_info & (INTR_INFO_INTR_TYPE_MASK |INTR_INFO_VECTOR_MASK )) == - (INTR_TYPE_EXCEPTION |1 )) { + (INTR_TYPE_HARD_EXCEPTION |1 )) { kvm_run->exit_reason =KVM_EXIT_DEBUG ;return 0 ; }
@@ -3237,7 +3241,8 @@ static void vmx_complete_interrupts(struct vcpu_vmx *vmx) vmx->vcpu.arch.nmi_injected = false; }kvm_clear_exception_queue (&vmx->vcpu); -if (idtv_info_valid && type ==INTR_TYPE_EXCEPTION ) { +if (idtv_info_valid && (type ==INTR_TYPE_HARD_EXCEPTION || + type ==INTR_TYPE_SOFT_EXCEPTION )) {if (idt_vectoring_info &VECTORING_INFO_DELIVER_CODE_MASK ) { error =vmcs_read32 (IDT_VECTORING_ERROR_CODE );kvm_queue_exception_e (&vmx->vcpu, vector, error);
PATCH v3 2/5 KVM: New guest debug interface
In reply to Jan KiszkaThis rips out the support for KVM_DEBUG_GUEST and introduces a new IOCTL
instead: KVM_SET_GUEST_DEBUG. The IOCTL payload consists of a generic part, controlling the "main switch" and the single-step feature. The arch specific part adds an x86 interface for intercepting both types of debug exceptions separately and re-injecting them when the host was not interested. Moveover, the foundation for guest debugging via debug registers is layed.
To signal breakpoint events properly back to userland, an arch-specific data block is now returned along KVM_EXIT_DEBUG. For x86, the arch block contains the PC, the debug exception, and relevant debug registers to tell debug events properly apart.
The availability of this new interface is signaled by KVM_CAP_SET_GUEST_DEBUG. Empty stubs for not yet supported archs are provided.
Note that both SVM and VTX are supported, but only the latter was tested yet. Based on the experience with all those VTX corner case, I would be fairly surprised if SVM will work out of the box.
---
arch/ia64/include/asm/kvm.h | 7 +++ arch/ia64/kvm/kvm-ia64.c | 4 +- arch/powerpc/include/asm/kvm.h | 7 +++ arch/powerpc/kvm/powerpc.c | 4 +- arch/s390/include/asm/kvm.h | 7 +++ arch/s390/kvm/kvm-s390.c | 4 +- arch/x86/include/asm/kvm.h | 18 ++++++++ arch/x86/include/asm/kvm_host.h | 9 ---- arch/x86/kvm/svm.c | 50 ++++++++++++++++++++- arch/x86/kvm/vmx.c | 93 +++++++++++++++------------------------ arch/x86/kvm/x86.c | 14 +++--- include/linux/kvm.h | 51 +++++++++++++++------ include/linux/kvm_host.h | 6 +-- virt/kvm/kvm_main.c | 6 +-- 14 files changed, 179 insertions(+), 101 deletions(-)
arch/ia64/include/asm/kvm.h +7 -0
@@ -208,4 +208,11 @@ struct kvm_sregs {struct kvm_fpu { }; +struct kvm_debug_exit_arch { +}; + +/* for KVM_SET_GUEST_DEBUG */ +struct kvm_guest_debug_arch { +}; +#endif
arch/ia64/kvm/kvm-ia64.c +2 -2
@@ -1315,8 +1315,8 @@ int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)return -EINVAL ; } -int kvm_arch_vcpu_ioctl_debug_guest (struct kvm_vcpu *vcpu, -struct kvm_debug_guest *dbg) +int kvm_arch_vcpu_ioctl_set_guest_debug (struct kvm_vcpu *vcpu, +struct kvm_guest_debug *dbg) {return -EINVAL ; }
arch/powerpc/include/asm/kvm.h +7 -0
@@ -52,4 +52,11 @@ struct kvm_fpu { __u64 fpr[32]; }; +struct kvm_debug_exit_arch { +}; + +/* for KVM_SET_GUEST_DEBUG */ +struct kvm_guest_debug_arch { +}; +#endif /* __LINUX_KVM_POWERPC_H */
arch/powerpc/kvm/powerpc.c +2 -2
@@ -230,8 +230,8 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)kvmppc_core_vcpu_put (vcpu); } -int kvm_arch_vcpu_ioctl_debug_guest (struct kvm_vcpu *vcpu, -struct kvm_debug_guest *dbg) +int kvm_arch_vcpu_ioctl_set_guest_debug (struct kvm_vcpu *vcpu, +struct kvm_guest_debug *dbg) {int i;
arch/s390/include/asm/kvm.h +7 -0
@@ -42,4 +42,11 @@ struct kvm_fpu { __u64 fprs[16]; }; +struct kvm_debug_exit_arch { +}; + +/* for KVM_SET_GUEST_DEBUG */ +struct kvm_guest_debug_arch { +}; +#endif
arch/s390/kvm/kvm-s390.c +2 -2
@@ -418,8 +418,8 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,return -EINVAL ;/* not implemented yet */ } -int kvm_arch_vcpu_ioctl_debug_guest (struct kvm_vcpu *vcpu, -struct kvm_debug_guest *dbg) +int kvm_arch_vcpu_ioctl_set_guest_debug (struct kvm_vcpu *vcpu, +struct kvm_guest_debug *dbg) {return -EINVAL ;/* not implemented yet */ }
arch/x86/include/asm/kvm.h +18 -0
@@ -205,6 +205,24 @@ struct kvm_pit_channel_state {__s64 count_load_time; }; +struct kvm_debug_exit_arch { +__u32 exception; +__u32 pad; +__u64 pc; +__u64 dr6; +__u64 dr7; +}; + +#define KVM_GUESTDBG_USE_SW_BP 0x00010000 +#define KVM_GUESTDBG_USE_HW_BP 0x00020000 +#define KVM_GUESTDBG_INJECT_DB 0x00040000 +#define KVM_GUESTDBG_INJECT_BP 0x00080000 + +/* for KVM_SET_GUEST_DEBUG */ +struct kvm_guest_debug_arch { +__u64 debugreg[8 ]; +}; +struct kvm_pit_state {struct kvm_pit_channel_state channels[3 ]; };
arch/x86/include/asm/kvm_host.h +1 -8
@@ -134,12 +134,6 @@ enum {#define KVM_NR_MEM_OBJS 40 -struct kvm_guest_debug { -int enabled; -unsigned long bp[4 ]; -int singlestep; -}; -/* * We don't want allocation failures within the mmu code, so we preallocate * enough memory for a single page fault in a cache.
@@ -446,8 +440,7 @@ struct kvm_x86_ops {void (*vcpu_put)(struct kvm_vcpu *vcpu);int (*set_guest_debug)(struct kvm_vcpu *vcpu, -struct kvm_debug_guest *dbg); -void (*guest_debug_pre)(struct kvm_vcpu *vcpu); +struct kvm_guest_debug *dbg);int (*get_msr)(struct kvm_vcpu *vcpu,u32 msr_index,u64 *pdata);int (*set_msr)(struct kvm_vcpu *vcpu,u32 msr_index,u64 data);u64 (*get_segment_base)(struct kvm_vcpu *vcpu,int seg);
arch/x86/kvm/svm.c +48 -2
69 lines not on this page · raw message
arch/x86/kvm/vmx.c +36 -57
145 lines not on this page · raw message
arch/x86/kvm/x86.c +8 -6
@@ -2976,9 +2976,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) goto out; } -if (vcpu->guest_debug.enabled) - kvm_x86_ops->guest_debug_pre (vcpu); - vcpu->guest_mode =1 ;/* * Make sure that guest_mode assignment won't happen after
@@ -3189,7 +3186,7 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)/* * Don't leak debug flags in case they were set for guest debugging */ -if (vcpu->guest_debug.enabled && vcpu->guest_debug.singlestep) +if (vcpu->guest_debug &KVM_GUESTDBG_SINGLESTEP ) regs->rflags &= ~(X86_EFLAGS_TF |X86_EFLAGS_RF );vcpu_put (vcpu);
@@ -3808,8 +3805,8 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,return 0 ; } -int kvm_arch_vcpu_ioctl_debug_guest (struct kvm_vcpu *vcpu, -struct kvm_debug_guest *dbg) +int kvm_arch_vcpu_ioctl_set_guest_debug (struct kvm_vcpu *vcpu, +struct kvm_guest_debug *dbg) {int r;
@@ -3817,6 +3814,11 @@ int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu, r = kvm_x86_ops->set_guest_debug (vcpu, dbg); +if (dbg->control &KVM_GUESTDBG_INJECT_DB ) +kvm_queue_exception (vcpu,DB_VECTOR ); +else if (dbg->control &KVM_GUESTDBG_INJECT_BP ) +kvm_queue_exception (vcpu,BP_VECTOR ); +vcpu_put (vcpu);return r;
include/linux/kvm.h +35 -16
87 lines not on this page · raw message
include/linux/kvm_host.h +3 -3
@@ -73,7 +73,7 @@ struct kvm_vcpu {struct kvm_run *run;int guest_mode;unsigned long requests; -struct kvm_guest_debug guest_debug; +unsigned long guest_debug;int fpu_active;int guest_fpu_loaded;wait_queue_head_t wq;
@@ -255,8 +255,8 @@ int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, struct kvm_mp_state *mp_state);int kvm_arch_vcpu_ioctl_set_mpstate (struct kvm_vcpu *vcpu,struct kvm_mp_state *mp_state); -int kvm_arch_vcpu_ioctl_debug_guest (struct kvm_vcpu *vcpu, -struct kvm_debug_guest *dbg); +int kvm_arch_vcpu_ioctl_set_guest_debug (struct kvm_vcpu *vcpu, +struct kvm_guest_debug *dbg);int kvm_arch_vcpu_ioctl_run (struct kvm_vcpu *vcpu,struct kvm_run *kvm_run);int kvm_arch_init (void *opaque);
virt/kvm/kvm_main.c +3 -3
@@ -1697,13 +1697,13 @@ out_free2: r =0 ;break ; } -case KVM_DEBUG_GUEST : { -struct kvm_debug_guest dbg; +case KVM_SET_GUEST_DEBUG : { +struct kvm_guest_debug dbg; r = -EFAULT ;if (copy_from_user (&dbg, argp,sizeof dbg)) goto out; - r =kvm_arch_vcpu_ioctl_debug_guest (vcpu, &dbg); + r =kvm_arch_vcpu_ioctl_set_guest_debug (vcpu, &dbg);if (r) goto out; r =0 ;
PATCH v3 3/5 KVM: VMX: Allow single-stepping when uninterruptible
In reply to Jan KiszkaWhen single-stepping over STI and MOV SS, we must clear the corresponding interruptibility bits in the guest state. Otherwise vmentry fails as it then expects bit 14 (BS) in pending debug exceptions being set, but that's not correct for the guest debugging case.
Note that clearing those bits is safe as we check for interruptibility based on the original state and do not inject interrupts or NMIs if guest interruptibility was blocked.
---
arch/x86/kvm/vmx.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-)
arch/x86/kvm/vmx.c +10 -0
@@ -2477,6 +2477,11 @@ static void do_interrupt_requests(struct kvm_vcpu *vcpu, {vmx_update_window_states (vcpu); +if (vcpu->guest_debug &KVM_GUESTDBG_SINGLESTEP ) +vmcs_clear_bits (GUEST_INTERRUPTIBILITY_INFO , +GUEST_INTR_STATE_STI | +GUEST_INTR_STATE_MOV_SS ); +if (vcpu->arch.nmi_pending && !vcpu->arch.nmi_injected) {if (vcpu->arch.interrupt.pending) {enable_nmi_window (vcpu);
@@ -3243,6 +3248,11 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu)vmx_update_window_states (vcpu); +if (vcpu->guest_debug &KVM_GUESTDBG_SINGLESTEP ) +vmcs_clear_bits (GUEST_INTERRUPTIBILITY_INFO , +GUEST_INTR_STATE_STI | +GUEST_INTR_STATE_MOV_SS ); +if (vcpu->arch.nmi_pending && !vcpu->arch.nmi_injected) {if (vcpu->arch.interrupt.pending) {enable_nmi_window (vcpu);
PATCH v3 4/5 KVM: x86: Virtualize debug registers
In reply to Jan KiszkaSo far KVM only had basic x86 debug register support, once introduced to realize guest debugging that way. The guest itself was not able to use those registers.
This patch now adds (almost) full support for guest self-debugging via hardware registers. It refactors the code, moving generic parts out of SVM (VMX was already cleaned up by the KVM_SET_GUEST_DEBUG patches), and it ensures that the registers are properly switched between host and guest.
This patch also prepares debug register usage by the host. The latter will (once wired-up by the following patch) allow for hardware breakpoints/watchpoints in guest code. If this is enabled, the guest will only see faked debug registers without functionality, but with content reflecting the guest's modifications.
Tested on Intel only, but SVM /should/ work as well, but who knows...
Known limitations: Trapping on tss switch won't work - most probably on Intel.
Credits also go to Joerg Roedel - I used his once posted debugging series as platform for this patch.
---
arch/x86/include/asm/kvm_host.h | 22 +++++++ arch/x86/include/asm/vmx.h | 2 - arch/x86/kvm/kvm_svm.h | 6 -- arch/x86/kvm/svm.c | 116 ++++++++++++++------------------------- arch/x86/kvm/vmx.c | 114 +++++++++++++++++++++++++++++++++----- arch/x86/kvm/x86.c | 29 ++++++++++ 6 files changed, 193 insertions(+), 96 deletions(-)
arch/x86/include/asm/kvm_host.h +22 -0
@@ -134,6 +134,19 @@ enum {#define KVM_NR_MEM_OBJS 40 +#define KVM_NR_DB_REGS 4 + +#define DR6_BD (1 << 13) +#define DR6_BS (1 << 14) +#define DR6_FIXED_1 0xffff0ff0 +#define DR6_VOLATILE 0x0000e00f + +#define DR7_BP_EN_MASK 0x000000ff +#define DR7_GE (1 << 9) +#define DR7_GD (1 << 13) +#define DR7_FIXED_1 0x00000400 +#define DR7_VOLATILE 0xffff23ff +/* * We don't want allocation failures within the mmu code, so we preallocate * enough memory for a single page fault in a cache.
@@ -332,6 +345,15 @@ struct kvm_vcpu_arch {struct mtrr_state_type mtrr_state;u32 pat; + +int switch_db_regs; +unsigned long host_db[KVM_NR_DB_REGS ]; +unsigned long host_dr6; +unsigned long host_dr7; +unsigned long db[KVM_NR_DB_REGS ]; +unsigned long dr6; +unsigned long dr7; +unsigned long eff_db[KVM_NR_DB_REGS ]; };struct kvm_mem_alias {
arch/x86/include/asm/vmx.h +1 -1
@@ -312,7 +312,7 @@ enum vmcs_field {#define DEBUG_REG_ACCESS_TYPE 0x10/* 4, direction of access */ #define TYPE_MOV_TO_DR (0 << 4)#define TYPE_MOV_FROM_DR (1 << 4) -#define DEBUG_REG_ACCESS_REG 0xf00/* 11:8, general purpose reg. */ +#define DEBUG_REG_ACCESS_REG (eq) (((eq) >> 8) & 0xf)/* 11:8, general purpose reg. */ /* segment AR */
arch/x86/kvm/kvm_svm.h +0 -6
@@ -18,7 +18,6 @@ static const u32 host_save_user_msrs[] = { };#define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs) -#define NUM_DB_REGS 4struct kvm_vcpu ;
@@ -29,16 +28,11 @@ struct vcpu_svm {struct svm_cpu_data *svm_data;uint64_t asid_generation; -unsigned long db_regs[NUM_DB_REGS ]; -u64 next_rip;u64 host_user_msrs[NR_HOST_SAVE_USER_MSRS ];u64 host_gs_base;unsigned long host_cr2; -unsigned long host_db_regs[NUM_DB_REGS ]; -unsigned long host_dr6; -unsigned long host_dr7;u32 *msrpm; };
arch/x86/kvm/svm.c +43 -73
188 lines not on this page · raw message
arch/x86/kvm/vmx.c +98 -16
173 lines not on this page · raw message
arch/x86/kvm/x86.c +29 -0
@@ -2996,10 +2996,34 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)kvm_guest_enter (); +get_debugreg (vcpu->arch.host_dr6,6 ); +get_debugreg (vcpu->arch.host_dr7,7 ); +if (unlikely (vcpu->arch.switch_db_regs)) { +get_debugreg (vcpu->arch.host_db[0 ],0 ); +get_debugreg (vcpu->arch.host_db[1 ],1 ); +get_debugreg (vcpu->arch.host_db[2 ],2 ); +get_debugreg (vcpu->arch.host_db[3 ],3 ); + +set_debugreg (0 ,7 ); +set_debugreg (vcpu->arch.eff_db[0 ],0 ); +set_debugreg (vcpu->arch.eff_db[1 ],1 ); +set_debugreg (vcpu->arch.eff_db[2 ],2 ); +set_debugreg (vcpu->arch.eff_db[3 ],3 ); + }KVMTRACE_0D (VMENTRY , vcpu, entryexit); kvm_x86_ops->run (vcpu, kvm_run); +if (unlikely (vcpu->arch.switch_db_regs)) { +set_debugreg (0 ,7 ); +set_debugreg (vcpu->arch.host_db[0 ],0 ); +set_debugreg (vcpu->arch.host_db[1 ],1 ); +set_debugreg (vcpu->arch.host_db[2 ],2 ); +set_debugreg (vcpu->arch.host_db[3 ],3 ); + } +set_debugreg (vcpu->arch.host_dr6,6 ); +set_debugreg (vcpu->arch.host_dr7,7 ); + vcpu->guest_mode =0 ;local_irq_enable ();
@@ -4006,6 +4030,11 @@ int kvm_arch_vcpu_reset(struct kvm_vcpu *vcpu) vcpu->arch.nmi_pending = false; vcpu->arch.nmi_injected = false; + vcpu->arch.switch_db_regs =0 ; +memset (vcpu->arch.db,0 ,sizeof (vcpu->arch.db)); + vcpu->arch.dr6 =DR6_FIXED_1 ; + vcpu->arch.dr7 =DR7_FIXED_1 ; +return kvm_x86_ops->vcpu_reset (vcpu); }
PATCH v3 5/5 KVM: x86: Wire-up hardware breakpoints for guest debugging
In reply to Jan KiszkaAdd the remaining bits to make use of debug registers also for guest debugging, thus enabling the use of hardware breakpoints and watchpoints.
---
arch/x86/kvm/svm.c | 5 +++++ arch/x86/kvm/vmx.c | 5 +++++ arch/x86/kvm/x86.c | 14 +++++++++++++- 3 files changed, 23 insertions(+), 1 deletions(-)
arch/x86/kvm/svm.c +5 -0
@@ -895,6 +895,11 @@ static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg) }else vcpu->guest_debug =0 ; +if (vcpu->guest_debug &KVM_GUESTDBG_USE_HW_BP ) + svm->vmcb->save.dr7 = dbg->arch.debugreg[7 ]; +else + svm->vmcb->save.dr7 = vcpu->arch.dr7; +if (vcpu->guest_debug &KVM_GUESTDBG_SINGLESTEP ) svm->vmcb->save.rflags |=X86_EFLAGS_TF |X86_EFLAGS_RF ;else if (old_debug &KVM_GUESTDBG_SINGLESTEP )
arch/x86/kvm/vmx.c +5 -0
@@ -1016,6 +1016,11 @@ static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg)if (!(vcpu->guest_debug &KVM_GUESTDBG_ENABLE )) vcpu->guest_debug =0 ; +if (vcpu->guest_debug &KVM_GUESTDBG_USE_HW_BP ) +vmcs_writel (GUEST_DR7 , dbg->arch.debugreg[7 ]); +else +vmcs_writel (GUEST_DR7 , vcpu->arch.dr7); + flags =vmcs_readl (GUEST_RFLAGS );if (vcpu->guest_debug &KVM_GUESTDBG_SINGLESTEP ) flags |=X86_EFLAGS_TF |X86_EFLAGS_RF ;
arch/x86/kvm/x86.c +13 -1
@@ -3832,10 +3832,22 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,int kvm_arch_vcpu_ioctl_set_guest_debug (struct kvm_vcpu *vcpu,struct kvm_guest_debug *dbg) { -int r; +int i, r;vcpu_load (vcpu); +if ((dbg->control & (KVM_GUESTDBG_ENABLE |KVM_GUESTDBG_USE_HW_BP )) == + (KVM_GUESTDBG_ENABLE |KVM_GUESTDBG_USE_HW_BP )) { +for (i =0 ; i <KVM_NR_DB_REGS ; ++i) + vcpu->arch.eff_db[i] = dbg->arch.debugreg[i]; + vcpu->arch.switch_db_regs = + (dbg->arch.debugreg[7 ] &DR7_BP_EN_MASK ); + }else { +for (i =0 ; i <KVM_NR_DB_REGS ; i++) + vcpu->arch.eff_db[i] = vcpu->arch.db[i]; + vcpu->arch.switch_db_regs = (vcpu->arch.dr7 &DR7_BP_EN_MASK ); + } + r = kvm_x86_ops->set_guest_debug (vcpu, dbg);if (dbg->control &KVM_GUESTDBG_INJECT_DB )
Avi Kivity
AppliedQuoted 12 lines · Jan Kiszka
This is the kernel part of the guest debugging / debug register emulation patch series.
Changes since last round (was v1, skipped v2 to remain in sync with user space series):
- Reworked patch 3 (single-stepping over STI / MOV SS on VMX)
- Rebased over latest gitMeanwhile basic tests on a SVM host indicate that this platform is fine the series as well.
Applied all, thanks.
Signature · 1 line
error compiling committee.c: too many arguments to function