# HG changeset patch
# User Keir Fraser <keir@xxxxxxxxxxxxx>
# Date 1194444944 0
# Node ID 00db9ec39831dc092cefc8bbf747ef90d19241a9
# Parent c982fe8a9f91faffe2bf08b308bca8a6e8f6c0f0
x86: Fix PV guest CR4 handling. We should not leak hidden CR4 bits
into guest CR4 value.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
xen/arch/x86/domain.c | 23 ++++++++++++++---------
xen/arch/x86/traps.c | 3 ++-
xen/include/asm-x86/domain.h | 7 +++++++
3 files changed, 23 insertions(+), 10 deletions(-)
diff -r c982fe8a9f91 -r 00db9ec39831 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c Wed Nov 07 13:41:29 2007 +0000
+++ b/xen/arch/x86/domain.c Wed Nov 07 14:15:44 2007 +0000
@@ -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 *
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(st
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]) )
{
diff -r c982fe8a9f91 -r 00db9ec39831 xen/arch/x86/traps.c
--- a/xen/arch/x86/traps.c Wed Nov 07 13:41:29 2007 +0000
+++ b/xen/arch/x86/traps.c Wed Nov 07 14:15:44 2007 +0000
@@ -1797,7 +1797,8 @@ static int emulate_privileged_op(struct
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:
diff -r c982fe8a9f91 -r 00db9ec39831 xen/include/asm-x86/domain.h
--- a/xen/include/asm-x86/domain.h Wed Nov 07 13:41:29 2007 +0000
+++ b/xen/include/asm-x86/domain.h Wed Nov 07 14:15:44 2007 +0000
@@ -350,7 +350,14 @@ 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__ */
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|