ia64/xen-unstable

changeset 16186:3e7c86602c70

hvm/x86: MTRR/PAT virtualisation.
Signed-off-by: Disheng Su <disheng.su@intel.com>
author Keir Fraser <keir@xensource.com>
date Mon Oct 22 14:19:22 2007 +0100 (2007-10-22)
parents 42d8dadb5864
children dc2ff26bbdf6
files xen/arch/x86/cpu/common.c xen/arch/x86/cpu/mtrr/generic.c xen/arch/x86/cpu/mtrr/main.c xen/arch/x86/cpu/mtrr/mtrr.h xen/arch/x86/hvm/Makefile xen/arch/x86/hvm/hvm.c xen/arch/x86/hvm/mtrr.c xen/arch/x86/hvm/vmx/vmcs.c xen/arch/x86/hvm/vmx/vmx.c xen/arch/x86/mm.c xen/arch/x86/mm/shadow/common.c xen/arch/x86/mm/shadow/multi.c xen/include/asm-x86/cpufeature.h xen/include/asm-x86/hvm/domain.h xen/include/asm-x86/hvm/support.h xen/include/asm-x86/hvm/vcpu.h xen/include/asm-x86/msr-index.h xen/include/asm-x86/mtrr.h
line diff
     1.1 --- a/xen/arch/x86/cpu/common.c	Mon Oct 22 13:04:32 2007 +0100
     1.2 +++ b/xen/arch/x86/cpu/common.c	Mon Oct 22 14:19:22 2007 +0100
     1.3 @@ -23,6 +23,12 @@ static int disable_x86_serial_nr __devin
     1.4  
     1.5  struct cpu_dev * cpu_devs[X86_VENDOR_NUM] = {};
     1.6  
     1.7 +/*
     1.8 + * Default host IA32_CR_PAT value to cover all memory types.
     1.9 + * BIOS usually sets it to 0x07040600070406.
    1.10 + */
    1.11 +u64 host_pat = 0x050100070406;
    1.12 +
    1.13  static void default_init(struct cpuinfo_x86 * c)
    1.14  {
    1.15  	/* Not much we can do here... */
    1.16 @@ -557,6 +563,9 @@ void __devinit cpu_init(void)
    1.17  	}
    1.18  	printk(KERN_INFO "Initializing CPU#%d\n", cpu);
    1.19  
    1.20 +	if (cpu_has_pat)
    1.21 +		wrmsrl(MSR_IA32_CR_PAT, host_pat);
    1.22 +
    1.23  	*(unsigned short *)(&gdt_load[0]) = LAST_RESERVED_GDT_BYTE;
    1.24  	*(unsigned long  *)(&gdt_load[2]) = GDT_VIRT_START(current);
    1.25  	asm volatile ( "lgdt %0" : "=m" (gdt_load) );
     2.1 --- a/xen/arch/x86/cpu/mtrr/generic.c	Mon Oct 22 13:04:32 2007 +0100
     2.2 +++ b/xen/arch/x86/cpu/mtrr/generic.c	Mon Oct 22 14:19:22 2007 +0100
     2.3 @@ -11,14 +11,6 @@
     2.4  #include <asm/cpufeature.h>
     2.5  #include "mtrr.h"
     2.6  
     2.7 -struct mtrr_state {
     2.8 -	struct mtrr_var_range *var_ranges;
     2.9 -	mtrr_type fixed_ranges[NUM_FIXED_RANGES];
    2.10 -	unsigned char enabled;
    2.11 -	unsigned char have_fixed;
    2.12 -	mtrr_type def_type;
    2.13 -};
    2.14 -
    2.15  struct fixed_range_block {
    2.16  	int base_msr; /* start address of an MTRR block */
    2.17  	int ranges;   /* number of MTRRs in this block  */
    2.18 @@ -32,7 +24,7 @@ static struct fixed_range_block fixed_ra
    2.19  };
    2.20  
    2.21  static unsigned long smp_changes_mask;
    2.22 -static struct mtrr_state mtrr_state = {};
    2.23 +struct mtrr_state mtrr_state = {};
    2.24  
    2.25  /*  Get the MSR pair relating to a var range  */
    2.26  static void
    2.27 @@ -88,6 +80,9 @@ void __init get_mtrr_state(void)
    2.28  	rdmsr(MTRRdefType_MSR, lo, dummy);
    2.29  	mtrr_state.def_type = (lo & 0xff);
    2.30  	mtrr_state.enabled = (lo & 0xc00) >> 10;
    2.31 +
    2.32 +	/* Store mtrr_cap for HVM MTRR virtualisation. */
    2.33 +	rdmsrl(MTRRcap_MSR, mtrr_state.mtrr_cap);
    2.34  }
    2.35  
    2.36  /*  Some BIOS's are fucked and don't set all MTRRs the same!  */
    2.37 @@ -107,6 +102,7 @@ void __init mtrr_state_warn(void)
    2.38  	printk(KERN_INFO "mtrr: corrected configuration.\n");
    2.39  }
    2.40  
    2.41 +extern bool_t is_var_mtrr_overlapped(struct mtrr_state *m);
    2.42  /* Doesn't attempt to pass an error out to MTRR users
    2.43     because it's quite complicated in some cases and probably not
    2.44     worth it because the best error handling is to ignore it. */
    2.45 @@ -116,6 +112,8 @@ void mtrr_wrmsr(unsigned msr, unsigned a
    2.46  		printk(KERN_ERR
    2.47  			"MTRR: CPU %u: Writing MSR %x to %x:%x failed\n",
    2.48  			smp_processor_id(), msr, a, b);
    2.49 +	/* Cache overlap status for efficient HVM MTRR virtualisation. */
    2.50 +	mtrr_state.overlapped = is_var_mtrr_overlapped(&mtrr_state);
    2.51  }
    2.52  
    2.53  /**
     3.1 --- a/xen/arch/x86/cpu/mtrr/main.c	Mon Oct 22 13:04:32 2007 +0100
     3.2 +++ b/xen/arch/x86/cpu/mtrr/main.c	Mon Oct 22 14:19:22 2007 +0100
     3.3 @@ -588,6 +588,8 @@ struct mtrr_value {
     3.4  	unsigned long	lsize;
     3.5  };
     3.6  
     3.7 +extern void global_init_mtrr_pat(void);
     3.8 +
     3.9  /**
    3.10   * mtrr_bp_init - initialize mtrrs on the boot CPU
    3.11   *
    3.12 @@ -654,8 +656,11 @@ void __init mtrr_bp_init(void)
    3.13  	if (mtrr_if) {
    3.14  		set_num_var_ranges();
    3.15  		init_table();
    3.16 -		if (use_intel())
    3.17 +		if (use_intel()) {
    3.18  			get_mtrr_state();
    3.19 +			/* initialize some global data for MTRR/PAT virutalization */
    3.20 +			global_init_mtrr_pat();
    3.21 +		}
    3.22  	}
    3.23  }
    3.24  
     4.1 --- a/xen/arch/x86/cpu/mtrr/mtrr.h	Mon Oct 22 13:04:32 2007 +0100
     4.2 +++ b/xen/arch/x86/cpu/mtrr/mtrr.h	Mon Oct 22 14:19:22 2007 +0100
     4.3 @@ -13,7 +13,6 @@
     4.4  #define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
     4.5  #define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
     4.6  
     4.7 -#define NUM_FIXED_RANGES 88
     4.8  #define MTRRfix64K_00000_MSR 0x250
     4.9  #define MTRRfix16K_80000_MSR 0x258
    4.10  #define MTRRfix16K_A0000_MSR 0x259
    4.11 @@ -30,9 +29,6 @@
    4.12  #define MTRR_CHANGE_MASK_VARIABLE  0x02
    4.13  #define MTRR_CHANGE_MASK_DEFTYPE   0x04
    4.14  
    4.15 -/* In the Intel processor's MTRR interface, the MTRR type is always held in
    4.16 -   an 8 bit field: */
    4.17 -typedef u8 mtrr_type;
    4.18  
    4.19  struct mtrr_ops {
    4.20  	u32	vendor;
    4.21 @@ -69,13 +65,6 @@ struct set_mtrr_context {
    4.22  	u32 ccr3;
    4.23  };
    4.24  
    4.25 -struct mtrr_var_range {
    4.26 -	u32 base_lo;
    4.27 -	u32 base_hi;
    4.28 -	u32 mask_lo;
    4.29 -	u32 mask_hi;
    4.30 -};
    4.31 -
    4.32  void set_mtrr_done(struct set_mtrr_context *ctxt);
    4.33  void set_mtrr_cache_disable(struct set_mtrr_context *ctxt);
    4.34  void set_mtrr_prepare_save(struct set_mtrr_context *ctxt);
     5.1 --- a/xen/arch/x86/hvm/Makefile	Mon Oct 22 13:04:32 2007 +0100
     5.2 +++ b/xen/arch/x86/hvm/Makefile	Mon Oct 22 14:19:22 2007 +0100
     5.3 @@ -7,6 +7,7 @@ obj-y += instrlen.o
     5.4  obj-y += intercept.o
     5.5  obj-y += io.o
     5.6  obj-y += irq.o
     5.7 +obj-y += mtrr.o
     5.8  obj-y += platform.o
     5.9  obj-y += pmtimer.o
    5.10  obj-y += rtc.o
     6.1 --- a/xen/arch/x86/hvm/hvm.c	Mon Oct 22 13:04:32 2007 +0100
     6.2 +++ b/xen/arch/x86/hvm/hvm.c	Mon Oct 22 14:19:22 2007 +0100
     6.3 @@ -226,6 +226,7 @@ int hvm_domain_initialise(struct domain 
     6.4  
     6.5      spin_lock_init(&d->arch.hvm_domain.pbuf_lock);
     6.6      spin_lock_init(&d->arch.hvm_domain.irq_lock);
     6.7 +    spin_lock_init(&d->arch.hvm_domain.uc_lock);
     6.8  
     6.9      rc = paging_enable(d, PG_refcounts|PG_translate|PG_external);
    6.10      if ( rc != 0 )
    6.11 @@ -417,27 +418,22 @@ static int hvm_load_cpu_ctxt(struct doma
    6.12  HVM_REGISTER_SAVE_RESTORE(CPU, hvm_save_cpu_ctxt, hvm_load_cpu_ctxt,
    6.13                            1, HVMSR_PER_VCPU);
    6.14  
    6.15 +extern int reset_vmsr(struct mtrr_state *m, u64 *p);
    6.16 +
    6.17  int hvm_vcpu_initialise(struct vcpu *v)
    6.18  {
    6.19      int rc;
    6.20  
    6.21      if ( (rc = vlapic_init(v)) != 0 )
    6.22 -        return rc;
    6.23 +        goto fail1;
    6.24  
    6.25      if ( (rc = hvm_funcs.vcpu_initialise(v)) != 0 )
    6.26 -    {
    6.27 -        vlapic_destroy(v);
    6.28 -        return rc;
    6.29 -    }
    6.30 +        goto fail2;
    6.31  
    6.32      /* Create ioreq event channel. */
    6.33      rc = alloc_unbound_xen_event_channel(v, 0);
    6.34      if ( rc < 0 )
    6.35 -    {
    6.36 -        hvm_funcs.vcpu_destroy(v);
    6.37 -        vlapic_destroy(v);
    6.38 -        return rc;
    6.39 -    }
    6.40 +        goto fail3;
    6.41  
    6.42      /* Register ioreq event channel. */
    6.43      v->arch.hvm_vcpu.xen_port = rc;
    6.44 @@ -449,6 +445,10 @@ int hvm_vcpu_initialise(struct vcpu *v)
    6.45      spin_lock_init(&v->arch.hvm_vcpu.tm_lock);
    6.46      INIT_LIST_HEAD(&v->arch.hvm_vcpu.tm_list);
    6.47  
    6.48 +    rc = reset_vmsr(&v->arch.hvm_vcpu.mtrr, &v->arch.hvm_vcpu.pat_cr);
    6.49 +    if ( rc != 0 )
    6.50 +        goto fail3;
    6.51 +
    6.52      v->arch.guest_context.user_regs.eflags = 2;
    6.53  
    6.54      if ( v->vcpu_id == 0 )
    6.55 @@ -468,6 +468,13 @@ int hvm_vcpu_initialise(struct vcpu *v)
    6.56      }
    6.57  
    6.58      return 0;
    6.59 +
    6.60 + fail3:
    6.61 +    hvm_funcs.vcpu_destroy(v);
    6.62 + fail2:
    6.63 +    vlapic_destroy(v);
    6.64 + fail1:
    6.65 +    return rc;
    6.66  }
    6.67  
    6.68  void hvm_vcpu_destroy(struct vcpu *v)
    6.69 @@ -606,6 +613,32 @@ int hvm_set_efer(uint64_t value)
    6.70      return 1;
    6.71  }
    6.72  
    6.73 +extern void shadow_blow_tables_per_domain(struct domain *d);
    6.74 +extern bool_t mtrr_pat_not_equal(struct vcpu *vd, struct vcpu *vs);
    6.75 +
    6.76 +/* Exit UC mode only if all VCPUs agree on MTRR/PAT and are not in no_fill. */
    6.77 +static bool_t domain_exit_uc_mode(struct vcpu *v)
    6.78 +{
    6.79 +    struct domain *d = v->domain;
    6.80 +    struct vcpu *vs;
    6.81 +
    6.82 +    for_each_vcpu ( d, vs )
    6.83 +    {
    6.84 +        if ( (vs == v) || !vs->is_initialised )
    6.85 +            continue;
    6.86 +        if ( (vs->arch.hvm_vcpu.cache_mode == NO_FILL_CACHE_MODE) ||
    6.87 +             mtrr_pat_not_equal(vs, v) )
    6.88 +            return 0;
    6.89 +    }
    6.90 +
    6.91 +    return 1;
    6.92 +}
    6.93 +
    6.94 +static void local_flush_cache(void *info)
    6.95 +{
    6.96 +    wbinvd();
    6.97 +}
    6.98 +
    6.99  int hvm_set_cr0(unsigned long value)
   6.100  {
   6.101      struct vcpu *v = current;
   6.102 @@ -686,6 +719,41 @@ int hvm_set_cr0(unsigned long value)
   6.103          }
   6.104      }
   6.105  
   6.106 +    if ( !list_empty(&(domain_hvm_iommu(v->domain)->pdev_list)) )
   6.107 +    {
   6.108 +        if ( (value & X86_CR0_CD) && !(value & X86_CR0_NW) )
   6.109 +        {
   6.110 +            /* Entering no fill cache mode. */
   6.111 +            spin_lock(&v->domain->arch.hvm_domain.uc_lock);
   6.112 +            v->arch.hvm_vcpu.cache_mode = NO_FILL_CACHE_MODE;
   6.113 +
   6.114 +            if ( !v->domain->arch.hvm_domain.is_in_uc_mode )
   6.115 +            {
   6.116 +                /* Flush physical caches. */
   6.117 +                on_each_cpu(local_flush_cache, NULL, 1, 1);
   6.118 +                /* Shadow pagetables must recognise UC mode. */
   6.119 +                v->domain->arch.hvm_domain.is_in_uc_mode = 1;
   6.120 +                shadow_blow_tables_per_domain(v->domain);
   6.121 +            }
   6.122 +            spin_unlock(&v->domain->arch.hvm_domain.uc_lock);
   6.123 +        }
   6.124 +        else if ( !(value & (X86_CR0_CD | X86_CR0_NW)) &&
   6.125 +                  (v->arch.hvm_vcpu.cache_mode == NO_FILL_CACHE_MODE) )
   6.126 +        {
   6.127 +            /* Exit from no fill cache mode. */
   6.128 +            spin_lock(&v->domain->arch.hvm_domain.uc_lock);
   6.129 +            v->arch.hvm_vcpu.cache_mode = NORMAL_CACHE_MODE;
   6.130 +
   6.131 +            if ( domain_exit_uc_mode(v) )
   6.132 +            {
   6.133 +                /* Shadow pagetables must recognise normal caching mode. */
   6.134 +                v->domain->arch.hvm_domain.is_in_uc_mode = 0;
   6.135 +                shadow_blow_tables_per_domain(v->domain);
   6.136 +            }
   6.137 +            spin_unlock(&v->domain->arch.hvm_domain.uc_lock);
   6.138 +        }
   6.139 +    }
   6.140 +
   6.141      v->arch.hvm_vcpu.guest_cr[0] = value;
   6.142      hvm_update_guest_cr(v, 0);
   6.143  
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/xen/arch/x86/hvm/mtrr.c	Mon Oct 22 14:19:22 2007 +0100
     7.3 @@ -0,0 +1,687 @@
     7.4 +/*
     7.5 + * mtrr.c: MTRR/PAT virtualization
     7.6 + *
     7.7 + * Copyright (c) 2007, Intel Corporation.
     7.8 + *
     7.9 + * This program is free software; you can redistribute it and/or modify it
    7.10 + * under the terms and conditions of the GNU General Public License,
    7.11 + * version 2, as published by the Free Software Foundation.
    7.12 + *
    7.13 + * This program is distributed in the hope it will be useful, but WITHOUT
    7.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    7.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
    7.16 + * more details.
    7.17 + *
    7.18 + * You should have received a copy of the GNU General Public License along with
    7.19 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
    7.20 + * Place - Suite 330, Boston, MA 02111-1307 USA.
    7.21 + */
    7.22 +
    7.23 +#include <public/hvm/e820.h>
    7.24 +#include <xen/types.h>
    7.25 +#include <asm/e820.h>
    7.26 +#include <asm/paging.h>
    7.27 +#include <asm/p2m.h>
    7.28 +#include <xen/domain_page.h>
    7.29 +#include <stdbool.h>
    7.30 +#include <asm/mtrr.h>
    7.31 +#include <asm/hvm/support.h>
    7.32 +
    7.33 +/* Xen holds the native MTRR MSRs */
    7.34 +extern struct mtrr_state mtrr_state;
    7.35 +
    7.36 +static u64 phys_base_msr_mask;
    7.37 +static u64 phys_mask_msr_mask;
    7.38 +static u32 size_or_mask;
    7.39 +static u32 size_and_mask;
    7.40 +
    7.41 +static void init_pat_entry_tbl(u64 pat);
    7.42 +static void init_mtrr_epat_tbl(void);
    7.43 +static unsigned char get_mtrr_type(struct mtrr_state *m, paddr_t pa);
    7.44 +/* get page attribute fields (PAn) from PAT MSR */
    7.45 +#define pat_cr_2_paf(pat_cr,n)  ((((u64)pat_cr) >> ((n)<<3)) & 0xff)
    7.46 +/* pat entry to PTE flags (PAT, PCD, PWT bits) */
    7.47 +static unsigned char pat_entry_2_pte_flags[8] = {
    7.48 +    0,           _PAGE_PWT,
    7.49 +    _PAGE_PCD,   _PAGE_PCD | _PAGE_PWT,
    7.50 +    _PAGE_PAT,   _PAGE_PAT | _PAGE_PWT,
    7.51 +    _PAGE_PAT | _PAGE_PCD, _PAGE_PAT | _PAGE_PCD | _PAGE_PWT };
    7.52 +
    7.53 +/* effective mm type lookup table, according to MTRR and PAT */
    7.54 +static u8 mm_type_tbl[MTRR_NUM_TYPES][PAT_TYPE_NUMS] = {
    7.55 +/********PAT(UC,WC,RS,RS,WT,WP,WB,UC-)*/
    7.56 +/* RS means reserved type(2,3), and type is hardcoded here */
    7.57 + /*MTRR(UC):(UC,WC,RS,RS,UC,UC,UC,UC)*/
    7.58 +            {0, 1, 2, 2, 0, 0, 0, 0},
    7.59 + /*MTRR(WC):(UC,WC,RS,RS,UC,UC,WC,WC)*/
    7.60 +            {0, 1, 2, 2, 0, 0, 1, 1},
    7.61 + /*MTRR(RS):(RS,RS,RS,RS,RS,RS,RS,RS)*/
    7.62 +            {2, 2, 2, 2, 2, 2, 2, 2},
    7.63 + /*MTRR(RS):(RS,RS,RS,RS,RS,RS,RS,RS)*/
    7.64 +            {2, 2, 2, 2, 2, 2, 2, 2},
    7.65 + /*MTRR(WT):(UC,WC,RS,RS,WT,WP,WT,UC)*/
    7.66 +            {0, 1, 2, 2, 4, 5, 4, 0},
    7.67 + /*MTRR(WP):(UC,WC,RS,RS,WT,WP,WP,WC)*/
    7.68 +            {0, 1, 2, 2, 4, 5, 5, 1},
    7.69 + /*MTRR(WB):(UC,WC,RS,RS,WT,WP,WB,UC)*/
    7.70 +            {0, 1, 2, 2, 4, 5, 6, 0}
    7.71 +};
    7.72 +
    7.73 +/* reverse lookup table, to find a pat type according to MTRR and effective
    7.74 + * memory type. This table is dynamically generated
    7.75 + */
    7.76 +static u8 mtrr_epat_tbl[MTRR_NUM_TYPES][MEMORY_NUM_TYPES];
    7.77 +
    7.78 +/* lookup table for PAT entry of a given PAT value in host pat */
    7.79 +static u8 pat_entry_tbl[PAT_TYPE_NUMS];
    7.80 +
    7.81 +static void get_mtrr_range(uint64_t base_msr, uint64_t mask_msr,
    7.82 +                           uint64_t *base, uint64_t *end)
    7.83 +{
    7.84 +    uint32_t mask_lo = (uint32_t)mask_msr;
    7.85 +    uint32_t mask_hi = (uint32_t)(mask_msr >> 32);
    7.86 +    uint32_t base_lo = (uint32_t)base_msr;
    7.87 +    uint32_t base_hi = (uint32_t)(base_msr >> 32);
    7.88 +    uint32_t size;
    7.89 +
    7.90 +    if ( (mask_lo & 0x800) == 0 )
    7.91 +    {
    7.92 +        /* Invalid (i.e. free) range */
    7.93 +        *base = 0;
    7.94 +        *end = 0;
    7.95 +        return;
    7.96 +    }
    7.97 +
    7.98 +    /* Work out the shifted address mask. */
    7.99 +    mask_lo = (size_or_mask | (mask_hi << (32 - PAGE_SHIFT)) |
   7.100 +               (mask_lo >> PAGE_SHIFT));
   7.101 +
   7.102 +    /* This works correctly if size is a power of two (a contiguous range). */
   7.103 +    size = -mask_lo;
   7.104 +    *base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT;
   7.105 +    *end = *base + size - 1;
   7.106 +}
   7.107 +
   7.108 +bool_t is_var_mtrr_overlapped(struct mtrr_state *m)
   7.109 +{
   7.110 +    int seg, i;
   7.111 +    uint64_t phys_base, phys_mask, phys_base_pre, phys_mask_pre;
   7.112 +    uint64_t base_pre, end_pre, base, end;
   7.113 +    uint8_t num_var_ranges = (u8)m->mtrr_cap;
   7.114 +
   7.115 +    for ( i = 0; i < num_var_ranges; i++ )
   7.116 +    {
   7.117 +        phys_base_pre = ((u64*)m->var_ranges)[i*2];
   7.118 +        phys_mask_pre = ((u64*)m->var_ranges)[i*2 + 1];
   7.119 +
   7.120 +        get_mtrr_range(phys_base_pre, phys_mask_pre,
   7.121 +                        &base_pre, &end_pre);
   7.122 +
   7.123 +        for ( seg = i + 1; seg < num_var_ranges; seg ++ )
   7.124 +        {
   7.125 +            phys_base = ((u64*)m->var_ranges)[seg*2];
   7.126 +            phys_mask = ((u64*)m->var_ranges)[seg*2 + 1];
   7.127 +
   7.128 +            get_mtrr_range(phys_base, phys_mask,
   7.129 +                            &base, &end);
   7.130 +
   7.131 +            if ( ((base_pre != end_pre) && (base != end))
   7.132 +                 || ((base >= base_pre) && (base <= end_pre))
   7.133 +                 || ((end >= base_pre) && (end <= end_pre))
   7.134 +                 || ((base_pre >= base) && (base_pre <= end))
   7.135 +                 || ((end_pre >= base) && (end_pre <= end)) )
   7.136 +            {
   7.137 +                /* MTRR is overlapped. */
   7.138 +                return 1;
   7.139 +            }
   7.140 +        }
   7.141 +    }
   7.142 +    return 0;
   7.143 +}
   7.144 +
   7.145 +/* reserved mtrr for guest OS */
   7.146 +#define RESERVED_MTRR 2
   7.147 +#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
   7.148 +#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
   7.149 +bool mtrr_var_range_msr_set(struct mtrr_state *m, u32 msr, u64 msr_content);
   7.150 +bool mtrr_def_type_msr_set(struct mtrr_state *m, u64 msr_content);
   7.151 +bool mtrr_fix_range_msr_set(struct mtrr_state *m, int row, u64 msr_content);
   7.152 +static void set_var_mtrr(unsigned int reg, struct mtrr_state *m,
   7.153 +                    unsigned int base, unsigned int size,
   7.154 +                    unsigned int type)
   7.155 +{
   7.156 +    struct mtrr_var_range *vr;
   7.157 +
   7.158 +    vr = &m->var_ranges[reg];
   7.159 +
   7.160 +    if ( size == 0 )
   7.161 +    {
   7.162 +        /* The invalid bit is kept in the mask, so we simply clear the
   7.163 +         * relevant mask register to disable a range.
   7.164 +         */
   7.165 +        mtrr_var_range_msr_set(m, MTRRphysMask_MSR(reg), 0);
   7.166 +    }
   7.167 +    else
   7.168 +    {
   7.169 +        vr->base_lo = base << PAGE_SHIFT | type;
   7.170 +        vr->base_hi = (base & size_and_mask) >> (32 - PAGE_SHIFT);
   7.171 +        vr->mask_lo = -size << PAGE_SHIFT | 0x800;
   7.172 +        vr->mask_hi = (-size & size_and_mask) >> (32 - PAGE_SHIFT);
   7.173 +
   7.174 +        mtrr_var_range_msr_set(m, MTRRphysBase_MSR(reg), *(unsigned long *)vr);
   7.175 +        mtrr_var_range_msr_set(m, MTRRphysMask_MSR(reg),
   7.176 +                               *((unsigned long *)vr + 1));
   7.177 +    }
   7.178 +}
   7.179 +/* From Intel Vol. III Section 10.11.4, the Range Size and Base Alignment has
   7.180 + * some kind of requirement:
   7.181 + * 1. The range size must be 2^N byte for N >= 12 (i.e 4KB minimum).
   7.182 + * 2. The base address must be 2^N aligned, where the N here is equal to
   7.183 + * the N in previous requirement. So a 8K range must be 8K aligned not 4K aligned.
   7.184 + */
   7.185 +static unsigned int range_to_mtrr(unsigned int reg, struct mtrr_state *m,
   7.186 +    unsigned int range_startk, unsigned int range_sizek, unsigned char type)
   7.187 +{
   7.188 +    if ( !range_sizek || (reg >= ((m->mtrr_cap & 0xff) - RESERVED_MTRR)) )
   7.189 +        return reg;
   7.190 +
   7.191 +    while ( range_sizek )
   7.192 +    {
   7.193 +        unsigned int max_align, align, sizek;
   7.194 +
   7.195 +        max_align = (range_startk == 0) ? 32 : ffs(range_startk);
   7.196 +        align = min_t(unsigned int, fls(range_sizek), max_align);
   7.197 +        sizek = 1 << (align - 1);
   7.198 +
   7.199 +        set_var_mtrr(reg++, m, range_startk, sizek, type);
   7.200 +
   7.201 +        range_startk += sizek;
   7.202 +        range_sizek  -= sizek;
   7.203 +
   7.204 +        if ( reg >= ((m->mtrr_cap & 0xff) - RESERVED_MTRR) )
   7.205 +            break;
   7.206 +    }
   7.207 +
   7.208 +    return reg;
   7.209 +}
   7.210 +
   7.211 +static void setup_fixed_mtrrs(struct vcpu *v)
   7.212 +{
   7.213 +    uint64_t content;
   7.214 +    int i;
   7.215 +    struct mtrr_state *m = &v->arch.hvm_vcpu.mtrr;
   7.216 +
   7.217 +    /* 1. Map (0~A0000) as WB */
   7.218 +    content = 0x0606060606060606ull;
   7.219 +    mtrr_fix_range_msr_set(m, 0, content);
   7.220 +    mtrr_fix_range_msr_set(m, 1, content);
   7.221 +    /* 2. Map VRAM(A0000~C0000) as WC */
   7.222 +    content = 0x0101010101010101;
   7.223 +    mtrr_fix_range_msr_set(m, 2, content);
   7.224 +    /* 3. Map (C0000~100000) as UC */
   7.225 +    for ( i = 3; i < 11; i++)
   7.226 +        mtrr_fix_range_msr_set(m, i, 0);
   7.227 +}
   7.228 +
   7.229 +static void setup_var_mtrrs(struct vcpu *v)
   7.230 +{
   7.231 +    p2m_type_t p2m;
   7.232 +    unsigned long e820_mfn;
   7.233 +    char *p = NULL;
   7.234 +    unsigned char nr = 0;
   7.235 +    int i;
   7.236 +    unsigned int reg = 0;
   7.237 +    unsigned long size = 0;
   7.238 +    unsigned long addr = 0;
   7.239 +    struct e820entry *e820_table;
   7.240 +
   7.241 +    e820_mfn = mfn_x(gfn_to_mfn(v->domain,
   7.242 +                    HVM_E820_PAGE >> PAGE_SHIFT, &p2m));
   7.243 +
   7.244 +    p = (char *)map_domain_page(e820_mfn);
   7.245 +
   7.246 +    nr = *(unsigned char*)(p + HVM_E820_NR_OFFSET);
   7.247 +    e820_table = (struct e820entry*)(p + HVM_E820_OFFSET);
   7.248 +    /* search E820 table, set MTRR for RAM */
   7.249 +    for ( i = 0; i < nr; i++)
   7.250 +    {
   7.251 +        if ( (e820_table[i].addr >= 0x100000) &&
   7.252 +             (e820_table[i].type == E820_RAM) )
   7.253 +        {
   7.254 +            if ( e820_table[i].addr == 0x100000 )
   7.255 +            {
   7.256 +                size = e820_table[i].size + 0x100000 + PAGE_SIZE * 3;
   7.257 +                addr = 0;
   7.258 +            }
   7.259 +            else
   7.260 +            {
   7.261 +                /* Larger than 4G */
   7.262 +                size = e820_table[i].size;
   7.263 +                addr = e820_table[i].addr;
   7.264 +            }
   7.265 +
   7.266 +            reg = range_to_mtrr(reg, &v->arch.hvm_vcpu.mtrr,
   7.267 +                                addr >> PAGE_SHIFT, size >> PAGE_SHIFT,
   7.268 +                                MTRR_TYPE_WRBACK);
   7.269 +        }
   7.270 +    }
   7.271 +}
   7.272 +
   7.273 +void init_mtrr_in_hyper(struct vcpu *v)
   7.274 +{
   7.275 +    /* TODO:MTRR should be initialized in BIOS or other places.
   7.276 +     * workaround to do it in here
   7.277 +     */
   7.278 +    if ( v->arch.hvm_vcpu.mtrr.is_initialized )
   7.279 +        return;
   7.280 +
   7.281 +    setup_fixed_mtrrs(v);
   7.282 +    setup_var_mtrrs(v);
   7.283 +    /* enable mtrr */
   7.284 +    mtrr_def_type_msr_set(&v->arch.hvm_vcpu.mtrr, 0xc00);
   7.285 +
   7.286 +    v->arch.hvm_vcpu.mtrr.is_initialized = 1;
   7.287 +}
   7.288 +
   7.289 +static int reset_mtrr(struct mtrr_state *m)
   7.290 +{
   7.291 +    m->var_ranges = xmalloc_array(struct mtrr_var_range, MTRR_VCNT);
   7.292 +    if ( m->var_ranges == NULL )
   7.293 +        return -ENOMEM;
   7.294 +    memset(m->var_ranges, 0, MTRR_VCNT * sizeof(struct mtrr_var_range));
   7.295 +    memset(m->fixed_ranges, 0, sizeof(m->fixed_ranges));
   7.296 +    m->enabled = 0;
   7.297 +    m->def_type = 0;/*mtrr is disabled*/
   7.298 +    m->mtrr_cap = (0x5<<8)|MTRR_VCNT;/*wc,fix enabled, and vcnt=8*/
   7.299 +    m->overlapped = 0;
   7.300 +    return 0;
   7.301 +}
   7.302 +
   7.303 +/* init global variables for MTRR and PAT */
   7.304 +void global_init_mtrr_pat(void)
   7.305 +{
   7.306 +    extern u64 host_pat;
   7.307 +    u32 phys_addr;
   7.308 +
   7.309 +    init_mtrr_epat_tbl();
   7.310 +    init_pat_entry_tbl(host_pat);
   7.311 +    /* Get max physical address, set some global variable */
   7.312 +    if ( cpuid_eax(0x80000000) < 0x80000008 )
   7.313 +        phys_addr = 36;
   7.314 +    else
   7.315 +        phys_addr = cpuid_eax(0x80000008);
   7.316 +
   7.317 +    phys_base_msr_mask = ~((((u64)1) << phys_addr) - 1) | 0xf00UL;
   7.318 +    phys_mask_msr_mask = ~((((u64)1) << phys_addr) - 1) | 0x7ffUL;
   7.319 +
   7.320 +    size_or_mask = ~((1 << (phys_addr - PAGE_SHIFT)) - 1);
   7.321 +    size_and_mask = ~size_or_mask & 0xfff00000;
   7.322 +}
   7.323 +
   7.324 +static void init_pat_entry_tbl(u64 pat)
   7.325 +{
   7.326 +    int i, j;
   7.327 +
   7.328 +    memset(&pat_entry_tbl, INVALID_MEM_TYPE,
   7.329 +           PAT_TYPE_NUMS * sizeof(pat_entry_tbl[0]));
   7.330 +
   7.331 +    for ( i = 0; i < PAT_TYPE_NUMS; i++ )
   7.332 +    {
   7.333 +        for ( j = 0; j < PAT_TYPE_NUMS; j++ )
   7.334 +        {
   7.335 +            if ( pat_cr_2_paf(pat, j) == i )
   7.336 +            {
   7.337 +                pat_entry_tbl[i] = j;
   7.338 +                break;
   7.339 +            }
   7.340 +        }
   7.341 +    }
   7.342 +}
   7.343 +
   7.344 +unsigned char pat_type_2_pte_flags(unsigned char pat_type)
   7.345 +{
   7.346 +    int pat_entry = pat_entry_tbl[pat_type];
   7.347 +
   7.348 +    /* INVALID_MEM_TYPE, means doesn't find the pat_entry in host pat for
   7.349 +     * a given pat_type. If host pat covers all the pat types,
   7.350 +     * it can't happen.
   7.351 +     */
   7.352 +    if ( likely(pat_entry != INVALID_MEM_TYPE) )
   7.353 +        return pat_entry_2_pte_flags[pat_entry];
   7.354 +
   7.355 +    return pat_entry_2_pte_flags[pat_entry_tbl[PAT_TYPE_UNCACHABLE]];
   7.356 +}
   7.357 +
   7.358 +int reset_vmsr(struct mtrr_state *m, u64 *pat_ptr)
   7.359 +{
   7.360 +    int rc;
   7.361 +
   7.362 +    rc = reset_mtrr(m);
   7.363 +    if ( rc != 0 )
   7.364 +        return rc;
   7.365 +
   7.366 +    *pat_ptr = ( (u64)PAT_TYPE_WRBACK) |                /* PAT0: WB */
   7.367 +        ( (u64)PAT_TYPE_WRTHROUGH << 8 ) |              /* PAT1: WT */
   7.368 +        ( (u64)PAT_TYPE_UC_MINUS << 16 ) |              /* PAT2: UC- */
   7.369 +        ( (u64)PAT_TYPE_UNCACHABLE << 24 ) |            /* PAT3: UC */
   7.370 +        ( (u64)PAT_TYPE_WRBACK << 32 ) |                /* PAT4: WB */
   7.371 +        ( (u64)PAT_TYPE_WRTHROUGH << 40 ) |             /* PAT5: WT */
   7.372 +        ( (u64)PAT_TYPE_UC_MINUS << 48 ) |              /* PAT6: UC- */
   7.373 +        ( (u64)PAT_TYPE_UNCACHABLE << 56 );             /* PAT7: UC */
   7.374 +
   7.375 +    return 0;
   7.376 +}
   7.377 +
   7.378 +/*
   7.379 + * Get MTRR memory type for physical address pa.
   7.380 + */
   7.381 +static unsigned char get_mtrr_type(struct mtrr_state *m, paddr_t pa)
   7.382 +{
   7.383 +   int    addr, seg, index;
   7.384 +   u8     overlap_mtrr = 0;
   7.385 +   u8     overlap_mtrr_pos = 0;
   7.386 +   u64    phys_base;
   7.387 +   u64    phys_mask;
   7.388 +   u8     num_var_ranges = m->mtrr_cap & 0xff;
   7.389 +
   7.390 +   if ( unlikely(!(m->enabled & 0x2)) )
   7.391 +       return MTRR_TYPE_UNCACHABLE;
   7.392 +
   7.393 +   if ( (pa < 0x100000) && (m->enabled & 1) )
   7.394 +   {
   7.395 +       /* Fixed range MTRR takes effective */
   7.396 +       addr = (unsigned int) pa;
   7.397 +       if ( addr < 0x80000 )
   7.398 +       {
   7.399 +           seg = (addr >> 16);
   7.400 +           return m->fixed_ranges[seg];
   7.401 +       }
   7.402 +       else if ( addr < 0xc0000 )
   7.403 +       {
   7.404 +           seg = (addr - 0x80000) >> 14;
   7.405 +           index = (seg >> 3) + 1;
   7.406 +           seg &= 7;            /* select 0-7 segments */
   7.407 +           return m->fixed_ranges[index*8 + seg];
   7.408 +       }
   7.409 +       else
   7.410 +       {
   7.411 +           /* 0xC0000 --- 0x100000 */
   7.412 +           seg = (addr - 0xc0000) >> 12;
   7.413 +           index = (seg >> 3) + 3;
   7.414 +           seg &= 7;            /* select 0-7 segments */
   7.415 +           return m->fixed_ranges[index*8 + seg];
   7.416 +       }
   7.417 +   }
   7.418 +
   7.419 +   /* Match with variable MTRRs. */
   7.420 +   for ( seg = 0; seg < num_var_ranges; seg++ )
   7.421 +   {
   7.422 +       phys_base = ((u64*)m->var_ranges)[seg*2];
   7.423 +       phys_mask = ((u64*)m->var_ranges)[seg*2 + 1];
   7.424 +       if ( phys_mask & (1 << MTRR_PHYSMASK_VALID_BIT) )
   7.425 +       {
   7.426 +           if ( ((u64) pa & phys_mask) >> MTRR_PHYSMASK_SHIFT ==
   7.427 +                (phys_base & phys_mask) >> MTRR_PHYSMASK_SHIFT )
   7.428 +           {
   7.429 +               if ( unlikely(m->overlapped) )
   7.430 +               {
   7.431 +                    overlap_mtrr |= 1 << (phys_base & MTRR_PHYSBASE_TYPE_MASK);
   7.432 +                    overlap_mtrr_pos = phys_base & MTRR_PHYSBASE_TYPE_MASK;
   7.433 +               }
   7.434 +               else
   7.435 +               {
   7.436 +                   /* If no overlap, return the found one */
   7.437 +                   return (phys_base & MTRR_PHYSBASE_TYPE_MASK);
   7.438 +               }
   7.439 +           }
   7.440 +       }
   7.441 +   }
   7.442 +
   7.443 +   /* Overlapped or not found. */
   7.444 +   if ( unlikely(overlap_mtrr == 0) )
   7.445 +       return m->def_type;
   7.446 +
   7.447 +   if ( likely(!(overlap_mtrr & ~( ((u8)1) << overlap_mtrr_pos ))) )
   7.448 +       /* Covers both one variable memory range matches and
   7.449 +        * two or more identical match.
   7.450 +        */
   7.451 +       return overlap_mtrr_pos;
   7.452 +
   7.453 +   if ( overlap_mtrr & 0x1 )
   7.454 +       /* Two or more match, one is UC. */
   7.455 +       return MTRR_TYPE_UNCACHABLE;
   7.456 +   
   7.457 +   if ( !(overlap_mtrr & 0xaf) )
   7.458 +       /* Two or more match, WT and WB. */
   7.459 +       return MTRR_TYPE_WRTHROUGH;
   7.460 +
   7.461 +   /* Behaviour is undefined, but return the last overlapped type. */
   7.462 +   return overlap_mtrr_pos;
   7.463 +}
   7.464 +
   7.465 +/*
   7.466 + * return the memory type from PAT.
   7.467 + * NOTE: valid only when paging is enabled.
   7.468 + *       Only 4K page PTE is supported now.
   7.469 + */
   7.470 +static unsigned char page_pat_type(u64 pat_cr, unsigned long pte_flags)
   7.471 +{
   7.472 +    int pat_entry;
   7.473 +
   7.474 +    /* PCD/PWT -> bit 1/0 of PAT entry */
   7.475 +    pat_entry = ( pte_flags >> 3 ) & 0x3;
   7.476 +    /* PAT bits as bit 2 of PAT entry */
   7.477 +    if ( pte_flags & _PAGE_PAT )
   7.478 +        pat_entry |= 4;
   7.479 +
   7.480 +    return (unsigned char)pat_cr_2_paf(pat_cr, pat_entry);
   7.481 +}
   7.482 +
   7.483 +/*
   7.484 + * Effective memory type for leaf page.
   7.485 + */
   7.486 +static u8 effective_mm_type(
   7.487 +        struct mtrr_state *m,
   7.488 +        u64 pat,
   7.489 +        paddr_t gpa,
   7.490 +        unsigned long pte_flags)
   7.491 +{
   7.492 +    unsigned char mtrr_mtype, pat_value, effective;
   7.493 +
   7.494 +    mtrr_mtype = get_mtrr_type(m, gpa);
   7.495 +
   7.496 +    pat_value = page_pat_type(pat, pte_flags);
   7.497 +
   7.498 +    effective = mm_type_tbl[mtrr_mtype][pat_value];
   7.499 +
   7.500 +    return effective;
   7.501 +}
   7.502 +
   7.503 +static void init_mtrr_epat_tbl(void)
   7.504 +{
   7.505 +    int i, j;
   7.506 +    /* set default value to an invalid type, just for checking conflict */
   7.507 +    memset(&mtrr_epat_tbl, INVALID_MEM_TYPE, sizeof(mtrr_epat_tbl));
   7.508 +
   7.509 +    for ( i = 0; i < MTRR_NUM_TYPES; i++ )
   7.510 +    {
   7.511 +        for ( j = 0; j < PAT_TYPE_NUMS; j++ )
   7.512 +        {
   7.513 +            int tmp = mm_type_tbl[i][j];
   7.514 +            if ( (tmp >= 0) && (tmp < MEMORY_NUM_TYPES) )
   7.515 +                mtrr_epat_tbl[i][tmp] = j;
   7.516 +        }
   7.517 +    }
   7.518 +}
   7.519 +
   7.520 +u32 get_pat_flags(struct vcpu *v,
   7.521 +                  u32 gl1e_flags,
   7.522 +                  paddr_t gpaddr,
   7.523 +                  paddr_t spaddr)
   7.524 +{
   7.525 +    u8 guest_eff_mm_type;
   7.526 +    u8 shadow_mtrr_type;
   7.527 +    u8 pat_entry_value;
   7.528 +    u64 pat = v->arch.hvm_vcpu.pat_cr;
   7.529 +    struct mtrr_state *g = &v->arch.hvm_vcpu.mtrr;
   7.530 +
   7.531 +    /* 1. Get the effective memory type of guest physical address,
   7.532 +     * with the pair of guest MTRR and PAT
   7.533 +     */
   7.534 +    guest_eff_mm_type = effective_mm_type(g, pat, gpaddr, gl1e_flags);
   7.535 +    /* 2. Get the memory type of host physical address, with MTRR */
   7.536 +    shadow_mtrr_type = get_mtrr_type(&mtrr_state, spaddr);
   7.537 +
   7.538 +    /* 3. Find the memory type in PAT, with host MTRR memory type
   7.539 +     * and guest effective memory type.
   7.540 +     */
   7.541 +    pat_entry_value = mtrr_epat_tbl[shadow_mtrr_type][guest_eff_mm_type];
   7.542 +    /* If conflit occurs(e.g host MTRR is UC, guest memory type is
   7.543 +     * WB),set UC as effective memory. Here, returning PAT_TYPE_UNCACHABLE will
   7.544 +     * always set effective memory as UC.
   7.545 +     */
   7.546 +    if ( pat_entry_value == INVALID_MEM_TYPE )
   7.547 +    {
   7.548 +        gdprintk(XENLOG_WARNING,
   7.549 +                 "Conflict occurs for a given guest l1e flags:%x "
   7.550 +                 "at %"PRIx64" (the effective mm type:%d), "
   7.551 +                 "because the host mtrr type is:%d\n",
   7.552 +                 gl1e_flags, (uint64_t)gpaddr, guest_eff_mm_type,
   7.553 +                 shadow_mtrr_type);
   7.554 +        pat_entry_value = PAT_TYPE_UNCACHABLE;
   7.555 +    }
   7.556 +    /* 4. Get the pte flags */
   7.557 +    return pat_type_2_pte_flags(pat_entry_value);
   7.558 +}
   7.559 +
   7.560 +/* Helper funtions for seting mtrr/pat */
   7.561 +bool pat_msr_set(u64 *pat, u64 msr_content)
   7.562 +{
   7.563 +    u8 *value = (u8*)&msr_content;
   7.564 +    int i;
   7.565 +
   7.566 +    if ( *pat != msr_content )
   7.567 +    {
   7.568 +        for ( i = 0; i < 8; i++ )
   7.569 +            if ( unlikely(!(value[i] == 0 || value[i] == 1 ||
   7.570 +                            value[i] == 4 || value[i] == 5 ||
   7.571 +                            value[i] == 6 || value[i] == 7)) )
   7.572 +                return 0;
   7.573 +
   7.574 +        *pat = msr_content;
   7.575 +    }
   7.576 +
   7.577 +    return 1;
   7.578 +}
   7.579 +
   7.580 +bool mtrr_def_type_msr_set(struct mtrr_state *m, u64 msr_content)
   7.581 +{
   7.582 +    u8 def_type = msr_content & 0xff;
   7.583 +    u8 enabled = (msr_content >> 10) & 0x3;
   7.584 +
   7.585 +    if ( unlikely(!(def_type == 0 || def_type == 1 || def_type == 4 ||
   7.586 +                    def_type == 5 || def_type == 6)) )
   7.587 +    {
   7.588 +         HVM_DBG_LOG(DBG_LEVEL_MSR, "invalid MTRR def type:%x\n", def_type);
   7.589 +         return 0;
   7.590 +    }
   7.591 +
   7.592 +    if ( unlikely(msr_content && (msr_content & ~0xcffUL)) )
   7.593 +    {
   7.594 +         HVM_DBG_LOG(DBG_LEVEL_MSR, "invalid msr content:%"PRIx64"\n",
   7.595 +                     msr_content);
   7.596 +         return 0;
   7.597 +    }
   7.598 +
   7.599 +    m->enabled = enabled;
   7.600 +    m->def_type = def_type;
   7.601 +
   7.602 +    return 1;
   7.603 +}
   7.604 +
   7.605 +bool mtrr_fix_range_msr_set(struct mtrr_state *m, int row, u64 msr_content)
   7.606 +{
   7.607 +    u64 *fixed_range_base = (u64 *)m->fixed_ranges;
   7.608 +
   7.609 +    if ( fixed_range_base[row] != msr_content )
   7.610 +    {
   7.611 +        u8 *range = (u8*)&msr_content;
   7.612 +        int i, type;
   7.613 +
   7.614 +        for ( i = 0; i < 8; i++ )
   7.615 +        {
   7.616 +            type = range[i];
   7.617 +            if ( unlikely(!(type == 0 || type == 1 ||
   7.618 +                            type == 4 || type == 5 || type == 6)) )
   7.619 +                return 0;
   7.620 +        }
   7.621 +
   7.622 +        fixed_range_base[row] = msr_content;
   7.623 +    }
   7.624 +
   7.625 +    return 1;
   7.626 +}
   7.627 +
   7.628 +bool mtrr_var_range_msr_set(struct mtrr_state *m, u32 msr, u64 msr_content)
   7.629 +{
   7.630 +    u32 index;
   7.631 +    u64 msr_mask;
   7.632 +    u64 *var_range_base = (u64*)m->var_ranges;
   7.633 +
   7.634 +    index = msr - MSR_IA32_MTRR_PHYSBASE0;
   7.635 +
   7.636 +    if ( var_range_base[index] != msr_content )
   7.637 +    {
   7.638 +        u32 type = msr_content & 0xff;
   7.639 +
   7.640 +        msr_mask = (index & 1) ? phys_mask_msr_mask : phys_base_msr_mask;
   7.641 +
   7.642 +        if ( unlikely(!(type == 0 || type == 1 ||
   7.643 +                        type == 4 || type == 5 || type == 6)) )
   7.644 +            return 0;
   7.645 +
   7.646 +        if ( unlikely(msr_content && (msr_content & msr_mask)) )
   7.647 +        {
   7.648 +            HVM_DBG_LOG(DBG_LEVEL_MSR, "invalid msr content:%"PRIx64"\n",
   7.649 +                        msr_content);
   7.650 +            return 0;
   7.651 +        }
   7.652 +
   7.653 +        var_range_base[index] = msr_content;
   7.654 +    }
   7.655 +
   7.656 +    m->overlapped = is_var_mtrr_overlapped(m);
   7.657 +
   7.658 +    return 1;
   7.659 +}
   7.660 +
   7.661 +bool_t mtrr_pat_not_equal(struct vcpu *vd, struct vcpu *vs)
   7.662 +{
   7.663 +    struct mtrr_state *md = &vd->arch.hvm_vcpu.mtrr;
   7.664 +    struct mtrr_state *ms = &vs->arch.hvm_vcpu.mtrr;
   7.665 +    int res;
   7.666 +    u8 num_var_ranges = (u8)md->mtrr_cap;
   7.667 +
   7.668 +    /* Test fixed ranges. */
   7.669 +    res = memcmp(md->fixed_ranges, ms->fixed_ranges,
   7.670 +            NUM_FIXED_RANGES*sizeof(mtrr_type));
   7.671 +    if ( res )
   7.672 +        return 1;
   7.673 +
   7.674 +    /* Test var ranges. */
   7.675 +    res = memcmp(md->var_ranges, ms->var_ranges,
   7.676 +            num_var_ranges*sizeof(struct mtrr_var_range));
   7.677 +    if ( res )
   7.678 +        return 1;
   7.679 +
   7.680 +    /* Test default type MSR. */
   7.681 +    if ( (md->def_type != ms->def_type)
   7.682 +            && (md->enabled != ms->enabled) )
   7.683 +        return 1;
   7.684 +
   7.685 +    /* Test PAT. */
   7.686 +    if ( vd->arch.hvm_vcpu.pat_cr != vs->arch.hvm_vcpu.pat_cr )
   7.687 +        return 1;
   7.688 +
   7.689 +    return 0;
   7.690 +}
     8.1 --- a/xen/arch/x86/hvm/vmx/vmcs.c	Mon Oct 22 13:04:32 2007 +0100
     8.2 +++ b/xen/arch/x86/hvm/vmx/vmcs.c	Mon Oct 22 14:19:22 2007 +0100
     8.3 @@ -756,6 +756,11 @@ void vm_resume_fail(unsigned long eflags
     8.4      domain_crash_synchronous();
     8.5  }
     8.6  
     8.7 +static void flush_cache(void *info)
     8.8 +{
     8.9 +    wbinvd();
    8.10 +}
    8.11 +
    8.12  void vmx_do_resume(struct vcpu *v)
    8.13  {
    8.14      bool_t debug_state;
    8.15 @@ -767,6 +772,18 @@ void vmx_do_resume(struct vcpu *v)
    8.16      }
    8.17      else
    8.18      {
    8.19 +        /* For pass-through domain, guest PCI-E device driver may leverage the
    8.20 +         * "Non-Snoop" I/O, and explicitly "WBINVD" or "CFLUSH" to a RAM space.
    8.21 +         * In that case, if migration occurs before "WBINVD" or "CFLUSH", need
    8.22 +         * to maintain data consistency.
    8.23 +         */
    8.24 +        if ( !list_empty(&(domain_hvm_iommu(v->domain)->pdev_list)) )
    8.25 +        {
    8.26 +            int cpu = v->arch.hvm_vmx.active_cpu;
    8.27 +            if ( cpu != -1 )
    8.28 +                on_selected_cpus(cpumask_of_cpu(cpu), flush_cache, NULL, 1, 1);
    8.29 +        }
    8.30 +
    8.31          vmx_clear_vmcs(v);
    8.32          vmx_load_vmcs(v);
    8.33          hvm_migrate_timers(v);
     9.1 --- a/xen/arch/x86/hvm/vmx/vmx.c	Mon Oct 22 13:04:32 2007 +0100
     9.2 +++ b/xen/arch/x86/hvm/vmx/vmx.c	Mon Oct 22 14:19:22 2007 +0100
     9.3 @@ -50,6 +50,7 @@
     9.4  #include <asm/hvm/vpt.h>
     9.5  #include <public/hvm/save.h>
     9.6  #include <asm/hvm/trace.h>
     9.7 +#include <stdbool.h>
     9.8  
     9.9  enum handler_return { HNDL_done, HNDL_unhandled, HNDL_exception_raised };
    9.10  
    9.11 @@ -2285,6 +2286,9 @@ static int vmx_do_msr_read(struct cpu_us
    9.12      u64 msr_content = 0;
    9.13      u32 ecx = regs->ecx, eax, edx;
    9.14      struct vcpu *v = current;
    9.15 +    int index;
    9.16 +    u64 *var_range_base = (u64*)v->arch.hvm_vcpu.mtrr.var_ranges;
    9.17 +    u64 *fixed_range_base =  (u64*)v->arch.hvm_vcpu.mtrr.fixed_ranges;
    9.18  
    9.19      HVM_DBG_LOG(DBG_LEVEL_1, "ecx=%x", ecx);
    9.20  
    9.21 @@ -2305,6 +2309,32 @@ static int vmx_do_msr_read(struct cpu_us
    9.22      case MSR_IA32_APICBASE:
    9.23          msr_content = vcpu_vlapic(v)->hw.apic_base_msr;
    9.24          break;
    9.25 +    case MSR_IA32_CR_PAT:
    9.26 +        msr_content = v->arch.hvm_vcpu.pat_cr;
    9.27 +        break;
    9.28 +    case MSR_MTRRcap:
    9.29 +        msr_content = v->arch.hvm_vcpu.mtrr.mtrr_cap;
    9.30 +        break;
    9.31 +    case MSR_MTRRdefType:
    9.32 +        msr_content = v->arch.hvm_vcpu.mtrr.def_type
    9.33 +                        | (v->arch.hvm_vcpu.mtrr.enabled << 10);
    9.34 +        break;
    9.35 +    case MSR_MTRRfix64K_00000:
    9.36 +        msr_content = fixed_range_base[0];
    9.37 +        break;
    9.38 +    case MSR_MTRRfix16K_80000:
    9.39 +    case MSR_MTRRfix16K_A0000:
    9.40 +        index = regs->ecx - MSR_MTRRfix16K_80000;
    9.41 +        msr_content = fixed_range_base[index + 1];
    9.42 +        break;
    9.43 +    case MSR_MTRRfix4K_C0000...MSR_MTRRfix4K_F8000:
    9.44 +        index = regs->ecx - MSR_MTRRfix4K_C0000;
    9.45 +        msr_content = fixed_range_base[index + 3];
    9.46 +        break;
    9.47 +    case MSR_IA32_MTRR_PHYSBASE0...MSR_IA32_MTRR_PHYSMASK7:
    9.48 +        index = regs->ecx - MSR_IA32_MTRR_PHYSBASE0;
    9.49 +        msr_content = var_range_base[index];
    9.50 +        break;
    9.51      case MSR_IA32_DEBUGCTLMSR:
    9.52          if ( vmx_read_guest_msr(v, ecx, &msr_content) != 0 )
    9.53              msr_content = 0;
    9.54 @@ -2428,11 +2458,19 @@ void vmx_vlapic_msr_changed(struct vcpu 
    9.55      vmx_vmcs_exit(v);
    9.56  }
    9.57  
    9.58 +extern bool mtrr_var_range_msr_set(struct mtrr_state *v,
    9.59 +        u32 msr, u64 msr_content);
    9.60 +extern bool mtrr_fix_range_msr_set(struct mtrr_state *v,
    9.61 +        int row, u64 msr_content);
    9.62 +extern bool mtrr_def_type_msr_set(struct mtrr_state *v, u64 msr_content);
    9.63 +extern bool pat_msr_set(u64 *pat, u64 msr);
    9.64 +
    9.65  static int vmx_do_msr_write(struct cpu_user_regs *regs)
    9.66  {
    9.67      u32 ecx = regs->ecx;
    9.68      u64 msr_content;
    9.69      struct vcpu *v = current;
    9.70 +    int index;
    9.71  
    9.72      HVM_DBG_LOG(DBG_LEVEL_1, "ecx=%x, eax=%x, edx=%x",
    9.73                  ecx, (u32)regs->eax, (u32)regs->edx);
    9.74 @@ -2459,6 +2497,38 @@ static int vmx_do_msr_write(struct cpu_u
    9.75      case MSR_IA32_APICBASE:
    9.76          vlapic_msr_set(vcpu_vlapic(v), msr_content);
    9.77          break;
    9.78 +    case MSR_IA32_CR_PAT:
    9.79 +        if ( !pat_msr_set(&v->arch.hvm_vcpu.pat_cr, msr_content) )
    9.80 +           goto gp_fault;
    9.81 +        break;
    9.82 +    case MSR_MTRRdefType:
    9.83 +        if ( !mtrr_def_type_msr_set(&v->arch.hvm_vcpu.mtrr, msr_content) )
    9.84 +           goto gp_fault;
    9.85 +        break;
    9.86 +    case MSR_MTRRfix64K_00000:
    9.87 +        if ( !mtrr_fix_range_msr_set(&v->arch.hvm_vcpu.mtrr, 0, msr_content) )
    9.88 +            goto gp_fault;
    9.89 +        break;
    9.90 +    case MSR_MTRRfix16K_80000:
    9.91 +    case MSR_MTRRfix16K_A0000:
    9.92 +        index = regs->ecx - MSR_MTRRfix16K_80000 + 1;
    9.93 +        if ( !mtrr_fix_range_msr_set(&v->arch.hvm_vcpu.mtrr,
    9.94 +                                     index, msr_content) )
    9.95 +            goto gp_fault;
    9.96 +        break;
    9.97 +    case MSR_MTRRfix4K_C0000...MSR_MTRRfix4K_F8000:
    9.98 +        index = regs->ecx - MSR_MTRRfix4K_C0000 + 3;
    9.99 +        if ( !mtrr_fix_range_msr_set(&v->arch.hvm_vcpu.mtrr,
   9.100 +                                     index, msr_content) )
   9.101 +            goto gp_fault;
   9.102 +        break;
   9.103 +    case MSR_IA32_MTRR_PHYSBASE0...MSR_IA32_MTRR_PHYSMASK7:
   9.104 +        if ( !mtrr_var_range_msr_set(&v->arch.hvm_vcpu.mtrr,
   9.105 +                                     regs->ecx, msr_content) )
   9.106 +            goto gp_fault;
   9.107 +        break;
   9.108 +    case MSR_MTRRcap:
   9.109 +        goto gp_fault;
   9.110      case MSR_IA32_DEBUGCTLMSR: {
   9.111          int i, rc = 0;
   9.112  
    10.1 --- a/xen/arch/x86/mm.c	Mon Oct 22 13:04:32 2007 +0100
    10.2 +++ b/xen/arch/x86/mm.c	Mon Oct 22 14:19:22 2007 +0100
    10.3 @@ -3115,6 +3115,15 @@ long arch_memory_op(int op, XEN_GUEST_HA
    10.4          case XENMAPSPACE_shared_info:
    10.5              if ( xatp.idx == 0 )
    10.6                  mfn = virt_to_mfn(d->shared_info);
    10.7 +            /* XXX: assumption here, this is called after E820 table is build
    10.8 +             * need the E820 to initialize MTRR.
    10.9 +             */
   10.10 +            if ( is_hvm_domain(d) ) {
   10.11 +                extern void init_mtrr_in_hyper(struct vcpu *);
   10.12 +                struct vcpu *vs;
   10.13 +                for_each_vcpu(d, vs)
   10.14 +                    init_mtrr_in_hyper(vs);
   10.15 +            }
   10.16              break;
   10.17          case XENMAPSPACE_grant_table:
   10.18              spin_lock(&d->grant_table->lock);
    11.1 --- a/xen/arch/x86/mm/shadow/common.c	Mon Oct 22 13:04:32 2007 +0100
    11.2 +++ b/xen/arch/x86/mm/shadow/common.c	Mon Oct 22 14:19:22 2007 +0100
    11.3 @@ -880,6 +880,14 @@ static void shadow_blow_tables(struct do
    11.4      flush_tlb_mask(d->domain_dirty_cpumask);
    11.5  }
    11.6  
    11.7 +void shadow_blow_tables_per_domain(struct domain *d)
    11.8 +{
    11.9 +    if ( shadow_mode_enabled(d) && d->vcpu[0] != NULL ) {
   11.10 +        shadow_lock(d);
   11.11 +        shadow_blow_tables(d);
   11.12 +        shadow_unlock(d);
   11.13 +    }
   11.14 +}
   11.15  
   11.16  #ifndef NDEBUG
   11.17  /* Blow all shadows of all shadowed domains: this can be used to cause the
    12.1 --- a/xen/arch/x86/mm/shadow/multi.c	Mon Oct 22 13:04:32 2007 +0100
    12.2 +++ b/xen/arch/x86/mm/shadow/multi.c	Mon Oct 22 14:19:22 2007 +0100
    12.3 @@ -33,6 +33,7 @@
    12.4  #include <asm/shadow.h>
    12.5  #include <asm/flushtlb.h>
    12.6  #include <asm/hvm/hvm.h>
    12.7 +#include <asm/mtrr.h>
    12.8  #include "private.h"
    12.9  #include "types.h"
   12.10  
   12.11 @@ -267,6 +268,11 @@ guest_walk_tables(struct vcpu *v, unsign
   12.12           * us reflect l2 changes later without touching the l1s. */
   12.13          int flags = (_PAGE_PRESENT|_PAGE_USER|_PAGE_RW|
   12.14                       _PAGE_ACCESSED|_PAGE_DIRTY);
   12.15 +        /* propagate PWT PCD to level 1 for PSE */
   12.16 +        if ( (guest_l2e_get_flags(*gw->l2e) & _PAGE_PWT) )
   12.17 +            flags |= _PAGE_PWT;
   12.18 +        if ( (guest_l2e_get_flags(*gw->l2e) & _PAGE_PCD) )
   12.19 +            flags |= _PAGE_PCD;
   12.20          /* PSE level 2 entries use bit 12 for PAT; propagate it to bit 7
   12.21           * of the level 1 */
   12.22          if ( (guest_l2e_get_flags(*gw->l2e) & _PAGE_PSE_PAT) ) 
   12.23 @@ -614,7 +620,12 @@ shadow_l4_index(mfn_t *smfn, u32 guest_i
   12.24  
   12.25  #endif // GUEST_PAGING_LEVELS >= 4
   12.26  
   12.27 -
   12.28 +extern u32 get_pat_flags(struct vcpu *v,
   12.29 +                  u32 gl1e_flags,
   12.30 +                  paddr_t gpaddr,
   12.31 +                  paddr_t spaddr);
   12.32 +
   12.33 +unsigned char pat_type_2_pte_flags(unsigned char pat_type);
   12.34  /**************************************************************************/
   12.35  /* Function which computes shadow entries from their corresponding guest
   12.36   * entries.  This is the "heart" of the shadow code. It operates using
   12.37 @@ -703,6 +714,17 @@ static always_inline void
   12.38          pass_thru_flags |= _PAGE_NX_BIT;
   12.39      sflags = gflags & pass_thru_flags;
   12.40  
   12.41 +    /* Only change memory caching type for pass-through domain */
   12.42 +    if ( (level == 1) && !list_empty(&(domain_hvm_iommu(d)->pdev_list)) ) {
   12.43 +        if ( v->domain->arch.hvm_domain.is_in_uc_mode )
   12.44 +            sflags |= pat_type_2_pte_flags(PAT_TYPE_UNCACHABLE);
   12.45 +        else
   12.46 +            sflags |= get_pat_flags(v,
   12.47 +                                    gflags,
   12.48 +                                    guest_l1e_get_paddr(*gp),
   12.49 +                                    mfn_x(target_mfn) << PAGE_SHIFT);
   12.50 +    }
   12.51 +
   12.52      // Set the A&D bits for higher level shadows.
   12.53      // Higher level entries do not, strictly speaking, have dirty bits, but
   12.54      // since we use shadow linear tables, each of these entries may, at some
   12.55 @@ -774,10 +796,6 @@ static always_inline void
   12.56          sflags |= _PAGE_USER;
   12.57      }
   12.58  
   12.59 -    /* MMIO addresses should never be cached */
   12.60 -    if ( p2m_is_mmio(p2mt) )
   12.61 -        sflags |= _PAGE_PCD;
   12.62 -
   12.63      *sp = shadow_l1e_from_mfn(target_mfn, sflags);
   12.64  
   12.65   done:
    13.1 --- a/xen/include/asm-x86/cpufeature.h	Mon Oct 22 13:04:32 2007 +0100
    13.2 +++ b/xen/include/asm-x86/cpufeature.h	Mon Oct 22 14:19:22 2007 +0100
    13.3 @@ -128,6 +128,7 @@
    13.4  #define cpu_has_tsc		boot_cpu_has(X86_FEATURE_TSC)
    13.5  #define cpu_has_pae		boot_cpu_has(X86_FEATURE_PAE)
    13.6  #define cpu_has_pge		boot_cpu_has(X86_FEATURE_PGE)
    13.7 +#define cpu_has_pat		boot_cpu_has(X86_FEATURE_PAT)
    13.8  #define cpu_has_apic		boot_cpu_has(X86_FEATURE_APIC)
    13.9  #define cpu_has_sep		boot_cpu_has(X86_FEATURE_SEP)
   13.10  #define cpu_has_mtrr		boot_cpu_has(X86_FEATURE_MTRR)
   13.11 @@ -152,6 +153,7 @@
   13.12  #define cpu_has_tsc		1
   13.13  #define cpu_has_pae		1
   13.14  #define cpu_has_pge		1
   13.15 +#define cpu_has_pat		1
   13.16  #define cpu_has_apic		boot_cpu_has(X86_FEATURE_APIC)
   13.17  #define cpu_has_sep		0
   13.18  #define cpu_has_mtrr		1
    14.1 --- a/xen/include/asm-x86/hvm/domain.h	Mon Oct 22 13:04:32 2007 +0100
    14.2 +++ b/xen/include/asm-x86/hvm/domain.h	Mon Oct 22 14:19:22 2007 +0100
    14.3 @@ -61,6 +61,12 @@ struct hvm_domain {
    14.4  
    14.5      unsigned long          vmx_apic_access_mfn;
    14.6  
    14.7 +    /* If one of vcpus of this domain is in no_fill_mode or
    14.8 +     * mtrr/pat between vcpus is not the same, set is_in_uc_mode
    14.9 +     */
   14.10 +    spinlock_t       uc_lock;
   14.11 +    bool_t           is_in_uc_mode;
   14.12 +
   14.13      /* Pass-through */
   14.14      struct hvm_iommu       hvm_iommu;
   14.15  };
    15.1 --- a/xen/include/asm-x86/hvm/support.h	Mon Oct 22 13:04:32 2007 +0100
    15.2 +++ b/xen/include/asm-x86/hvm/support.h	Mon Oct 22 14:19:22 2007 +0100
    15.3 @@ -64,6 +64,7 @@ static inline vcpu_iodata_t *get_ioreq(s
    15.4  #define DBG_LEVEL_VLAPIC_INTERRUPT  (1 << 8)
    15.5  #define DBG_LEVEL_IOAPIC            (1 << 9)
    15.6  #define DBG_LEVEL_HCALL             (1 << 10)
    15.7 +#define DBG_LEVEL_MSR               (1 << 11)
    15.8  
    15.9  extern unsigned int opt_hvm_debug_level;
   15.10  #define HVM_DBG_LOG(level, _f, _a...)                                         \
    16.1 --- a/xen/include/asm-x86/hvm/vcpu.h	Mon Oct 22 13:04:32 2007 +0100
    16.2 +++ b/xen/include/asm-x86/hvm/vcpu.h	Mon Oct 22 14:19:22 2007 +0100
    16.3 @@ -24,6 +24,7 @@
    16.4  #include <asm/hvm/vlapic.h>
    16.5  #include <asm/hvm/vmx/vmcs.h>
    16.6  #include <asm/hvm/svm/vmcb.h>
    16.7 +#include <asm/mtrr.h>
    16.8  
    16.9  #define HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM          0
   16.10  #define HVM_VCPU_INIT_SIPI_SIPI_STATE_WAIT_SIPI     1
   16.11 @@ -62,6 +63,12 @@ struct hvm_vcpu {
   16.12          struct arch_vmx_struct vmx;
   16.13          struct arch_svm_struct svm;
   16.14      } u;
   16.15 +
   16.16 +    struct mtrr_state   mtrr;
   16.17 +    u64                 pat_cr;
   16.18 +
   16.19 +    /* Which cache mode is this VCPU in (CR0:CD/NW)? */
   16.20 +    u8                  cache_mode;
   16.21  };
   16.22  
   16.23  #define ARCH_HVM_IO_WAIT         1   /* Waiting for I/O completion */
    17.1 --- a/xen/include/asm-x86/msr-index.h	Mon Oct 22 13:04:32 2007 +0100
    17.2 +++ b/xen/include/asm-x86/msr-index.h	Mon Oct 22 14:19:22 2007 +0100
    17.3 @@ -68,6 +68,25 @@
    17.4  #define MSR_IA32_LASTBRANCHTOIP		0x000001dc
    17.5  #define MSR_IA32_LASTINTFROMIP		0x000001dd
    17.6  #define MSR_IA32_LASTINTTOIP		0x000001de
    17.7 + 
    17.8 +#define MSR_IA32_MTRR_PHYSBASE0     0x00000200
    17.9 +#define MSR_IA32_MTRR_PHYSMASK0     0x00000201
   17.10 +#define MSR_IA32_MTRR_PHYSBASE1     0x00000202
   17.11 +#define MSR_IA32_MTRR_PHYSMASK1     0x00000203
   17.12 +#define MSR_IA32_MTRR_PHYSBASE2     0x00000204
   17.13 +#define MSR_IA32_MTRR_PHYSMASK2     0x00000205
   17.14 +#define MSR_IA32_MTRR_PHYSBASE3     0x00000206
   17.15 +#define MSR_IA32_MTRR_PHYSMASK3     0x00000207
   17.16 +#define MSR_IA32_MTRR_PHYSBASE4     0x00000208
   17.17 +#define MSR_IA32_MTRR_PHYSMASK4     0x00000209
   17.18 +#define MSR_IA32_MTRR_PHYSBASE5     0x0000020a
   17.19 +#define MSR_IA32_MTRR_PHYSMASK5     0x0000020b
   17.20 +#define MSR_IA32_MTRR_PHYSBASE6     0x0000020c
   17.21 +#define MSR_IA32_MTRR_PHYSMASK6     0x0000020d
   17.22 +#define MSR_IA32_MTRR_PHYSBASE7     0x0000020e
   17.23 +#define MSR_IA32_MTRR_PHYSMASK7     0x0000020f
   17.24 +
   17.25 +#define MSR_IA32_CR_PAT             0x00000277
   17.26  
   17.27  #define MSR_IA32_MC0_CTL		0x00000400
   17.28  #define MSR_IA32_MC0_STATUS		0x00000401
    18.1 --- a/xen/include/asm-x86/mtrr.h	Mon Oct 22 13:04:32 2007 +0100
    18.2 +++ b/xen/include/asm-x86/mtrr.h	Mon Oct 22 14:19:22 2007 +0100
    18.3 @@ -10,6 +10,55 @@
    18.4  #define MTRR_TYPE_WRPROT     5
    18.5  #define MTRR_TYPE_WRBACK     6
    18.6  #define MTRR_NUM_TYPES       7
    18.7 +#define MEMORY_NUM_TYPES     MTRR_NUM_TYPES
    18.8 +
    18.9 +#define MTRR_PHYSMASK_VALID_BIT  11
   18.10 +#define MTRR_PHYSMASK_SHIFT      12
   18.11 +
   18.12 +#define MTRR_PHYSBASE_TYPE_MASK  0xff   /* lowest 8 bits */
   18.13 +#define MTRR_PHYSBASE_SHIFT      12
   18.14 +#define MTRR_VCNT            8
   18.15 +
   18.16 +#define NORMAL_CACHE_MODE          0
   18.17 +#define NO_FILL_CACHE_MODE         2
   18.18 +
   18.19 +enum {
   18.20 +    PAT_TYPE_UNCACHABLE=0,
   18.21 +    PAT_TYPE_WRCOMB=1,
   18.22 +    PAT_TYPE_RESERVED=2,
   18.23 +    PAT_TYPE_WRTHROUGH=4,
   18.24 +    PAT_TYPE_WRPROT=5,
   18.25 +    PAT_TYPE_WRBACK=6,
   18.26 +    PAT_TYPE_UC_MINUS=7,
   18.27 +    PAT_TYPE_NUMS
   18.28 +};
   18.29 +
   18.30 +#define INVALID_MEM_TYPE PAT_TYPE_NUMS
   18.31 +
   18.32 +/* In the Intel processor's MTRR interface, the MTRR type is always held in
   18.33 +   an 8 bit field: */
   18.34 +typedef u8 mtrr_type;
   18.35 +
   18.36 +struct mtrr_var_range {
   18.37 +	u32 base_lo;
   18.38 +	u32 base_hi;
   18.39 +	u32 mask_lo;
   18.40 +	u32 mask_hi;
   18.41 +};
   18.42 +
   18.43 +#define NUM_FIXED_RANGES 88
   18.44 +struct mtrr_state {
   18.45 +	struct mtrr_var_range *var_ranges;
   18.46 +	mtrr_type fixed_ranges[NUM_FIXED_RANGES];
   18.47 +	unsigned char enabled;
   18.48 +	unsigned char have_fixed;
   18.49 +	mtrr_type def_type;
   18.50 +
   18.51 +	u64       mtrr_cap;
   18.52 +	/* ranges in var MSRs are overlapped or not:0(no overlapped) */
   18.53 +	bool_t    overlapped;
   18.54 +	bool_t    is_initialized;
   18.55 +};
   18.56  
   18.57  extern void mtrr_save_fixed_ranges(void *);
   18.58  extern void mtrr_save_state(void);