@@ -136,6 +136,8 @@ struct kvm_arch {
*/
#define KVM_ARCH_FLAG_REG_WIDTH_CONFIGURED 3
#define KVM_ARCH_FLAG_EL1_32BIT 4
+ /* Access to debug registers need to be emulated ? */
+#define KVM_ARCH_FLAG_EMULATE_DEBUG_REGS 5
unsigned long flags;
@@ -786,6 +788,7 @@ long kvm_vm_ioctl_mte_copy_tags(struct kvm *kvm,
void set_default_id_regs(struct kvm *kvm);
int kvm_set_id_reg_feature(struct kvm *kvm, u32 id, u8 field_shift, u8 fval);
+void kvm_vcpu_breakpoint_config(struct kvm_vcpu *vcpu);
/* Guest/host FPSIMD coordination helpers */
int kvm_arch_vcpu_run_map_fp(struct kvm_vcpu *vcpu);
@@ -106,10 +106,14 @@ static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
* (KVM_GUESTDBG_USE_HW is set).
* - The guest is not using debug (KVM_ARM64_DEBUG_DIRTY is clear).
* - The guest has enabled the OS Lock (debug exceptions are blocked).
+ * - The guest's access to debug registers needs to be emulated
+ * (the number of non-context aware breakpoints for the guest
+ * is decreased by userspace).
*/
if ((vcpu->guest_debug & KVM_GUESTDBG_USE_HW) ||
!(vcpu->arch.flags & KVM_ARM64_DEBUG_DIRTY) ||
- kvm_vcpu_os_lock_enabled(vcpu))
+ kvm_vcpu_os_lock_enabled(vcpu) ||
+ test_bit(KVM_ARCH_FLAG_EMULATE_DEBUG_REGS, &vcpu->kvm->arch.flags))
vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA;
trace_kvm_arm_set_dreg32("MDCR_EL2", vcpu->arch.mdcr_el2);
@@ -124,6 +128,7 @@ static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
*/
void kvm_arm_vcpu_init_debug(struct kvm_vcpu *vcpu)
{
+ kvm_vcpu_breakpoint_config(vcpu);
preempt_disable();
kvm_arm_setup_mdcr_el2(vcpu);
preempt_enable();
@@ -844,6 +844,41 @@ static bool trap_dbgauthstatus_el1(struct kvm_vcpu *vcpu,
}
}
+#define AA64DFR0_BRPS(v) \
+ ((u8)cpuid_feature_extract_unsigned_field(v, ID_AA64DFR0_BRPS_SHIFT))
+#define AA64DFR0_CTX_CMPS(v) \
+ ((u8)cpuid_feature_extract_unsigned_field(v, ID_AA64DFR0_CTX_CMPS_SHIFT))
+
+/*
+ * Set KVM_ARCH_FLAG_EMULATE_DEBUG_REGS in the VM flags when the number of
+ * non-context aware breakpoints for the guest is decreased by userspace
+ * (meaning that debug register accesses need to be emulated).
+ */
+void kvm_vcpu_breakpoint_config(struct kvm_vcpu *vcpu)
+{
+ u64 p_val = read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1);
+ u64 v_val = read_id_reg_with_encoding(vcpu, SYS_ID_AA64DFR0_EL1);
+ u8 v_nbpn, p_nbpn;
+ struct kvm *kvm = vcpu->kvm;
+
+ /*
+ * Check the number of normal (non-context aware) breakpoints
+ * for the guest and the host.
+ */
+ v_nbpn = AA64DFR0_BRPS(v_val) - AA64DFR0_CTX_CMPS(v_val);
+ p_nbpn = AA64DFR0_BRPS(p_val) - AA64DFR0_CTX_CMPS(p_val);
+ if (v_nbpn >= p_nbpn)
+ /*
+ * Nothing to do if the number of normal breakpoints for the
+ * guest is not decreased by userspace (meaning KVM doesn't
+ * need to emulate an access of debug registers).
+ */
+ return;
+
+ if (!test_bit(KVM_ARCH_FLAG_EMULATE_DEBUG_REGS, &kvm->arch.flags))
+ set_bit(KVM_ARCH_FLAG_EMULATE_DEBUG_REGS, &kvm->arch.flags);
+}
+
/*
* We want to avoid world-switching all the DBG registers all the
* time:
Highest numbered breakpoints must be context aware breakpoints (as specified by Arm ARM). If the number of non-context aware breakpoints for the guest is decreased by userspace, simply narrowing the breakpoints will be problematic because it will lead to narrowing context aware breakpoints for the guest. Introduce KVM_ARCH_FLAG_EMULATE_DEBUG_REGS for kvm->arch.flags to indicate trapping debug reg access is needed, and enable the trapping when the flag is set. Set the new flag at the first KVM_RUN if the number of non-context aware breakpoints for the guest is decreased by userspace. No code sets the new flag yet since ID_AA64DFR0_EL1 is not configurable by userspace. Signed-off-by: Reiji Watanabe <reijiw@google.com> --- arch/arm64/include/asm/kvm_host.h | 3 +++ arch/arm64/kvm/debug.c | 7 ++++++- arch/arm64/kvm/sys_regs.c | 35 +++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-)