]> xenbits.xensource.com Git - xen.git/commitdiff
x86: Fix PV guest CR4 handling. We should not leak hidden CR4 bits
authorKeir Fraser <keir@xensource.com>
Wed, 7 Nov 2007 14:15:44 +0000 (14:15 +0000)
committerKeir Fraser <keir@xensource.com>
Wed, 7 Nov 2007 14:15:44 +0000 (14:15 +0000)
into guest CR4 value.
Signed-off-by: Keir Fraser <keir@xensource.com>
xen/arch/x86/domain.c
xen/arch/x86/traps.c
xen/include/asm-x86/domain.h

index 1124dd66a554839d1b8dc85ec544e980f506dece..aaf7c979c613e2c8030d48e42f78437c6111f7e9 100644 (file)
@@ -415,7 +415,8 @@ int vcpu_initialise(struct vcpu *v)
             v->arch.cr3           = __pa(idle_pg_table);
         }
 
-        v->arch.guest_context.ctrlreg[4] = mmu_cr4_features;
+        v->arch.guest_context.ctrlreg[4] =
+            real_cr4_to_pv_guest_cr4(mmu_cr4_features);
     }
 
     v->arch.perdomain_ptes =
@@ -573,17 +574,18 @@ void arch_domain_destroy(struct domain *d)
 
 unsigned long pv_guest_cr4_fixup(unsigned long guest_cr4)
 {
-    unsigned long hv_cr4 = read_cr4(), hv_cr4_mask = ~X86_CR4_TSD;
+    unsigned long hv_cr4_mask, hv_cr4 = real_cr4_to_pv_guest_cr4(read_cr4());
+
+    hv_cr4_mask = ~X86_CR4_TSD;
     if ( cpu_has_de )
         hv_cr4_mask &= ~X86_CR4_DE;
 
-    if ( (guest_cr4 & hv_cr4_mask) !=
-         (hv_cr4 & hv_cr4_mask & ~(X86_CR4_PGE|X86_CR4_PSE)) )
+    if ( (guest_cr4 & hv_cr4_mask) != (hv_cr4 & hv_cr4_mask) )
         gdprintk(XENLOG_WARNING,
                  "Attempt to change CR4 flags %08lx -> %08lx\n",
                  hv_cr4 & ~(X86_CR4_PGE|X86_CR4_PSE), guest_cr4);
 
-    return  (hv_cr4 & hv_cr4_mask) | (guest_cr4 & ~hv_cr4_mask);
+    return (hv_cr4 & hv_cr4_mask) | (guest_cr4 & ~hv_cr4_mask);
 }
 
 /* This is called by arch_final_setup_guest and do_boot_vcpu */
@@ -684,8 +686,8 @@ int arch_set_info_guest(
     v->arch.guest_context.user_regs.eflags |= EF_IE;
 
     cr4 = v->arch.guest_context.ctrlreg[4];
-    v->arch.guest_context.ctrlreg[4] =
-        (cr4 == 0) ? mmu_cr4_features : pv_guest_cr4_fixup(cr4);
+    v->arch.guest_context.ctrlreg[4] = cr4 ? pv_guest_cr4_fixup(cr4) :
+        real_cr4_to_pv_guest_cr4(mmu_cr4_features);
 
     memset(v->arch.guest_context.debugreg, 0,
            sizeof(v->arch.guest_context.debugreg));
@@ -1223,11 +1225,14 @@ static void paravirt_ctxt_switch_from(struct vcpu *v)
 
 static void paravirt_ctxt_switch_to(struct vcpu *v)
 {
+    unsigned long cr4;
+
     set_int80_direct_trap(v);
     switch_kernel_stack(v);
 
-    if ( unlikely(read_cr4() != v->arch.guest_context.ctrlreg[4]) )
-        write_cr4(v->arch.guest_context.ctrlreg[4]);
+    cr4 = pv_guest_cr4_to_real_cr4(v->arch.guest_context.ctrlreg[4]);
+    if ( unlikely(cr4 != read_cr4()) )
+        write_cr4(cr4);
 
     if ( unlikely(v->arch.guest_context.debugreg[7]) )
     {
index 32ab678a9198474ae8993d8a785dbe6770a7433f..d8a1ec847d6cbb3409504c5b237db95b2bbd760b 100644 (file)
@@ -1797,7 +1797,8 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
 
         case 4: /* Write CR4 */
             v->arch.guest_context.ctrlreg[4] = pv_guest_cr4_fixup(*reg);
-            write_cr4(v->arch.guest_context.ctrlreg[4]);
+            write_cr4(pv_guest_cr4_to_real_cr4(
+                v->arch.guest_context.ctrlreg[4]));
             break;
 
         default:
index 28fbd7b1f73cfa1c79724aa787635a38a2589eb5..37ff3d53537751f1842efe6288322490d63cc36e 100644 (file)
@@ -350,8 +350,15 @@ struct arch_vcpu
 /* Continue the current hypercall via func(data) on specified cpu. */
 int continue_hypercall_on_cpu(int cpu, long (*func)(void *data), void *data);
 
+/* Clean up CR4 bits that are not under guest control. */
 unsigned long pv_guest_cr4_fixup(unsigned long guest_cr4);
 
+/* Convert between guest-visible and real CR4 values. */
+#define pv_guest_cr4_to_real_cr4(c) \
+    ((c) | (mmu_cr4_features & (X86_CR4_PGE | X86_CR4_PSE)))
+#define real_cr4_to_pv_guest_cr4(c) \
+    ((c) & ~(X86_CR4_PGE | X86_CR4_PSE))
+
 #endif /* __ASM_DOMAIN_H__ */
 
 /*