[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[xen master] x86/svm: Intercept CR0 writes selectively



commit 1b2f3cbc09885d7b31298f11daddaadbe59ed71d
Author:     Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
AuthorDate: Mon Sep 21 10:11:27 2026 +0200
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Mon Sep 21 10:11:27 2026 +0200

    x86/svm: Intercept CR0 writes selectively
    
    Since 3356d685dbda ("x86/svm: Remove lazy FPU support"), Xen does not
    need to track when the TS or MP bits change so opt to intercept CR0
    writes selectively. Aside from potentially reducing a few VMEXITs, this
    fixes a nested virt bug where L1 intercepts CR0_SEL_WRITE and L0
    intercepts CR0_WRITE. The hardware prioritizes CR0_WRITE and so L1 never
    sees any CR0 writes.
    
    Since CR0 TS/MP bits may now change behind Xen's back, sync CR0 on
    VMEXIT so that the emulator sees the correct values.
    
    Shadow mode continues to use the full CR0_WRITE intercept since with
    Shadow the CR0 in the VMCB is not the same as the value Xen tracks on
    behalf of the guest and allowing the guest to change one of them
    directly would be fragile.
    
    Signed-off-by: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
    Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx>
---
 xen/arch/x86/hvm/svm/svm.c  | 7 ++++++-
 xen/arch/x86/hvm/svm/vmcb.c | 7 +++++++
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index b5fc459e62..e6a0edcf71 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -1640,7 +1640,8 @@ static void svm_vmexit_do_cr_access(
 {
     int gp, cr, dir, rc;
 
-    cr = vmcb->exitcode - VMEXIT_CR0_READ;
+    cr = (vmcb->exitcode == VMEXIT_CR0_SEL_WRITE)
+         ? 16 : (vmcb->exitcode - VMEXIT_CR0_READ);
     dir = (cr > 15);
     cr &= 0xf;
     gp = vmcb->ei.mov_cr.gpr;
@@ -2519,7 +2520,10 @@ void asmlinkage svm_vmexit_handler(void)
 
     v->arch.hvm.guest_cr[2] = vmcb_get_cr2(vmcb);
     if ( paging_mode_hap(v->domain) )
+    {
+        v->arch.hvm.guest_cr[0] = vmcb_get_cr0(vmcb);
         v->arch.hvm.guest_cr[3] = v->arch.hvm.hw_cr[3] = vmcb_get_cr3(vmcb);
+    }
 
     if ( nestedhvm_enabled(v->domain) && nestedhvm_vcpu_in_guestmode(v) )
         vcpu_guestmode = 1;
@@ -2883,6 +2887,7 @@ void asmlinkage svm_vmexit_handler(void)
 
     case VMEXIT_CR0_READ ... VMEXIT_CR15_READ:
     case VMEXIT_CR0_WRITE ... VMEXIT_CR15_WRITE:
+    case VMEXIT_CR0_SEL_WRITE:
         if ( cpu_has_svm_decode && vmcb->ei.mov_cr.mov_insn )
             svm_vmexit_do_cr_access(vmcb, regs);
         else if ( !hvm_emulate_one_insn(x86_insn_is_cr_access, "CR access") )
diff --git a/xen/arch/x86/hvm/svm/vmcb.c b/xen/arch/x86/hvm/svm/vmcb.c
index 975a1eaef8..d069280a4d 100644
--- a/xen/arch/x86/hvm/svm/vmcb.c
+++ b/xen/arch/x86/hvm/svm/vmcb.c
@@ -154,6 +154,13 @@ static int construct_vmcb(struct vcpu *v)
         vmcb->_cr_intercepts &=
             ~(CR_INTERCEPT_CR3_READ|CR_INTERCEPT_CR3_WRITE);
 
+        /*
+         * Xen is not interested in changes to the MP and TS bits so use
+         * CR0_SEL_WRITE to avoid unnecessary intercepts.
+         */
+        vmcb->_cr_intercepts &= ~CR_INTERCEPT_CR0_WRITE;
+        vmcb->_general1_intercepts |= GENERAL1_INTERCEPT_CR0_SEL_WRITE;
+
         /*
          * No point in intercepting INVLPG if we don't have shadow pagetables
          * that need to be fixed up.
--
generated by git-patchbot for /home/xen/git/xen.git#master



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.