* [PATCH 1/7] KVM: add commentary for kvm_debug_exit_arch struct [not found] <1416931805-23223-1-git-send-email-alex.bennee@linaro.org> @ 2014-11-25 16:09 ` Alex Bennée [not found] ` <1416931805-23223-2-git-send-email-alex.bennee-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> 2014-11-25 16:10 ` [PATCH 5/7] KVM: arm64: guest debug, add support for single-step Alex Bennée 2014-11-25 16:10 ` [PATCH 7/7] KVM: arm64: guest debug, HW assisted debug support Alex Bennée 2 siblings, 1 reply; 15+ messages in thread From: Alex Bennée @ 2014-11-25 16:09 UTC (permalink / raw) To: kvm, linux-arm-kernel, kvmarm, christoffer.dall, marc.zyngier, peter.maydell, agraf Cc: jan.kiszka, dahi, r65777, bp, pbonzini, Alex Bennée, Gleb Natapov, open list:ABI/API, open list Bring into line with the commentary for the other structures and their KVM_EXIT_* cases. Signed-off-by: Alex Bennée <alex.bennee@linaro.org> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 6076882..523f476 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -226,6 +226,7 @@ struct kvm_run { __u32 count; __u64 data_offset; /* relative to kvm_run start */ } io; + /* KVM_EXIT_DEBUG */ struct { struct kvm_debug_exit_arch arch; } debug; -- 2.1.3 ^ permalink raw reply related [flat|nested] 15+ messages in thread
[parent not found: <1416931805-23223-2-git-send-email-alex.bennee-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>]
* Re: [PATCH 1/7] KVM: add commentary for kvm_debug_exit_arch struct [not found] ` <1416931805-23223-2-git-send-email-alex.bennee-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> @ 2014-11-26 14:20 ` Andrew Jones 0 siblings, 0 replies; 15+ messages in thread From: Andrew Jones @ 2014-11-26 14:20 UTC (permalink / raw) To: Alex Bennée Cc: kvm-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, kvmarm-FPEHb7Xf0XXUo1n7N8X6UoWGPAHP3yOg, christoffer.dall-QSEj5FYQhm4dnm+yROfE0A, marc.zyngier-5wv7dgnIgG8, peter.maydell-QSEj5FYQhm4dnm+yROfE0A, agraf-l3A5Bk7waGM, Gleb Natapov, jan.kiszka-kv7WeFo6aLtBDgjK7y7TUQ, open list, open list:ABI/API, dahi-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8, r65777-KZfg59tc24xl57MIdRCFDg, pbonzini-H+wXaHxf7aLQT0dZR+AlfA, bp-l3A5Bk7waGM On Tue, Nov 25, 2014 at 04:09:59PM +0000, Alex Bennée wrote: > Bring into line with the commentary for the other structures and their > KVM_EXIT_* cases. > > Signed-off-by: Alex Bennée <alex.bennee-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> > > diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h > index 6076882..523f476 100644 > --- a/include/uapi/linux/kvm.h > +++ b/include/uapi/linux/kvm.h > @@ -226,6 +226,7 @@ struct kvm_run { > __u32 count; > __u64 data_offset; /* relative to kvm_run start */ > } io; > + /* KVM_EXIT_DEBUG */ > struct { > struct kvm_debug_exit_arch arch; > } debug; > -- > 2.1.3 Can we change this to a 'KVM: add commentary for kvm exit type data' patch? We're also missing /* KVM_EXIT_INTERNAL_ERROR */ and /* KVM_EXIT_PAPR_HCALL */ > > _______________________________________________ > kvmarm mailing list > kvmarm-FPEHb7Xf0XXUo1n7N8X6UoWGPAHP3yOg@public.gmane.org > https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 5/7] KVM: arm64: guest debug, add support for single-step [not found] <1416931805-23223-1-git-send-email-alex.bennee@linaro.org> 2014-11-25 16:09 ` [PATCH 1/7] KVM: add commentary for kvm_debug_exit_arch struct Alex Bennée @ 2014-11-25 16:10 ` Alex Bennée [not found] ` <1416931805-23223-6-git-send-email-alex.bennee-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> 2014-11-30 10:21 ` Christoffer Dall 2014-11-25 16:10 ` [PATCH 7/7] KVM: arm64: guest debug, HW assisted debug support Alex Bennée 2 siblings, 2 replies; 15+ messages in thread From: Alex Bennée @ 2014-11-25 16:10 UTC (permalink / raw) To: kvm, linux-arm-kernel, kvmarm, christoffer.dall, marc.zyngier, peter.maydell, agraf Cc: jan.kiszka, dahi, r65777, bp, pbonzini, Alex Bennée, Gleb Natapov, Russell King, Catalin Marinas, Will Deacon, Lorenzo Pieralisi, open list, open list:ABI/API This adds support for single-stepping the guest. As userspace can and will manipulate guest registers before restarting any tweaking of the registers has to occur just before control is passed back to the guest. Furthermore while guest debugging is in effect we need to squash the ability of the guest to single-step itself as we have no easy way of re-entering the guest after the exception has been delivered to the hypervisor. Signed-off-by: Alex Bennée <alex.bennee@linaro.org> diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 48d26bb..a76daae 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -38,6 +38,7 @@ #include <asm/tlbflush.h> #include <asm/cacheflush.h> #include <asm/virt.h> +#include <asm/debug-monitors.h> #include <asm/kvm_arm.h> #include <asm/kvm_asm.h> #include <asm/kvm_mmu.h> @@ -300,6 +301,17 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) kvm_arm_set_running_vcpu(NULL); } +/** + * kvm_arch_vcpu_ioctl_set_guest_debug - Setup guest debugging + * @kvm: pointer to the KVM struct + * @kvm_guest_debug: the ioctl data buffer + * + * This sets up the VM for guest debugging. Care has to be taken when + * manipulating guest registers as these will be set/cleared by the + * hyper-visor controller, typically before each kvm_run event. As a + * result modification of the guest registers needs to take place + * after they have been restored in the hyp.S trampoline code. + */ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg) { @@ -317,8 +329,8 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, /* Single Step */ if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) { - kvm_info("SS requested, not yet implemented\n"); - return -EINVAL; + kvm_info("SS requested\n"); + route_el2 = true; } /* Software Break Points */ diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index 8da1043..78e5ae1 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -121,6 +121,7 @@ int main(void) DEFINE(VCPU_FAR_EL2, offsetof(struct kvm_vcpu, arch.fault.far_el2)); DEFINE(VCPU_HPFAR_EL2, offsetof(struct kvm_vcpu, arch.fault.hpfar_el2)); DEFINE(VCPU_DEBUG_FLAGS, offsetof(struct kvm_vcpu, arch.debug_flags)); + DEFINE(GUEST_DEBUG, offsetof(struct kvm_vcpu, guest_debug)); DEFINE(VCPU_HCR_EL2, offsetof(struct kvm_vcpu, arch.hcr_el2)); DEFINE(VCPU_MDCR_EL2, offsetof(struct kvm_vcpu, arch.mdcr_el2)); DEFINE(VCPU_IRQ_LINES, offsetof(struct kvm_vcpu, arch.irq_lines)); diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 28dc92b..6def054 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -91,6 +91,25 @@ static int kvm_handle_bkpt(struct kvm_vcpu *vcpu, struct kvm_run *run) return 0; } +/** + * kvm_handle_ss - handle single step exceptions + * + * @vcpu: the vcpu pointer + * + * See: ARM ARM D2.12 for the details. While the host is routing debug + * exceptions to it's handlers we have to suppress the ability of the + * guest to trigger exceptions. + */ +static int kvm_handle_ss(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + WARN_ON(!(vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)); + + run->exit_reason = KVM_EXIT_DEBUG; + run->debug.arch.exit_type = KVM_DEBUG_EXIT_SINGLE_STEP; + run->debug.arch.address = *vcpu_pc(vcpu); + return 0; +} + static exit_handle_fn arm_exit_handlers[] = { [ESR_EL2_EC_WFI] = kvm_handle_wfx, [ESR_EL2_EC_CP15_32] = kvm_handle_cp15_32, @@ -105,6 +124,7 @@ static exit_handle_fn arm_exit_handlers[] = { [ESR_EL2_EC_SYS64] = kvm_handle_sys_reg, [ESR_EL2_EC_IABT] = kvm_handle_guest_abort, [ESR_EL2_EC_DABT] = kvm_handle_guest_abort, + [ESR_EL2_EC_SOFTSTP] = kvm_handle_ss, [ESR_EL2_EC_BKPT32] = kvm_handle_bkpt, [ESR_EL2_EC_BRK64] = kvm_handle_bkpt, }; diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S index 3c733ea..c0bc218 100644 --- a/arch/arm64/kvm/hyp.S +++ b/arch/arm64/kvm/hyp.S @@ -16,6 +16,7 @@ */ #include <linux/linkage.h> +#include <linux/kvm.h> #include <asm/assembler.h> #include <asm/memory.h> @@ -168,6 +169,31 @@ // x19-x29, lr, sp*, elr*, spsr* restore_common_regs + // After restoring the guest registers but before we return to the guest + // we may want to make some final tweaks to support guest debugging. + ldr x3, [x0, #GUEST_DEBUG] + tbz x3, #KVM_GUESTDBG_ENABLE_SHIFT, 2f // No guest debug + + // x0 - preserved as VCPU ptr + // x1 - spsr + // x2 - mdscr + mrs x1, spsr_el2 + mrs x2, mdscr_el1 + + // See ARM ARM D2.12.3 The software step state machine + // If we are doing Single Step - set MDSCR_EL1.SS and PSTATE.SS + orr x1, x1, #DBG_SPSR_SS + orr x2, x2, #DBG_MDSCR_SS + tbnz x3, #KVM_GUESTDBG_SINGLESTEP_SHIFT, 1f + // If we are not doing Single Step we want to prevent the guest doing so + // as otherwise we will have to deal with the re-routed exceptions as we + // are doing other guest debug related things + eor x1, x1, #DBG_SPSR_SS + eor x2, x2, #DBG_MDSCR_SS +1: + msr spsr_el2, x1 + msr mdscr_el1, x2 +2: // Last bits of the 64bit state pop x2, x3 pop x0, x1 diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 523f476..347e5b0 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -7,6 +7,8 @@ * Note: you must update KVM_API_VERSION if you change this interface. */ +#ifndef __ASSEMBLY__ + #include <linux/types.h> #include <linux/compiler.h> #include <linux/ioctl.h> @@ -515,11 +517,6 @@ struct kvm_s390_irq { } u; }; -/* for KVM_SET_GUEST_DEBUG */ - -#define KVM_GUESTDBG_ENABLE 0x00000001 -#define KVM_GUESTDBG_SINGLESTEP 0x00000002 - struct kvm_guest_debug { __u32 control; __u32 pad; @@ -1189,4 +1186,15 @@ struct kvm_assigned_msix_entry { __u16 padding[3]; }; +#endif /* __ASSEMBLY__ */ + +/* for KVM_SET_GUEST_DEBUG */ + +#define KVM_GUESTDBG_ENABLE_SHIFT 0 +#define KVM_GUESTDBG_ENABLE (1 << KVM_GUESTDBG_ENABLE_SHIFT) +#define KVM_GUESTDBG_SINGLESTEP_SHIFT 1 +#define KVM_GUESTDBG_SINGLESTEP (1 << KVM_GUESTDBG_SINGLESTEP_SHIFT) + + + #endif /* __LINUX_KVM_H */ -- 2.1.3 ^ permalink raw reply related [flat|nested] 15+ messages in thread
[parent not found: <1416931805-23223-6-git-send-email-alex.bennee-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>]
* Re: [PATCH 5/7] KVM: arm64: guest debug, add support for single-step [not found] ` <1416931805-23223-6-git-send-email-alex.bennee-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> @ 2014-11-26 16:40 ` Andrew Jones [not found] ` <20141126164057.GE3245-EoAxxbxdFnFvD/m4c++uL6fLeoKvNuZc@public.gmane.org> 2014-11-26 19:27 ` Peter Maydell 1 sibling, 1 reply; 15+ messages in thread From: Andrew Jones @ 2014-11-26 16:40 UTC (permalink / raw) To: Alex Bennée Cc: kvm-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, kvmarm-FPEHb7Xf0XXUo1n7N8X6UoWGPAHP3yOg, christoffer.dall-QSEj5FYQhm4dnm+yROfE0A, marc.zyngier-5wv7dgnIgG8, peter.maydell-QSEj5FYQhm4dnm+yROfE0A, agraf-l3A5Bk7waGM, Lorenzo Pieralisi, Russell King, Gleb Natapov, jan.kiszka-kv7WeFo6aLtBDgjK7y7TUQ, Will Deacon, open list, open list:ABI/API, dahi-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8, Catalin Marinas, r65777-KZfg59tc24xl57MIdRCFDg, pbonzini-H+wXaHxf7aLQT0dZR+AlfA, bp-l3A5Bk7waGM On Tue, Nov 25, 2014 at 04:10:03PM +0000, Alex Bennée wrote: > This adds support for single-stepping the guest. As userspace can and > will manipulate guest registers before restarting any tweaking of the > registers has to occur just before control is passed back to the guest. > Furthermore while guest debugging is in effect we need to squash the > ability of the guest to single-step itself as we have no easy way of > re-entering the guest after the exception has been delivered to the > hypervisor. > > Signed-off-by: Alex Bennée <alex.bennee-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> > > diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c > index 48d26bb..a76daae 100644 > --- a/arch/arm/kvm/arm.c > +++ b/arch/arm/kvm/arm.c > @@ -38,6 +38,7 @@ > #include <asm/tlbflush.h> > #include <asm/cacheflush.h> > #include <asm/virt.h> > +#include <asm/debug-monitors.h> > #include <asm/kvm_arm.h> > #include <asm/kvm_asm.h> > #include <asm/kvm_mmu.h> > @@ -300,6 +301,17 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) > kvm_arm_set_running_vcpu(NULL); > } > > +/** > + * kvm_arch_vcpu_ioctl_set_guest_debug - Setup guest debugging > + * @kvm: pointer to the KVM struct > + * @kvm_guest_debug: the ioctl data buffer > + * > + * This sets up the VM for guest debugging. Care has to be taken when > + * manipulating guest registers as these will be set/cleared by the > + * hyper-visor controller, typically before each kvm_run event. As a > + * result modification of the guest registers needs to take place > + * after they have been restored in the hyp.S trampoline code. > + */ > int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, > struct kvm_guest_debug *dbg) > { > @@ -317,8 +329,8 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, > > /* Single Step */ > if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) { > - kvm_info("SS requested, not yet implemented\n"); > - return -EINVAL; > + kvm_info("SS requested\n"); > + route_el2 = true; > } > > /* Software Break Points */ > diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c > index 8da1043..78e5ae1 100644 > --- a/arch/arm64/kernel/asm-offsets.c > +++ b/arch/arm64/kernel/asm-offsets.c > @@ -121,6 +121,7 @@ int main(void) > DEFINE(VCPU_FAR_EL2, offsetof(struct kvm_vcpu, arch.fault.far_el2)); > DEFINE(VCPU_HPFAR_EL2, offsetof(struct kvm_vcpu, arch.fault.hpfar_el2)); > DEFINE(VCPU_DEBUG_FLAGS, offsetof(struct kvm_vcpu, arch.debug_flags)); > + DEFINE(GUEST_DEBUG, offsetof(struct kvm_vcpu, guest_debug)); > DEFINE(VCPU_HCR_EL2, offsetof(struct kvm_vcpu, arch.hcr_el2)); > DEFINE(VCPU_MDCR_EL2, offsetof(struct kvm_vcpu, arch.mdcr_el2)); > DEFINE(VCPU_IRQ_LINES, offsetof(struct kvm_vcpu, arch.irq_lines)); > diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c > index 28dc92b..6def054 100644 > --- a/arch/arm64/kvm/handle_exit.c > +++ b/arch/arm64/kvm/handle_exit.c > @@ -91,6 +91,25 @@ static int kvm_handle_bkpt(struct kvm_vcpu *vcpu, struct kvm_run *run) > return 0; > } > > +/** > + * kvm_handle_ss - handle single step exceptions > + * > + * @vcpu: the vcpu pointer same @run comment as other handler header in previous patch > + * > + * See: ARM ARM D2.12 for the details. While the host is routing debug > + * exceptions to it's handlers we have to suppress the ability of the > + * guest to trigger exceptions. > + */ > +static int kvm_handle_ss(struct kvm_vcpu *vcpu, struct kvm_run *run) > +{ > + WARN_ON(!(vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)); I'm not sure about this WARN_ON. Is there some scenario you were thinking of when you put it here? Is there some scenario where this could trigger so frequently we kill the log buffer? > + > + run->exit_reason = KVM_EXIT_DEBUG; > + run->debug.arch.exit_type = KVM_DEBUG_EXIT_SINGLE_STEP; > + run->debug.arch.address = *vcpu_pc(vcpu); > + return 0; > +} > + > static exit_handle_fn arm_exit_handlers[] = { > [ESR_EL2_EC_WFI] = kvm_handle_wfx, > [ESR_EL2_EC_CP15_32] = kvm_handle_cp15_32, > @@ -105,6 +124,7 @@ static exit_handle_fn arm_exit_handlers[] = { > [ESR_EL2_EC_SYS64] = kvm_handle_sys_reg, > [ESR_EL2_EC_IABT] = kvm_handle_guest_abort, > [ESR_EL2_EC_DABT] = kvm_handle_guest_abort, > + [ESR_EL2_EC_SOFTSTP] = kvm_handle_ss, > [ESR_EL2_EC_BKPT32] = kvm_handle_bkpt, > [ESR_EL2_EC_BRK64] = kvm_handle_bkpt, > }; > diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S > index 3c733ea..c0bc218 100644 > --- a/arch/arm64/kvm/hyp.S > +++ b/arch/arm64/kvm/hyp.S > @@ -16,6 +16,7 @@ > */ > > #include <linux/linkage.h> > +#include <linux/kvm.h> > > #include <asm/assembler.h> > #include <asm/memory.h> > @@ -168,6 +169,31 @@ > // x19-x29, lr, sp*, elr*, spsr* > restore_common_regs > > + // After restoring the guest registers but before we return to the guest > + // we may want to make some final tweaks to support guest debugging. > + ldr x3, [x0, #GUEST_DEBUG] > + tbz x3, #KVM_GUESTDBG_ENABLE_SHIFT, 2f // No guest debug > + > + // x0 - preserved as VCPU ptr > + // x1 - spsr > + // x2 - mdscr > + mrs x1, spsr_el2 > + mrs x2, mdscr_el1 > + > + // See ARM ARM D2.12.3 The software step state machine > + // If we are doing Single Step - set MDSCR_EL1.SS and PSTATE.SS > + orr x1, x1, #DBG_SPSR_SS > + orr x2, x2, #DBG_MDSCR_SS > + tbnz x3, #KVM_GUESTDBG_SINGLESTEP_SHIFT, 1f > + // If we are not doing Single Step we want to prevent the guest doing so > + // as otherwise we will have to deal with the re-routed exceptions as we > + // are doing other guest debug related things > + eor x1, x1, #DBG_SPSR_SS > + eor x2, x2, #DBG_MDSCR_SS > +1: > + msr spsr_el2, x1 > + msr mdscr_el1, x2 > +2: > // Last bits of the 64bit state > pop x2, x3 > pop x0, x1 > diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h > index 523f476..347e5b0 100644 > --- a/include/uapi/linux/kvm.h > +++ b/include/uapi/linux/kvm.h > @@ -7,6 +7,8 @@ > * Note: you must update KVM_API_VERSION if you change this interface. > */ > > +#ifndef __ASSEMBLY__ > + > #include <linux/types.h> > #include <linux/compiler.h> > #include <linux/ioctl.h> > @@ -515,11 +517,6 @@ struct kvm_s390_irq { > } u; > }; > > -/* for KVM_SET_GUEST_DEBUG */ > - > -#define KVM_GUESTDBG_ENABLE 0x00000001 > -#define KVM_GUESTDBG_SINGLESTEP 0x00000002 > - > struct kvm_guest_debug { > __u32 control; > __u32 pad; > @@ -1189,4 +1186,15 @@ struct kvm_assigned_msix_entry { > __u16 padding[3]; > }; > > +#endif /* __ASSEMBLY__ */ > + > +/* for KVM_SET_GUEST_DEBUG */ > + > +#define KVM_GUESTDBG_ENABLE_SHIFT 0 > +#define KVM_GUESTDBG_ENABLE (1 << KVM_GUESTDBG_ENABLE_SHIFT) > +#define KVM_GUESTDBG_SINGLESTEP_SHIFT 1 > +#define KVM_GUESTDBG_SINGLESTEP (1 << KVM_GUESTDBG_SINGLESTEP_SHIFT) EALIGN: we can tab these defines up better > + > + > + > #endif /* __LINUX_KVM_H */ > -- > 2.1.3 > > _______________________________________________ > kvmarm mailing list > kvmarm-FPEHb7Xf0XXUo1n7N8X6UoWGPAHP3yOg@public.gmane.org > https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply [flat|nested] 15+ messages in thread
[parent not found: <20141126164057.GE3245-EoAxxbxdFnFvD/m4c++uL6fLeoKvNuZc@public.gmane.org>]
* Re: [PATCH 5/7] KVM: arm64: guest debug, add support for single-step [not found] ` <20141126164057.GE3245-EoAxxbxdFnFvD/m4c++uL6fLeoKvNuZc@public.gmane.org> @ 2014-11-26 18:00 ` Alex Bennée 0 siblings, 0 replies; 15+ messages in thread From: Alex Bennée @ 2014-11-26 18:00 UTC (permalink / raw) To: Andrew Jones Cc: kvm-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, kvmarm-FPEHb7Xf0XXUo1n7N8X6UoWGPAHP3yOg, christoffer.dall-QSEj5FYQhm4dnm+yROfE0A, marc.zyngier-5wv7dgnIgG8, peter.maydell-QSEj5FYQhm4dnm+yROfE0A, agraf-l3A5Bk7waGM, Lorenzo Pieralisi, Russell King, Gleb Natapov, jan.kiszka-kv7WeFo6aLtBDgjK7y7TUQ, Will Deacon, open list, open list:ABI/API, dahi-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8, Catalin Marinas, r65777-KZfg59tc24xl57MIdRCFDg, pbonzini-H+wXaHxf7aLQT0dZR+AlfA, bp-l3A5Bk7waGM Andrew Jones <drjones-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> writes: > On Tue, Nov 25, 2014 at 04:10:03PM +0000, Alex Bennée wrote: >> This adds support for single-stepping the guest. As userspace can and >> will manipulate guest registers before restarting any tweaking of the >> registers has to occur just before control is passed back to the guest. >> Furthermore while guest debugging is in effect we need to squash the >> ability of the guest to single-step itself as we have no easy way of >> re-entering the guest after the exception has been delivered to the >> hypervisor. >> >> Signed-off-by: Alex Bennée <alex.bennee-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> >> >> diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c >> index 48d26bb..a76daae 100644 >> --- a/arch/arm/kvm/arm.c >> +++ b/arch/arm/kvm/arm.c >> @@ -38,6 +38,7 @@ >> #include <asm/tlbflush.h> >> #include <asm/cacheflush.h> >> #include <asm/virt.h> >> +#include <asm/debug-monitors.h> >> #include <asm/kvm_arm.h> >> #include <asm/kvm_asm.h> >> #include <asm/kvm_mmu.h> >> @@ -300,6 +301,17 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) >> kvm_arm_set_running_vcpu(NULL); >> } >> >> +/** >> + * kvm_arch_vcpu_ioctl_set_guest_debug - Setup guest debugging >> + * @kvm: pointer to the KVM struct >> + * @kvm_guest_debug: the ioctl data buffer >> + * >> + * This sets up the VM for guest debugging. Care has to be taken when >> + * manipulating guest registers as these will be set/cleared by the >> + * hyper-visor controller, typically before each kvm_run event. As a >> + * result modification of the guest registers needs to take place >> + * after they have been restored in the hyp.S trampoline code. >> + */ >> int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, >> struct kvm_guest_debug *dbg) >> { >> @@ -317,8 +329,8 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, >> >> /* Single Step */ >> if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) { >> - kvm_info("SS requested, not yet implemented\n"); >> - return -EINVAL; >> + kvm_info("SS requested\n"); >> + route_el2 = true; >> } >> >> /* Software Break Points */ >> diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c >> index 8da1043..78e5ae1 100644 >> --- a/arch/arm64/kernel/asm-offsets.c >> +++ b/arch/arm64/kernel/asm-offsets.c >> @@ -121,6 +121,7 @@ int main(void) >> DEFINE(VCPU_FAR_EL2, offsetof(struct kvm_vcpu, arch.fault.far_el2)); >> DEFINE(VCPU_HPFAR_EL2, offsetof(struct kvm_vcpu, arch.fault.hpfar_el2)); >> DEFINE(VCPU_DEBUG_FLAGS, offsetof(struct kvm_vcpu, arch.debug_flags)); >> + DEFINE(GUEST_DEBUG, offsetof(struct kvm_vcpu, guest_debug)); >> DEFINE(VCPU_HCR_EL2, offsetof(struct kvm_vcpu, arch.hcr_el2)); >> DEFINE(VCPU_MDCR_EL2, offsetof(struct kvm_vcpu, arch.mdcr_el2)); >> DEFINE(VCPU_IRQ_LINES, offsetof(struct kvm_vcpu, arch.irq_lines)); >> diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c >> index 28dc92b..6def054 100644 >> --- a/arch/arm64/kvm/handle_exit.c >> +++ b/arch/arm64/kvm/handle_exit.c >> @@ -91,6 +91,25 @@ static int kvm_handle_bkpt(struct kvm_vcpu *vcpu, struct kvm_run *run) >> return 0; >> } >> >> +/** >> + * kvm_handle_ss - handle single step exceptions >> + * >> + * @vcpu: the vcpu pointer > > same @run comment as other handler header in previous patch Yeah I think I'll be merging them all together given the comments about passing syndrome info directly. >> + * >> + * See: ARM ARM D2.12 for the details. While the host is routing debug >> + * exceptions to it's handlers we have to suppress the ability of the >> + * guest to trigger exceptions. >> + */ >> +static int kvm_handle_ss(struct kvm_vcpu *vcpu, struct kvm_run *run) >> +{ >> + WARN_ON(!(vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)); > > I'm not sure about this WARN_ON. Is there some scenario you were > thinking of when you put it here? Is there some scenario where this > could trigger so frequently we kill the log buffer? The main one I had in mind was not suppressing the guest's attempt to step while guest debugging was running. <snip> >> >> -/* for KVM_SET_GUEST_DEBUG */ >> - >> -#define KVM_GUESTDBG_ENABLE 0x00000001 >> -#define KVM_GUESTDBG_SINGLESTEP 0x00000002 >> - >> struct kvm_guest_debug { >> __u32 control; >> __u32 pad; >> @@ -1189,4 +1186,15 @@ struct kvm_assigned_msix_entry { >> __u16 padding[3]; >> }; >> >> +#endif /* __ASSEMBLY__ */ >> + >> +/* for KVM_SET_GUEST_DEBUG */ >> + >> +#define KVM_GUESTDBG_ENABLE_SHIFT 0 >> +#define KVM_GUESTDBG_ENABLE (1 << KVM_GUESTDBG_ENABLE_SHIFT) >> +#define KVM_GUESTDBG_SINGLESTEP_SHIFT 1 >> +#define KVM_GUESTDBG_SINGLESTEP (1 << KVM_GUESTDBG_SINGLESTEP_SHIFT) > > EALIGN: we can tab these defines up better Sure, I'll clean those up. -- Alex Bennée ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 5/7] KVM: arm64: guest debug, add support for single-step [not found] ` <1416931805-23223-6-git-send-email-alex.bennee-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> 2014-11-26 16:40 ` Andrew Jones @ 2014-11-26 19:27 ` Peter Maydell [not found] ` <CAFEAcA-cjM9yUXi6tc79UP0fBKAagtFKQgV3iAjz5DWr9yxZUQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 1 sibling, 1 reply; 15+ messages in thread From: Peter Maydell @ 2014-11-26 19:27 UTC (permalink / raw) To: Alex Bennée Cc: kvm-devel, arm-mail-list, kvmarm-FPEHb7Xf0XXUo1n7N8X6UoWGPAHP3yOg@public.gmane.org, Christoffer Dall, Marc Zyngier, Alexander Graf, J. Kiszka, David Hildenbrand, Bharat Bhushan, bp-l3A5Bk7waGM, Paolo Bonzini, Gleb Natapov, Russell King, Catalin Marinas, Will Deacon, Lorenzo Pieralisi, open list, open list:ABI/API On 25 November 2014 at 16:10, Alex Bennée <alex.bennee-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote: > This adds support for single-stepping the guest. As userspace can and > will manipulate guest registers before restarting any tweaking of the > registers has to occur just before control is passed back to the guest. > Furthermore while guest debugging is in effect we need to squash the > ability of the guest to single-step itself as we have no easy way of > re-entering the guest after the exception has been delivered to the > hypervisor. A corner case I don't think this patch handles: if the debugger tries to single step an insn which is emulated by the hypervisor (because it's a load/store which is trapped and handled as emulated mmio in userspace) then we won't correctly update the single-step state machine (and so we'll end up incorrectly stopping after the following insn rather than before, I think). You should be able to achieve this effect by simply always clearing the guest's PSTATE.SS when you advance the PC to skip the emulated instruction (cf the comment in the pseudocode SSAdvance() function). I think we should also be doing this PC advance on return from userspace's handling of the mmio rather than before we drop back to userspace as we do now, but I can't remember why I think that. Christoffer, I don't suppose you recall, do you? I think it was you I had this conversation with on IRC a month or so back... -- PMM ^ permalink raw reply [flat|nested] 15+ messages in thread
[parent not found: <CAFEAcA-cjM9yUXi6tc79UP0fBKAagtFKQgV3iAjz5DWr9yxZUQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH 5/7] KVM: arm64: guest debug, add support for single-step [not found] ` <CAFEAcA-cjM9yUXi6tc79UP0fBKAagtFKQgV3iAjz5DWr9yxZUQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2014-11-30 10:10 ` Christoffer Dall 2014-11-30 10:20 ` Peter Maydell 0 siblings, 1 reply; 15+ messages in thread From: Christoffer Dall @ 2014-11-30 10:10 UTC (permalink / raw) To: Peter Maydell Cc: Alex Bennée, kvm-devel, arm-mail-list, kvmarm-FPEHb7Xf0XXUo1n7N8X6UoWGPAHP3yOg@public.gmane.org, Marc Zyngier, Alexander Graf, J. Kiszka, David Hildenbrand, Bharat Bhushan, bp-l3A5Bk7waGM, Paolo Bonzini, Gleb Natapov, Russell King, Catalin Marinas, Will Deacon, Lorenzo Pieralisi, open list, open list:ABI/API On Wed, Nov 26, 2014 at 07:27:06PM +0000, Peter Maydell wrote: > On 25 November 2014 at 16:10, Alex Bennée <alex.bennee-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote: > > This adds support for single-stepping the guest. As userspace can and > > will manipulate guest registers before restarting any tweaking of the > > registers has to occur just before control is passed back to the guest. > > Furthermore while guest debugging is in effect we need to squash the > > ability of the guest to single-step itself as we have no easy way of > > re-entering the guest after the exception has been delivered to the > > hypervisor. > > A corner case I don't think this patch handles: if the debugger > tries to single step an insn which is emulated by the > hypervisor (because it's a load/store which is trapped and > handled as emulated mmio in userspace) then we won't > correctly update the single-step state machine (and so we'll end > up incorrectly stopping after the following insn rather than > before, I think). > > You should be able to achieve this effect by simply always clearing > the guest's PSTATE.SS when you advance the PC to skip the emulated > instruction (cf the comment in the pseudocode SSAdvance() function). > > I think we should also be doing this PC advance on return from > userspace's handling of the mmio rather than before we drop back > to userspace as we do now, but I can't remember why I think that. > Christoffer, I don't suppose you recall, do you? I think it was > you I had this conversation with on IRC a month or so back... > I don't remember clearly, no. Was it not during lunch at LCU we had this conversation? In any case, I think it was related to how userspace observes the state of the CPU, because when you do the MMIO operation emulation in userspace, currently if you observe the PC though GET_ONE_REG, you'll see a PC pointing to the next instruction, not the one you're emulating which is strange. Not sure what the relation to a guest single-stepping itself was. -Christoffer ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 5/7] KVM: arm64: guest debug, add support for single-step 2014-11-30 10:10 ` Christoffer Dall @ 2014-11-30 10:20 ` Peter Maydell 0 siblings, 0 replies; 15+ messages in thread From: Peter Maydell @ 2014-11-30 10:20 UTC (permalink / raw) To: Christoffer Dall Cc: Alex Bennée, kvm-devel, arm-mail-list, kvmarm-FPEHb7Xf0XXUo1n7N8X6UoWGPAHP3yOg@public.gmane.org, Marc Zyngier, Alexander Graf, J. Kiszka, David Hildenbrand, Bharat Bhushan, bp-l3A5Bk7waGM, Paolo Bonzini, Gleb Natapov, Russell King, Catalin Marinas, Will Deacon, Lorenzo Pieralisi, open list, open list:ABI/API On 30 November 2014 at 10:10, Christoffer Dall <christoffer.dall-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote: > In any case, I think it was related to how userspace observes the state > of the CPU, because when you do the MMIO operation emulation in > userspace, currently if you observe the PC though GET_ONE_REG, you'll > see a PC pointing to the next instruction, not the one you're emulating > which is strange. Also if we ever add support for userspace to say "this MMIO should fault" then we definitely need the PC-advance to happen afterwards, not before. > Not sure what the relation to a guest single-stepping itself was. I think it just came up in the course of that discussion, because single-step handling also needs to perform an action (clear PSTATE.SS) as part of the "advance over this insn" operation. But I think that you're right that doing the advance before dropping out to userspace is no worse for singlestep than it is for any other case. -- PMM ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 5/7] KVM: arm64: guest debug, add support for single-step 2014-11-25 16:10 ` [PATCH 5/7] KVM: arm64: guest debug, add support for single-step Alex Bennée [not found] ` <1416931805-23223-6-git-send-email-alex.bennee-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> @ 2014-11-30 10:21 ` Christoffer Dall 2014-12-01 11:50 ` Alex Bennée 1 sibling, 1 reply; 15+ messages in thread From: Christoffer Dall @ 2014-11-30 10:21 UTC (permalink / raw) To: Alex Bennée Cc: kvm, linux-arm-kernel, kvmarm, marc.zyngier, peter.maydell, agraf, jan.kiszka, dahi, r65777, bp, pbonzini, Gleb Natapov, Russell King, Catalin Marinas, Will Deacon, Lorenzo Pieralisi, open list, open list:ABI/API On Tue, Nov 25, 2014 at 04:10:03PM +0000, Alex Bennée wrote: > This adds support for single-stepping the guest. As userspace can and > will manipulate guest registers before restarting any tweaking of the > registers has to occur just before control is passed back to the guest. > Furthermore while guest debugging is in effect we need to squash the > ability of the guest to single-step itself as we have no easy way of > re-entering the guest after the exception has been delivered to the > hypervisor. Admittedly this is a corner case, but wouldn't the only really nasty bit of this be to emulate the guest debug exception? > > Signed-off-by: Alex Bennée <alex.bennee@linaro.org> > > diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c > index 48d26bb..a76daae 100644 > --- a/arch/arm/kvm/arm.c > +++ b/arch/arm/kvm/arm.c > @@ -38,6 +38,7 @@ > #include <asm/tlbflush.h> > #include <asm/cacheflush.h> > #include <asm/virt.h> > +#include <asm/debug-monitors.h> > #include <asm/kvm_arm.h> > #include <asm/kvm_asm.h> > #include <asm/kvm_mmu.h> > @@ -300,6 +301,17 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) > kvm_arm_set_running_vcpu(NULL); > } > > +/** > + * kvm_arch_vcpu_ioctl_set_guest_debug - Setup guest debugging > + * @kvm: pointer to the KVM struct > + * @kvm_guest_debug: the ioctl data buffer > + * > + * This sets up the VM for guest debugging. Care has to be taken when > + * manipulating guest registers as these will be set/cleared by the > + * hyper-visor controller, typically before each kvm_run event. As a hypervisor > + * result modification of the guest registers needs to take place > + * after they have been restored in the hyp.S trampoline code. I don't understand this?? > + */ > int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, > struct kvm_guest_debug *dbg) > { > @@ -317,8 +329,8 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, > > /* Single Step */ > if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) { > - kvm_info("SS requested, not yet implemented\n"); > - return -EINVAL; > + kvm_info("SS requested\n"); > + route_el2 = true; > } > > /* Software Break Points */ > diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c > index 8da1043..78e5ae1 100644 > --- a/arch/arm64/kernel/asm-offsets.c > +++ b/arch/arm64/kernel/asm-offsets.c > @@ -121,6 +121,7 @@ int main(void) > DEFINE(VCPU_FAR_EL2, offsetof(struct kvm_vcpu, arch.fault.far_el2)); > DEFINE(VCPU_HPFAR_EL2, offsetof(struct kvm_vcpu, arch.fault.hpfar_el2)); > DEFINE(VCPU_DEBUG_FLAGS, offsetof(struct kvm_vcpu, arch.debug_flags)); > + DEFINE(GUEST_DEBUG, offsetof(struct kvm_vcpu, guest_debug)); > DEFINE(VCPU_HCR_EL2, offsetof(struct kvm_vcpu, arch.hcr_el2)); > DEFINE(VCPU_MDCR_EL2, offsetof(struct kvm_vcpu, arch.mdcr_el2)); > DEFINE(VCPU_IRQ_LINES, offsetof(struct kvm_vcpu, arch.irq_lines)); > diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c > index 28dc92b..6def054 100644 > --- a/arch/arm64/kvm/handle_exit.c > +++ b/arch/arm64/kvm/handle_exit.c > @@ -91,6 +91,25 @@ static int kvm_handle_bkpt(struct kvm_vcpu *vcpu, struct kvm_run *run) > return 0; > } > > +/** > + * kvm_handle_ss - handle single step exceptions > + * > + * @vcpu: the vcpu pointer > + * > + * See: ARM ARM D2.12 for the details. While the host is routing debug > + * exceptions to it's handlers we have to suppress the ability of the its handlers > + * guest to trigger exceptions. not really sure why this comment is here? Does it really help anyone reading this specific function or does it just confuse people more? > + */ > +static int kvm_handle_ss(struct kvm_vcpu *vcpu, struct kvm_run *run) > +{ > + WARN_ON(!(vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)); is this something that can actually happen or should it be a BUG_ON() - which may even go away once you're doing hacking on this? > + > + run->exit_reason = KVM_EXIT_DEBUG; > + run->debug.arch.exit_type = KVM_DEBUG_EXIT_SINGLE_STEP; > + run->debug.arch.address = *vcpu_pc(vcpu); > + return 0; > +} > + > static exit_handle_fn arm_exit_handlers[] = { > [ESR_EL2_EC_WFI] = kvm_handle_wfx, > [ESR_EL2_EC_CP15_32] = kvm_handle_cp15_32, > @@ -105,6 +124,7 @@ static exit_handle_fn arm_exit_handlers[] = { > [ESR_EL2_EC_SYS64] = kvm_handle_sys_reg, > [ESR_EL2_EC_IABT] = kvm_handle_guest_abort, > [ESR_EL2_EC_DABT] = kvm_handle_guest_abort, > + [ESR_EL2_EC_SOFTSTP] = kvm_handle_ss, > [ESR_EL2_EC_BKPT32] = kvm_handle_bkpt, > [ESR_EL2_EC_BRK64] = kvm_handle_bkpt, > }; > diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S > index 3c733ea..c0bc218 100644 > --- a/arch/arm64/kvm/hyp.S > +++ b/arch/arm64/kvm/hyp.S > @@ -16,6 +16,7 @@ > */ > > #include <linux/linkage.h> > +#include <linux/kvm.h> > > #include <asm/assembler.h> > #include <asm/memory.h> > @@ -168,6 +169,31 @@ > // x19-x29, lr, sp*, elr*, spsr* > restore_common_regs > > + // After restoring the guest registers but before we return to the guest > + // we may want to make some final tweaks to support guest debugging. "we may want" sounds like we're not sure what we'll be doing here. We probably want to write something like "If the guest is being debugged we need to set blah blah blah". > + ldr x3, [x0, #GUEST_DEBUG] > + tbz x3, #KVM_GUESTDBG_ENABLE_SHIFT, 2f // No guest debug > + > + // x0 - preserved as VCPU ptr > + // x1 - spsr > + // x2 - mdscr not sure we need this comment > + mrs x1, spsr_el2 > + mrs x2, mdscr_el1 > + > + // See ARM ARM D2.12.3 The software step state machine > + // If we are doing Single Step - set MDSCR_EL1.SS and PSTATE.SS > + orr x1, x1, #DBG_SPSR_SS > + orr x2, x2, #DBG_MDSCR_SS > + tbnz x3, #KVM_GUESTDBG_SINGLESTEP_SHIFT, 1f > + // If we are not doing Single Step we want to prevent the guest doing so > + // as otherwise we will have to deal with the re-routed exceptions as we > + // are doing other guest debug related things > + eor x1, x1, #DBG_SPSR_SS > + eor x2, x2, #DBG_MDSCR_SS this really confuses me: so you're setting the SS bits in both registers, and then if we're not single-stepping the guest, you clear both bits again? Wouldn't it be much simper to mask off the bits with a 'bic' and then setting the bits when needed? Alternatively, we could manage all these registers from C code and just save/restore them off the VCPU struct. > +1: > + msr spsr_el2, x1 > + msr mdscr_el1, x2 > +2: > // Last bits of the 64bit state > pop x2, x3 > pop x0, x1 > diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h > index 523f476..347e5b0 100644 > --- a/include/uapi/linux/kvm.h > +++ b/include/uapi/linux/kvm.h > @@ -7,6 +7,8 @@ > * Note: you must update KVM_API_VERSION if you change this interface. > */ > > +#ifndef __ASSEMBLY__ > + > #include <linux/types.h> > #include <linux/compiler.h> > #include <linux/ioctl.h> > @@ -515,11 +517,6 @@ struct kvm_s390_irq { > } u; > }; > > -/* for KVM_SET_GUEST_DEBUG */ > - > -#define KVM_GUESTDBG_ENABLE 0x00000001 > -#define KVM_GUESTDBG_SINGLESTEP 0x00000002 > - > struct kvm_guest_debug { > __u32 control; > __u32 pad; > @@ -1189,4 +1186,15 @@ struct kvm_assigned_msix_entry { > __u16 padding[3]; > }; > > +#endif /* __ASSEMBLY__ */ > + > +/* for KVM_SET_GUEST_DEBUG */ > + > +#define KVM_GUESTDBG_ENABLE_SHIFT 0 > +#define KVM_GUESTDBG_ENABLE (1 << KVM_GUESTDBG_ENABLE_SHIFT) > +#define KVM_GUESTDBG_SINGLESTEP_SHIFT 1 > +#define KVM_GUESTDBG_SINGLESTEP (1 << KVM_GUESTDBG_SINGLESTEP_SHIFT) > + > + > + > #endif /* __LINUX_KVM_H */ > -- > 2.1.3 > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 5/7] KVM: arm64: guest debug, add support for single-step 2014-11-30 10:21 ` Christoffer Dall @ 2014-12-01 11:50 ` Alex Bennée [not found] ` <87r3wj1te1.fsf-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> 0 siblings, 1 reply; 15+ messages in thread From: Alex Bennée @ 2014-12-01 11:50 UTC (permalink / raw) To: Christoffer Dall Cc: kvm-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, kvmarm-FPEHb7Xf0XXUo1n7N8X6UoWGPAHP3yOg, marc.zyngier-5wv7dgnIgG8, peter.maydell-QSEj5FYQhm4dnm+yROfE0A, agraf-l3A5Bk7waGM, jan.kiszka-kv7WeFo6aLtBDgjK7y7TUQ, dahi-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8, r65777-KZfg59tc24xl57MIdRCFDg, bp-l3A5Bk7waGM, pbonzini-H+wXaHxf7aLQT0dZR+AlfA, Gleb Natapov, Russell King, Catalin Marinas, Will Deacon, Lorenzo Pieralisi, open list, open list:ABI/API Christoffer Dall <christoffer.dall-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> writes: > On Tue, Nov 25, 2014 at 04:10:03PM +0000, Alex Bennée wrote: >> This adds support for single-stepping the guest. As userspace can and >> will manipulate guest registers before restarting any tweaking of the >> registers has to occur just before control is passed back to the guest. >> Furthermore while guest debugging is in effect we need to squash the >> ability of the guest to single-step itself as we have no easy way of >> re-entering the guest after the exception has been delivered to the >> hypervisor. > > Admittedly this is a corner case, but wouldn't the only really nasty bit > of this be to emulate the guest debug exception? Well yes - currently this is all squashed by ignoring the guest's wishes while we are debugging (save for SW breakpoints). > >> >> Signed-off-by: Alex Bennée <alex.bennee-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> >> >> diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c >> index 48d26bb..a76daae 100644 >> --- a/arch/arm/kvm/arm.c >> +++ b/arch/arm/kvm/arm.c >> @@ -38,6 +38,7 @@ >> #include <asm/tlbflush.h> >> #include <asm/cacheflush.h> >> #include <asm/virt.h> >> +#include <asm/debug-monitors.h> >> #include <asm/kvm_arm.h> >> #include <asm/kvm_asm.h> >> #include <asm/kvm_mmu.h> >> @@ -300,6 +301,17 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) >> kvm_arm_set_running_vcpu(NULL); >> } >> >> +/** >> + * kvm_arch_vcpu_ioctl_set_guest_debug - Setup guest debugging >> + * @kvm: pointer to the KVM struct >> + * @kvm_guest_debug: the ioctl data buffer >> + * >> + * This sets up the VM for guest debugging. Care has to be taken when >> + * manipulating guest registers as these will be set/cleared by the >> + * hyper-visor controller, typically before each kvm_run event. As a > > hypervisor > >> + * result modification of the guest registers needs to take place >> + * after they have been restored in the hyp.S trampoline code. > > I don't understand this?? We can't use GET/SET one reg to manipulate the registers we want as these are the guest visible versions and subject to modification by userspace. This is why the debugging code makes it's changes after the guest state has been restored. > >> + */ >> int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, >> struct kvm_guest_debug *dbg) >> { >> @@ -317,8 +329,8 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, >> >> /* Single Step */ >> if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) { >> - kvm_info("SS requested, not yet implemented\n"); >> - return -EINVAL; >> + kvm_info("SS requested\n"); >> + route_el2 = true; >> } >> >> /* Software Break Points */ >> diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c >> index 8da1043..78e5ae1 100644 >> --- a/arch/arm64/kernel/asm-offsets.c >> +++ b/arch/arm64/kernel/asm-offsets.c >> @@ -121,6 +121,7 @@ int main(void) >> DEFINE(VCPU_FAR_EL2, offsetof(struct kvm_vcpu, arch.fault.far_el2)); >> DEFINE(VCPU_HPFAR_EL2, offsetof(struct kvm_vcpu, arch.fault.hpfar_el2)); >> DEFINE(VCPU_DEBUG_FLAGS, offsetof(struct kvm_vcpu, arch.debug_flags)); >> + DEFINE(GUEST_DEBUG, offsetof(struct kvm_vcpu, guest_debug)); >> DEFINE(VCPU_HCR_EL2, offsetof(struct kvm_vcpu, arch.hcr_el2)); >> DEFINE(VCPU_MDCR_EL2, offsetof(struct kvm_vcpu, arch.mdcr_el2)); >> DEFINE(VCPU_IRQ_LINES, offsetof(struct kvm_vcpu, arch.irq_lines)); >> diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c >> index 28dc92b..6def054 100644 >> --- a/arch/arm64/kvm/handle_exit.c >> +++ b/arch/arm64/kvm/handle_exit.c >> @@ -91,6 +91,25 @@ static int kvm_handle_bkpt(struct kvm_vcpu *vcpu, struct kvm_run *run) >> return 0; >> } >> >> +/** >> + * kvm_handle_ss - handle single step exceptions >> + * >> + * @vcpu: the vcpu pointer >> + * >> + * See: ARM ARM D2.12 for the details. While the host is routing debug >> + * exceptions to it's handlers we have to suppress the ability of the > > its handlers > >> + * guest to trigger exceptions. > > not really sure why this comment is here? Does it really help anyone > reading this specific function or does it just confuse people more? > >> + */ >> +static int kvm_handle_ss(struct kvm_vcpu *vcpu, struct kvm_run *run) >> +{ >> + WARN_ON(!(vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)); > > is this something that can actually happen or should it be a BUG_ON() - > which may even go away once you're doing hacking on this? It shouldn't happen. I was treating more like an assert, failure of which would indicate something has gone wrong somewhere although generally not worth bringing the kernel down for. > >> + >> + run->exit_reason = KVM_EXIT_DEBUG; >> + run->debug.arch.exit_type = KVM_DEBUG_EXIT_SINGLE_STEP; >> + run->debug.arch.address = *vcpu_pc(vcpu); >> + return 0; >> +} >> + >> static exit_handle_fn arm_exit_handlers[] = { >> [ESR_EL2_EC_WFI] = kvm_handle_wfx, >> [ESR_EL2_EC_CP15_32] = kvm_handle_cp15_32, >> @@ -105,6 +124,7 @@ static exit_handle_fn arm_exit_handlers[] = { >> [ESR_EL2_EC_SYS64] = kvm_handle_sys_reg, >> [ESR_EL2_EC_IABT] = kvm_handle_guest_abort, >> [ESR_EL2_EC_DABT] = kvm_handle_guest_abort, >> + [ESR_EL2_EC_SOFTSTP] = kvm_handle_ss, >> [ESR_EL2_EC_BKPT32] = kvm_handle_bkpt, >> [ESR_EL2_EC_BRK64] = kvm_handle_bkpt, >> }; >> diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S >> index 3c733ea..c0bc218 100644 >> --- a/arch/arm64/kvm/hyp.S >> +++ b/arch/arm64/kvm/hyp.S >> @@ -16,6 +16,7 @@ >> */ >> >> #include <linux/linkage.h> >> +#include <linux/kvm.h> >> >> #include <asm/assembler.h> >> #include <asm/memory.h> >> @@ -168,6 +169,31 @@ >> // x19-x29, lr, sp*, elr*, spsr* >> restore_common_regs >> >> + // After restoring the guest registers but before we return to the guest >> + // we may want to make some final tweaks to support guest debugging. > > "we may want" sounds like we're not sure what we'll be doing here. We > probably want to write something like "If the guest is being debugged we > need to set blah blah blah". > >> + ldr x3, [x0, #GUEST_DEBUG] >> + tbz x3, #KVM_GUESTDBG_ENABLE_SHIFT, 2f // No guest debug >> + >> + // x0 - preserved as VCPU ptr >> + // x1 - spsr >> + // x2 - mdscr > > not sure we need this comment > >> + mrs x1, spsr_el2 >> + mrs x2, mdscr_el1 >> + >> + // See ARM ARM D2.12.3 The software step state machine >> + // If we are doing Single Step - set MDSCR_EL1.SS and PSTATE.SS >> + orr x1, x1, #DBG_SPSR_SS >> + orr x2, x2, #DBG_MDSCR_SS >> + tbnz x3, #KVM_GUESTDBG_SINGLESTEP_SHIFT, 1f >> + // If we are not doing Single Step we want to prevent the guest doing so >> + // as otherwise we will have to deal with the re-routed exceptions as we >> + // are doing other guest debug related things >> + eor x1, x1, #DBG_SPSR_SS >> + eor x2, x2, #DBG_MDSCR_SS > > this really confuses me: so you're setting the SS bits in both > registers, and then if we're not single-stepping the guest, you clear > both bits again? > > Wouldn't it be much simper to mask off the bits with a 'bic' and then > setting the bits when needed? Is there a non-vector BIC #imm? I was being frugal with register usage at this point. The orr/eor steps where just to avoid having too many branch cases. > Alternatively, we could manage all these registers from C code and just > save/restore them off the VCPU struct. Yes but this has to be done as we run into the hyp.S code after all guest registers are confirmed as the changes are on-top of whatever the guest view is (for the _el1 regs). Where would you suggest that goes? >> +1: >> + msr spsr_el2, x1 >> + msr mdscr_el1, x2 >> +2: >> // Last bits of the 64bit state >> pop x2, x3 >> pop x0, x1 >> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h >> index 523f476..347e5b0 100644 >> --- a/include/uapi/linux/kvm.h >> +++ b/include/uapi/linux/kvm.h >> @@ -7,6 +7,8 @@ >> * Note: you must update KVM_API_VERSION if you change this interface. >> */ >> >> +#ifndef __ASSEMBLY__ >> + >> #include <linux/types.h> >> #include <linux/compiler.h> >> #include <linux/ioctl.h> >> @@ -515,11 +517,6 @@ struct kvm_s390_irq { >> } u; >> }; >> >> -/* for KVM_SET_GUEST_DEBUG */ >> - >> -#define KVM_GUESTDBG_ENABLE 0x00000001 >> -#define KVM_GUESTDBG_SINGLESTEP 0x00000002 >> - >> struct kvm_guest_debug { >> __u32 control; >> __u32 pad; >> @@ -1189,4 +1186,15 @@ struct kvm_assigned_msix_entry { >> __u16 padding[3]; >> }; >> >> +#endif /* __ASSEMBLY__ */ >> + >> +/* for KVM_SET_GUEST_DEBUG */ >> + >> +#define KVM_GUESTDBG_ENABLE_SHIFT 0 >> +#define KVM_GUESTDBG_ENABLE (1 << KVM_GUESTDBG_ENABLE_SHIFT) >> +#define KVM_GUESTDBG_SINGLESTEP_SHIFT 1 >> +#define KVM_GUESTDBG_SINGLESTEP (1 << KVM_GUESTDBG_SINGLESTEP_SHIFT) >> + >> + >> + >> #endif /* __LINUX_KVM_H */ >> -- >> 2.1.3 >> -- Alex Bennée ^ permalink raw reply [flat|nested] 15+ messages in thread
[parent not found: <87r3wj1te1.fsf-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>]
* Re: [PATCH 5/7] KVM: arm64: guest debug, add support for single-step [not found] ` <87r3wj1te1.fsf-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> @ 2014-12-02 13:17 ` Christoffer Dall 0 siblings, 0 replies; 15+ messages in thread From: Christoffer Dall @ 2014-12-02 13:17 UTC (permalink / raw) To: Alex Bennée Cc: kvm-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, kvmarm-FPEHb7Xf0XXUo1n7N8X6UoWGPAHP3yOg, marc.zyngier-5wv7dgnIgG8, peter.maydell-QSEj5FYQhm4dnm+yROfE0A, agraf-l3A5Bk7waGM, jan.kiszka-kv7WeFo6aLtBDgjK7y7TUQ, dahi-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8, r65777-KZfg59tc24xl57MIdRCFDg, bp-l3A5Bk7waGM, pbonzini-H+wXaHxf7aLQT0dZR+AlfA, Gleb Natapov, Russell King, Catalin Marinas, Will Deacon, Lorenzo Pieralisi, open list, open list:ABI/API On Mon, Dec 01, 2014 at 11:50:14AM +0000, Alex Bennée wrote: > > Christoffer Dall <christoffer.dall-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> writes: > > > On Tue, Nov 25, 2014 at 04:10:03PM +0000, Alex Bennée wrote: > >> This adds support for single-stepping the guest. As userspace can and > >> will manipulate guest registers before restarting any tweaking of the > >> registers has to occur just before control is passed back to the guest. > >> Furthermore while guest debugging is in effect we need to squash the > >> ability of the guest to single-step itself as we have no easy way of > >> re-entering the guest after the exception has been delivered to the > >> hypervisor. > > > > Admittedly this is a corner case, but wouldn't the only really nasty bit > > of this be to emulate the guest debug exception? > > Well yes - currently this is all squashed by ignoring the guest's wishes > while we are debugging (save for SW breakpoints). > > > > >> > >> Signed-off-by: Alex Bennée <alex.bennee-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> > >> > >> diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c > >> index 48d26bb..a76daae 100644 > >> --- a/arch/arm/kvm/arm.c > >> +++ b/arch/arm/kvm/arm.c > >> @@ -38,6 +38,7 @@ > >> #include <asm/tlbflush.h> > >> #include <asm/cacheflush.h> > >> #include <asm/virt.h> > >> +#include <asm/debug-monitors.h> > >> #include <asm/kvm_arm.h> > >> #include <asm/kvm_asm.h> > >> #include <asm/kvm_mmu.h> > >> @@ -300,6 +301,17 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) > >> kvm_arm_set_running_vcpu(NULL); > >> } > >> > >> +/** > >> + * kvm_arch_vcpu_ioctl_set_guest_debug - Setup guest debugging > >> + * @kvm: pointer to the KVM struct > >> + * @kvm_guest_debug: the ioctl data buffer > >> + * > >> + * This sets up the VM for guest debugging. Care has to be taken when > >> + * manipulating guest registers as these will be set/cleared by the > >> + * hyper-visor controller, typically before each kvm_run event. As a > > > > hypervisor > > > >> + * result modification of the guest registers needs to take place > >> + * after they have been restored in the hyp.S trampoline code. > > > > I don't understand this?? > > We can't use GET/SET one reg to manipulate the registers we want as > these are the guest visible versions and subject to modification by > userspace. This is why the debugging code makes it's changes after the > guest state has been restored. > eh, once you're in the KVM_RUN ioctl, user space can't fiddle your VCPU regs because you're holding the vcpu mutex, so doing stuff in some callout from kvm_arch_vcpu_ioctl_run() seems every bid as valid for this case as doing it in EL2. In fact, the only reason why we're doing anything in EL2 is when you're accessing state only accessible in EL2, when you need to write the whole thing in assembly (like the context switch of GP registers) etc. If it doesn't have huge performance costs, we should use C-code in EL1 to the furthest extent possible. > > > >> + */ > >> int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, > >> struct kvm_guest_debug *dbg) > >> { > >> @@ -317,8 +329,8 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, > >> > >> /* Single Step */ > >> if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) { > >> - kvm_info("SS requested, not yet implemented\n"); > >> - return -EINVAL; > >> + kvm_info("SS requested\n"); > >> + route_el2 = true; > >> } > >> > >> /* Software Break Points */ > >> diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c > >> index 8da1043..78e5ae1 100644 > >> --- a/arch/arm64/kernel/asm-offsets.c > >> +++ b/arch/arm64/kernel/asm-offsets.c > >> @@ -121,6 +121,7 @@ int main(void) > >> DEFINE(VCPU_FAR_EL2, offsetof(struct kvm_vcpu, arch.fault.far_el2)); > >> DEFINE(VCPU_HPFAR_EL2, offsetof(struct kvm_vcpu, arch.fault.hpfar_el2)); > >> DEFINE(VCPU_DEBUG_FLAGS, offsetof(struct kvm_vcpu, arch.debug_flags)); > >> + DEFINE(GUEST_DEBUG, offsetof(struct kvm_vcpu, guest_debug)); > >> DEFINE(VCPU_HCR_EL2, offsetof(struct kvm_vcpu, arch.hcr_el2)); > >> DEFINE(VCPU_MDCR_EL2, offsetof(struct kvm_vcpu, arch.mdcr_el2)); > >> DEFINE(VCPU_IRQ_LINES, offsetof(struct kvm_vcpu, arch.irq_lines)); > >> diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c > >> index 28dc92b..6def054 100644 > >> --- a/arch/arm64/kvm/handle_exit.c > >> +++ b/arch/arm64/kvm/handle_exit.c > >> @@ -91,6 +91,25 @@ static int kvm_handle_bkpt(struct kvm_vcpu *vcpu, struct kvm_run *run) > >> return 0; > >> } > >> > >> +/** > >> + * kvm_handle_ss - handle single step exceptions > >> + * > >> + * @vcpu: the vcpu pointer > >> + * > >> + * See: ARM ARM D2.12 for the details. While the host is routing debug > >> + * exceptions to it's handlers we have to suppress the ability of the > > > > its handlers > > > >> + * guest to trigger exceptions. > > > > not really sure why this comment is here? Does it really help anyone > > reading this specific function or does it just confuse people more? > > > >> + */ > >> +static int kvm_handle_ss(struct kvm_vcpu *vcpu, struct kvm_run *run) > >> +{ > >> + WARN_ON(!(vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)); > > > > is this something that can actually happen or should it be a BUG_ON() - > > which may even go away once you're doing hacking on this? > > It shouldn't happen. I was treating more like an assert, failure of > which would indicate something has gone wrong somewhere although > generally not worth bringing the kernel down for. > huh, I guess that's fair enough, but somewhat unconventional for kernel code. Typically I read WARN_ON (I could be wrong here) as something that may happen under extreme circumstances (debugging turned on, crazy low-memory situations etc.), but not as something that catches a bug. I've seen the argument before that if something that sholdn't ever happen in the kernel, indeed does happen in the kernel, then that is a bug, and then you should panic(). So I do feel that this is either a kvm_info()/kvm_err() situation or a BUG_ON() situation, or nothing at all. > > > >> + > >> + run->exit_reason = KVM_EXIT_DEBUG; > >> + run->debug.arch.exit_type = KVM_DEBUG_EXIT_SINGLE_STEP; > >> + run->debug.arch.address = *vcpu_pc(vcpu); > >> + return 0; > >> +} > >> + > >> static exit_handle_fn arm_exit_handlers[] = { > >> [ESR_EL2_EC_WFI] = kvm_handle_wfx, > >> [ESR_EL2_EC_CP15_32] = kvm_handle_cp15_32, > >> @@ -105,6 +124,7 @@ static exit_handle_fn arm_exit_handlers[] = { > >> [ESR_EL2_EC_SYS64] = kvm_handle_sys_reg, > >> [ESR_EL2_EC_IABT] = kvm_handle_guest_abort, > >> [ESR_EL2_EC_DABT] = kvm_handle_guest_abort, > >> + [ESR_EL2_EC_SOFTSTP] = kvm_handle_ss, > >> [ESR_EL2_EC_BKPT32] = kvm_handle_bkpt, > >> [ESR_EL2_EC_BRK64] = kvm_handle_bkpt, > >> }; > >> diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S > >> index 3c733ea..c0bc218 100644 > >> --- a/arch/arm64/kvm/hyp.S > >> +++ b/arch/arm64/kvm/hyp.S > >> @@ -16,6 +16,7 @@ > >> */ > >> > >> #include <linux/linkage.h> > >> +#include <linux/kvm.h> > >> > >> #include <asm/assembler.h> > >> #include <asm/memory.h> > >> @@ -168,6 +169,31 @@ > >> // x19-x29, lr, sp*, elr*, spsr* > >> restore_common_regs > >> > >> + // After restoring the guest registers but before we return to the guest > >> + // we may want to make some final tweaks to support guest debugging. > > > > "we may want" sounds like we're not sure what we'll be doing here. We > > probably want to write something like "If the guest is being debugged we > > need to set blah blah blah". > > > >> + ldr x3, [x0, #GUEST_DEBUG] > >> + tbz x3, #KVM_GUESTDBG_ENABLE_SHIFT, 2f // No guest debug > >> + > >> + // x0 - preserved as VCPU ptr > >> + // x1 - spsr > >> + // x2 - mdscr > > > > not sure we need this comment > > > >> + mrs x1, spsr_el2 > >> + mrs x2, mdscr_el1 > >> + > >> + // See ARM ARM D2.12.3 The software step state machine > >> + // If we are doing Single Step - set MDSCR_EL1.SS and PSTATE.SS > >> + orr x1, x1, #DBG_SPSR_SS > >> + orr x2, x2, #DBG_MDSCR_SS > >> + tbnz x3, #KVM_GUESTDBG_SINGLESTEP_SHIFT, 1f > >> + // If we are not doing Single Step we want to prevent the guest doing so > >> + // as otherwise we will have to deal with the re-routed exceptions as we > >> + // are doing other guest debug related things > >> + eor x1, x1, #DBG_SPSR_SS > >> + eor x2, x2, #DBG_MDSCR_SS > > > > this really confuses me: so you're setting the SS bits in both > > registers, and then if we're not single-stepping the guest, you clear > > both bits again? > > > > Wouldn't it be much simper to mask off the bits with a 'bic' and then > > setting the bits when needed? > > Is there a non-vector BIC #imm? I was being frugal with register usage > at this point. The orr/eor steps where just to avoid having too many > branch cases. > there are "bic x3, x3, #1" and such in this very file, so I would guess, yes. > > Alternatively, we could manage all these registers from C code and just > > save/restore them off the VCPU struct. > > Yes but this has to be done as we run into the hyp.S code after all > guest registers are confirmed as the changes are on-top of whatever the > guest view is (for the _el1 regs). > > Where would you suggest that goes? > As a call-out from the arch-specific KVM_RUN ioctl, call kvm_setup_guest_debug() or something like that, just like we do to check if our vmid is valid and to setup the vgic state and so on. Does that work? -Christoffer ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 7/7] KVM: arm64: guest debug, HW assisted debug support [not found] <1416931805-23223-1-git-send-email-alex.bennee@linaro.org> 2014-11-25 16:09 ` [PATCH 1/7] KVM: add commentary for kvm_debug_exit_arch struct Alex Bennée 2014-11-25 16:10 ` [PATCH 5/7] KVM: arm64: guest debug, add support for single-step Alex Bennée @ 2014-11-25 16:10 ` Alex Bennée [not found] ` <1416931805-23223-8-git-send-email-alex.bennee-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> 2014-11-30 10:34 ` Christoffer Dall 2 siblings, 2 replies; 15+ messages in thread From: Alex Bennée @ 2014-11-25 16:10 UTC (permalink / raw) To: kvm, linux-arm-kernel, kvmarm, christoffer.dall, marc.zyngier, peter.maydell, agraf Cc: jan.kiszka, dahi, r65777, bp, pbonzini, Alex Bennée, Gleb Natapov, Jonathan Corbet, Russell King, Catalin Marinas, Will Deacon, Lorenzo Pieralisi, AKASHI Takahiro, Srivatsa S. Bhat, open list:DOCUMENTATION, open list, open list:ABI/API This adds support for userspace to control the HW debug registers for guest debug. We'll only copy the $ARCH defined number across as that's all that hyp.S will use anyway. I've moved some helper functions into the hw_breakpoint.h header for re-use. As with single step we need to tweak the guest registers to enable the exceptions but we don't want to overwrite the guest copy of these registers so this is done close to the guest entry. Two new capabilities have been added to the KVM_EXTENSION ioctl to allow userspace to query the number of hardware break and watch points available on the host hardware. Signed-off-by: Alex Bennée <alex.bennee@linaro.org> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 9383359..5e8c673 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2593,7 +2593,7 @@ The top 16 bits of the control field are architecture specific control flags which can include the following: - KVM_GUESTDBG_USE_SW_BP: using software breakpoints [x86, arm64] - - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390] + - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390, arm64] - KVM_GUESTDBG_INJECT_DB: inject DB type exception [x86] - KVM_GUESTDBG_INJECT_BP: inject BP type exception [x86] - KVM_GUESTDBG_EXIT_PENDING: trigger an immediate guest exit [s390] @@ -2606,7 +2606,10 @@ we need to ensure the guest vCPUs architecture specific registers are updated to the correct (supplied) values. The second part of the structure is architecture specific and -typically contains a set of debug registers. +typically contains a set of debug registers. For arm64 the number of +debug registers is implementation defined and can be determined by +querying the KVM_CAP_GUEST_DEBUG_HW_BPS and KVM_CAP_GUEST_DEBUG_HW_WPS +capabilities. When debug events exit the main run loop with the reason KVM_EXIT_DEBUG with the kvm_debug_exit_arch part of the kvm_run diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index a76daae..c8ec23a 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -39,6 +39,7 @@ #include <asm/cacheflush.h> #include <asm/virt.h> #include <asm/debug-monitors.h> +#include <asm/hw_breakpoint.h> #include <asm/kvm_arm.h> #include <asm/kvm_asm.h> #include <asm/kvm_mmu.h> @@ -341,8 +342,37 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, /* Hardware assisted Break and Watch points */ if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) { - kvm_info("HW BP support requested, not yet implemented\n"); - return -EINVAL; + int i; + int nb = get_num_brps(); + int nw = get_num_wrps(); + + /* Copy across up to IMPDEF debug registers to our + * shadow copy in the vcpu structure. The hyp.S code + * will then set them up before we re-enter the guest. + */ + memcpy(vcpu->arch.guest_debug_regs.dbg_bcr, + dbg->arch.dbg_bcr, sizeof(__u64)*nb); + memcpy(vcpu->arch.guest_debug_regs.dbg_bvr, + dbg->arch.dbg_bvr, sizeof(__u64)*nb); + memcpy(vcpu->arch.guest_debug_regs.dbg_wcr, + dbg->arch.dbg_wcr, sizeof(__u64)*nw); + memcpy(vcpu->arch.guest_debug_regs.dbg_wvr, + dbg->arch.dbg_wvr, sizeof(__u64)*nw); + + kvm_info("HW BP support requested\n"); + for (i = 0; i < nb; i++) { + kvm_info("%d: dbg_bcr=0x%llx dbg_bvr=0x%llx\n", + i, + vcpu->arch.guest_debug_regs.dbg_bcr[i], + vcpu->arch.guest_debug_regs.dbg_bvr[i]); + } + for (i = 0; i < nw; i++) { + kvm_info("%d: dbg_wcr=0x%llx dbg_wvr=0x%llx\n", + i, + vcpu->arch.guest_debug_regs.dbg_wcr[i], + vcpu->arch.guest_debug_regs.dbg_wvr[i]); + } + route_el2 = true; } /* If we are going to handle any debug exceptions we need to diff --git a/arch/arm64/include/asm/hw_breakpoint.h b/arch/arm64/include/asm/hw_breakpoint.h index 52b484b..c450552 100644 --- a/arch/arm64/include/asm/hw_breakpoint.h +++ b/arch/arm64/include/asm/hw_breakpoint.h @@ -130,6 +130,18 @@ static inline void ptrace_hw_copy_thread(struct task_struct *task) } #endif +/* Determine number of BRP registers available. */ +static inline int get_num_brps(void) +{ + return ((read_cpuid(ID_AA64DFR0_EL1) >> 12) & 0xf) + 1; +} + +/* Determine number of WRP registers available. */ +static inline int get_num_wrps(void) +{ + return ((read_cpuid(ID_AA64DFR0_EL1) >> 20) & 0xf) + 1; +} + extern struct pmu perf_ops_bp; #endif /* __KERNEL__ */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 38b0f07..e386bf4 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -103,8 +103,9 @@ struct kvm_vcpu_arch { /* Exception Information */ struct kvm_vcpu_fault_info fault; - /* Debug state */ + /* Guest debug state */ u64 debug_flags; + struct kvm_guest_debug_arch guest_debug_regs; /* Pointer to host CPU context */ kvm_cpu_context_t *host_cpu_context; diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index 78e5ae1..c9ecfd3 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -122,6 +122,10 @@ int main(void) DEFINE(VCPU_HPFAR_EL2, offsetof(struct kvm_vcpu, arch.fault.hpfar_el2)); DEFINE(VCPU_DEBUG_FLAGS, offsetof(struct kvm_vcpu, arch.debug_flags)); DEFINE(GUEST_DEBUG, offsetof(struct kvm_vcpu, guest_debug)); + DEFINE(GUEST_DEBUG_BCR, offsetof(struct kvm_vcpu, arch.guest_debug_regs.dbg_bcr)); + DEFINE(GUEST_DEBUG_BVR, offsetof(struct kvm_vcpu, arch.guest_debug_regs.dbg_bvr)); + DEFINE(GUEST_DEBUG_WCR, offsetof(struct kvm_vcpu, arch.guest_debug_regs.dbg_wcr)); + DEFINE(GUEST_DEBUG_WVR, offsetof(struct kvm_vcpu, arch.guest_debug_regs.dbg_wvr)); DEFINE(VCPU_HCR_EL2, offsetof(struct kvm_vcpu, arch.hcr_el2)); DEFINE(VCPU_MDCR_EL2, offsetof(struct kvm_vcpu, arch.mdcr_el2)); DEFINE(VCPU_IRQ_LINES, offsetof(struct kvm_vcpu, arch.irq_lines)); diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c index df1cf15..45dcc6f 100644 --- a/arch/arm64/kernel/hw_breakpoint.c +++ b/arch/arm64/kernel/hw_breakpoint.c @@ -49,18 +49,6 @@ static DEFINE_PER_CPU(int, stepping_kernel_bp); static int core_num_brps; static int core_num_wrps; -/* Determine number of BRP registers available. */ -static int get_num_brps(void) -{ - return ((read_cpuid(ID_AA64DFR0_EL1) >> 12) & 0xf) + 1; -} - -/* Determine number of WRP registers available. */ -static int get_num_wrps(void) -{ - return ((read_cpuid(ID_AA64DFR0_EL1) >> 20) & 0xf) + 1; -} - int hw_breakpoint_slots(int type) { /* diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 6def054..d024e47 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -110,6 +110,42 @@ static int kvm_handle_ss(struct kvm_vcpu *vcpu, struct kvm_run *run) return 0; } +/** + * kvm_handle_hw_bp - handle HW assisted break point + * + * @vcpu: the vcpu pointer + * + */ +static int kvm_handle_hw_bp(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + WARN_ON(!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)); + + run->exit_reason = KVM_EXIT_DEBUG; + run->debug.arch.exit_type = KVM_DEBUG_EXIT_HW_BKPT; + run->debug.arch.address = *vcpu_pc(vcpu); + return 0; +} + +/** + * kvm_handle_watch - handle HW assisted watch point + * + * @vcpu: the vcpu pointer + * + * These are basically the same as breakpoints (and indeed may use the + * breakpoint in a linked fashion). However they generate a specific + * exception so we trap it here for reporting to the guest. + * + */ +static int kvm_handle_watch(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + WARN_ON(!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)); + + run->exit_reason = KVM_EXIT_DEBUG; + run->debug.arch.exit_type = KVM_DEBUG_EXIT_HW_WTPT; + run->debug.arch.address = *vcpu_pc(vcpu); + return 0; +} + static exit_handle_fn arm_exit_handlers[] = { [ESR_EL2_EC_WFI] = kvm_handle_wfx, [ESR_EL2_EC_CP15_32] = kvm_handle_cp15_32, @@ -125,6 +161,8 @@ static exit_handle_fn arm_exit_handlers[] = { [ESR_EL2_EC_IABT] = kvm_handle_guest_abort, [ESR_EL2_EC_DABT] = kvm_handle_guest_abort, [ESR_EL2_EC_SOFTSTP] = kvm_handle_ss, + [ESR_EL2_EC_WATCHPT] = kvm_handle_watch, + [ESR_EL2_EC_BREAKPT] = kvm_handle_hw_bp, [ESR_EL2_EC_BKPT32] = kvm_handle_bkpt, [ESR_EL2_EC_BRK64] = kvm_handle_bkpt, }; diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S index b38ce3d..96f71ab 100644 --- a/arch/arm64/kvm/hyp.S +++ b/arch/arm64/kvm/hyp.S @@ -18,6 +18,7 @@ #include <linux/linkage.h> #include <linux/kvm.h> +#include <uapi/asm/kvm.h> #include <asm/assembler.h> #include <asm/memory.h> #include <asm/asm-offsets.h> @@ -174,6 +175,7 @@ ldr x3, [x0, #GUEST_DEBUG] tbz x3, #KVM_GUESTDBG_ENABLE_SHIFT, 2f // No guest debug + // Both Step and HW BP/WP ops need to modify spsr_el2 and mdscr_el1 // x0 - preserved as VCPU ptr // x1 - spsr // x2 - mdscr @@ -191,6 +193,11 @@ eor x1, x1, #DBG_SPSR_SS eor x2, x2, #DBG_MDSCR_SS 1: + // If we are doing HW BP/WP - set MDSCR_EL1.KDE/MDE + tbz x3, #KVM_GUESTDBG_USE_HW_BP_SHIFT, 3f + orr x2, x2, #DBG_MDSCR_KDE + orr x2, x2, #DBG_MDSCR_MDE +3: msr spsr_el2, x1 msr mdscr_el1, x2 2: @@ -815,6 +822,33 @@ __restore_debug: ret +/* Setup debug state for debug of guest */ +__setup_debug: + // x0: vcpu base address + // x3: ptr to guest registers passed to setup_debug_registers + // x5..x20/x26: trashed + + mrs x26, id_aa64dfr0_el1 + ubfx x24, x26, #12, #4 // Extract BRPs + ubfx x25, x26, #20, #4 // Extract WRPs + mov w26, #15 + sub w24, w26, w24 // How many BPs to skip + sub w25, w26, w25 // How many WPs to skip + + mov x4, x24 + add x3, x0, #GUEST_DEBUG_BCR + setup_debug_registers dbgbcr + add x3, x0, #GUEST_DEBUG_BVR + setup_debug_registers dbgbvr + + mov x4, x25 + add x3, x0, #GUEST_DEBUG_WCR + setup_debug_registers dbgwcr + add x3, x0, #GUEST_DEBUG_WVR + setup_debug_registers dbgwvr + + ret + __save_fpsimd: save_fpsimd ret @@ -861,6 +895,13 @@ ENTRY(__kvm_vcpu_run) bl __restore_sysregs bl __restore_fpsimd + // Now is the time to set-up the debug registers if we + // are debugging the guest + ldr x3, [x0, #GUEST_DEBUG] + tbz x3, #KVM_GUESTDBG_USE_HW_BP_SHIFT, 2f + bl __setup_debug + b 1f +2: skip_debug_state x3, 1f bl __restore_debug 1: @@ -881,6 +922,11 @@ __kvm_vcpu_return: bl __save_fpsimd bl __save_sysregs + // If we are debugging the guest don't save debug registers + // otherwise we'll be trashing are only good copy we have. + ldr x3, [x0, #GUEST_DEBUG] + tbnz x3, #KVM_GUESTDBG_USE_HW_BP_SHIFT, 1f + skip_debug_state x3, 1f bl __save_debug 1: diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index 70a7816..0de6caa 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -64,6 +64,12 @@ int kvm_arch_dev_ioctl_check_extension(long ext) case KVM_CAP_ARM_EL1_32BIT: r = cpu_has_32bit_el1(); break; + case KVM_CAP_GUEST_DEBUG_HW_BPS: + r = get_num_brps(); + break; + case KVM_CAP_GUEST_DEBUG_HW_WPS: + r = get_num_wrps(); + break; default: r = 0; } diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 347e5b0..49a5f97 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -759,6 +759,8 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_PPC_FIXUP_HCALL 103 #define KVM_CAP_PPC_ENABLE_HCALL 104 #define KVM_CAP_CHECK_EXTENSION_VM 105 +#define KVM_CAP_GUEST_DEBUG_HW_BPS 106 +#define KVM_CAP_GUEST_DEBUG_HW_WPS 107 #ifdef KVM_CAP_IRQ_ROUTING -- 2.1.3 ^ permalink raw reply related [flat|nested] 15+ messages in thread
[parent not found: <1416931805-23223-8-git-send-email-alex.bennee-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>]
* Re: [PATCH 7/7] KVM: arm64: guest debug, HW assisted debug support [not found] ` <1416931805-23223-8-git-send-email-alex.bennee-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> @ 2014-11-26 17:34 ` Andrew Jones 0 siblings, 0 replies; 15+ messages in thread From: Andrew Jones @ 2014-11-26 17:34 UTC (permalink / raw) To: Alex Bennée Cc: kvm-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, kvmarm-FPEHb7Xf0XXUo1n7N8X6UoWGPAHP3yOg, christoffer.dall-QSEj5FYQhm4dnm+yROfE0A, marc.zyngier-5wv7dgnIgG8, peter.maydell-QSEj5FYQhm4dnm+yROfE0A, agraf-l3A5Bk7waGM, Lorenzo Pieralisi, Russell King, Jonathan Corbet, Gleb Natapov, jan.kiszka-kv7WeFo6aLtBDgjK7y7TUQ, AKASHI Takahiro, open list:DOCUMENTATION, Will Deacon, open list, open list:ABI/API, dahi-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8, Catalin Marinas, Srivatsa S. Bhat, r65777-KZfg59tc24xl57MIdRCFDg, pbonzini-H+wXaHxf7aLQT0dZR+AlfA, bp-l3A5Bk7waGM On Tue, Nov 25, 2014 at 04:10:05PM +0000, Alex Bennée wrote: > This adds support for userspace to control the HW debug registers for > guest debug. We'll only copy the $ARCH defined number across as that's > all that hyp.S will use anyway. I've moved some helper functions into > the hw_breakpoint.h header for re-use. > > As with single step we need to tweak the guest registers to enable the > exceptions but we don't want to overwrite the guest copy of these > registers so this is done close to the guest entry. > > Two new capabilities have been added to the KVM_EXTENSION ioctl to allow > userspace to query the number of hardware break and watch points > available on the host hardware. > > Signed-off-by: Alex Bennée <alex.bennee-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> > > diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt > index 9383359..5e8c673 100644 > --- a/Documentation/virtual/kvm/api.txt > +++ b/Documentation/virtual/kvm/api.txt > @@ -2593,7 +2593,7 @@ The top 16 bits of the control field are architecture specific control > flags which can include the following: > > - KVM_GUESTDBG_USE_SW_BP: using software breakpoints [x86, arm64] > - - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390] > + - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390, arm64] > - KVM_GUESTDBG_INJECT_DB: inject DB type exception [x86] > - KVM_GUESTDBG_INJECT_BP: inject BP type exception [x86] > - KVM_GUESTDBG_EXIT_PENDING: trigger an immediate guest exit [s390] > @@ -2606,7 +2606,10 @@ we need to ensure the guest vCPUs architecture specific registers are > updated to the correct (supplied) values. > > The second part of the structure is architecture specific and > -typically contains a set of debug registers. > +typically contains a set of debug registers. For arm64 the number of > +debug registers is implementation defined and can be determined by > +querying the KVM_CAP_GUEST_DEBUG_HW_BPS and KVM_CAP_GUEST_DEBUG_HW_WPS > +capabilities. > > When debug events exit the main run loop with the reason > KVM_EXIT_DEBUG with the kvm_debug_exit_arch part of the kvm_run > diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c > index a76daae..c8ec23a 100644 > --- a/arch/arm/kvm/arm.c > +++ b/arch/arm/kvm/arm.c > @@ -39,6 +39,7 @@ > #include <asm/cacheflush.h> > #include <asm/virt.h> > #include <asm/debug-monitors.h> > +#include <asm/hw_breakpoint.h> > #include <asm/kvm_arm.h> > #include <asm/kvm_asm.h> > #include <asm/kvm_mmu.h> > @@ -341,8 +342,37 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, > > /* Hardware assisted Break and Watch points */ > if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) { > - kvm_info("HW BP support requested, not yet implemented\n"); > - return -EINVAL; > + int i; > + int nb = get_num_brps(); > + int nw = get_num_wrps(); > + > + /* Copy across up to IMPDEF debug registers to our > + * shadow copy in the vcpu structure. The hyp.S code > + * will then set them up before we re-enter the guest. > + */ > + memcpy(vcpu->arch.guest_debug_regs.dbg_bcr, > + dbg->arch.dbg_bcr, sizeof(__u64)*nb); > + memcpy(vcpu->arch.guest_debug_regs.dbg_bvr, > + dbg->arch.dbg_bvr, sizeof(__u64)*nb); > + memcpy(vcpu->arch.guest_debug_regs.dbg_wcr, > + dbg->arch.dbg_wcr, sizeof(__u64)*nw); > + memcpy(vcpu->arch.guest_debug_regs.dbg_wvr, > + dbg->arch.dbg_wvr, sizeof(__u64)*nw); > + > + kvm_info("HW BP support requested\n"); > + for (i = 0; i < nb; i++) { > + kvm_info("%d: dbg_bcr=0x%llx dbg_bvr=0x%llx\n", > + i, > + vcpu->arch.guest_debug_regs.dbg_bcr[i], > + vcpu->arch.guest_debug_regs.dbg_bvr[i]); > + } > + for (i = 0; i < nw; i++) { > + kvm_info("%d: dbg_wcr=0x%llx dbg_wvr=0x%llx\n", > + i, > + vcpu->arch.guest_debug_regs.dbg_wcr[i], > + vcpu->arch.guest_debug_regs.dbg_wvr[i]); > + } I think we decided to drop the kvm_info's. Here's several more lines of logging to drop too. > + route_el2 = true; > } > > /* If we are going to handle any debug exceptions we need to > diff --git a/arch/arm64/include/asm/hw_breakpoint.h b/arch/arm64/include/asm/hw_breakpoint.h > index 52b484b..c450552 100644 > --- a/arch/arm64/include/asm/hw_breakpoint.h > +++ b/arch/arm64/include/asm/hw_breakpoint.h > @@ -130,6 +130,18 @@ static inline void ptrace_hw_copy_thread(struct task_struct *task) > } > #endif > > +/* Determine number of BRP registers available. */ > +static inline int get_num_brps(void) > +{ > + return ((read_cpuid(ID_AA64DFR0_EL1) >> 12) & 0xf) + 1; > +} > + > +/* Determine number of WRP registers available. */ > +static inline int get_num_wrps(void) > +{ > + return ((read_cpuid(ID_AA64DFR0_EL1) >> 20) & 0xf) + 1; > +} > + > extern struct pmu perf_ops_bp; > > #endif /* __KERNEL__ */ > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h > index 38b0f07..e386bf4 100644 > --- a/arch/arm64/include/asm/kvm_host.h > +++ b/arch/arm64/include/asm/kvm_host.h > @@ -103,8 +103,9 @@ struct kvm_vcpu_arch { > /* Exception Information */ > struct kvm_vcpu_fault_info fault; > > - /* Debug state */ > + /* Guest debug state */ > u64 debug_flags; > + struct kvm_guest_debug_arch guest_debug_regs; > > /* Pointer to host CPU context */ > kvm_cpu_context_t *host_cpu_context; > diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c > index 78e5ae1..c9ecfd3 100644 > --- a/arch/arm64/kernel/asm-offsets.c > +++ b/arch/arm64/kernel/asm-offsets.c > @@ -122,6 +122,10 @@ int main(void) > DEFINE(VCPU_HPFAR_EL2, offsetof(struct kvm_vcpu, arch.fault.hpfar_el2)); > DEFINE(VCPU_DEBUG_FLAGS, offsetof(struct kvm_vcpu, arch.debug_flags)); > DEFINE(GUEST_DEBUG, offsetof(struct kvm_vcpu, guest_debug)); > + DEFINE(GUEST_DEBUG_BCR, offsetof(struct kvm_vcpu, arch.guest_debug_regs.dbg_bcr)); > + DEFINE(GUEST_DEBUG_BVR, offsetof(struct kvm_vcpu, arch.guest_debug_regs.dbg_bvr)); > + DEFINE(GUEST_DEBUG_WCR, offsetof(struct kvm_vcpu, arch.guest_debug_regs.dbg_wcr)); > + DEFINE(GUEST_DEBUG_WVR, offsetof(struct kvm_vcpu, arch.guest_debug_regs.dbg_wvr)); > DEFINE(VCPU_HCR_EL2, offsetof(struct kvm_vcpu, arch.hcr_el2)); > DEFINE(VCPU_MDCR_EL2, offsetof(struct kvm_vcpu, arch.mdcr_el2)); > DEFINE(VCPU_IRQ_LINES, offsetof(struct kvm_vcpu, arch.irq_lines)); > diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c > index df1cf15..45dcc6f 100644 > --- a/arch/arm64/kernel/hw_breakpoint.c > +++ b/arch/arm64/kernel/hw_breakpoint.c > @@ -49,18 +49,6 @@ static DEFINE_PER_CPU(int, stepping_kernel_bp); > static int core_num_brps; > static int core_num_wrps; > > -/* Determine number of BRP registers available. */ > -static int get_num_brps(void) > -{ > - return ((read_cpuid(ID_AA64DFR0_EL1) >> 12) & 0xf) + 1; > -} > - > -/* Determine number of WRP registers available. */ > -static int get_num_wrps(void) > -{ > - return ((read_cpuid(ID_AA64DFR0_EL1) >> 20) & 0xf) + 1; > -} > - > int hw_breakpoint_slots(int type) > { > /* > diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c > index 6def054..d024e47 100644 > --- a/arch/arm64/kvm/handle_exit.c > +++ b/arch/arm64/kvm/handle_exit.c > @@ -110,6 +110,42 @@ static int kvm_handle_ss(struct kvm_vcpu *vcpu, struct kvm_run *run) > return 0; > } > > +/** > + * kvm_handle_hw_bp - handle HW assisted break point > + * > + * @vcpu: the vcpu pointer @run > + * > + */ > +static int kvm_handle_hw_bp(struct kvm_vcpu *vcpu, struct kvm_run *run) > +{ > + WARN_ON(!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)); Another WARN_ON to consider dropping. > + > + run->exit_reason = KVM_EXIT_DEBUG; > + run->debug.arch.exit_type = KVM_DEBUG_EXIT_HW_BKPT; > + run->debug.arch.address = *vcpu_pc(vcpu); > + return 0; > +} > + > +/** > + * kvm_handle_watch - handle HW assisted watch point > + * > + * @vcpu: the vcpu pointer @run > + * > + * These are basically the same as breakpoints (and indeed may use the > + * breakpoint in a linked fashion). However they generate a specific > + * exception so we trap it here for reporting to the guest. > + * > + */ > +static int kvm_handle_watch(struct kvm_vcpu *vcpu, struct kvm_run *run) > +{ > + WARN_ON(!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)); > + drop WARN_ON? > + run->exit_reason = KVM_EXIT_DEBUG; > + run->debug.arch.exit_type = KVM_DEBUG_EXIT_HW_WTPT; > + run->debug.arch.address = *vcpu_pc(vcpu); > + return 0; > +} > + > static exit_handle_fn arm_exit_handlers[] = { > [ESR_EL2_EC_WFI] = kvm_handle_wfx, > [ESR_EL2_EC_CP15_32] = kvm_handle_cp15_32, > @@ -125,6 +161,8 @@ static exit_handle_fn arm_exit_handlers[] = { > [ESR_EL2_EC_IABT] = kvm_handle_guest_abort, > [ESR_EL2_EC_DABT] = kvm_handle_guest_abort, > [ESR_EL2_EC_SOFTSTP] = kvm_handle_ss, > + [ESR_EL2_EC_WATCHPT] = kvm_handle_watch, > + [ESR_EL2_EC_BREAKPT] = kvm_handle_hw_bp, > [ESR_EL2_EC_BKPT32] = kvm_handle_bkpt, > [ESR_EL2_EC_BRK64] = kvm_handle_bkpt, > }; > diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S > index b38ce3d..96f71ab 100644 > --- a/arch/arm64/kvm/hyp.S > +++ b/arch/arm64/kvm/hyp.S > @@ -18,6 +18,7 @@ > #include <linux/linkage.h> > #include <linux/kvm.h> > > +#include <uapi/asm/kvm.h> > #include <asm/assembler.h> > #include <asm/memory.h> > #include <asm/asm-offsets.h> > @@ -174,6 +175,7 @@ > ldr x3, [x0, #GUEST_DEBUG] > tbz x3, #KVM_GUESTDBG_ENABLE_SHIFT, 2f // No guest debug > > + // Both Step and HW BP/WP ops need to modify spsr_el2 and mdscr_el1 Comment not quite right, since they both don't need to modify both. Step modifies both. BP/WP modifies mdscr. > // x0 - preserved as VCPU ptr > // x1 - spsr > // x2 - mdscr > @@ -191,6 +193,11 @@ > eor x1, x1, #DBG_SPSR_SS > eor x2, x2, #DBG_MDSCR_SS > 1: > + // If we are doing HW BP/WP - set MDSCR_EL1.KDE/MDE > + tbz x3, #KVM_GUESTDBG_USE_HW_BP_SHIFT, 3f > + orr x2, x2, #DBG_MDSCR_KDE > + orr x2, x2, #DBG_MDSCR_MDE We don't need to make sure KDE/MDE are cleared when we're not doing BP/WP, as we do with the SS bit? > +3: > msr spsr_el2, x1 > msr mdscr_el1, x2 > 2: Not super pleasant to have the labels occur in 1,3,2 order, but whatever. > @@ -815,6 +822,33 @@ __restore_debug: > > ret > > +/* Setup debug state for debug of guest */ > +__setup_debug: > + // x0: vcpu base address > + // x3: ptr to guest registers passed to setup_debug_registers > + // x5..x20/x26: trashed Same comment on this header as for __restore_debug's new header in a previous patch. > + > + mrs x26, id_aa64dfr0_el1 > + ubfx x24, x26, #12, #4 // Extract BRPs > + ubfx x25, x26, #20, #4 // Extract WRPs > + mov w26, #15 > + sub w24, w26, w24 // How many BPs to skip > + sub w25, w26, w25 // How many WPs to skip > + > + mov x4, x24 > + add x3, x0, #GUEST_DEBUG_BCR > + setup_debug_registers dbgbcr Now I see why the name change of restore_debug to setup_debug_registers, it fits better here in __setup_debug. Should we name is something that fits both better? > + add x3, x0, #GUEST_DEBUG_BVR > + setup_debug_registers dbgbvr > + > + mov x4, x25 > + add x3, x0, #GUEST_DEBUG_WCR > + setup_debug_registers dbgwcr > + add x3, x0, #GUEST_DEBUG_WVR > + setup_debug_registers dbgwvr > + > + ret > + > __save_fpsimd: > save_fpsimd > ret > @@ -861,6 +895,13 @@ ENTRY(__kvm_vcpu_run) > bl __restore_sysregs > bl __restore_fpsimd > > + // Now is the time to set-up the debug registers if we > + // are debugging the guest ^^^ whitespace > + ldr x3, [x0, #GUEST_DEBUG] > + tbz x3, #KVM_GUESTDBG_USE_HW_BP_SHIFT, 2f > + bl __setup_debug > + b 1f > +2: > skip_debug_state x3, 1f > bl __restore_debug > 1: > @@ -881,6 +922,11 @@ __kvm_vcpu_return: > bl __save_fpsimd > bl __save_sysregs > > + // If we are debugging the guest don't save debug registers > + // otherwise we'll be trashing are only good copy we have. ^^ the > + ldr x3, [x0, #GUEST_DEBUG] > + tbnz x3, #KVM_GUESTDBG_USE_HW_BP_SHIFT, 1f > + > skip_debug_state x3, 1f > bl __save_debug I feel like there should be a more elegant way to merge the selection of __setup_debug vs. __restore_debug and skip_debug_state. > 1: > diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c > index 70a7816..0de6caa 100644 > --- a/arch/arm64/kvm/reset.c > +++ b/arch/arm64/kvm/reset.c > @@ -64,6 +64,12 @@ int kvm_arch_dev_ioctl_check_extension(long ext) > case KVM_CAP_ARM_EL1_32BIT: > r = cpu_has_32bit_el1(); > break; > + case KVM_CAP_GUEST_DEBUG_HW_BPS: > + r = get_num_brps(); > + break; > + case KVM_CAP_GUEST_DEBUG_HW_WPS: > + r = get_num_wrps(); ^ extra space here > + break; > default: > r = 0; > } > diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h > index 347e5b0..49a5f97 100644 > --- a/include/uapi/linux/kvm.h > +++ b/include/uapi/linux/kvm.h > @@ -759,6 +759,8 @@ struct kvm_ppc_smmu_info { > #define KVM_CAP_PPC_FIXUP_HCALL 103 > #define KVM_CAP_PPC_ENABLE_HCALL 104 > #define KVM_CAP_CHECK_EXTENSION_VM 105 > +#define KVM_CAP_GUEST_DEBUG_HW_BPS 106 > +#define KVM_CAP_GUEST_DEBUG_HW_WPS 107 > > #ifdef KVM_CAP_IRQ_ROUTING > > -- > 2.1.3 > > _______________________________________________ > kvmarm mailing list > kvmarm-FPEHb7Xf0XXUo1n7N8X6UoWGPAHP3yOg@public.gmane.org > https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 7/7] KVM: arm64: guest debug, HW assisted debug support 2014-11-25 16:10 ` [PATCH 7/7] KVM: arm64: guest debug, HW assisted debug support Alex Bennée [not found] ` <1416931805-23223-8-git-send-email-alex.bennee-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> @ 2014-11-30 10:34 ` Christoffer Dall 2014-12-01 11:54 ` Alex Bennée 1 sibling, 1 reply; 15+ messages in thread From: Christoffer Dall @ 2014-11-30 10:34 UTC (permalink / raw) To: Alex Bennée Cc: kvm, linux-arm-kernel, kvmarm, marc.zyngier, peter.maydell, agraf, jan.kiszka, dahi, r65777, bp, pbonzini, Gleb Natapov, Jonathan Corbet, Russell King, Catalin Marinas, Will Deacon, Lorenzo Pieralisi, AKASHI Takahiro, Srivatsa S. Bhat, open list:DOCUMENTATION, open list, open list:ABI/API On Tue, Nov 25, 2014 at 04:10:05PM +0000, Alex Bennée wrote: > This adds support for userspace to control the HW debug registers for > guest debug. We'll only copy the $ARCH defined number across as that's > all that hyp.S will use anyway. I've moved some helper functions into > the hw_breakpoint.h header for re-use. > > As with single step we need to tweak the guest registers to enable the > exceptions but we don't want to overwrite the guest copy of these > registers so this is done close to the guest entry. > > Two new capabilities have been added to the KVM_EXTENSION ioctl to allow > userspace to query the number of hardware break and watch points > available on the host hardware. > > Signed-off-by: Alex Bennée <alex.bennee@linaro.org> > > diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt > index 9383359..5e8c673 100644 > --- a/Documentation/virtual/kvm/api.txt > +++ b/Documentation/virtual/kvm/api.txt > @@ -2593,7 +2593,7 @@ The top 16 bits of the control field are architecture specific control > flags which can include the following: > > - KVM_GUESTDBG_USE_SW_BP: using software breakpoints [x86, arm64] > - - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390] > + - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390, arm64] > - KVM_GUESTDBG_INJECT_DB: inject DB type exception [x86] > - KVM_GUESTDBG_INJECT_BP: inject BP type exception [x86] > - KVM_GUESTDBG_EXIT_PENDING: trigger an immediate guest exit [s390] > @@ -2606,7 +2606,10 @@ we need to ensure the guest vCPUs architecture specific registers are > updated to the correct (supplied) values. > > The second part of the structure is architecture specific and > -typically contains a set of debug registers. > +typically contains a set of debug registers. For arm64 the number of new paragraph for the arch-specific stuff. > +debug registers is implementation defined and can be determined by > +querying the KVM_CAP_GUEST_DEBUG_HW_BPS and KVM_CAP_GUEST_DEBUG_HW_WPS > +capabilities. > > When debug events exit the main run loop with the reason > KVM_EXIT_DEBUG with the kvm_debug_exit_arch part of the kvm_run > diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c > index a76daae..c8ec23a 100644 > --- a/arch/arm/kvm/arm.c > +++ b/arch/arm/kvm/arm.c > @@ -39,6 +39,7 @@ > #include <asm/cacheflush.h> > #include <asm/virt.h> > #include <asm/debug-monitors.h> > +#include <asm/hw_breakpoint.h> > #include <asm/kvm_arm.h> > #include <asm/kvm_asm.h> > #include <asm/kvm_mmu.h> > @@ -341,8 +342,37 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, > > /* Hardware assisted Break and Watch points */ > if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) { > - kvm_info("HW BP support requested, not yet implemented\n"); > - return -EINVAL; > + int i; > + int nb = get_num_brps(); > + int nw = get_num_wrps(); > + > + /* Copy across up to IMPDEF debug registers to our coding style > + * shadow copy in the vcpu structure. The hyp.S code > + * will then set them up before we re-enter the guest. > + */ > + memcpy(vcpu->arch.guest_debug_regs.dbg_bcr, > + dbg->arch.dbg_bcr, sizeof(__u64)*nb); > + memcpy(vcpu->arch.guest_debug_regs.dbg_bvr, > + dbg->arch.dbg_bvr, sizeof(__u64)*nb); > + memcpy(vcpu->arch.guest_debug_regs.dbg_wcr, > + dbg->arch.dbg_wcr, sizeof(__u64)*nw); > + memcpy(vcpu->arch.guest_debug_regs.dbg_wvr, > + dbg->arch.dbg_wvr, sizeof(__u64)*nw); > + > + kvm_info("HW BP support requested\n"); > + for (i = 0; i < nb; i++) { > + kvm_info("%d: dbg_bcr=0x%llx dbg_bvr=0x%llx\n", > + i, > + vcpu->arch.guest_debug_regs.dbg_bcr[i], > + vcpu->arch.guest_debug_regs.dbg_bvr[i]); > + } > + for (i = 0; i < nw; i++) { > + kvm_info("%d: dbg_wcr=0x%llx dbg_wvr=0x%llx\n", > + i, > + vcpu->arch.guest_debug_regs.dbg_wcr[i], > + vcpu->arch.guest_debug_regs.dbg_wvr[i]); > + } > + route_el2 = true; > } > > /* If we are going to handle any debug exceptions we need to > diff --git a/arch/arm64/include/asm/hw_breakpoint.h b/arch/arm64/include/asm/hw_breakpoint.h > index 52b484b..c450552 100644 > --- a/arch/arm64/include/asm/hw_breakpoint.h > +++ b/arch/arm64/include/asm/hw_breakpoint.h > @@ -130,6 +130,18 @@ static inline void ptrace_hw_copy_thread(struct task_struct *task) > } > #endif > > +/* Determine number of BRP registers available. */ > +static inline int get_num_brps(void) > +{ > + return ((read_cpuid(ID_AA64DFR0_EL1) >> 12) & 0xf) + 1; > +} > + > +/* Determine number of WRP registers available. */ > +static inline int get_num_wrps(void) > +{ > + return ((read_cpuid(ID_AA64DFR0_EL1) >> 20) & 0xf) + 1; > +} > + > extern struct pmu perf_ops_bp; > > #endif /* __KERNEL__ */ > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h > index 38b0f07..e386bf4 100644 > --- a/arch/arm64/include/asm/kvm_host.h > +++ b/arch/arm64/include/asm/kvm_host.h > @@ -103,8 +103,9 @@ struct kvm_vcpu_arch { > /* Exception Information */ > struct kvm_vcpu_fault_info fault; > > - /* Debug state */ > + /* Guest debug state */ > u64 debug_flags; > + struct kvm_guest_debug_arch guest_debug_regs; > > /* Pointer to host CPU context */ > kvm_cpu_context_t *host_cpu_context; > diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c > index 78e5ae1..c9ecfd3 100644 > --- a/arch/arm64/kernel/asm-offsets.c > +++ b/arch/arm64/kernel/asm-offsets.c > @@ -122,6 +122,10 @@ int main(void) > DEFINE(VCPU_HPFAR_EL2, offsetof(struct kvm_vcpu, arch.fault.hpfar_el2)); > DEFINE(VCPU_DEBUG_FLAGS, offsetof(struct kvm_vcpu, arch.debug_flags)); > DEFINE(GUEST_DEBUG, offsetof(struct kvm_vcpu, guest_debug)); > + DEFINE(GUEST_DEBUG_BCR, offsetof(struct kvm_vcpu, arch.guest_debug_regs.dbg_bcr)); > + DEFINE(GUEST_DEBUG_BVR, offsetof(struct kvm_vcpu, arch.guest_debug_regs.dbg_bvr)); > + DEFINE(GUEST_DEBUG_WCR, offsetof(struct kvm_vcpu, arch.guest_debug_regs.dbg_wcr)); > + DEFINE(GUEST_DEBUG_WVR, offsetof(struct kvm_vcpu, arch.guest_debug_regs.dbg_wvr)); > DEFINE(VCPU_HCR_EL2, offsetof(struct kvm_vcpu, arch.hcr_el2)); > DEFINE(VCPU_MDCR_EL2, offsetof(struct kvm_vcpu, arch.mdcr_el2)); > DEFINE(VCPU_IRQ_LINES, offsetof(struct kvm_vcpu, arch.irq_lines)); > diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c > index df1cf15..45dcc6f 100644 > --- a/arch/arm64/kernel/hw_breakpoint.c > +++ b/arch/arm64/kernel/hw_breakpoint.c > @@ -49,18 +49,6 @@ static DEFINE_PER_CPU(int, stepping_kernel_bp); > static int core_num_brps; > static int core_num_wrps; > > -/* Determine number of BRP registers available. */ > -static int get_num_brps(void) > -{ > - return ((read_cpuid(ID_AA64DFR0_EL1) >> 12) & 0xf) + 1; > -} > - > -/* Determine number of WRP registers available. */ > -static int get_num_wrps(void) > -{ > - return ((read_cpuid(ID_AA64DFR0_EL1) >> 20) & 0xf) + 1; > -} > - > int hw_breakpoint_slots(int type) > { > /* > diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c > index 6def054..d024e47 100644 > --- a/arch/arm64/kvm/handle_exit.c > +++ b/arch/arm64/kvm/handle_exit.c > @@ -110,6 +110,42 @@ static int kvm_handle_ss(struct kvm_vcpu *vcpu, struct kvm_run *run) > return 0; > } > > +/** > + * kvm_handle_hw_bp - handle HW assisted break point > + * > + * @vcpu: the vcpu pointer > + * > + */ > +static int kvm_handle_hw_bp(struct kvm_vcpu *vcpu, struct kvm_run *run) > +{ > + WARN_ON(!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)); > + > + run->exit_reason = KVM_EXIT_DEBUG; > + run->debug.arch.exit_type = KVM_DEBUG_EXIT_HW_BKPT; > + run->debug.arch.address = *vcpu_pc(vcpu); > + return 0; > +} > + > +/** > + * kvm_handle_watch - handle HW assisted watch point > + * > + * @vcpu: the vcpu pointer > + * > + * These are basically the same as breakpoints (and indeed may use the > + * breakpoint in a linked fashion). However they generate a specific > + * exception so we trap it here for reporting to the guest. > + * > + */ > +static int kvm_handle_watch(struct kvm_vcpu *vcpu, struct kvm_run *run) > +{ > + WARN_ON(!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)); > + > + run->exit_reason = KVM_EXIT_DEBUG; > + run->debug.arch.exit_type = KVM_DEBUG_EXIT_HW_WTPT; > + run->debug.arch.address = *vcpu_pc(vcpu); > + return 0; > +} the usual comments about the @run documentation and let's get rid of all these WARN_ON() statements. > + > static exit_handle_fn arm_exit_handlers[] = { > [ESR_EL2_EC_WFI] = kvm_handle_wfx, > [ESR_EL2_EC_CP15_32] = kvm_handle_cp15_32, > @@ -125,6 +161,8 @@ static exit_handle_fn arm_exit_handlers[] = { > [ESR_EL2_EC_IABT] = kvm_handle_guest_abort, > [ESR_EL2_EC_DABT] = kvm_handle_guest_abort, > [ESR_EL2_EC_SOFTSTP] = kvm_handle_ss, > + [ESR_EL2_EC_WATCHPT] = kvm_handle_watch, > + [ESR_EL2_EC_BREAKPT] = kvm_handle_hw_bp, > [ESR_EL2_EC_BKPT32] = kvm_handle_bkpt, > [ESR_EL2_EC_BRK64] = kvm_handle_bkpt, > }; > diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S > index b38ce3d..96f71ab 100644 > --- a/arch/arm64/kvm/hyp.S > +++ b/arch/arm64/kvm/hyp.S > @@ -18,6 +18,7 @@ > #include <linux/linkage.h> > #include <linux/kvm.h> > > +#include <uapi/asm/kvm.h> > #include <asm/assembler.h> > #include <asm/memory.h> > #include <asm/asm-offsets.h> > @@ -174,6 +175,7 @@ > ldr x3, [x0, #GUEST_DEBUG] > tbz x3, #KVM_GUESTDBG_ENABLE_SHIFT, 2f // No guest debug > > + // Both Step and HW BP/WP ops need to modify spsr_el2 and mdscr_el1 > // x0 - preserved as VCPU ptr > // x1 - spsr > // x2 - mdscr > @@ -191,6 +193,11 @@ > eor x1, x1, #DBG_SPSR_SS > eor x2, x2, #DBG_MDSCR_SS > 1: > + // If we are doing HW BP/WP - set MDSCR_EL1.KDE/MDE > + tbz x3, #KVM_GUESTDBG_USE_HW_BP_SHIFT, 3f > + orr x2, x2, #DBG_MDSCR_KDE > + orr x2, x2, #DBG_MDSCR_MDE > +3: > msr spsr_el2, x1 > msr mdscr_el1, x2 > 2: > @@ -815,6 +822,33 @@ __restore_debug: > > ret > > +/* Setup debug state for debug of guest */ > +__setup_debug: > + // x0: vcpu base address > + // x3: ptr to guest registers passed to setup_debug_registers > + // x5..x20/x26: trashed > + > + mrs x26, id_aa64dfr0_el1 > + ubfx x24, x26, #12, #4 // Extract BRPs > + ubfx x25, x26, #20, #4 // Extract WRPs > + mov w26, #15 > + sub w24, w26, w24 // How many BPs to skip > + sub w25, w26, w25 // How many WPs to skip > + > + mov x4, x24 > + add x3, x0, #GUEST_DEBUG_BCR > + setup_debug_registers dbgbcr > + add x3, x0, #GUEST_DEBUG_BVR > + setup_debug_registers dbgbvr > + > + mov x4, x25 > + add x3, x0, #GUEST_DEBUG_WCR > + setup_debug_registers dbgwcr > + add x3, x0, #GUEST_DEBUG_WVR > + setup_debug_registers dbgwvr > + > + ret > + > __save_fpsimd: > save_fpsimd > ret > @@ -861,6 +895,13 @@ ENTRY(__kvm_vcpu_run) > bl __restore_sysregs > bl __restore_fpsimd > > + // Now is the time to set-up the debug registers if we > + // are debugging the guest > + ldr x3, [x0, #GUEST_DEBUG] > + tbz x3, #KVM_GUESTDBG_USE_HW_BP_SHIFT, 2f > + bl __setup_debug > + b 1f > +2: > skip_debug_state x3, 1f > bl __restore_debug > 1: > @@ -881,6 +922,11 @@ __kvm_vcpu_return: > bl __save_fpsimd > bl __save_sysregs > > + // If we are debugging the guest don't save debug registers > + // otherwise we'll be trashing are only good copy we have. > + ldr x3, [x0, #GUEST_DEBUG] > + tbnz x3, #KVM_GUESTDBG_USE_HW_BP_SHIFT, 1f > + we're introducing an awful lot of conditionals in the assembly code with these patches, can you re-consider if there's a cleaner abstraction that allows us to deal with some of this stuff in C-code? -Christoffer ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 7/7] KVM: arm64: guest debug, HW assisted debug support 2014-11-30 10:34 ` Christoffer Dall @ 2014-12-01 11:54 ` Alex Bennée 0 siblings, 0 replies; 15+ messages in thread From: Alex Bennée @ 2014-12-01 11:54 UTC (permalink / raw) To: Christoffer Dall Cc: kvm, linux-arm-kernel, kvmarm, marc.zyngier, peter.maydell, agraf, jan.kiszka, dahi, r65777, bp, pbonzini, Gleb Natapov, Jonathan Corbet, Russell King, Catalin Marinas, Will Deacon, Lorenzo Pieralisi, AKASHI Takahiro, Srivatsa S. Bhat, open list:DOCUMENTATION, open list, open list:ABI/API Christoffer Dall <christoffer.dall@linaro.org> writes: > On Tue, Nov 25, 2014 at 04:10:05PM +0000, Alex Bennée wrote: <snip> >> --- a/arch/arm64/kvm/hyp.S >> +++ b/arch/arm64/kvm/hyp.S >> @@ -18,6 +18,7 @@ >> #include <linux/linkage.h> >> #include <linux/kvm.h> >> >> +#include <uapi/asm/kvm.h> >> #include <asm/assembler.h> >> #include <asm/memory.h> >> #include <asm/asm-offsets.h> >> @@ -174,6 +175,7 @@ >> ldr x3, [x0, #GUEST_DEBUG] >> tbz x3, #KVM_GUESTDBG_ENABLE_SHIFT, 2f // No guest debug >> >> + // Both Step and HW BP/WP ops need to modify spsr_el2 and mdscr_el1 >> // x0 - preserved as VCPU ptr >> // x1 - spsr >> // x2 - mdscr >> @@ -191,6 +193,11 @@ >> eor x1, x1, #DBG_SPSR_SS >> eor x2, x2, #DBG_MDSCR_SS >> 1: >> + // If we are doing HW BP/WP - set MDSCR_EL1.KDE/MDE >> + tbz x3, #KVM_GUESTDBG_USE_HW_BP_SHIFT, 3f >> + orr x2, x2, #DBG_MDSCR_KDE >> + orr x2, x2, #DBG_MDSCR_MDE >> +3: >> msr spsr_el2, x1 >> msr mdscr_el1, x2 >> 2: >> @@ -815,6 +822,33 @@ __restore_debug: >> >> ret >> >> +/* Setup debug state for debug of guest */ >> +__setup_debug: >> + // x0: vcpu base address >> + // x3: ptr to guest registers passed to setup_debug_registers >> + // x5..x20/x26: trashed >> + >> + mrs x26, id_aa64dfr0_el1 >> + ubfx x24, x26, #12, #4 // Extract BRPs >> + ubfx x25, x26, #20, #4 // Extract WRPs >> + mov w26, #15 >> + sub w24, w26, w24 // How many BPs to skip >> + sub w25, w26, w25 // How many WPs to skip >> + >> + mov x4, x24 >> + add x3, x0, #GUEST_DEBUG_BCR >> + setup_debug_registers dbgbcr >> + add x3, x0, #GUEST_DEBUG_BVR >> + setup_debug_registers dbgbvr >> + >> + mov x4, x25 >> + add x3, x0, #GUEST_DEBUG_WCR >> + setup_debug_registers dbgwcr >> + add x3, x0, #GUEST_DEBUG_WVR >> + setup_debug_registers dbgwvr >> + >> + ret >> + >> __save_fpsimd: >> save_fpsimd >> ret >> @@ -861,6 +895,13 @@ ENTRY(__kvm_vcpu_run) >> bl __restore_sysregs >> bl __restore_fpsimd >> >> + // Now is the time to set-up the debug registers if we >> + // are debugging the guest >> + ldr x3, [x0, #GUEST_DEBUG] >> + tbz x3, #KVM_GUESTDBG_USE_HW_BP_SHIFT, 2f >> + bl __setup_debug >> + b 1f >> +2: >> skip_debug_state x3, 1f >> bl __restore_debug >> 1: >> @@ -881,6 +922,11 @@ __kvm_vcpu_return: >> bl __save_fpsimd >> bl __save_sysregs >> >> + // If we are debugging the guest don't save debug registers >> + // otherwise we'll be trashing are only good copy we have. >> + ldr x3, [x0, #GUEST_DEBUG] >> + tbnz x3, #KVM_GUESTDBG_USE_HW_BP_SHIFT, 1f >> + > > we're introducing an awful lot of conditionals in the assembly code with > these patches, can you re-consider if there's a cleaner abstraction that > allows us to deal with some of this stuff in C-code? See previous mail. It would be good but we need a place to do it before we enter hyp.S on a KVM_RUN ioctl. I'm open to suggestions. > > -Christoffer -- Alex Bennée ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2014-12-02 13:17 UTC | newest] Thread overview: 15+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- [not found] <1416931805-23223-1-git-send-email-alex.bennee@linaro.org> 2014-11-25 16:09 ` [PATCH 1/7] KVM: add commentary for kvm_debug_exit_arch struct Alex Bennée [not found] ` <1416931805-23223-2-git-send-email-alex.bennee-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> 2014-11-26 14:20 ` Andrew Jones 2014-11-25 16:10 ` [PATCH 5/7] KVM: arm64: guest debug, add support for single-step Alex Bennée [not found] ` <1416931805-23223-6-git-send-email-alex.bennee-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> 2014-11-26 16:40 ` Andrew Jones [not found] ` <20141126164057.GE3245-EoAxxbxdFnFvD/m4c++uL6fLeoKvNuZc@public.gmane.org> 2014-11-26 18:00 ` Alex Bennée 2014-11-26 19:27 ` Peter Maydell [not found] ` <CAFEAcA-cjM9yUXi6tc79UP0fBKAagtFKQgV3iAjz5DWr9yxZUQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2014-11-30 10:10 ` Christoffer Dall 2014-11-30 10:20 ` Peter Maydell 2014-11-30 10:21 ` Christoffer Dall 2014-12-01 11:50 ` Alex Bennée [not found] ` <87r3wj1te1.fsf-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> 2014-12-02 13:17 ` Christoffer Dall 2014-11-25 16:10 ` [PATCH 7/7] KVM: arm64: guest debug, HW assisted debug support Alex Bennée [not found] ` <1416931805-23223-8-git-send-email-alex.bennee-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> 2014-11-26 17:34 ` Andrew Jones 2014-11-30 10:34 ` Christoffer Dall 2014-12-01 11:54 ` Alex Bennée
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).