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

[Xen-changelog] [xen-unstable] hvm/x86: MTRR/PAT virtualisation.



# HG changeset patch
# User Keir Fraser <keir@xxxxxxxxxxxxx>
# Date 1193059162 -3600
# Node ID 3e7c86602c70d2d587aafbef957d644f48cd6da9
# Parent  42d8dadb5864eac0140262b9475a7b1ed150b607
hvm/x86: MTRR/PAT virtualisation.
Signed-off-by: Disheng Su <disheng.su@xxxxxxxxx>
---
 xen/arch/x86/cpu/common.c         |    9 
 xen/arch/x86/cpu/mtrr/generic.c   |   16 
 xen/arch/x86/cpu/mtrr/main.c      |    7 
 xen/arch/x86/cpu/mtrr/mtrr.h      |   11 
 xen/arch/x86/hvm/Makefile         |    1 
 xen/arch/x86/hvm/hvm.c            |   88 ++++
 xen/arch/x86/hvm/mtrr.c           |  687 ++++++++++++++++++++++++++++++++++++++
 xen/arch/x86/hvm/vmx/vmcs.c       |   17 
 xen/arch/x86/hvm/vmx/vmx.c        |   70 +++
 xen/arch/x86/mm.c                 |    9 
 xen/arch/x86/mm/shadow/common.c   |    8 
 xen/arch/x86/mm/shadow/multi.c    |   28 +
 xen/include/asm-x86/cpufeature.h  |    2 
 xen/include/asm-x86/hvm/domain.h  |    6 
 xen/include/asm-x86/hvm/support.h |    1 
 xen/include/asm-x86/hvm/vcpu.h    |    7 
 xen/include/asm-x86/msr-index.h   |   19 +
 xen/include/asm-x86/mtrr.h        |   49 ++
 18 files changed, 999 insertions(+), 36 deletions(-)

diff -r 42d8dadb5864 -r 3e7c86602c70 xen/arch/x86/cpu/common.c
--- a/xen/arch/x86/cpu/common.c Mon Oct 22 13:04:32 2007 +0100
+++ b/xen/arch/x86/cpu/common.c Mon Oct 22 14:19:22 2007 +0100
@@ -22,6 +22,12 @@ static int disable_x86_serial_nr __devin
 static int disable_x86_serial_nr __devinitdata = 0;
 
 struct cpu_dev * cpu_devs[X86_VENDOR_NUM] = {};
+
+/*
+ * Default host IA32_CR_PAT value to cover all memory types.
+ * BIOS usually sets it to 0x07040600070406.
+ */
+u64 host_pat = 0x050100070406;
 
 static void default_init(struct cpuinfo_x86 * c)
 {
@@ -557,6 +563,9 @@ void __devinit cpu_init(void)
        }
        printk(KERN_INFO "Initializing CPU#%d\n", cpu);
 
+       if (cpu_has_pat)
+               wrmsrl(MSR_IA32_CR_PAT, host_pat);
+
        *(unsigned short *)(&gdt_load[0]) = LAST_RESERVED_GDT_BYTE;
        *(unsigned long  *)(&gdt_load[2]) = GDT_VIRT_START(current);
        asm volatile ( "lgdt %0" : "=m" (gdt_load) );
diff -r 42d8dadb5864 -r 3e7c86602c70 xen/arch/x86/cpu/mtrr/generic.c
--- a/xen/arch/x86/cpu/mtrr/generic.c   Mon Oct 22 13:04:32 2007 +0100
+++ b/xen/arch/x86/cpu/mtrr/generic.c   Mon Oct 22 14:19:22 2007 +0100
@@ -11,14 +11,6 @@
 #include <asm/cpufeature.h>
 #include "mtrr.h"
 
-struct mtrr_state {
-       struct mtrr_var_range *var_ranges;
-       mtrr_type fixed_ranges[NUM_FIXED_RANGES];
-       unsigned char enabled;
-       unsigned char have_fixed;
-       mtrr_type def_type;
-};
-
 struct fixed_range_block {
        int base_msr; /* start address of an MTRR block */
        int ranges;   /* number of MTRRs in this block  */
@@ -32,7 +24,7 @@ static struct fixed_range_block fixed_ra
 };
 
 static unsigned long smp_changes_mask;
-static struct mtrr_state mtrr_state = {};
+struct mtrr_state mtrr_state = {};
 
 /*  Get the MSR pair relating to a var range  */
 static void
@@ -88,6 +80,9 @@ void __init get_mtrr_state(void)
        rdmsr(MTRRdefType_MSR, lo, dummy);
        mtrr_state.def_type = (lo & 0xff);
        mtrr_state.enabled = (lo & 0xc00) >> 10;
+
+       /* Store mtrr_cap for HVM MTRR virtualisation. */
+       rdmsrl(MTRRcap_MSR, mtrr_state.mtrr_cap);
 }
 
 /*  Some BIOS's are fucked and don't set all MTRRs the same!  */
@@ -107,6 +102,7 @@ void __init mtrr_state_warn(void)
        printk(KERN_INFO "mtrr: corrected configuration.\n");
 }
 
+extern bool_t is_var_mtrr_overlapped(struct mtrr_state *m);
 /* Doesn't attempt to pass an error out to MTRR users
    because it's quite complicated in some cases and probably not
    worth it because the best error handling is to ignore it. */
@@ -116,6 +112,8 @@ void mtrr_wrmsr(unsigned msr, unsigned a
                printk(KERN_ERR
                        "MTRR: CPU %u: Writing MSR %x to %x:%x failed\n",
                        smp_processor_id(), msr, a, b);
+       /* Cache overlap status for efficient HVM MTRR virtualisation. */
+       mtrr_state.overlapped = is_var_mtrr_overlapped(&mtrr_state);
 }
 
 /**
diff -r 42d8dadb5864 -r 3e7c86602c70 xen/arch/x86/cpu/mtrr/main.c
--- a/xen/arch/x86/cpu/mtrr/main.c      Mon Oct 22 13:04:32 2007 +0100
+++ b/xen/arch/x86/cpu/mtrr/main.c      Mon Oct 22 14:19:22 2007 +0100
@@ -588,6 +588,8 @@ struct mtrr_value {
        unsigned long   lsize;
 };
 
+extern void global_init_mtrr_pat(void);
+
 /**
  * mtrr_bp_init - initialize mtrrs on the boot CPU
  *
@@ -654,8 +656,11 @@ void __init mtrr_bp_init(void)
        if (mtrr_if) {
                set_num_var_ranges();
                init_table();
-               if (use_intel())
+               if (use_intel()) {
                        get_mtrr_state();
+                       /* initialize some global data for MTRR/PAT 
virutalization */
+                       global_init_mtrr_pat();
+               }
        }
 }
 
diff -r 42d8dadb5864 -r 3e7c86602c70 xen/arch/x86/cpu/mtrr/mtrr.h
--- a/xen/arch/x86/cpu/mtrr/mtrr.h      Mon Oct 22 13:04:32 2007 +0100
+++ b/xen/arch/x86/cpu/mtrr/mtrr.h      Mon Oct 22 14:19:22 2007 +0100
@@ -13,7 +13,6 @@
 #define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
 #define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
 
-#define NUM_FIXED_RANGES 88
 #define MTRRfix64K_00000_MSR 0x250
 #define MTRRfix16K_80000_MSR 0x258
 #define MTRRfix16K_A0000_MSR 0x259
@@ -30,9 +29,6 @@
 #define MTRR_CHANGE_MASK_VARIABLE  0x02
 #define MTRR_CHANGE_MASK_DEFTYPE   0x04
 
-/* In the Intel processor's MTRR interface, the MTRR type is always held in
-   an 8 bit field: */
-typedef u8 mtrr_type;
 
 struct mtrr_ops {
        u32     vendor;
@@ -69,13 +65,6 @@ struct set_mtrr_context {
        u32 ccr3;
 };
 
-struct mtrr_var_range {
-       u32 base_lo;
-       u32 base_hi;
-       u32 mask_lo;
-       u32 mask_hi;
-};
-
 void set_mtrr_done(struct set_mtrr_context *ctxt);
 void set_mtrr_cache_disable(struct set_mtrr_context *ctxt);
 void set_mtrr_prepare_save(struct set_mtrr_context *ctxt);
diff -r 42d8dadb5864 -r 3e7c86602c70 xen/arch/x86/hvm/Makefile
--- a/xen/arch/x86/hvm/Makefile Mon Oct 22 13:04:32 2007 +0100
+++ b/xen/arch/x86/hvm/Makefile Mon Oct 22 14:19:22 2007 +0100
@@ -7,6 +7,7 @@ obj-y += intercept.o
 obj-y += intercept.o
 obj-y += io.o
 obj-y += irq.o
+obj-y += mtrr.o
 obj-y += platform.o
 obj-y += pmtimer.o
 obj-y += rtc.o
diff -r 42d8dadb5864 -r 3e7c86602c70 xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c    Mon Oct 22 13:04:32 2007 +0100
+++ b/xen/arch/x86/hvm/hvm.c    Mon Oct 22 14:19:22 2007 +0100
@@ -226,6 +226,7 @@ int hvm_domain_initialise(struct domain 
 
     spin_lock_init(&d->arch.hvm_domain.pbuf_lock);
     spin_lock_init(&d->arch.hvm_domain.irq_lock);
+    spin_lock_init(&d->arch.hvm_domain.uc_lock);
 
     rc = paging_enable(d, PG_refcounts|PG_translate|PG_external);
     if ( rc != 0 )
@@ -417,27 +418,22 @@ HVM_REGISTER_SAVE_RESTORE(CPU, hvm_save_
 HVM_REGISTER_SAVE_RESTORE(CPU, hvm_save_cpu_ctxt, hvm_load_cpu_ctxt,
                           1, HVMSR_PER_VCPU);
 
+extern int reset_vmsr(struct mtrr_state *m, u64 *p);
+
 int hvm_vcpu_initialise(struct vcpu *v)
 {
     int rc;
 
     if ( (rc = vlapic_init(v)) != 0 )
-        return rc;
+        goto fail1;
 
     if ( (rc = hvm_funcs.vcpu_initialise(v)) != 0 )
-    {
-        vlapic_destroy(v);
-        return rc;
-    }
+        goto fail2;
 
     /* Create ioreq event channel. */
     rc = alloc_unbound_xen_event_channel(v, 0);
     if ( rc < 0 )
-    {
-        hvm_funcs.vcpu_destroy(v);
-        vlapic_destroy(v);
-        return rc;
-    }
+        goto fail3;
 
     /* Register ioreq event channel. */
     v->arch.hvm_vcpu.xen_port = rc;
@@ -448,6 +444,10 @@ int hvm_vcpu_initialise(struct vcpu *v)
 
     spin_lock_init(&v->arch.hvm_vcpu.tm_lock);
     INIT_LIST_HEAD(&v->arch.hvm_vcpu.tm_list);
+
+    rc = reset_vmsr(&v->arch.hvm_vcpu.mtrr, &v->arch.hvm_vcpu.pat_cr);
+    if ( rc != 0 )
+        goto fail3;
 
     v->arch.guest_context.user_regs.eflags = 2;
 
@@ -468,6 +468,13 @@ int hvm_vcpu_initialise(struct vcpu *v)
     }
 
     return 0;
+
+ fail3:
+    hvm_funcs.vcpu_destroy(v);
+ fail2:
+    vlapic_destroy(v);
+ fail1:
+    return rc;
 }
 
 void hvm_vcpu_destroy(struct vcpu *v)
@@ -604,6 +611,32 @@ int hvm_set_efer(uint64_t value)
     hvm_update_guest_efer(v);
 
     return 1;
+}
+
+extern void shadow_blow_tables_per_domain(struct domain *d);
+extern bool_t mtrr_pat_not_equal(struct vcpu *vd, struct vcpu *vs);
+
+/* Exit UC mode only if all VCPUs agree on MTRR/PAT and are not in no_fill. */
+static bool_t domain_exit_uc_mode(struct vcpu *v)
+{
+    struct domain *d = v->domain;
+    struct vcpu *vs;
+
+    for_each_vcpu ( d, vs )
+    {
+        if ( (vs == v) || !vs->is_initialised )
+            continue;
+        if ( (vs->arch.hvm_vcpu.cache_mode == NO_FILL_CACHE_MODE) ||
+             mtrr_pat_not_equal(vs, v) )
+            return 0;
+    }
+
+    return 1;
+}
+
+static void local_flush_cache(void *info)
+{
+    wbinvd();
 }
 
 int hvm_set_cr0(unsigned long value)
@@ -683,6 +716,41 @@ int hvm_set_cr0(unsigned long value)
         {
             put_page(pagetable_get_page(v->arch.guest_table));
             v->arch.guest_table = pagetable_null();
+        }
+    }
+
+    if ( !list_empty(&(domain_hvm_iommu(v->domain)->pdev_list)) )
+    {
+        if ( (value & X86_CR0_CD) && !(value & X86_CR0_NW) )
+        {
+            /* Entering no fill cache mode. */
+            spin_lock(&v->domain->arch.hvm_domain.uc_lock);
+            v->arch.hvm_vcpu.cache_mode = NO_FILL_CACHE_MODE;
+
+            if ( !v->domain->arch.hvm_domain.is_in_uc_mode )
+            {
+                /* Flush physical caches. */
+                on_each_cpu(local_flush_cache, NULL, 1, 1);
+                /* Shadow pagetables must recognise UC mode. */
+                v->domain->arch.hvm_domain.is_in_uc_mode = 1;
+                shadow_blow_tables_per_domain(v->domain);
+            }
+            spin_unlock(&v->domain->arch.hvm_domain.uc_lock);
+        }
+        else if ( !(value & (X86_CR0_CD | X86_CR0_NW)) &&
+                  (v->arch.hvm_vcpu.cache_mode == NO_FILL_CACHE_MODE) )
+        {
+            /* Exit from no fill cache mode. */
+            spin_lock(&v->domain->arch.hvm_domain.uc_lock);
+            v->arch.hvm_vcpu.cache_mode = NORMAL_CACHE_MODE;
+
+            if ( domain_exit_uc_mode(v) )
+            {
+                /* Shadow pagetables must recognise normal caching mode. */
+                v->domain->arch.hvm_domain.is_in_uc_mode = 0;
+                shadow_blow_tables_per_domain(v->domain);
+            }
+            spin_unlock(&v->domain->arch.hvm_domain.uc_lock);
         }
     }
 
diff -r 42d8dadb5864 -r 3e7c86602c70 xen/arch/x86/hvm/mtrr.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/x86/hvm/mtrr.c   Mon Oct 22 14:19:22 2007 +0100
@@ -0,0 +1,687 @@
+/*
+ * mtrr.c: MTRR/PAT virtualization
+ *
+ * Copyright (c) 2007, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <public/hvm/e820.h>
+#include <xen/types.h>
+#include <asm/e820.h>
+#include <asm/paging.h>
+#include <asm/p2m.h>
+#include <xen/domain_page.h>
+#include <stdbool.h>
+#include <asm/mtrr.h>
+#include <asm/hvm/support.h>
+
+/* Xen holds the native MTRR MSRs */
+extern struct mtrr_state mtrr_state;
+
+static u64 phys_base_msr_mask;
+static u64 phys_mask_msr_mask;
+static u32 size_or_mask;
+static u32 size_and_mask;
+
+static void init_pat_entry_tbl(u64 pat);
+static void init_mtrr_epat_tbl(void);
+static unsigned char get_mtrr_type(struct mtrr_state *m, paddr_t pa);
+/* get page attribute fields (PAn) from PAT MSR */
+#define pat_cr_2_paf(pat_cr,n)  ((((u64)pat_cr) >> ((n)<<3)) & 0xff)
+/* pat entry to PTE flags (PAT, PCD, PWT bits) */
+static unsigned char pat_entry_2_pte_flags[8] = {
+    0,           _PAGE_PWT,
+    _PAGE_PCD,   _PAGE_PCD | _PAGE_PWT,
+    _PAGE_PAT,   _PAGE_PAT | _PAGE_PWT,
+    _PAGE_PAT | _PAGE_PCD, _PAGE_PAT | _PAGE_PCD | _PAGE_PWT };
+
+/* effective mm type lookup table, according to MTRR and PAT */
+static u8 mm_type_tbl[MTRR_NUM_TYPES][PAT_TYPE_NUMS] = {
+/********PAT(UC,WC,RS,RS,WT,WP,WB,UC-)*/
+/* RS means reserved type(2,3), and type is hardcoded here */
+ /*MTRR(UC):(UC,WC,RS,RS,UC,UC,UC,UC)*/
+            {0, 1, 2, 2, 0, 0, 0, 0},
+ /*MTRR(WC):(UC,WC,RS,RS,UC,UC,WC,WC)*/
+            {0, 1, 2, 2, 0, 0, 1, 1},
+ /*MTRR(RS):(RS,RS,RS,RS,RS,RS,RS,RS)*/
+            {2, 2, 2, 2, 2, 2, 2, 2},
+ /*MTRR(RS):(RS,RS,RS,RS,RS,RS,RS,RS)*/
+            {2, 2, 2, 2, 2, 2, 2, 2},
+ /*MTRR(WT):(UC,WC,RS,RS,WT,WP,WT,UC)*/
+            {0, 1, 2, 2, 4, 5, 4, 0},
+ /*MTRR(WP):(UC,WC,RS,RS,WT,WP,WP,WC)*/
+            {0, 1, 2, 2, 4, 5, 5, 1},
+ /*MTRR(WB):(UC,WC,RS,RS,WT,WP,WB,UC)*/
+            {0, 1, 2, 2, 4, 5, 6, 0}
+};
+
+/* reverse lookup table, to find a pat type according to MTRR and effective
+ * memory type. This table is dynamically generated
+ */
+static u8 mtrr_epat_tbl[MTRR_NUM_TYPES][MEMORY_NUM_TYPES];
+
+/* lookup table for PAT entry of a given PAT value in host pat */
+static u8 pat_entry_tbl[PAT_TYPE_NUMS];
+
+static void get_mtrr_range(uint64_t base_msr, uint64_t mask_msr,
+                           uint64_t *base, uint64_t *end)
+{
+    uint32_t mask_lo = (uint32_t)mask_msr;
+    uint32_t mask_hi = (uint32_t)(mask_msr >> 32);
+    uint32_t base_lo = (uint32_t)base_msr;
+    uint32_t base_hi = (uint32_t)(base_msr >> 32);
+    uint32_t size;
+
+    if ( (mask_lo & 0x800) == 0 )
+    {
+        /* Invalid (i.e. free) range */
+        *base = 0;
+        *end = 0;
+        return;
+    }
+
+    /* Work out the shifted address mask. */
+    mask_lo = (size_or_mask | (mask_hi << (32 - PAGE_SHIFT)) |
+               (mask_lo >> PAGE_SHIFT));
+
+    /* This works correctly if size is a power of two (a contiguous range). */
+    size = -mask_lo;
+    *base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT;
+    *end = *base + size - 1;
+}
+
+bool_t is_var_mtrr_overlapped(struct mtrr_state *m)
+{
+    int seg, i;
+    uint64_t phys_base, phys_mask, phys_base_pre, phys_mask_pre;
+    uint64_t base_pre, end_pre, base, end;
+    uint8_t num_var_ranges = (u8)m->mtrr_cap;
+
+    for ( i = 0; i < num_var_ranges; i++ )
+    {
+        phys_base_pre = ((u64*)m->var_ranges)[i*2];
+        phys_mask_pre = ((u64*)m->var_ranges)[i*2 + 1];
+
+        get_mtrr_range(phys_base_pre, phys_mask_pre,
+                        &base_pre, &end_pre);
+
+        for ( seg = i + 1; seg < num_var_ranges; seg ++ )
+        {
+            phys_base = ((u64*)m->var_ranges)[seg*2];
+            phys_mask = ((u64*)m->var_ranges)[seg*2 + 1];
+
+            get_mtrr_range(phys_base, phys_mask,
+                            &base, &end);
+
+            if ( ((base_pre != end_pre) && (base != end))
+                 || ((base >= base_pre) && (base <= end_pre))
+                 || ((end >= base_pre) && (end <= end_pre))
+                 || ((base_pre >= base) && (base_pre <= end))
+                 || ((end_pre >= base) && (end_pre <= end)) )
+            {
+                /* MTRR is overlapped. */
+                return 1;
+            }
+        }
+    }
+    return 0;
+}
+
+/* reserved mtrr for guest OS */
+#define RESERVED_MTRR 2
+#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
+#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
+bool mtrr_var_range_msr_set(struct mtrr_state *m, u32 msr, u64 msr_content);
+bool mtrr_def_type_msr_set(struct mtrr_state *m, u64 msr_content);
+bool mtrr_fix_range_msr_set(struct mtrr_state *m, int row, u64 msr_content);
+static void set_var_mtrr(unsigned int reg, struct mtrr_state *m,
+                    unsigned int base, unsigned int size,
+                    unsigned int type)
+{
+    struct mtrr_var_range *vr;
+
+    vr = &m->var_ranges[reg];
+
+    if ( size == 0 )
+    {
+        /* The invalid bit is kept in the mask, so we simply clear the
+         * relevant mask register to disable a range.
+         */
+        mtrr_var_range_msr_set(m, MTRRphysMask_MSR(reg), 0);
+    }
+    else
+    {
+        vr->base_lo = base << PAGE_SHIFT | type;
+        vr->base_hi = (base & size_and_mask) >> (32 - PAGE_SHIFT);
+        vr->mask_lo = -size << PAGE_SHIFT | 0x800;
+        vr->mask_hi = (-size & size_and_mask) >> (32 - PAGE_SHIFT);
+
+        mtrr_var_range_msr_set(m, MTRRphysBase_MSR(reg), *(unsigned long *)vr);
+        mtrr_var_range_msr_set(m, MTRRphysMask_MSR(reg),
+                               *((unsigned long *)vr + 1));
+    }
+}
+/* From Intel Vol. III Section 10.11.4, the Range Size and Base Alignment has
+ * some kind of requirement:
+ * 1. The range size must be 2^N byte for N >= 12 (i.e 4KB minimum).
+ * 2. The base address must be 2^N aligned, where the N here is equal to
+ * the N in previous requirement. So a 8K range must be 8K aligned not 4K 
aligned.
+ */
+static unsigned int range_to_mtrr(unsigned int reg, struct mtrr_state *m,
+    unsigned int range_startk, unsigned int range_sizek, unsigned char type)
+{
+    if ( !range_sizek || (reg >= ((m->mtrr_cap & 0xff) - RESERVED_MTRR)) )
+        return reg;
+
+    while ( range_sizek )
+    {
+        unsigned int max_align, align, sizek;
+
+        max_align = (range_startk == 0) ? 32 : ffs(range_startk);
+        align = min_t(unsigned int, fls(range_sizek), max_align);
+        sizek = 1 << (align - 1);
+
+        set_var_mtrr(reg++, m, range_startk, sizek, type);
+
+        range_startk += sizek;
+        range_sizek  -= sizek;
+
+        if ( reg >= ((m->mtrr_cap & 0xff) - RESERVED_MTRR) )
+            break;
+    }
+
+    return reg;
+}
+
+static void setup_fixed_mtrrs(struct vcpu *v)
+{
+    uint64_t content;
+    int i;
+    struct mtrr_state *m = &v->arch.hvm_vcpu.mtrr;
+
+    /* 1. Map (0~A0000) as WB */
+    content = 0x0606060606060606ull;
+    mtrr_fix_range_msr_set(m, 0, content);
+    mtrr_fix_range_msr_set(m, 1, content);
+    /* 2. Map VRAM(A0000~C0000) as WC */
+    content = 0x0101010101010101;
+    mtrr_fix_range_msr_set(m, 2, content);
+    /* 3. Map (C0000~100000) as UC */
+    for ( i = 3; i < 11; i++)
+        mtrr_fix_range_msr_set(m, i, 0);
+}
+
+static void setup_var_mtrrs(struct vcpu *v)
+{
+    p2m_type_t p2m;
+    unsigned long e820_mfn;
+    char *p = NULL;
+    unsigned char nr = 0;
+    int i;
+    unsigned int reg = 0;
+    unsigned long size = 0;
+    unsigned long addr = 0;
+    struct e820entry *e820_table;
+
+    e820_mfn = mfn_x(gfn_to_mfn(v->domain,
+                    HVM_E820_PAGE >> PAGE_SHIFT, &p2m));
+
+    p = (char *)map_domain_page(e820_mfn);
+
+    nr = *(unsigned char*)(p + HVM_E820_NR_OFFSET);
+    e820_table = (struct e820entry*)(p + HVM_E820_OFFSET);
+    /* search E820 table, set MTRR for RAM */
+    for ( i = 0; i < nr; i++)
+    {
+        if ( (e820_table[i].addr >= 0x100000) &&
+             (e820_table[i].type == E820_RAM) )
+        {
+            if ( e820_table[i].addr == 0x100000 )
+            {
+                size = e820_table[i].size + 0x100000 + PAGE_SIZE * 3;
+                addr = 0;
+            }
+            else
+            {
+                /* Larger than 4G */
+                size = e820_table[i].size;
+                addr = e820_table[i].addr;
+            }
+
+            reg = range_to_mtrr(reg, &v->arch.hvm_vcpu.mtrr,
+                                addr >> PAGE_SHIFT, size >> PAGE_SHIFT,
+                                MTRR_TYPE_WRBACK);
+        }
+    }
+}
+
+void init_mtrr_in_hyper(struct vcpu *v)
+{
+    /* TODO:MTRR should be initialized in BIOS or other places.
+     * workaround to do it in here
+     */
+    if ( v->arch.hvm_vcpu.mtrr.is_initialized )
+        return;
+
+    setup_fixed_mtrrs(v);
+    setup_var_mtrrs(v);
+    /* enable mtrr */
+    mtrr_def_type_msr_set(&v->arch.hvm_vcpu.mtrr, 0xc00);
+
+    v->arch.hvm_vcpu.mtrr.is_initialized = 1;
+}
+
+static int reset_mtrr(struct mtrr_state *m)
+{
+    m->var_ranges = xmalloc_array(struct mtrr_var_range, MTRR_VCNT);
+    if ( m->var_ranges == NULL )
+        return -ENOMEM;
+    memset(m->var_ranges, 0, MTRR_VCNT * sizeof(struct mtrr_var_range));
+    memset(m->fixed_ranges, 0, sizeof(m->fixed_ranges));
+    m->enabled = 0;
+    m->def_type = 0;/*mtrr is disabled*/
+    m->mtrr_cap = (0x5<<8)|MTRR_VCNT;/*wc,fix enabled, and vcnt=8*/
+    m->overlapped = 0;
+    return 0;
+}
+
+/* init global variables for MTRR and PAT */
+void global_init_mtrr_pat(void)
+{
+    extern u64 host_pat;
+    u32 phys_addr;
+
+    init_mtrr_epat_tbl();
+    init_pat_entry_tbl(host_pat);
+    /* Get max physical address, set some global variable */
+    if ( cpuid_eax(0x80000000) < 0x80000008 )
+        phys_addr = 36;
+    else
+        phys_addr = cpuid_eax(0x80000008);
+
+    phys_base_msr_mask = ~((((u64)1) << phys_addr) - 1) | 0xf00UL;
+    phys_mask_msr_mask = ~((((u64)1) << phys_addr) - 1) | 0x7ffUL;
+
+    size_or_mask = ~((1 << (phys_addr - PAGE_SHIFT)) - 1);
+    size_and_mask = ~size_or_mask & 0xfff00000;
+}
+
+static void init_pat_entry_tbl(u64 pat)
+{
+    int i, j;
+
+    memset(&pat_entry_tbl, INVALID_MEM_TYPE,
+           PAT_TYPE_NUMS * sizeof(pat_entry_tbl[0]));
+
+    for ( i = 0; i < PAT_TYPE_NUMS; i++ )
+    {
+        for ( j = 0; j < PAT_TYPE_NUMS; j++ )
+        {
+            if ( pat_cr_2_paf(pat, j) == i )
+            {
+                pat_entry_tbl[i] = j;
+                break;
+            }
+        }
+    }
+}
+
+unsigned char pat_type_2_pte_flags(unsigned char pat_type)
+{
+    int pat_entry = pat_entry_tbl[pat_type];
+
+    /* INVALID_MEM_TYPE, means doesn't find the pat_entry in host pat for
+     * a given pat_type. If host pat covers all the pat types,
+     * it can't happen.
+     */
+    if ( likely(pat_entry != INVALID_MEM_TYPE) )
+        return pat_entry_2_pte_flags[pat_entry];
+
+    return pat_entry_2_pte_flags[pat_entry_tbl[PAT_TYPE_UNCACHABLE]];
+}
+
+int reset_vmsr(struct mtrr_state *m, u64 *pat_ptr)
+{
+    int rc;
+
+    rc = reset_mtrr(m);
+    if ( rc != 0 )
+        return rc;
+
+    *pat_ptr = ( (u64)PAT_TYPE_WRBACK) |                /* PAT0: WB */
+        ( (u64)PAT_TYPE_WRTHROUGH << 8 ) |              /* PAT1: WT */
+        ( (u64)PAT_TYPE_UC_MINUS << 16 ) |              /* PAT2: UC- */
+        ( (u64)PAT_TYPE_UNCACHABLE << 24 ) |            /* PAT3: UC */
+        ( (u64)PAT_TYPE_WRBACK << 32 ) |                /* PAT4: WB */
+        ( (u64)PAT_TYPE_WRTHROUGH << 40 ) |             /* PAT5: WT */
+        ( (u64)PAT_TYPE_UC_MINUS << 48 ) |              /* PAT6: UC- */
+        ( (u64)PAT_TYPE_UNCACHABLE << 56 );             /* PAT7: UC */
+
+    return 0;
+}
+
+/*
+ * Get MTRR memory type for physical address pa.
+ */
+static unsigned char get_mtrr_type(struct mtrr_state *m, paddr_t pa)
+{
+   int    addr, seg, index;
+   u8     overlap_mtrr = 0;
+   u8     overlap_mtrr_pos = 0;
+   u64    phys_base;
+   u64    phys_mask;
+   u8     num_var_ranges = m->mtrr_cap & 0xff;
+
+   if ( unlikely(!(m->enabled & 0x2)) )
+       return MTRR_TYPE_UNCACHABLE;
+
+   if ( (pa < 0x100000) && (m->enabled & 1) )
+   {
+       /* Fixed range MTRR takes effective */
+       addr = (unsigned int) pa;
+       if ( addr < 0x80000 )
+       {
+           seg = (addr >> 16);
+           return m->fixed_ranges[seg];
+       }
+       else if ( addr < 0xc0000 )
+       {
+           seg = (addr - 0x80000) >> 14;
+           index = (seg >> 3) + 1;
+           seg &= 7;            /* select 0-7 segments */
+           return m->fixed_ranges[index*8 + seg];
+       }
+       else
+       {
+           /* 0xC0000 --- 0x100000 */
+           seg = (addr - 0xc0000) >> 12;
+           index = (seg >> 3) + 3;
+           seg &= 7;            /* select 0-7 segments */
+           return m->fixed_ranges[index*8 + seg];
+       }
+   }
+
+   /* Match with variable MTRRs. */
+   for ( seg = 0; seg < num_var_ranges; seg++ )
+   {
+       phys_base = ((u64*)m->var_ranges)[seg*2];
+       phys_mask = ((u64*)m->var_ranges)[seg*2 + 1];
+       if ( phys_mask & (1 << MTRR_PHYSMASK_VALID_BIT) )
+       {
+           if ( ((u64) pa & phys_mask) >> MTRR_PHYSMASK_SHIFT ==
+                (phys_base & phys_mask) >> MTRR_PHYSMASK_SHIFT )
+           {
+               if ( unlikely(m->overlapped) )
+               {
+                    overlap_mtrr |= 1 << (phys_base & MTRR_PHYSBASE_TYPE_MASK);
+                    overlap_mtrr_pos = phys_base & MTRR_PHYSBASE_TYPE_MASK;
+               }
+               else
+               {
+                   /* If no overlap, return the found one */
+                   return (phys_base & MTRR_PHYSBASE_TYPE_MASK);
+               }
+           }
+       }
+   }
+
+   /* Overlapped or not found. */
+   if ( unlikely(overlap_mtrr == 0) )
+       return m->def_type;
+
+   if ( likely(!(overlap_mtrr & ~( ((u8)1) << overlap_mtrr_pos ))) )
+       /* Covers both one variable memory range matches and
+        * two or more identical match.
+        */
+       return overlap_mtrr_pos;
+
+   if ( overlap_mtrr & 0x1 )
+       /* Two or more match, one is UC. */
+       return MTRR_TYPE_UNCACHABLE;
+   
+   if ( !(overlap_mtrr & 0xaf) )
+       /* Two or more match, WT and WB. */
+       return MTRR_TYPE_WRTHROUGH;
+
+   /* Behaviour is undefined, but return the last overlapped type. */
+   return overlap_mtrr_pos;
+}
+
+/*
+ * return the memory type from PAT.
+ * NOTE: valid only when paging is enabled.
+ *       Only 4K page PTE is supported now.
+ */
+static unsigned char page_pat_type(u64 pat_cr, unsigned long pte_flags)
+{
+    int pat_entry;
+
+    /* PCD/PWT -> bit 1/0 of PAT entry */
+    pat_entry = ( pte_flags >> 3 ) & 0x3;
+    /* PAT bits as bit 2 of PAT entry */
+    if ( pte_flags & _PAGE_PAT )
+        pat_entry |= 4;
+
+    return (unsigned char)pat_cr_2_paf(pat_cr, pat_entry);
+}
+
+/*
+ * Effective memory type for leaf page.
+ */
+static u8 effective_mm_type(
+        struct mtrr_state *m,
+        u64 pat,
+        paddr_t gpa,
+        unsigned long pte_flags)
+{
+    unsigned char mtrr_mtype, pat_value, effective;
+
+    mtrr_mtype = get_mtrr_type(m, gpa);
+
+    pat_value = page_pat_type(pat, pte_flags);
+
+    effective = mm_type_tbl[mtrr_mtype][pat_value];
+
+    return effective;
+}
+
+static void init_mtrr_epat_tbl(void)
+{
+    int i, j;
+    /* set default value to an invalid type, just for checking conflict */
+    memset(&mtrr_epat_tbl, INVALID_MEM_TYPE, sizeof(mtrr_epat_tbl));
+
+    for ( i = 0; i < MTRR_NUM_TYPES; i++ )
+    {
+        for ( j = 0; j < PAT_TYPE_NUMS; j++ )
+        {
+            int tmp = mm_type_tbl[i][j];
+            if ( (tmp >= 0) && (tmp < MEMORY_NUM_TYPES) )
+                mtrr_epat_tbl[i][tmp] = j;
+        }
+    }
+}
+
+u32 get_pat_flags(struct vcpu *v,
+                  u32 gl1e_flags,
+                  paddr_t gpaddr,
+                  paddr_t spaddr)
+{
+    u8 guest_eff_mm_type;
+    u8 shadow_mtrr_type;
+    u8 pat_entry_value;
+    u64 pat = v->arch.hvm_vcpu.pat_cr;
+    struct mtrr_state *g = &v->arch.hvm_vcpu.mtrr;
+
+    /* 1. Get the effective memory type of guest physical address,
+     * with the pair of guest MTRR and PAT
+     */
+    guest_eff_mm_type = effective_mm_type(g, pat, gpaddr, gl1e_flags);
+    /* 2. Get the memory type of host physical address, with MTRR */
+    shadow_mtrr_type = get_mtrr_type(&mtrr_state, spaddr);
+
+    /* 3. Find the memory type in PAT, with host MTRR memory type
+     * and guest effective memory type.
+     */
+    pat_entry_value = mtrr_epat_tbl[shadow_mtrr_type][guest_eff_mm_type];
+    /* If conflit occurs(e.g host MTRR is UC, guest memory type is
+     * WB),set UC as effective memory. Here, returning PAT_TYPE_UNCACHABLE will
+     * always set effective memory as UC.
+     */
+    if ( pat_entry_value == INVALID_MEM_TYPE )
+    {
+        gdprintk(XENLOG_WARNING,
+                 "Conflict occurs for a given guest l1e flags:%x "
+                 "at %"PRIx64" (the effective mm type:%d), "
+                 "because the host mtrr type is:%d\n",
+                 gl1e_flags, (uint64_t)gpaddr, guest_eff_mm_type,
+                 shadow_mtrr_type);
+        pat_entry_value = PAT_TYPE_UNCACHABLE;
+    }
+    /* 4. Get the pte flags */
+    return pat_type_2_pte_flags(pat_entry_value);
+}
+
+/* Helper funtions for seting mtrr/pat */
+bool pat_msr_set(u64 *pat, u64 msr_content)
+{
+    u8 *value = (u8*)&msr_content;
+    int i;
+
+    if ( *pat != msr_content )
+    {
+        for ( i = 0; i < 8; i++ )
+            if ( unlikely(!(value[i] == 0 || value[i] == 1 ||
+                            value[i] == 4 || value[i] == 5 ||
+                            value[i] == 6 || value[i] == 7)) )
+                return 0;
+
+        *pat = msr_content;
+    }
+
+    return 1;
+}
+
+bool mtrr_def_type_msr_set(struct mtrr_state *m, u64 msr_content)
+{
+    u8 def_type = msr_content & 0xff;
+    u8 enabled = (msr_content >> 10) & 0x3;
+
+    if ( unlikely(!(def_type == 0 || def_type == 1 || def_type == 4 ||
+                    def_type == 5 || def_type == 6)) )
+    {
+         HVM_DBG_LOG(DBG_LEVEL_MSR, "invalid MTRR def type:%x\n", def_type);
+         return 0;
+    }
+
+    if ( unlikely(msr_content && (msr_content & ~0xcffUL)) )
+    {
+         HVM_DBG_LOG(DBG_LEVEL_MSR, "invalid msr content:%"PRIx64"\n",
+                     msr_content);
+         return 0;
+    }
+
+    m->enabled = enabled;
+    m->def_type = def_type;
+
+    return 1;
+}
+
+bool mtrr_fix_range_msr_set(struct mtrr_state *m, int row, u64 msr_content)
+{
+    u64 *fixed_range_base = (u64 *)m->fixed_ranges;
+
+    if ( fixed_range_base[row] != msr_content )
+    {
+        u8 *range = (u8*)&msr_content;
+        int i, type;
+
+        for ( i = 0; i < 8; i++ )
+        {
+            type = range[i];
+            if ( unlikely(!(type == 0 || type == 1 ||
+                            type == 4 || type == 5 || type == 6)) )
+                return 0;
+        }
+
+        fixed_range_base[row] = msr_content;
+    }
+
+    return 1;
+}
+
+bool mtrr_var_range_msr_set(struct mtrr_state *m, u32 msr, u64 msr_content)
+{
+    u32 index;
+    u64 msr_mask;
+    u64 *var_range_base = (u64*)m->var_ranges;
+
+    index = msr - MSR_IA32_MTRR_PHYSBASE0;
+
+    if ( var_range_base[index] != msr_content )
+    {
+        u32 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;
+        }
+
+        var_range_base[index] = msr_content;
+    }
+
+    m->overlapped = is_var_mtrr_overlapped(m);
+
+    return 1;
+}
+
+bool_t mtrr_pat_not_equal(struct vcpu *vd, struct vcpu *vs)
+{
+    struct mtrr_state *md = &vd->arch.hvm_vcpu.mtrr;
+    struct mtrr_state *ms = &vs->arch.hvm_vcpu.mtrr;
+    int res;
+    u8 num_var_ranges = (u8)md->mtrr_cap;
+
+    /* Test fixed ranges. */
+    res = memcmp(md->fixed_ranges, ms->fixed_ranges,
+            NUM_FIXED_RANGES*sizeof(mtrr_type));
+    if ( res )
+        return 1;
+
+    /* Test var ranges. */
+    res = memcmp(md->var_ranges, ms->var_ranges,
+            num_var_ranges*sizeof(struct mtrr_var_range));
+    if ( res )
+        return 1;
+
+    /* Test default type MSR. */
+    if ( (md->def_type != ms->def_type)
+            && (md->enabled != ms->enabled) )
+        return 1;
+
+    /* Test PAT. */
+    if ( vd->arch.hvm_vcpu.pat_cr != vs->arch.hvm_vcpu.pat_cr )
+        return 1;
+
+    return 0;
+}
diff -r 42d8dadb5864 -r 3e7c86602c70 xen/arch/x86/hvm/vmx/vmcs.c
--- a/xen/arch/x86/hvm/vmx/vmcs.c       Mon Oct 22 13:04:32 2007 +0100
+++ b/xen/arch/x86/hvm/vmx/vmcs.c       Mon Oct 22 14:19:22 2007 +0100
@@ -756,6 +756,11 @@ void vm_resume_fail(unsigned long eflags
     domain_crash_synchronous();
 }
 
+static void flush_cache(void *info)
+{
+    wbinvd();
+}
+
 void vmx_do_resume(struct vcpu *v)
 {
     bool_t debug_state;
@@ -767,6 +772,18 @@ void vmx_do_resume(struct vcpu *v)
     }
     else
     {
+        /* For pass-through domain, guest PCI-E device driver may leverage the
+         * "Non-Snoop" I/O, and explicitly "WBINVD" or "CFLUSH" to a RAM space.
+         * In that case, if migration occurs before "WBINVD" or "CFLUSH", need
+         * to maintain data consistency.
+         */
+        if ( !list_empty(&(domain_hvm_iommu(v->domain)->pdev_list)) )
+        {
+            int cpu = v->arch.hvm_vmx.active_cpu;
+            if ( cpu != -1 )
+                on_selected_cpus(cpumask_of_cpu(cpu), flush_cache, NULL, 1, 1);
+        }
+
         vmx_clear_vmcs(v);
         vmx_load_vmcs(v);
         hvm_migrate_timers(v);
diff -r 42d8dadb5864 -r 3e7c86602c70 xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c        Mon Oct 22 13:04:32 2007 +0100
+++ b/xen/arch/x86/hvm/vmx/vmx.c        Mon Oct 22 14:19:22 2007 +0100
@@ -50,6 +50,7 @@
 #include <asm/hvm/vpt.h>
 #include <public/hvm/save.h>
 #include <asm/hvm/trace.h>
+#include <stdbool.h>
 
 enum handler_return { HNDL_done, HNDL_unhandled, HNDL_exception_raised };
 
@@ -2285,6 +2286,9 @@ static int vmx_do_msr_read(struct cpu_us
     u64 msr_content = 0;
     u32 ecx = regs->ecx, eax, edx;
     struct vcpu *v = current;
+    int index;
+    u64 *var_range_base = (u64*)v->arch.hvm_vcpu.mtrr.var_ranges;
+    u64 *fixed_range_base =  (u64*)v->arch.hvm_vcpu.mtrr.fixed_ranges;
 
     HVM_DBG_LOG(DBG_LEVEL_1, "ecx=%x", ecx);
 
@@ -2304,6 +2308,32 @@ static int vmx_do_msr_read(struct cpu_us
         break;
     case MSR_IA32_APICBASE:
         msr_content = vcpu_vlapic(v)->hw.apic_base_msr;
+        break;
+    case MSR_IA32_CR_PAT:
+        msr_content = v->arch.hvm_vcpu.pat_cr;
+        break;
+    case MSR_MTRRcap:
+        msr_content = v->arch.hvm_vcpu.mtrr.mtrr_cap;
+        break;
+    case MSR_MTRRdefType:
+        msr_content = v->arch.hvm_vcpu.mtrr.def_type
+                        | (v->arch.hvm_vcpu.mtrr.enabled << 10);
+        break;
+    case MSR_MTRRfix64K_00000:
+        msr_content = fixed_range_base[0];
+        break;
+    case MSR_MTRRfix16K_80000:
+    case MSR_MTRRfix16K_A0000:
+        index = regs->ecx - MSR_MTRRfix16K_80000;
+        msr_content = fixed_range_base[index + 1];
+        break;
+    case MSR_MTRRfix4K_C0000...MSR_MTRRfix4K_F8000:
+        index = regs->ecx - MSR_MTRRfix4K_C0000;
+        msr_content = fixed_range_base[index + 3];
+        break;
+    case MSR_IA32_MTRR_PHYSBASE0...MSR_IA32_MTRR_PHYSMASK7:
+        index = regs->ecx - MSR_IA32_MTRR_PHYSBASE0;
+        msr_content = var_range_base[index];
         break;
     case MSR_IA32_DEBUGCTLMSR:
         if ( vmx_read_guest_msr(v, ecx, &msr_content) != 0 )
@@ -2428,11 +2458,19 @@ void vmx_vlapic_msr_changed(struct vcpu 
     vmx_vmcs_exit(v);
 }
 
+extern bool mtrr_var_range_msr_set(struct mtrr_state *v,
+        u32 msr, u64 msr_content);
+extern bool mtrr_fix_range_msr_set(struct mtrr_state *v,
+        int row, u64 msr_content);
+extern bool mtrr_def_type_msr_set(struct mtrr_state *v, u64 msr_content);
+extern bool pat_msr_set(u64 *pat, u64 msr);
+
 static int vmx_do_msr_write(struct cpu_user_regs *regs)
 {
     u32 ecx = regs->ecx;
     u64 msr_content;
     struct vcpu *v = current;
+    int index;
 
     HVM_DBG_LOG(DBG_LEVEL_1, "ecx=%x, eax=%x, edx=%x",
                 ecx, (u32)regs->eax, (u32)regs->edx);
@@ -2459,6 +2497,38 @@ static int vmx_do_msr_write(struct cpu_u
     case MSR_IA32_APICBASE:
         vlapic_msr_set(vcpu_vlapic(v), msr_content);
         break;
+    case MSR_IA32_CR_PAT:
+        if ( !pat_msr_set(&v->arch.hvm_vcpu.pat_cr, msr_content) )
+           goto gp_fault;
+        break;
+    case MSR_MTRRdefType:
+        if ( !mtrr_def_type_msr_set(&v->arch.hvm_vcpu.mtrr, msr_content) )
+           goto gp_fault;
+        break;
+    case MSR_MTRRfix64K_00000:
+        if ( !mtrr_fix_range_msr_set(&v->arch.hvm_vcpu.mtrr, 0, msr_content) )
+            goto gp_fault;
+        break;
+    case MSR_MTRRfix16K_80000:
+    case MSR_MTRRfix16K_A0000:
+        index = regs->ecx - MSR_MTRRfix16K_80000 + 1;
+        if ( !mtrr_fix_range_msr_set(&v->arch.hvm_vcpu.mtrr,
+                                     index, msr_content) )
+            goto gp_fault;
+        break;
+    case MSR_MTRRfix4K_C0000...MSR_MTRRfix4K_F8000:
+        index = regs->ecx - MSR_MTRRfix4K_C0000 + 3;
+        if ( !mtrr_fix_range_msr_set(&v->arch.hvm_vcpu.mtrr,
+                                     index, msr_content) )
+            goto gp_fault;
+        break;
+    case MSR_IA32_MTRR_PHYSBASE0...MSR_IA32_MTRR_PHYSMASK7:
+        if ( !mtrr_var_range_msr_set(&v->arch.hvm_vcpu.mtrr,
+                                     regs->ecx, msr_content) )
+            goto gp_fault;
+        break;
+    case MSR_MTRRcap:
+        goto gp_fault;
     case MSR_IA32_DEBUGCTLMSR: {
         int i, rc = 0;
 
diff -r 42d8dadb5864 -r 3e7c86602c70 xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Mon Oct 22 13:04:32 2007 +0100
+++ b/xen/arch/x86/mm.c Mon Oct 22 14:19:22 2007 +0100
@@ -3115,6 +3115,15 @@ long arch_memory_op(int op, XEN_GUEST_HA
         case XENMAPSPACE_shared_info:
             if ( xatp.idx == 0 )
                 mfn = virt_to_mfn(d->shared_info);
+            /* XXX: assumption here, this is called after E820 table is build
+             * need the E820 to initialize MTRR.
+             */
+            if ( is_hvm_domain(d) ) {
+                extern void init_mtrr_in_hyper(struct vcpu *);
+                struct vcpu *vs;
+                for_each_vcpu(d, vs)
+                    init_mtrr_in_hyper(vs);
+            }
             break;
         case XENMAPSPACE_grant_table:
             spin_lock(&d->grant_table->lock);
diff -r 42d8dadb5864 -r 3e7c86602c70 xen/arch/x86/mm/shadow/common.c
--- a/xen/arch/x86/mm/shadow/common.c   Mon Oct 22 13:04:32 2007 +0100
+++ b/xen/arch/x86/mm/shadow/common.c   Mon Oct 22 14:19:22 2007 +0100
@@ -880,6 +880,14 @@ static void shadow_blow_tables(struct do
     flush_tlb_mask(d->domain_dirty_cpumask);
 }
 
+void shadow_blow_tables_per_domain(struct domain *d)
+{
+    if ( shadow_mode_enabled(d) && d->vcpu[0] != NULL ) {
+        shadow_lock(d);
+        shadow_blow_tables(d);
+        shadow_unlock(d);
+    }
+}
 
 #ifndef NDEBUG
 /* Blow all shadows of all shadowed domains: this can be used to cause the
diff -r 42d8dadb5864 -r 3e7c86602c70 xen/arch/x86/mm/shadow/multi.c
--- a/xen/arch/x86/mm/shadow/multi.c    Mon Oct 22 13:04:32 2007 +0100
+++ b/xen/arch/x86/mm/shadow/multi.c    Mon Oct 22 14:19:22 2007 +0100
@@ -33,6 +33,7 @@
 #include <asm/shadow.h>
 #include <asm/flushtlb.h>
 #include <asm/hvm/hvm.h>
+#include <asm/mtrr.h>
 #include "private.h"
 #include "types.h"
 
@@ -267,6 +268,11 @@ guest_walk_tables(struct vcpu *v, unsign
          * us reflect l2 changes later without touching the l1s. */
         int flags = (_PAGE_PRESENT|_PAGE_USER|_PAGE_RW|
                      _PAGE_ACCESSED|_PAGE_DIRTY);
+        /* propagate PWT PCD to level 1 for PSE */
+        if ( (guest_l2e_get_flags(*gw->l2e) & _PAGE_PWT) )
+            flags |= _PAGE_PWT;
+        if ( (guest_l2e_get_flags(*gw->l2e) & _PAGE_PCD) )
+            flags |= _PAGE_PCD;
         /* PSE level 2 entries use bit 12 for PAT; propagate it to bit 7
          * of the level 1 */
         if ( (guest_l2e_get_flags(*gw->l2e) & _PAGE_PSE_PAT) ) 
@@ -614,7 +620,12 @@ shadow_l4_index(mfn_t *smfn, u32 guest_i
 
 #endif // GUEST_PAGING_LEVELS >= 4
 
-
+extern u32 get_pat_flags(struct vcpu *v,
+                  u32 gl1e_flags,
+                  paddr_t gpaddr,
+                  paddr_t spaddr);
+
+unsigned char pat_type_2_pte_flags(unsigned char pat_type);
 /**************************************************************************/
 /* Function which computes shadow entries from their corresponding guest
  * entries.  This is the "heart" of the shadow code. It operates using
@@ -703,6 +714,17 @@ _sh_propagate(struct vcpu *v,
         pass_thru_flags |= _PAGE_NX_BIT;
     sflags = gflags & pass_thru_flags;
 
+    /* Only change memory caching type for pass-through domain */
+    if ( (level == 1) && !list_empty(&(domain_hvm_iommu(d)->pdev_list)) ) {
+        if ( v->domain->arch.hvm_domain.is_in_uc_mode )
+            sflags |= pat_type_2_pte_flags(PAT_TYPE_UNCACHABLE);
+        else
+            sflags |= get_pat_flags(v,
+                                    gflags,
+                                    guest_l1e_get_paddr(*gp),
+                                    mfn_x(target_mfn) << PAGE_SHIFT);
+    }
+
     // Set the A&D bits for higher level shadows.
     // Higher level entries do not, strictly speaking, have dirty bits, but
     // since we use shadow linear tables, each of these entries may, at some
@@ -773,10 +795,6 @@ _sh_propagate(struct vcpu *v,
     {
         sflags |= _PAGE_USER;
     }
-
-    /* MMIO addresses should never be cached */
-    if ( p2m_is_mmio(p2mt) )
-        sflags |= _PAGE_PCD;
 
     *sp = shadow_l1e_from_mfn(target_mfn, sflags);
 
diff -r 42d8dadb5864 -r 3e7c86602c70 xen/include/asm-x86/cpufeature.h
--- a/xen/include/asm-x86/cpufeature.h  Mon Oct 22 13:04:32 2007 +0100
+++ b/xen/include/asm-x86/cpufeature.h  Mon Oct 22 14:19:22 2007 +0100
@@ -128,6 +128,7 @@
 #define cpu_has_tsc            boot_cpu_has(X86_FEATURE_TSC)
 #define cpu_has_pae            boot_cpu_has(X86_FEATURE_PAE)
 #define cpu_has_pge            boot_cpu_has(X86_FEATURE_PGE)
+#define cpu_has_pat            boot_cpu_has(X86_FEATURE_PAT)
 #define cpu_has_apic           boot_cpu_has(X86_FEATURE_APIC)
 #define cpu_has_sep            boot_cpu_has(X86_FEATURE_SEP)
 #define cpu_has_mtrr           boot_cpu_has(X86_FEATURE_MTRR)
@@ -152,6 +153,7 @@
 #define cpu_has_tsc            1
 #define cpu_has_pae            1
 #define cpu_has_pge            1
+#define cpu_has_pat            1
 #define cpu_has_apic           boot_cpu_has(X86_FEATURE_APIC)
 #define cpu_has_sep            0
 #define cpu_has_mtrr           1
diff -r 42d8dadb5864 -r 3e7c86602c70 xen/include/asm-x86/hvm/domain.h
--- a/xen/include/asm-x86/hvm/domain.h  Mon Oct 22 13:04:32 2007 +0100
+++ b/xen/include/asm-x86/hvm/domain.h  Mon Oct 22 14:19:22 2007 +0100
@@ -61,6 +61,12 @@ struct hvm_domain {
 
     unsigned long          vmx_apic_access_mfn;
 
+    /* If one of vcpus of this domain is in no_fill_mode or
+     * mtrr/pat between vcpus is not the same, set is_in_uc_mode
+     */
+    spinlock_t       uc_lock;
+    bool_t           is_in_uc_mode;
+
     /* Pass-through */
     struct hvm_iommu       hvm_iommu;
 };
diff -r 42d8dadb5864 -r 3e7c86602c70 xen/include/asm-x86/hvm/support.h
--- a/xen/include/asm-x86/hvm/support.h Mon Oct 22 13:04:32 2007 +0100
+++ b/xen/include/asm-x86/hvm/support.h Mon Oct 22 14:19:22 2007 +0100
@@ -64,6 +64,7 @@ static inline vcpu_iodata_t *get_ioreq(s
 #define DBG_LEVEL_VLAPIC_INTERRUPT  (1 << 8)
 #define DBG_LEVEL_IOAPIC            (1 << 9)
 #define DBG_LEVEL_HCALL             (1 << 10)
+#define DBG_LEVEL_MSR               (1 << 11)
 
 extern unsigned int opt_hvm_debug_level;
 #define HVM_DBG_LOG(level, _f, _a...)                                         \
diff -r 42d8dadb5864 -r 3e7c86602c70 xen/include/asm-x86/hvm/vcpu.h
--- a/xen/include/asm-x86/hvm/vcpu.h    Mon Oct 22 13:04:32 2007 +0100
+++ b/xen/include/asm-x86/hvm/vcpu.h    Mon Oct 22 14:19:22 2007 +0100
@@ -24,6 +24,7 @@
 #include <asm/hvm/vlapic.h>
 #include <asm/hvm/vmx/vmcs.h>
 #include <asm/hvm/svm/vmcb.h>
+#include <asm/mtrr.h>
 
 #define HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM          0
 #define HVM_VCPU_INIT_SIPI_SIPI_STATE_WAIT_SIPI     1
@@ -62,6 +63,12 @@ struct hvm_vcpu {
         struct arch_vmx_struct vmx;
         struct arch_svm_struct svm;
     } u;
+
+    struct mtrr_state   mtrr;
+    u64                 pat_cr;
+
+    /* Which cache mode is this VCPU in (CR0:CD/NW)? */
+    u8                  cache_mode;
 };
 
 #define ARCH_HVM_IO_WAIT         1   /* Waiting for I/O completion */
diff -r 42d8dadb5864 -r 3e7c86602c70 xen/include/asm-x86/msr-index.h
--- a/xen/include/asm-x86/msr-index.h   Mon Oct 22 13:04:32 2007 +0100
+++ b/xen/include/asm-x86/msr-index.h   Mon Oct 22 14:19:22 2007 +0100
@@ -68,6 +68,25 @@
 #define MSR_IA32_LASTBRANCHTOIP                0x000001dc
 #define MSR_IA32_LASTINTFROMIP         0x000001dd
 #define MSR_IA32_LASTINTTOIP           0x000001de
+ 
+#define MSR_IA32_MTRR_PHYSBASE0     0x00000200
+#define MSR_IA32_MTRR_PHYSMASK0     0x00000201
+#define MSR_IA32_MTRR_PHYSBASE1     0x00000202
+#define MSR_IA32_MTRR_PHYSMASK1     0x00000203
+#define MSR_IA32_MTRR_PHYSBASE2     0x00000204
+#define MSR_IA32_MTRR_PHYSMASK2     0x00000205
+#define MSR_IA32_MTRR_PHYSBASE3     0x00000206
+#define MSR_IA32_MTRR_PHYSMASK3     0x00000207
+#define MSR_IA32_MTRR_PHYSBASE4     0x00000208
+#define MSR_IA32_MTRR_PHYSMASK4     0x00000209
+#define MSR_IA32_MTRR_PHYSBASE5     0x0000020a
+#define MSR_IA32_MTRR_PHYSMASK5     0x0000020b
+#define MSR_IA32_MTRR_PHYSBASE6     0x0000020c
+#define MSR_IA32_MTRR_PHYSMASK6     0x0000020d
+#define MSR_IA32_MTRR_PHYSBASE7     0x0000020e
+#define MSR_IA32_MTRR_PHYSMASK7     0x0000020f
+
+#define MSR_IA32_CR_PAT             0x00000277
 
 #define MSR_IA32_MC0_CTL               0x00000400
 #define MSR_IA32_MC0_STATUS            0x00000401
diff -r 42d8dadb5864 -r 3e7c86602c70 xen/include/asm-x86/mtrr.h
--- a/xen/include/asm-x86/mtrr.h        Mon Oct 22 13:04:32 2007 +0100
+++ b/xen/include/asm-x86/mtrr.h        Mon Oct 22 14:19:22 2007 +0100
@@ -10,6 +10,55 @@
 #define MTRR_TYPE_WRPROT     5
 #define MTRR_TYPE_WRBACK     6
 #define MTRR_NUM_TYPES       7
+#define MEMORY_NUM_TYPES     MTRR_NUM_TYPES
+
+#define MTRR_PHYSMASK_VALID_BIT  11
+#define MTRR_PHYSMASK_SHIFT      12
+
+#define MTRR_PHYSBASE_TYPE_MASK  0xff   /* lowest 8 bits */
+#define MTRR_PHYSBASE_SHIFT      12
+#define MTRR_VCNT            8
+
+#define NORMAL_CACHE_MODE          0
+#define NO_FILL_CACHE_MODE         2
+
+enum {
+    PAT_TYPE_UNCACHABLE=0,
+    PAT_TYPE_WRCOMB=1,
+    PAT_TYPE_RESERVED=2,
+    PAT_TYPE_WRTHROUGH=4,
+    PAT_TYPE_WRPROT=5,
+    PAT_TYPE_WRBACK=6,
+    PAT_TYPE_UC_MINUS=7,
+    PAT_TYPE_NUMS
+};
+
+#define INVALID_MEM_TYPE PAT_TYPE_NUMS
+
+/* In the Intel processor's MTRR interface, the MTRR type is always held in
+   an 8 bit field: */
+typedef u8 mtrr_type;
+
+struct mtrr_var_range {
+       u32 base_lo;
+       u32 base_hi;
+       u32 mask_lo;
+       u32 mask_hi;
+};
+
+#define NUM_FIXED_RANGES 88
+struct mtrr_state {
+       struct mtrr_var_range *var_ranges;
+       mtrr_type fixed_ranges[NUM_FIXED_RANGES];
+       unsigned char enabled;
+       unsigned char have_fixed;
+       mtrr_type def_type;
+
+       u64       mtrr_cap;
+       /* ranges in var MSRs are overlapped or not:0(no overlapped) */
+       bool_t    overlapped;
+       bool_t    is_initialized;
+};
 
 extern void mtrr_save_fixed_ranges(void *);
 extern void mtrr_save_state(void);

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

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