From: Tom Lendacky <thomas.lenda...@amd.com>

Since the guest register state of an SEV-ES guest is encrypted, debugging
is not supported. Update the code to prevent guest debugging when the
guest has protected state.

Additionally, an SEV-ES guest must only and always intercept DR7 reads and
writes. Update set_dr_intercepts() and clr_dr_intercepts() to account for
this.

Signed-off-by: Tom Lendacky <thomas.lenda...@amd.com>
---
 arch/x86/kvm/svm/svm.c |  9 +++++
 arch/x86/kvm/svm/svm.h | 81 +++++++++++++++++++++++-------------------
 arch/x86/kvm/x86.c     |  3 ++
 3 files changed, 57 insertions(+), 36 deletions(-)

diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 857d0d3f2752..513cf667dff4 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -1806,6 +1806,9 @@ static void svm_set_dr6(struct vcpu_svm *svm, unsigned 
long value)
 {
        struct vmcb *vmcb = svm->vmcb;
 
+       if (svm->vcpu.arch.guest_state_protected)
+               return;
+
        if (unlikely(value != vmcb->save.dr6)) {
                vmcb->save.dr6 = value;
                vmcb_mark_dirty(vmcb, VMCB_DR);
@@ -1816,6 +1819,9 @@ static void svm_sync_dirty_debug_regs(struct kvm_vcpu 
*vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
+       if (vcpu->arch.guest_state_protected)
+               return;
+
        get_debugreg(vcpu->arch.db[0], 0);
        get_debugreg(vcpu->arch.db[1], 1);
        get_debugreg(vcpu->arch.db[2], 2);
@@ -1834,6 +1840,9 @@ static void svm_set_dr7(struct kvm_vcpu *vcpu, unsigned 
long value)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
+       if (vcpu->arch.guest_state_protected)
+               return;
+
        svm->vmcb->save.dr7 = value;
        vmcb_mark_dirty(svm->vmcb, VMCB_DR);
 }
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 80a359f3cf20..abfe53d6b3dc 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -199,6 +199,28 @@ static inline struct kvm_svm *to_kvm_svm(struct kvm *kvm)
        return container_of(kvm, struct kvm_svm, kvm);
 }
 
+static inline bool sev_guest(struct kvm *kvm)
+{
+#ifdef CONFIG_KVM_AMD_SEV
+       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+
+       return sev->active;
+#else
+       return false;
+#endif
+}
+
+static inline bool sev_es_guest(struct kvm *kvm)
+{
+#ifdef CONFIG_KVM_AMD_SEV
+       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+
+       return sev_guest(kvm) && sev->es_active;
+#else
+       return false;
+#endif
+}
+
 static inline void vmcb_mark_all_dirty(struct vmcb *vmcb)
 {
        vmcb->control.clean = 0;
@@ -250,21 +272,24 @@ static inline void set_dr_intercepts(struct vcpu_svm *svm)
 {
        struct vmcb *vmcb = get_host_vmcb(svm);
 
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR0_READ);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR1_READ);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR2_READ);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR3_READ);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR4_READ);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR5_READ);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR6_READ);
+       if (!sev_es_guest(svm->vcpu.kvm)) {
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR0_READ);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR1_READ);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR2_READ);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR3_READ);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR4_READ);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR5_READ);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR6_READ);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR0_WRITE);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR1_WRITE);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR2_WRITE);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR3_WRITE);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR4_WRITE);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR5_WRITE);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR6_WRITE);
+       }
+
        vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_READ);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR0_WRITE);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR1_WRITE);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR2_WRITE);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR3_WRITE);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR4_WRITE);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR5_WRITE);
-       vmcb_set_intercept(&vmcb->control, INTERCEPT_DR6_WRITE);
        vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_WRITE);
 
        recalc_intercepts(svm);
@@ -276,6 +301,12 @@ static inline void clr_dr_intercepts(struct vcpu_svm *svm)
 
        vmcb->control.intercepts[INTERCEPT_DR] = 0;
 
+       /* DR7 access must remain intercepted for an SEV-ES guest */
+       if (sev_es_guest(svm->vcpu.kvm)) {
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_READ);
+               vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_WRITE);
+       }
+
        recalc_intercepts(svm);
 }
 
@@ -481,28 +512,6 @@ void svm_vcpu_unblocking(struct kvm_vcpu *vcpu);
 
 extern unsigned int max_sev_asid;
 
-static inline bool sev_guest(struct kvm *kvm)
-{
-#ifdef CONFIG_KVM_AMD_SEV
-       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
-
-       return sev->active;
-#else
-       return false;
-#endif
-}
-
-static inline bool sev_es_guest(struct kvm *kvm)
-{
-#ifdef CONFIG_KVM_AMD_SEV
-       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
-
-       return sev_guest(kvm) && sev->es_active;
-#else
-       return false;
-#endif
-}
-
 static inline bool svm_sev_enabled(void)
 {
        return IS_ENABLED(CONFIG_KVM_AMD_SEV) ? max_sev_asid : 0;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index b6809a2851d2..de0e35083df5 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -9671,6 +9671,9 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu 
*vcpu,
        unsigned long rflags;
        int i, r;
 
+       if (vcpu->arch.guest_state_protected)
+               return -EINVAL;
+
        vcpu_load(vcpu);
 
        if (dbg->control & (KVM_GUESTDBG_INJECT_DB | KVM_GUESTDBG_INJECT_BP)) {
-- 
2.28.0

Reply via email to