aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir@xen.org>2010-11-09 20:42:20 +0000
committerKeir Fraser <keir@xen.org>2010-11-09 20:42:20 +0000
commit923ecbaa8faa1523edec2c6d585c683fc58748a8 (patch)
tree50b7042775815af64c7b3008ca8162171c1bf1b4
parentb62d7a084709c07b58264d0086c73105261a3303 (diff)
downloadxen-923ecbaa8faa1523edec2c6d585c683fc58748a8.tar.gz
xen-923ecbaa8faa1523edec2c6d585c683fc58748a8.tar.bz2
xen-923ecbaa8faa1523edec2c6d585c683fc58748a8.zip
x86 hvm: Fix MTRR physaddr-width check.
Should be checking against physaddr width presented to teh guest, rather than the host physaddr width. Signed-off-by: Keir Fraser <keir@xen.org> xen-unstable changeset: 22374:9997a1418633 xen-unstable date: Tue Nov 09 11:48:43 2010 +0000
-rw-r--r--xen/arch/x86/hvm/hvm.c2
-rw-r--r--xen/arch/x86/hvm/mtrr.c56
-rw-r--r--xen/include/asm-x86/mtrr.h5
3 files changed, 31 insertions, 32 deletions
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index bd33fc5449..6048380728 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -2120,7 +2120,7 @@ int hvm_msr_write_intercept(struct cpu_user_regs *regs)
case MSR_IA32_MTRR_PHYSBASE0...MSR_IA32_MTRR_PHYSMASK7:
if ( !mtrr )
goto gp_fault;
- if ( !mtrr_var_range_msr_set(&v->arch.hvm_vcpu.mtrr,
+ if ( !mtrr_var_range_msr_set(v->domain, &v->arch.hvm_vcpu.mtrr,
regs->ecx, msr_content) )
goto gp_fault;
break;
diff --git a/xen/arch/x86/hvm/mtrr.c b/xen/arch/x86/hvm/mtrr.c
index efdbe0aa8a..82815a01ea 100644
--- a/xen/arch/x86/hvm/mtrr.c
+++ b/xen/arch/x86/hvm/mtrr.c
@@ -30,10 +30,7 @@
extern struct mtrr_state mtrr_state;
-static uint64_t phys_base_msr_mask;
-static uint64_t phys_mask_msr_mask;
static uint32_t size_or_mask;
-static uint32_t size_and_mask;
/* Get page attribute fields (PAn) from PAT MSR. */
#define pat_cr_2_paf(pat_cr,n) ((((uint64_t)pat_cr) >> ((n)<<3)) & 0xff)
@@ -181,11 +178,7 @@ static int hvm_mtrr_pat_init(void)
if ( cpuid_eax(0x80000000) >= 0x80000008 )
phys_addr = (uint8_t)cpuid_eax(0x80000008);
- phys_base_msr_mask = ~((((uint64_t)1) << phys_addr) - 1) | 0xf00UL;
- phys_mask_msr_mask = ~((((uint64_t)1) << phys_addr) - 1) | 0x7ffUL;
-
size_or_mask = ~((1 << (phys_addr - PAGE_SHIFT)) - 1);
- size_and_mask = ~size_or_mask & 0xfff00000;
return 0;
}
@@ -482,34 +475,39 @@ bool_t mtrr_fix_range_msr_set(struct mtrr_state *m, uint32_t row,
return 1;
}
-bool_t mtrr_var_range_msr_set(struct mtrr_state *m, uint32_t msr,
- uint64_t msr_content)
+bool_t mtrr_var_range_msr_set(
+ struct domain *d, struct mtrr_state *m, uint32_t msr, uint64_t msr_content)
{
- uint32_t index;
+ uint32_t index, type, phys_addr, eax, ebx, ecx, edx;
uint64_t msr_mask;
uint64_t *var_range_base = (uint64_t*)m->var_ranges;
index = msr - MSR_IA32_MTRR_PHYSBASE0;
+ if ( var_range_base[index] == msr_content )
+ return 1;
- if ( var_range_base[index] != msr_content )
- {
- uint32_t type = msr_content & 0xff;
-
- msr_mask = (index & 1) ? phys_mask_msr_mask : phys_base_msr_mask;
-
- if ( unlikely(!(type == 0 || type == 1 ||
- type == 4 || type == 5 || type == 6)) )
- return 0;
-
- if ( unlikely(msr_content && (msr_content & msr_mask)) )
- {
- HVM_DBG_LOG(DBG_LEVEL_MSR, "invalid msr content:%"PRIx64"\n",
- msr_content);
- return 0;
- }
+ type = (uint8_t)msr_content;
+ if ( unlikely(!(type == 0 || type == 1 ||
+ type == 4 || type == 5 || type == 6)) )
+ return 0;
- var_range_base[index] = msr_content;
+ phys_addr = 36;
+ domain_cpuid(d, 0x80000000, 0, &eax, &ebx, &ecx, &edx);
+ if ( eax >= 0x80000008 )
+ {
+ domain_cpuid(d, 0x80000008, 0, &eax, &ebx, &ecx, &edx);
+ phys_addr = (uint8_t)eax;
}
+ msr_mask = ~((((uint64_t)1) << phys_addr) - 1);
+ msr_mask |= (index & 1) ? 0x7ffUL : 0xf00UL;
+ if ( unlikely(msr_content && (msr_content & msr_mask)) )
+ {
+ HVM_DBG_LOG(DBG_LEVEL_MSR, "invalid msr content:%"PRIx64"\n",
+ msr_content);
+ return 0;
+ }
+
+ var_range_base[index] = msr_content;
m->overlapped = is_var_mtrr_overlapped(m);
@@ -692,9 +690,9 @@ static int hvm_load_mtrr_msr(struct domain *d, hvm_domain_context_t *h)
for ( i = 0; i < MTRR_VCNT; i++ )
{
- mtrr_var_range_msr_set(mtrr_state,
+ mtrr_var_range_msr_set(d, mtrr_state,
MTRRphysBase_MSR(i), hw_mtrr.msr_mtrr_var[i*2]);
- mtrr_var_range_msr_set(mtrr_state,
+ mtrr_var_range_msr_set(d, mtrr_state,
MTRRphysMask_MSR(i), hw_mtrr.msr_mtrr_var[i*2+1]);
}
diff --git a/xen/include/asm-x86/mtrr.h b/xen/include/asm-x86/mtrr.h
index 0e9e47e227..b43b2925bc 100644
--- a/xen/include/asm-x86/mtrr.h
+++ b/xen/include/asm-x86/mtrr.h
@@ -76,8 +76,9 @@ extern void mtrr_aps_sync_begin(void);
extern void mtrr_aps_sync_end(void);
extern void mtrr_bp_restore(void);
-extern bool_t mtrr_var_range_msr_set(struct mtrr_state *v,
- uint32_t msr, uint64_t msr_content);
+extern bool_t mtrr_var_range_msr_set(
+ struct domain *d, struct mtrr_state *m,
+ uint32_t msr, uint64_t msr_content);
extern bool_t mtrr_fix_range_msr_set(struct mtrr_state *v,
uint32_t row, uint64_t msr_content);
extern bool_t mtrr_def_type_msr_set(struct mtrr_state *v, uint64_t msr_content);