ia64/xen-unstable
changeset 19080:175a425e9b55
EPT/VT-d: Enhance MTRR/PAT virtualization when EPT/VT-d both enabled
Set effective memory type for EPT according to the VT-d snoop control
capability, and also includes some cleanups for EPT & VT-d both enabled.
Signed-off-by: Edwin Zhai <Edwin.Zhai@intel.com>
Signed-off-by: Xiaohui Xin <xiaohui.xin@intel.com>
Set effective memory type for EPT according to the VT-d snoop control
capability, and also includes some cleanups for EPT & VT-d both enabled.
Signed-off-by: Edwin Zhai <Edwin.Zhai@intel.com>
Signed-off-by: Xiaohui Xin <xiaohui.xin@intel.com>
author | Keir Fraser <keir.fraser@citrix.com> |
---|---|
date | Fri Jan 23 14:42:29 2009 +0000 (2009-01-23) |
parents | f3240cd3cd2b |
children | 257802327958 |
files | xen/arch/x86/hvm/mtrr.c xen/arch/x86/mm/hap/p2m-ept.c xen/drivers/passthrough/iommu.c xen/drivers/passthrough/vtd/dmar.c xen/drivers/passthrough/vtd/iommu.c xen/drivers/passthrough/vtd/iommu.h xen/include/asm-x86/hvm/vmx/vmx.h xen/include/asm-x86/mtrr.h xen/include/xen/iommu.h |
line diff
1.1 --- a/xen/arch/x86/hvm/mtrr.c Fri Jan 23 14:32:41 2009 +0000 1.2 +++ b/xen/arch/x86/hvm/mtrr.c Fri Jan 23 14:42:29 2009 +0000 1.3 @@ -702,12 +702,15 @@ HVM_REGISTER_SAVE_RESTORE(MTRR, hvm_save 1.4 1, HVMSR_PER_VCPU); 1.5 1.6 uint8_t epte_get_entry_emt( 1.7 - struct domain *d, unsigned long gfn, unsigned long mfn) 1.8 + struct domain *d, unsigned long gfn, 1.9 + unsigned long mfn, uint8_t *igmt, int direct_mmio) 1.10 { 1.11 uint8_t gmtrr_mtype, hmtrr_mtype; 1.12 uint32_t type; 1.13 struct vcpu *v = current; 1.14 1.15 + *igmt = 0; 1.16 + 1.17 if ( (current->domain != d) && ((v = d->vcpu[0]) == NULL) ) 1.18 return MTRR_TYPE_WRBACK; 1.19 1.20 @@ -723,6 +726,21 @@ uint8_t epte_get_entry_emt( 1.21 if ( hvm_get_mem_pinned_cacheattr(d, gfn, &type) ) 1.22 return type; 1.23 1.24 + if ( !iommu_enabled ) 1.25 + { 1.26 + *igmt = 1; 1.27 + return MTRR_TYPE_WRBACK; 1.28 + } 1.29 + 1.30 + if ( direct_mmio ) 1.31 + return MTRR_TYPE_UNCACHABLE; 1.32 + 1.33 + if ( iommu_snoop ) 1.34 + { 1.35 + *igmt = 1; 1.36 + return MTRR_TYPE_WRBACK; 1.37 + } 1.38 + 1.39 gmtrr_mtype = get_mtrr_type(&v->arch.hvm_vcpu.mtrr, (gfn << PAGE_SHIFT)); 1.40 hmtrr_mtype = get_mtrr_type(&mtrr_state, (mfn << PAGE_SHIFT)); 1.41 return ((gmtrr_mtype <= hmtrr_mtype) ? gmtrr_mtype : hmtrr_mtype);
2.1 --- a/xen/arch/x86/mm/hap/p2m-ept.c Fri Jan 23 14:32:41 2009 +0000 2.2 +++ b/xen/arch/x86/mm/hap/p2m-ept.c Fri Jan 23 14:42:29 2009 +0000 2.3 @@ -66,6 +66,7 @@ static int ept_set_middle_entry(struct d 2.4 list_add_tail(&pg->list, &d->arch.p2m->pages); 2.5 2.6 ept_entry->emt = 0; 2.7 + ept_entry->igmt = 0; 2.8 ept_entry->sp_avail = 0; 2.9 ept_entry->avail1 = 0; 2.10 ept_entry->mfn = page_to_mfn(pg); 2.11 @@ -114,9 +115,13 @@ static int ept_next_level(struct domain 2.12 } 2.13 } 2.14 2.15 +/* 2.16 + * TODO: ept_set_entry() computes 'need_modify_vtd_table' for itself, 2.17 + * by observing whether any gfn->mfn translations are modified. 2.18 + */ 2.19 static int 2.20 -ept_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn, 2.21 - unsigned int order, p2m_type_t p2mt) 2.22 +_ept_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn, 2.23 + unsigned int order, p2m_type_t p2mt, int need_modify_vtd_table) 2.24 { 2.25 ept_entry_t *table = NULL; 2.26 unsigned long gfn_remainder = gfn, offset = 0; 2.27 @@ -124,6 +129,8 @@ ept_set_entry(struct domain *d, unsigned 2.28 u32 index; 2.29 int i, rv = 0, ret = 0; 2.30 int walk_level = order / EPT_TABLE_ORDER; 2.31 + int direct_mmio = (p2mt == p2m_mmio_direct); 2.32 + uint8_t igmt = 0; 2.33 2.34 /* we only support 4k and 2m pages now */ 2.35 2.36 @@ -157,7 +164,9 @@ ept_set_entry(struct domain *d, unsigned 2.37 { 2.38 if ( mfn_valid(mfn_x(mfn)) || (p2mt == p2m_mmio_direct) ) 2.39 { 2.40 - ept_entry->emt = epte_get_entry_emt(d, gfn, mfn_x(mfn)); 2.41 + ept_entry->emt = epte_get_entry_emt(d, gfn, mfn_x(mfn), 2.42 + &igmt, direct_mmio); 2.43 + ept_entry->igmt = igmt; 2.44 ept_entry->sp_avail = walk_level ? 1 : 0; 2.45 2.46 if ( ret == GUEST_TABLE_SUPER_PAGE ) 2.47 @@ -208,7 +217,10 @@ ept_set_entry(struct domain *d, unsigned 2.48 { 2.49 split_ept_entry = split_table + i; 2.50 split_ept_entry->emt = epte_get_entry_emt(d, 2.51 - gfn-offset+i, split_mfn+i); 2.52 + gfn-offset+i, split_mfn+i, 2.53 + &igmt, direct_mmio); 2.54 + split_ept_entry->igmt = igmt; 2.55 + 2.56 split_ept_entry->sp_avail = 0; 2.57 2.58 split_ept_entry->mfn = split_mfn+i; 2.59 @@ -223,7 +235,10 @@ ept_set_entry(struct domain *d, unsigned 2.60 2.61 /* Set the destinated 4k page as normal */ 2.62 split_ept_entry = split_table + offset; 2.63 - split_ept_entry->emt = epte_get_entry_emt(d, gfn, mfn_x(mfn)); 2.64 + split_ept_entry->emt = epte_get_entry_emt(d, gfn, mfn_x(mfn), 2.65 + &igmt, direct_mmio); 2.66 + split_ept_entry->igmt = igmt; 2.67 + 2.68 split_ept_entry->mfn = mfn_x(mfn); 2.69 split_ept_entry->avail1 = p2mt; 2.70 ept_p2m_type_to_flags(split_ept_entry, p2mt); 2.71 @@ -246,7 +261,8 @@ out: 2.72 2.73 /* Now the p2m table is not shared with vt-d page table */ 2.74 2.75 - if ( iommu_enabled && is_hvm_domain(d) ) 2.76 + if ( iommu_enabled && is_hvm_domain(d) 2.77 + && need_modify_vtd_table ) 2.78 { 2.79 if ( p2mt == p2m_ram_rw ) 2.80 { 2.81 @@ -273,6 +289,17 @@ out: 2.82 return rv; 2.83 } 2.84 2.85 +static int 2.86 +ept_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn, 2.87 + unsigned int order, p2m_type_t p2mt) 2.88 +{ 2.89 + /* ept_set_entry() are called from set_entry(), 2.90 + * We should always create VT-d page table acording 2.91 + * to the gfn to mfn translations changes. 2.92 + */ 2.93 + return _ept_set_entry(d, gfn, mfn, order, p2mt, 1); 2.94 +} 2.95 + 2.96 /* Read ept p2m entries */ 2.97 static mfn_t ept_get_entry(struct domain *d, unsigned long gfn, p2m_type_t *t, 2.98 p2m_query_t q) 2.99 @@ -395,18 +422,30 @@ void ept_change_entry_emt_with_range(str 2.100 * Set emt for super page. 2.101 */ 2.102 order = EPT_TABLE_ORDER; 2.103 - ept_set_entry(d, gfn, _mfn(mfn), order, p2mt); 2.104 + /* vmx_set_uc_mode() dont' touch the gfn to mfn 2.105 + * translations, only modify the emt field of the EPT entries. 2.106 + * so we need not modify the current VT-d page tables. 2.107 + */ 2.108 + _ept_set_entry(d, gfn, _mfn(mfn), order, p2mt, 0); 2.109 gfn += 0x1FF; 2.110 } 2.111 else 2.112 { 2.113 - /* change emt for partial entries of the 2m area */ 2.114 - ept_set_entry(d, gfn, _mfn(mfn), order, p2mt); 2.115 + /* 1)change emt for partial entries of the 2m area. 2.116 + * 2)vmx_set_uc_mode() dont' touch the gfn to mfn 2.117 + * translations, only modify the emt field of the EPT entries. 2.118 + * so we need not modify the current VT-d page tables. 2.119 + */ 2.120 + _ept_set_entry(d, gfn, _mfn(mfn), order, p2mt,0); 2.121 gfn = ((gfn >> EPT_TABLE_ORDER) << EPT_TABLE_ORDER) + 0x1FF; 2.122 } 2.123 } 2.124 - else /* gfn assigned with 4k */ 2.125 - ept_set_entry(d, gfn, _mfn(mfn), order, p2mt); 2.126 + else /* 1)gfn assigned with 4k 2.127 + * 2)vmx_set_uc_mode() dont' touch the gfn to mfn 2.128 + * translations, only modify the emt field of the EPT entries. 2.129 + * so we need not modify the current VT-d page tables. 2.130 + */ 2.131 + _ept_set_entry(d, gfn, _mfn(mfn), order, p2mt, 0); 2.132 } 2.133 } 2.134
3.1 --- a/xen/drivers/passthrough/iommu.c Fri Jan 23 14:32:41 2009 +0000 3.2 +++ b/xen/drivers/passthrough/iommu.c Fri Jan 23 14:42:29 2009 +0000 3.3 @@ -39,6 +39,7 @@ int iommu_enabled = 0; 3.4 int iommu_pv_enabled = 0; 3.5 int force_iommu = 0; 3.6 int iommu_passthrough = 0; 3.7 +int iommu_snoop = 0; 3.8 3.9 static void __init parse_iommu_param(char *s) 3.10 {
4.1 --- a/xen/drivers/passthrough/vtd/dmar.c Fri Jan 23 14:32:41 2009 +0000 4.2 +++ b/xen/drivers/passthrough/vtd/dmar.c Fri Jan 23 14:42:29 2009 +0000 4.3 @@ -29,6 +29,7 @@ 4.4 #include <xen/pci_regs.h> 4.5 #include <asm/string.h> 4.6 #include "dmar.h" 4.7 +#include "iommu.h" 4.8 4.9 int vtd_enabled = 1; 4.10 4.11 @@ -508,6 +509,8 @@ static int __init acpi_parse_dmar(struct 4.12 int acpi_dmar_init(void) 4.13 { 4.14 int rc; 4.15 + struct acpi_drhd_unit *drhd; 4.16 + struct iommu *iommu; 4.17 4.18 rc = -ENODEV; 4.19 if ( force_iommu ) 4.20 @@ -524,7 +527,20 @@ int acpi_dmar_init(void) 4.21 if ( list_empty(&acpi_drhd_units) ) 4.22 goto fail; 4.23 4.24 - printk("Intel VT-d has been enabled\n"); 4.25 + /* Giving that all devices within guest use same io page table, 4.26 + * enable snoop control only if all VT-d engines support it. 4.27 + */ 4.28 + iommu_snoop = 1; 4.29 + for_each_drhd_unit ( drhd ) 4.30 + { 4.31 + iommu = drhd->iommu; 4.32 + if ( !ecap_snp_ctl(iommu->ecap) ) { 4.33 + iommu_snoop = 0; 4.34 + break; 4.35 + } 4.36 + } 4.37 + 4.38 + printk("Intel VT-d has been enabled, snoop_control=%d.\n", iommu_snoop); 4.39 4.40 return 0; 4.41
5.1 --- a/xen/drivers/passthrough/vtd/iommu.c Fri Jan 23 14:32:41 2009 +0000 5.2 +++ b/xen/drivers/passthrough/vtd/iommu.c Fri Jan 23 14:42:29 2009 +0000 5.3 @@ -1482,6 +1482,11 @@ int intel_iommu_map_page( 5.4 pte_present = dma_pte_present(*pte); 5.5 dma_set_pte_addr(*pte, (paddr_t)mfn << PAGE_SHIFT_4K); 5.6 dma_set_pte_prot(*pte, DMA_PTE_READ | DMA_PTE_WRITE); 5.7 + 5.8 + /* Set the SNP on leaf page table if Snoop Control available */ 5.9 + if ( iommu_snoop ) 5.10 + dma_set_pte_snp(*pte); 5.11 + 5.12 iommu_flush_cache_entry(pte); 5.13 spin_unlock(&hd->mapping_lock); 5.14 unmap_vtd_domain_page(page);
6.1 --- a/xen/drivers/passthrough/vtd/iommu.h Fri Jan 23 14:32:41 2009 +0000 6.2 +++ b/xen/drivers/passthrough/vtd/iommu.h Fri Jan 23 14:42:29 2009 +0000 6.3 @@ -104,6 +104,7 @@ 6.4 #define ecap_ext_intr(e) ((e >> 4) & 0x1) 6.5 #define ecap_cache_hints(e) ((e >> 5) & 0x1) 6.6 #define ecap_pass_thru(e) ((e >> 6) & 0x1) 6.7 +#define ecap_snp_ctl(e) ((e >> 7) & 0x1) 6.8 6.9 /* IOTLB_REG */ 6.10 #define DMA_TLB_FLUSH_GRANU_OFFSET 60 6.11 @@ -260,10 +261,12 @@ struct dma_pte { 6.12 }; 6.13 #define DMA_PTE_READ (1) 6.14 #define DMA_PTE_WRITE (2) 6.15 +#define DMA_PTE_SNP (1 << 11) 6.16 #define dma_clear_pte(p) do {(p).val = 0;} while(0) 6.17 #define dma_set_pte_readable(p) do {(p).val |= DMA_PTE_READ;} while(0) 6.18 #define dma_set_pte_writable(p) do {(p).val |= DMA_PTE_WRITE;} while(0) 6.19 #define dma_set_pte_superpage(p) do {(p).val |= (1 << 7);} while(0) 6.20 +#define dma_set_pte_snp(p) do {(p).val |= DMA_PTE_SNP;} while(0) 6.21 #define dma_set_pte_prot(p, prot) \ 6.22 do {(p).val = ((p).val & ~3) | ((prot) & 3); } while (0) 6.23 #define dma_pte_addr(p) ((p).val & PAGE_MASK_4K)
7.1 --- a/xen/include/asm-x86/hvm/vmx/vmx.h Fri Jan 23 14:32:41 2009 +0000 7.2 +++ b/xen/include/asm-x86/hvm/vmx/vmx.h Fri Jan 23 14:42:29 2009 +0000 7.3 @@ -33,7 +33,8 @@ typedef union { 7.4 u64 r : 1, 7.5 w : 1, 7.6 x : 1, 7.7 - emt : 4, 7.8 + emt : 3, 7.9 + igmt : 1, 7.10 sp_avail : 1, 7.11 avail1 : 4, 7.12 mfn : 45,
8.1 --- a/xen/include/asm-x86/mtrr.h Fri Jan 23 14:32:41 2009 +0000 8.2 +++ b/xen/include/asm-x86/mtrr.h Fri Jan 23 14:42:29 2009 +0000 8.3 @@ -64,9 +64,11 @@ extern int mtrr_del_page(int reg, unsign 8.4 extern void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi); 8.5 extern u32 get_pat_flags(struct vcpu *v, u32 gl1e_flags, paddr_t gpaddr, 8.6 paddr_t spaddr); 8.7 -extern uint8_t epte_get_entry_emt(struct domain *d, unsigned long gfn, unsigned long mfn); 8.8 -extern void ept_change_entry_emt_with_range(struct domain *d, unsigned long start_gfn, 8.9 - unsigned long end_gfn); 8.10 +extern uint8_t epte_get_entry_emt( 8.11 + struct domain *d, unsigned long gfn, unsigned long mfn, 8.12 + uint8_t *igmt, int direct_mmio); 8.13 +extern void ept_change_entry_emt_with_range( 8.14 + struct domain *d, unsigned long start_gfn, unsigned long end_gfn); 8.15 extern unsigned char pat_type_2_pte_flags(unsigned char pat_type); 8.16 8.17 #endif /* __ASM_X86_MTRR_H__ */
9.1 --- a/xen/include/xen/iommu.h Fri Jan 23 14:32:41 2009 +0000 9.2 +++ b/xen/include/xen/iommu.h Fri Jan 23 14:42:29 2009 +0000 9.3 @@ -31,6 +31,7 @@ extern int iommu_enabled; 9.4 extern int iommu_pv_enabled; 9.5 extern int force_iommu; 9.6 extern int iommu_passthrough; 9.7 +extern int iommu_snoop; 9.8 9.9 #define domain_hvm_iommu(d) (&d->arch.hvm_domain.hvm_iommu) 9.10