diff --git a/emulators/xen-kernel/Makefile b/emulators/xen-kernel/Makefile index 612a23cb3462..24c222999c77 100644 --- a/emulators/xen-kernel/Makefile +++ b/emulators/xen-kernel/Makefile @@ -1,47 +1,52 @@ PORTNAME= xen PORTVERSION= 4.15.0 -PORTREVISION= 0 +PORTREVISION= 1 CATEGORIES= emulators MASTER_SITES= http://downloads.xenproject.org/release/xen/${PORTVERSION}/ PKGNAMESUFFIX= -kernel MAINTAINER= royger@FreeBSD.org COMMENT= Hypervisor using a microkernel design LICENSE= GPLv2 ONLY_FOR_ARCHS= amd64 USES= cpe gmake python:build bison # Ports build environment has ARCH=amd64 set which disables Xen automatic arch # detection, but amd64 is not a valid arch for Xen. Hardcode x86_64 on the # command line in order to overwrite the one from the environment. MAKE_ARGS= clang=y PYTHON=${PYTHON_CMD} ARCH=x86_64 NO_MTREE= yes STRIP= # PLIST_FILES= /boot/xen \ lib/debug/boot/xen.debug +# Fix grant/foreign mapping cache attributes on Intel. +EXTRA_PATCHES+= ${PATCHDIR}/0001-x86-mtrr-remove-stale-function-prototype.patch:-p1 \ + ${PATCHDIR}/0002-x86-mtrr-move-epte_get_entry_emt-to-p2m-ept.c.patch:-p1 \ + ${PATCHDIR}/0003-x86-ept-force-WB-cache-attributes-for-grant-and-fore.patch:-p1 + .include .if ${OPSYS} != FreeBSD IGNORE= only supported on FreeBSD .endif .if ${OSVERSION} < 1200074 IGNORE= only supported on FreeBSD 12.0 or newer .endif # The ports native 'build' target cannot be used because it sets # CFLAGS, and that breaks the Xen build system. do-build: ${MAKE_CMD} -j${MAKE_JOBS_NUMBER} -C ${WRKSRC} build-xen ${MAKE_ARGS} do-install: ${MKDIR} ${STAGEDIR}/boot ${MKDIR} ${STAGEDIR}${PREFIX}/lib/debug/boot/ ${INSTALL_PROGRAM} ${WRKSRC}/xen/xen ${STAGEDIR}/boot ${INSTALL_DATA} ${WRKSRC}/xen/xen-syms ${STAGEDIR}${PREFIX}/lib/debug/boot/xen.debug .include diff --git a/emulators/xen-kernel/files/0001-x86-mtrr-remove-stale-function-prototype.patch b/emulators/xen-kernel/files/0001-x86-mtrr-remove-stale-function-prototype.patch new file mode 100644 index 000000000000..b4cd1a4061ce --- /dev/null +++ b/emulators/xen-kernel/files/0001-x86-mtrr-remove-stale-function-prototype.patch @@ -0,0 +1,31 @@ +From c8aaa97f84170192b05b3020a55c69f71d84629f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= +Date: Mon, 31 May 2021 12:47:12 +0200 +Subject: [PATCH 1/3] x86/mtrr: remove stale function prototype +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes: 1c84d04673 ('VMX: remove the problematic set_uc_mode logic') +Signed-off-by: Roger Pau Monné +Acked-by: Jan Beulich +--- + xen/include/asm-x86/mtrr.h | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/xen/include/asm-x86/mtrr.h b/xen/include/asm-x86/mtrr.h +index 4be704cb6a..24e5de5c22 100644 +--- a/xen/include/asm-x86/mtrr.h ++++ b/xen/include/asm-x86/mtrr.h +@@ -78,8 +78,6 @@ extern u32 get_pat_flags(struct vcpu *v, u32 gl1e_flags, paddr_t gpaddr, + extern int epte_get_entry_emt(struct domain *, unsigned long gfn, mfn_t mfn, + unsigned int order, uint8_t *ipat, + bool_t 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); + extern int hold_mtrr_updates_on_aps; + extern void mtrr_aps_sync_begin(void); +-- +2.31.1 + diff --git a/emulators/xen-kernel/files/0002-x86-mtrr-move-epte_get_entry_emt-to-p2m-ept.c.patch b/emulators/xen-kernel/files/0002-x86-mtrr-move-epte_get_entry_emt-to-p2m-ept.c.patch new file mode 100644 index 000000000000..5490b63534c0 --- /dev/null +++ b/emulators/xen-kernel/files/0002-x86-mtrr-move-epte_get_entry_emt-to-p2m-ept.c.patch @@ -0,0 +1,377 @@ +From bad7fc7a20452f5ba5e2aaf0019affec7fa87271 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= +Date: Thu, 17 Jun 2021 17:58:11 +0200 +Subject: [PATCH 2/3] x86/mtrr: move epte_get_entry_emt to p2m-ept.c +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is an EPT specific function, so it shouldn't live in the generic +mtrr file. Such movement is also needed for future work that will +require passing a p2m_type_t parameter to epte_get_entry_emt, and +making that type visible to the mtrr users is cumbersome and +unneeded. + +Moving epte_get_entry_emt out of mtrr.c requires making the helper to +get the MTRR type of an address from the mtrr state public. While +there rename the function to start with the mtrr prefix, like other +mtrr related functions. + +While there fix some of the types of the function parameters. + +No functional change intended. + +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +Reviewed-by: Kevin Tian +--- + xen/arch/x86/hvm/mtrr.c | 109 +--------------------------- + xen/arch/x86/mm/p2m-ept.c | 115 ++++++++++++++++++++++++++++-- + xen/include/asm-x86/hvm/vmx/vmx.h | 2 + + xen/include/asm-x86/mtrr.h | 5 +- + 4 files changed, 117 insertions(+), 114 deletions(-) + +diff --git a/xen/arch/x86/hvm/mtrr.c b/xen/arch/x86/hvm/mtrr.c +index fb051d59c3..4a9f3177ed 100644 +--- a/xen/arch/x86/hvm/mtrr.c ++++ b/xen/arch/x86/hvm/mtrr.c +@@ -194,8 +194,7 @@ void hvm_vcpu_cacheattr_destroy(struct vcpu *v) + * May return a negative value when order > 0, indicating to the caller + * that the respective mapping needs splitting. + */ +-static int get_mtrr_type(const struct mtrr_state *m, +- paddr_t pa, unsigned int order) ++int mtrr_get_type(const struct mtrr_state *m, paddr_t pa, unsigned int order) + { + uint8_t overlap_mtrr = 0; + uint8_t overlap_mtrr_pos = 0; +@@ -323,7 +322,7 @@ static uint8_t effective_mm_type(struct mtrr_state *m, + * just use it + */ + if ( gmtrr_mtype == NO_HARDCODE_MEM_TYPE ) +- mtrr_mtype = get_mtrr_type(m, gpa, 0); ++ mtrr_mtype = mtrr_get_type(m, gpa, 0); + else + mtrr_mtype = gmtrr_mtype; + +@@ -350,7 +349,7 @@ uint32_t get_pat_flags(struct vcpu *v, + guest_eff_mm_type = effective_mm_type(g, pat, gpaddr, + gl1e_flags, gmtrr_mtype); + /* 2. Get the memory type of host physical address, with MTRR */ +- shadow_mtrr_type = get_mtrr_type(&mtrr_state, spaddr, 0); ++ shadow_mtrr_type = mtrr_get_type(&mtrr_state, spaddr, 0); + + /* 3. Find the memory type in PAT, with host MTRR memory type + * and guest effective memory type. +@@ -789,108 +788,6 @@ void memory_type_changed(struct domain *d) + } + } + +-int epte_get_entry_emt(struct domain *d, unsigned long gfn, mfn_t mfn, +- unsigned int order, uint8_t *ipat, bool_t direct_mmio) +-{ +- int gmtrr_mtype, hmtrr_mtype; +- struct vcpu *v = current; +- unsigned long i; +- +- *ipat = 0; +- +- if ( v->domain != d ) +- v = d->vcpu ? d->vcpu[0] : NULL; +- +- /* Mask, not add, for order so it works with INVALID_MFN on unmapping */ +- if ( rangeset_overlaps_range(mmio_ro_ranges, mfn_x(mfn), +- mfn_x(mfn) | ((1UL << order) - 1)) ) +- { +- if ( !order || rangeset_contains_range(mmio_ro_ranges, mfn_x(mfn), +- mfn_x(mfn) | ((1UL << order) - 1)) ) +- { +- *ipat = 1; +- return MTRR_TYPE_UNCACHABLE; +- } +- /* Force invalid memory type so resolve_misconfig() will split it */ +- return -1; +- } +- +- if ( !mfn_valid(mfn) ) +- { +- *ipat = 1; +- return MTRR_TYPE_UNCACHABLE; +- } +- +- if ( !direct_mmio && !is_iommu_enabled(d) && !cache_flush_permitted(d) ) +- { +- *ipat = 1; +- return MTRR_TYPE_WRBACK; +- } +- +- for ( i = 0; i < (1ul << order); i++ ) +- { +- if ( is_special_page(mfn_to_page(mfn_add(mfn, i))) ) +- { +- if ( order ) +- return -1; +- *ipat = 1; +- return MTRR_TYPE_WRBACK; +- } +- } +- +- if ( direct_mmio ) +- return MTRR_TYPE_UNCACHABLE; +- +- gmtrr_mtype = hvm_get_mem_pinned_cacheattr(d, _gfn(gfn), order); +- if ( gmtrr_mtype >= 0 ) +- { +- *ipat = 1; +- return gmtrr_mtype != PAT_TYPE_UC_MINUS ? gmtrr_mtype +- : MTRR_TYPE_UNCACHABLE; +- } +- if ( gmtrr_mtype == -EADDRNOTAVAIL ) +- return -1; +- +- gmtrr_mtype = is_hvm_domain(d) && v ? +- get_mtrr_type(&v->arch.hvm.mtrr, +- gfn << PAGE_SHIFT, order) : +- MTRR_TYPE_WRBACK; +- hmtrr_mtype = get_mtrr_type(&mtrr_state, mfn_x(mfn) << PAGE_SHIFT, order); +- if ( gmtrr_mtype < 0 || hmtrr_mtype < 0 ) +- return -1; +- +- /* If both types match we're fine. */ +- if ( likely(gmtrr_mtype == hmtrr_mtype) ) +- return hmtrr_mtype; +- +- /* If either type is UC, we have to go with that one. */ +- if ( gmtrr_mtype == MTRR_TYPE_UNCACHABLE || +- hmtrr_mtype == MTRR_TYPE_UNCACHABLE ) +- return MTRR_TYPE_UNCACHABLE; +- +- /* If either type is WB, we have to go with the other one. */ +- if ( gmtrr_mtype == MTRR_TYPE_WRBACK ) +- return hmtrr_mtype; +- if ( hmtrr_mtype == MTRR_TYPE_WRBACK ) +- return gmtrr_mtype; +- +- /* +- * At this point we have disagreeing WC, WT, or WP types. The only +- * combination that can be cleanly resolved is WT:WP. The ones involving +- * WC need to be converted to UC, both due to the memory ordering +- * differences and because WC disallows reads to be cached (WT and WP +- * permit this), while WT and WP require writes to go straight to memory +- * (WC can buffer them). +- */ +- if ( (gmtrr_mtype == MTRR_TYPE_WRTHROUGH && +- hmtrr_mtype == MTRR_TYPE_WRPROT) || +- (gmtrr_mtype == MTRR_TYPE_WRPROT && +- hmtrr_mtype == MTRR_TYPE_WRTHROUGH) ) +- return MTRR_TYPE_WRPROT; +- +- return MTRR_TYPE_UNCACHABLE; +-} +- + /* + * Local variables: + * mode: C +diff --git a/xen/arch/x86/mm/p2m-ept.c b/xen/arch/x86/mm/p2m-ept.c +index 23d411f01d..542fe5ef34 100644 +--- a/xen/arch/x86/mm/p2m-ept.c ++++ b/xen/arch/x86/mm/p2m-ept.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -485,6 +486,109 @@ static int ept_invalidate_emt_range(struct p2m_domain *p2m, + return rc; + } + ++int epte_get_entry_emt(struct domain *d, gfn_t gfn, mfn_t mfn, ++ unsigned int order, bool *ipat, bool direct_mmio) ++{ ++ int gmtrr_mtype, hmtrr_mtype; ++ struct vcpu *v = current; ++ unsigned long i; ++ ++ *ipat = false; ++ ++ if ( v->domain != d ) ++ v = d->vcpu ? d->vcpu[0] : NULL; ++ ++ /* Mask, not add, for order so it works with INVALID_MFN on unmapping */ ++ if ( rangeset_overlaps_range(mmio_ro_ranges, mfn_x(mfn), ++ mfn_x(mfn) | ((1UL << order) - 1)) ) ++ { ++ if ( !order || rangeset_contains_range(mmio_ro_ranges, mfn_x(mfn), ++ mfn_x(mfn) | ((1UL << order) - 1)) ) ++ { ++ *ipat = true; ++ return MTRR_TYPE_UNCACHABLE; ++ } ++ /* Force invalid memory type so resolve_misconfig() will split it */ ++ return -1; ++ } ++ ++ if ( !mfn_valid(mfn) ) ++ { ++ *ipat = true; ++ return MTRR_TYPE_UNCACHABLE; ++ } ++ ++ if ( !direct_mmio && !is_iommu_enabled(d) && !cache_flush_permitted(d) ) ++ { ++ *ipat = true; ++ return MTRR_TYPE_WRBACK; ++ } ++ ++ for ( i = 0; i < (1ul << order); i++ ) ++ { ++ if ( is_special_page(mfn_to_page(mfn_add(mfn, i))) ) ++ { ++ if ( order ) ++ return -1; ++ *ipat = true; ++ return MTRR_TYPE_WRBACK; ++ } ++ } ++ ++ if ( direct_mmio ) ++ return MTRR_TYPE_UNCACHABLE; ++ ++ gmtrr_mtype = hvm_get_mem_pinned_cacheattr(d, gfn, order); ++ if ( gmtrr_mtype >= 0 ) ++ { ++ *ipat = true; ++ return gmtrr_mtype != PAT_TYPE_UC_MINUS ? gmtrr_mtype ++ : MTRR_TYPE_UNCACHABLE; ++ } ++ if ( gmtrr_mtype == -EADDRNOTAVAIL ) ++ return -1; ++ ++ gmtrr_mtype = is_hvm_domain(d) && v ? ++ mtrr_get_type(&v->arch.hvm.mtrr, ++ gfn << PAGE_SHIFT, order) : ++ MTRR_TYPE_WRBACK; ++ hmtrr_mtype = mtrr_get_type(&mtrr_state, mfn_x(mfn) << PAGE_SHIFT, ++ order); ++ if ( gmtrr_mtype < 0 || hmtrr_mtype < 0 ) ++ return -1; ++ ++ /* If both types match we're fine. */ ++ if ( likely(gmtrr_mtype == hmtrr_mtype) ) ++ return hmtrr_mtype; ++ ++ /* If either type is UC, we have to go with that one. */ ++ if ( gmtrr_mtype == MTRR_TYPE_UNCACHABLE || ++ hmtrr_mtype == MTRR_TYPE_UNCACHABLE ) ++ return MTRR_TYPE_UNCACHABLE; ++ ++ /* If either type is WB, we have to go with the other one. */ ++ if ( gmtrr_mtype == MTRR_TYPE_WRBACK ) ++ return hmtrr_mtype; ++ if ( hmtrr_mtype == MTRR_TYPE_WRBACK ) ++ return gmtrr_mtype; ++ ++ /* ++ * At this point we have disagreeing WC, WT, or WP types. The only ++ * combination that can be cleanly resolved is WT:WP. The ones involving ++ * WC need to be converted to UC, both due to the memory ordering ++ * differences and because WC disallows reads to be cached (WT and WP ++ * permit this), while WT and WP require writes to go straight to memory ++ * (WC can buffer them). ++ */ ++ if ( (gmtrr_mtype == MTRR_TYPE_WRTHROUGH && ++ hmtrr_mtype == MTRR_TYPE_WRPROT) || ++ (gmtrr_mtype == MTRR_TYPE_WRPROT && ++ hmtrr_mtype == MTRR_TYPE_WRTHROUGH) ) ++ return MTRR_TYPE_WRPROT; ++ ++ return MTRR_TYPE_UNCACHABLE; ++} ++ + /* + * Resolve deliberately mis-configured (EMT field set to an invalid value) + * entries in the page table hierarchy for the given GFN: +@@ -519,7 +623,7 @@ static int resolve_misconfig(struct p2m_domain *p2m, unsigned long gfn) + + if ( level == 0 || is_epte_superpage(&e) ) + { +- uint8_t ipat = 0; ++ bool ipat; + + if ( e.emt != MTRR_NUM_TYPES ) + break; +@@ -535,7 +639,7 @@ static int resolve_misconfig(struct p2m_domain *p2m, unsigned long gfn) + e.emt = 0; + if ( !is_epte_valid(&e) || !is_epte_present(&e) ) + continue; +- e.emt = epte_get_entry_emt(p2m->domain, gfn + i, ++ e.emt = epte_get_entry_emt(p2m->domain, _gfn(gfn + i), + _mfn(e.mfn), 0, &ipat, + e.sa_p2mt == p2m_mmio_direct); + e.ipat = ipat; +@@ -553,7 +657,8 @@ static int resolve_misconfig(struct p2m_domain *p2m, unsigned long gfn) + } + else + { +- int emt = epte_get_entry_emt(p2m->domain, gfn, _mfn(e.mfn), ++ int emt = epte_get_entry_emt(p2m->domain, _gfn(gfn), ++ _mfn(e.mfn), + level * EPT_TABLE_ORDER, &ipat, + e.sa_p2mt == p2m_mmio_direct); + bool_t recalc = e.recalc; +@@ -678,7 +783,7 @@ ept_set_entry(struct p2m_domain *p2m, gfn_t gfn_, mfn_t mfn, + int ret, rc = 0; + bool_t entry_written = 0; + bool_t direct_mmio = (p2mt == p2m_mmio_direct); +- uint8_t ipat = 0; ++ bool ipat = false; + bool_t need_modify_vtd_table = 1; + bool_t vtd_pte_present = 0; + unsigned int iommu_flags = p2m_get_iommu_flags(p2mt, mfn); +@@ -790,7 +895,7 @@ ept_set_entry(struct p2m_domain *p2m, gfn_t gfn_, mfn_t mfn, + + if ( mfn_valid(mfn) || p2m_allows_invalid_mfn(p2mt) ) + { +- int emt = epte_get_entry_emt(p2m->domain, gfn, mfn, ++ int emt = epte_get_entry_emt(p2m->domain, _gfn(gfn), mfn, + i * EPT_TABLE_ORDER, &ipat, direct_mmio); + + if ( emt >= 0 ) +diff --git a/xen/include/asm-x86/hvm/vmx/vmx.h b/xen/include/asm-x86/hvm/vmx/vmx.h +index 534e9fc221..f668ee1f09 100644 +--- a/xen/include/asm-x86/hvm/vmx/vmx.h ++++ b/xen/include/asm-x86/hvm/vmx/vmx.h +@@ -599,6 +599,8 @@ void ept_p2m_uninit(struct p2m_domain *p2m); + + void ept_walk_table(struct domain *d, unsigned long gfn); + bool_t ept_handle_misconfig(uint64_t gpa); ++int epte_get_entry_emt(struct domain *d, gfn_t gfn, mfn_t mfn, ++ unsigned int order, bool *ipat, bool direct_mmio); + void setup_ept_dump(void); + void p2m_init_altp2m_ept(struct domain *d, unsigned int i); + /* Locate an alternate p2m by its EPTP */ +diff --git a/xen/include/asm-x86/mtrr.h b/xen/include/asm-x86/mtrr.h +index 24e5de5c22..e0fd1005ce 100644 +--- a/xen/include/asm-x86/mtrr.h ++++ b/xen/include/asm-x86/mtrr.h +@@ -72,12 +72,11 @@ extern int mtrr_add_page(unsigned long base, unsigned long size, + unsigned int type, char increment); + extern int mtrr_del(int reg, unsigned long base, unsigned long size); + extern int mtrr_del_page(int reg, unsigned long base, unsigned long size); ++extern int mtrr_get_type(const struct mtrr_state *m, paddr_t pa, ++ unsigned int order); + 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, uint8_t gmtrr_mtype); +-extern int epte_get_entry_emt(struct domain *, unsigned long gfn, mfn_t mfn, +- unsigned int order, uint8_t *ipat, +- bool_t direct_mmio); + extern unsigned char pat_type_2_pte_flags(unsigned char pat_type); + extern int hold_mtrr_updates_on_aps; + extern void mtrr_aps_sync_begin(void); +-- +2.31.1 + diff --git a/emulators/xen-kernel/files/0003-x86-ept-force-WB-cache-attributes-for-grant-and-fore.patch b/emulators/xen-kernel/files/0003-x86-ept-force-WB-cache-attributes-for-grant-and-fore.patch new file mode 100644 index 000000000000..8119283dd746 --- /dev/null +++ b/emulators/xen-kernel/files/0003-x86-ept-force-WB-cache-attributes-for-grant-and-fore.patch @@ -0,0 +1,139 @@ +From 8ce6832518035a17e2d89a98235359f3d551f2c1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= +Date: Thu, 17 Jun 2021 18:00:57 +0200 +Subject: [PATCH 3/3] x86/ept: force WB cache attributes for grant and foreign + maps +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Force WB type for grants and foreign pages. Those are usually mapped +over unpopulated physical ranges in the p2m, and those ranges would +usually be UC in the MTRR state, which is unlikely to be the correct +cache attribute. It's also cumbersome (or even impossible) for the +guest to be setting the MTRR type for all those mappings as WB, as +MTRR ranges are finite. + +Note that this is not an issue on AMD because WB cache attribute is +already set on grants and foreign mappings in the p2m and MTRR types +are ignored. Also on AMD Xen cannot force a cache attribute because of +the lack of ignore PAT equivalent, so the behavior here slightly +diverges between AMD and Intel (or EPT vs NPT/shadow). + +Signed-off-by: Roger Pau Monné +Reviewed-by: Jan Beulich +Reviewed-by: Kevin Tian +--- + xen/arch/x86/mm/p2m-ept.c | 38 +++++++++++++++++++++++++------ + xen/include/asm-x86/hvm/vmx/vmx.h | 2 +- + 2 files changed, 32 insertions(+), 8 deletions(-) + +diff --git a/xen/arch/x86/mm/p2m-ept.c b/xen/arch/x86/mm/p2m-ept.c +index 542fe5ef34..41ab3c199a 100644 +--- a/xen/arch/x86/mm/p2m-ept.c ++++ b/xen/arch/x86/mm/p2m-ept.c +@@ -487,7 +487,7 @@ static int ept_invalidate_emt_range(struct p2m_domain *p2m, + } + + int epte_get_entry_emt(struct domain *d, gfn_t gfn, mfn_t mfn, +- unsigned int order, bool *ipat, bool direct_mmio) ++ unsigned int order, bool *ipat, p2m_type_t type) + { + int gmtrr_mtype, hmtrr_mtype; + struct vcpu *v = current; +@@ -518,7 +518,8 @@ int epte_get_entry_emt(struct domain *d, gfn_t gfn, mfn_t mfn, + return MTRR_TYPE_UNCACHABLE; + } + +- if ( !direct_mmio && !is_iommu_enabled(d) && !cache_flush_permitted(d) ) ++ if ( type != p2m_mmio_direct && !is_iommu_enabled(d) && ++ !cache_flush_permitted(d) ) + { + *ipat = true; + return MTRR_TYPE_WRBACK; +@@ -535,9 +536,33 @@ int epte_get_entry_emt(struct domain *d, gfn_t gfn, mfn_t mfn, + } + } + +- if ( direct_mmio ) ++ switch ( type ) ++ { ++ case p2m_mmio_direct: + return MTRR_TYPE_UNCACHABLE; + ++ case p2m_grant_map_ro: ++ case p2m_grant_map_rw: ++ case p2m_map_foreign: ++ /* ++ * Force WB type for grants and foreign pages. Those are usually mapped ++ * over unpopulated physical ranges in the p2m, and those would usually ++ * be UC in the MTRR state, which is unlikely to be the correct cache ++ * attribute. It's also cumbersome (or even impossible) for the guest ++ * to be setting the MTRR type for all those mappings as WB, as MTRR ++ * ranges are finite. ++ * ++ * Note that on AMD we cannot force a cache attribute because of the ++ * lack of ignore PAT equivalent, so the behavior here slightly ++ * diverges. See p2m_type_to_flags for the AMD attributes. ++ */ ++ *ipat = true; ++ return MTRR_TYPE_WRBACK; ++ ++ default: ++ break; ++ } ++ + gmtrr_mtype = hvm_get_mem_pinned_cacheattr(d, gfn, order); + if ( gmtrr_mtype >= 0 ) + { +@@ -641,7 +666,7 @@ static int resolve_misconfig(struct p2m_domain *p2m, unsigned long gfn) + continue; + e.emt = epte_get_entry_emt(p2m->domain, _gfn(gfn + i), + _mfn(e.mfn), 0, &ipat, +- e.sa_p2mt == p2m_mmio_direct); ++ e.sa_p2mt); + e.ipat = ipat; + + nt = p2m_recalc_type(e.recalc, e.sa_p2mt, p2m, gfn + i); +@@ -660,7 +685,7 @@ static int resolve_misconfig(struct p2m_domain *p2m, unsigned long gfn) + int emt = epte_get_entry_emt(p2m->domain, _gfn(gfn), + _mfn(e.mfn), + level * EPT_TABLE_ORDER, &ipat, +- e.sa_p2mt == p2m_mmio_direct); ++ e.sa_p2mt); + bool_t recalc = e.recalc; + + if ( recalc && p2m_is_changeable(e.sa_p2mt) ) +@@ -782,7 +807,6 @@ ept_set_entry(struct p2m_domain *p2m, gfn_t gfn_, mfn_t mfn, + unsigned long fn_mask = !mfn_eq(mfn, INVALID_MFN) ? (gfn | mfn_x(mfn)) : gfn; + int ret, rc = 0; + bool_t entry_written = 0; +- bool_t direct_mmio = (p2mt == p2m_mmio_direct); + bool ipat = false; + bool_t need_modify_vtd_table = 1; + bool_t vtd_pte_present = 0; +@@ -896,7 +920,7 @@ ept_set_entry(struct p2m_domain *p2m, gfn_t gfn_, mfn_t mfn, + if ( mfn_valid(mfn) || p2m_allows_invalid_mfn(p2mt) ) + { + int emt = epte_get_entry_emt(p2m->domain, _gfn(gfn), mfn, +- i * EPT_TABLE_ORDER, &ipat, direct_mmio); ++ i * EPT_TABLE_ORDER, &ipat, p2mt); + + if ( emt >= 0 ) + new_entry.emt = emt; +diff --git a/xen/include/asm-x86/hvm/vmx/vmx.h b/xen/include/asm-x86/hvm/vmx/vmx.h +index f668ee1f09..0deb507490 100644 +--- a/xen/include/asm-x86/hvm/vmx/vmx.h ++++ b/xen/include/asm-x86/hvm/vmx/vmx.h +@@ -600,7 +600,7 @@ void ept_p2m_uninit(struct p2m_domain *p2m); + void ept_walk_table(struct domain *d, unsigned long gfn); + bool_t ept_handle_misconfig(uint64_t gpa); + int epte_get_entry_emt(struct domain *d, gfn_t gfn, mfn_t mfn, +- unsigned int order, bool *ipat, bool direct_mmio); ++ unsigned int order, bool *ipat, p2m_type_t type); + void setup_ept_dump(void); + void p2m_init_altp2m_ept(struct domain *d, unsigned int i); + /* Locate an alternate p2m by its EPTP */ +-- +2.31.1 +