diff -r 9854a2ab9608 xen/arch/x86/hvm/mtrr.c --- a/xen/arch/x86/hvm/mtrr.c Wed Jan 21 20:25:08 2009 -0500 +++ b/xen/arch/x86/hvm/mtrr.c Wed Jan 21 20:28:42 2009 -0500 @@ -702,11 +702,14 @@ 1, HVMSR_PER_VCPU); uint8_t epte_get_entry_emt( - struct domain *d, unsigned long gfn, unsigned long mfn) + struct domain *d, unsigned long gfn, + unsigned long mfn, uint8_t *igmt, int direct_mmio) { uint8_t gmtrr_mtype, hmtrr_mtype; uint32_t type; struct vcpu *v = current; + + *igmt = 0; if ( (current->domain != d) && ((v = d->vcpu[0]) == NULL) ) return MTRR_TYPE_WRBACK; @@ -723,6 +726,21 @@ if ( hvm_get_mem_pinned_cacheattr(d, gfn, &type) ) return type; + if ( !iommu_enabled ) + { + *igmt = 1; + return MTRR_TYPE_WRBACK; + } + + if ( direct_mmio ) + return MTRR_TYPE_UNCACHABLE; + + if ( iommu_snoop ) + { + *igmt = 1; + return MTRR_TYPE_WRBACK; + } + gmtrr_mtype = get_mtrr_type(&v->arch.hvm_vcpu.mtrr, (gfn << PAGE_SHIFT)); hmtrr_mtype = get_mtrr_type(&mtrr_state, (mfn << PAGE_SHIFT)); return ((gmtrr_mtype <= hmtrr_mtype) ? gmtrr_mtype : hmtrr_mtype); diff -r 9854a2ab9608 xen/arch/x86/hvm/vmx/vmx.c --- a/xen/arch/x86/hvm/vmx/vmx.c Wed Jan 21 20:25:08 2009 -0500 +++ b/xen/arch/x86/hvm/vmx/vmx.c Wed Jan 21 20:28:42 2009 -0500 @@ -1306,9 +1306,11 @@ static void vmx_set_uc_mode(struct vcpu *v) { + v->domain->arch.hvm_domain.is_untaint = 1; if ( paging_mode_hap(v->domain) ) ept_change_entry_emt_with_range( v->domain, 0, v->domain->arch.p2m->max_mapped_pfn); + v->domain->arch.hvm_domain.is_untaint = 0; vpid_sync_all(); } diff -r 9854a2ab9608 xen/arch/x86/mm/hap/p2m-ept.c --- a/xen/arch/x86/mm/hap/p2m-ept.c Wed Jan 21 20:25:08 2009 -0500 +++ b/xen/arch/x86/mm/hap/p2m-ept.c Wed Jan 21 20:28:42 2009 -0500 @@ -66,6 +66,7 @@ list_add_tail(&pg->list, &d->arch.p2m->pages); ept_entry->emt = 0; + ept_entry->igmt = 0; ept_entry->sp_avail = 0; ept_entry->avail1 = 0; ept_entry->mfn = page_to_mfn(pg); @@ -124,6 +125,8 @@ u32 index; int i, rv = 0, ret = 0; int walk_level = order / EPT_TABLE_ORDER; + int direct_mmio = (p2mt == p2m_mmio_direct); + uint8_t igmt = 0; /* we only support 4k and 2m pages now */ @@ -157,7 +160,9 @@ { if ( mfn_valid(mfn_x(mfn)) || (p2mt == p2m_mmio_direct) ) { - ept_entry->emt = epte_get_entry_emt(d, gfn, mfn_x(mfn)); + ept_entry->emt = epte_get_entry_emt(d, gfn, mfn_x(mfn), + &igmt, direct_mmio); + ept_entry->igmt = igmt; ept_entry->sp_avail = walk_level ? 1 : 0; if ( ret == GUEST_TABLE_SUPER_PAGE ) @@ -208,7 +213,10 @@ { split_ept_entry = split_table + i; split_ept_entry->emt = epte_get_entry_emt(d, - gfn-offset+i, split_mfn+i); + gfn-offset+i, split_mfn+i, + &igmt, direct_mmio); + split_ept_entry->igmt = igmt; + split_ept_entry->sp_avail = 0; split_ept_entry->mfn = split_mfn+i; @@ -223,7 +231,10 @@ /* Set the destinated 4k page as normal */ split_ept_entry = split_table + offset; - split_ept_entry->emt = epte_get_entry_emt(d, gfn, mfn_x(mfn)); + split_ept_entry->emt = epte_get_entry_emt(d, gfn, mfn_x(mfn), + &igmt, direct_mmio); + split_ept_entry->igmt = igmt; + split_ept_entry->mfn = mfn_x(mfn); split_ept_entry->avail1 = p2mt; ept_p2m_type_to_flags(split_ept_entry, p2mt); @@ -246,7 +257,8 @@ /* Now the p2m table is not shared with vt-d page table */ - if ( iommu_enabled && is_hvm_domain(d) ) + if ( iommu_enabled && is_hvm_domain(d) && + !current->domain->arch.hvm_domain.is_untaint ) { if ( p2mt == p2m_ram_rw ) { diff -r 9854a2ab9608 xen/drivers/passthrough/iommu.c --- a/xen/drivers/passthrough/iommu.c Wed Jan 21 20:25:08 2009 -0500 +++ b/xen/drivers/passthrough/iommu.c Wed Jan 21 20:28:42 2009 -0500 @@ -39,6 +39,7 @@ int iommu_pv_enabled = 0; int force_iommu = 0; int iommu_passthrough = 0; +int iommu_snoop = 0; static void __init parse_iommu_param(char *s) { diff -r 9854a2ab9608 xen/drivers/passthrough/vtd/dmar.c --- a/xen/drivers/passthrough/vtd/dmar.c Wed Jan 21 20:25:08 2009 -0500 +++ b/xen/drivers/passthrough/vtd/dmar.c Wed Jan 21 20:28:42 2009 -0500 @@ -29,6 +29,7 @@ #include #include #include "dmar.h" +#include "iommu.h" int vtd_enabled = 1; @@ -508,6 +509,8 @@ int acpi_dmar_init(void) { int rc; + struct acpi_drhd_unit *drhd; + struct iommu *iommu; rc = -ENODEV; if ( force_iommu ) @@ -524,7 +527,20 @@ if ( list_empty(&acpi_drhd_units) ) goto fail; - printk("Intel VT-d has been enabled\n"); + /* Giving that all devices within guest use same io page table, + * enable snoop control only if all VT-d engines support it. + */ + iommu_snoop = 1; + for_each_drhd_unit ( drhd ) + { + iommu = drhd->iommu; + if ( !ecap_snp_ctl(iommu->ecap) ) { + iommu_snoop = 0; + break; + } + } + + printk("Intel VT-d has been enabled, snoop_control=%d.\n", iommu_snoop); return 0; diff -r 9854a2ab9608 xen/drivers/passthrough/vtd/iommu.c --- a/xen/drivers/passthrough/vtd/iommu.c Wed Jan 21 20:25:08 2009 -0500 +++ b/xen/drivers/passthrough/vtd/iommu.c Wed Jan 21 20:28:42 2009 -0500 @@ -1482,6 +1482,11 @@ pte_present = dma_pte_present(*pte); dma_set_pte_addr(*pte, (paddr_t)mfn << PAGE_SHIFT_4K); dma_set_pte_prot(*pte, DMA_PTE_READ | DMA_PTE_WRITE); + + /* Set the SNP on leaf page table if Snoop Control available */ + if ( iommu_snoop ) + dma_set_pte_snp(*pte); + iommu_flush_cache_entry(pte); spin_unlock(&hd->mapping_lock); unmap_vtd_domain_page(page); diff -r 9854a2ab9608 xen/drivers/passthrough/vtd/iommu.h --- a/xen/drivers/passthrough/vtd/iommu.h Wed Jan 21 20:25:08 2009 -0500 +++ b/xen/drivers/passthrough/vtd/iommu.h Wed Jan 21 20:28:42 2009 -0500 @@ -104,6 +104,7 @@ #define ecap_ext_intr(e) ((e >> 4) & 0x1) #define ecap_cache_hints(e) ((e >> 5) & 0x1) #define ecap_pass_thru(e) ((e >> 6) & 0x1) +#define ecap_snp_ctl(e) ((e >> 7) & 0x1) /* IOTLB_REG */ #define DMA_TLB_FLUSH_GRANU_OFFSET 60 @@ -260,10 +261,12 @@ }; #define DMA_PTE_READ (1) #define DMA_PTE_WRITE (2) +#define DMA_PTE_SNP (1 << 11) #define dma_clear_pte(p) do {(p).val = 0;} while(0) #define dma_set_pte_readable(p) do {(p).val |= DMA_PTE_READ;} while(0) #define dma_set_pte_writable(p) do {(p).val |= DMA_PTE_WRITE;} while(0) #define dma_set_pte_superpage(p) do {(p).val |= (1 << 7);} while(0) +#define dma_set_pte_snp(p) do {(p).val |= DMA_PTE_SNP;} while(0) #define dma_set_pte_prot(p, prot) \ do {(p).val = ((p).val & ~3) | ((prot) & 3); } while (0) #define dma_pte_addr(p) ((p).val & PAGE_MASK_4K) diff -r 9854a2ab9608 xen/include/asm-x86/hvm/domain.h --- a/xen/include/asm-x86/hvm/domain.h Wed Jan 21 20:25:08 2009 -0500 +++ b/xen/include/asm-x86/hvm/domain.h Wed Jan 21 20:28:42 2009 -0500 @@ -71,6 +71,7 @@ */ spinlock_t uc_lock; bool_t is_in_uc_mode; + bool_t is_untaint; /* Pass-through */ struct hvm_iommu hvm_iommu; diff -r 9854a2ab9608 xen/include/asm-x86/hvm/vmx/vmx.h --- a/xen/include/asm-x86/hvm/vmx/vmx.h Wed Jan 21 20:25:08 2009 -0500 +++ b/xen/include/asm-x86/hvm/vmx/vmx.h Wed Jan 21 20:28:42 2009 -0500 @@ -33,7 +33,8 @@ u64 r : 1, w : 1, x : 1, - emt : 4, + emt : 3, + igmt : 1, sp_avail : 1, avail1 : 4, mfn : 45, diff -r 9854a2ab9608 xen/include/asm-x86/mtrr.h --- a/xen/include/asm-x86/mtrr.h Wed Jan 21 20:25:08 2009 -0500 +++ b/xen/include/asm-x86/mtrr.h Wed Jan 21 20:28:42 2009 -0500 @@ -64,7 +64,7 @@ extern void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi); extern u32 get_pat_flags(struct vcpu *v, u32 gl1e_flags, paddr_t gpaddr, paddr_t spaddr); -extern uint8_t epte_get_entry_emt(struct domain *d, unsigned long gfn, unsigned long mfn); +extern uint8_t epte_get_entry_emt(struct domain *d, unsigned long gfn, unsigned long mfn, uint8_t *igmt, int direct_mmio); extern void ept_change_entry_emt_with_range(struct domain *d, unsigned long start_gfn, unsigned long end_gfn); extern unsigned char pat_type_2_pte_flags(unsigned char pat_type); diff -r 9854a2ab9608 xen/include/xen/iommu.h --- a/xen/include/xen/iommu.h Wed Jan 21 20:25:08 2009 -0500 +++ b/xen/include/xen/iommu.h Wed Jan 21 20:28:42 2009 -0500 @@ -31,6 +31,7 @@ extern int iommu_pv_enabled; extern int force_iommu; extern int iommu_passthrough; +extern int iommu_snoop; #define domain_hvm_iommu(d) (&d->arch.hvm_domain.hvm_iommu)