Let pat_pfn_immune_to_uc_mtrr() check MTRR type for PFNs in untracked PAT range. pat_pfn_immune_to_uc_mtrr() is used by KVM to distinguish MMIO PFNs and give them UC memory type in the EPT page tables. When pat_pfn_immune_to_uc_mtrr() identifies a PFN as having a PAT type of UC/WC/UC-, it indicates that the PFN should be accessed using an uncacheable memory type. Consequently, KVM maps it with UC in the EPT to ensure that the guest's memory access is uncacheable. Internally, pat_pfn_immune_to_uc_mtrr() utilizes lookup_memtype() to determine PAT type for a PFN. For a PFN outside untracked PAT range, the returned PAT type is either - The type set by memtype_reserve() (which, in turn, calls pat_x_mtrr_type() to adjust the requested type to UC- if the requested type is WB but the MTRR type does not match WB), - Or UC-, if memtype_reserve() has not yet been invoked for this PFN. However, lookup_memtype() defaults to returning WB for PFNs within the untracked PAT range, regardless of their actual MTRR type. This behavior could lead KVM to misclassify the PFN as non-MMIO, permitting cacheable guest access. Such access might result in MCE on certain platforms, (e.g. clflush on VGA range (0xA0000-0xBFFFF) triggers MCE on some platforms). Hence, invoke pat_x_mtrr_type() for PFNs within the untracked PAT range so as to take MTRR type into account to mitigate potential MCEs. Fixes: b8d7044bcff7 ("x86/mm: add a function to check if a pfn is UC/UC-/WC") Cc: Kevin Tian <kevin.tian@xxxxxxxxx> Signed-off-by: Yan Zhao <yan.y.zhao@xxxxxxxxx> --- arch/x86/mm/pat/memtype.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/x86/mm/pat/memtype.c b/arch/x86/mm/pat/memtype.c index 36b603d0cdde..e85e8c5737ad 100644 --- a/arch/x86/mm/pat/memtype.c +++ b/arch/x86/mm/pat/memtype.c @@ -705,7 +705,17 @@ static enum page_cache_mode lookup_memtype(u64 paddr) */ bool pat_pfn_immune_to_uc_mtrr(unsigned long pfn) { - enum page_cache_mode cm = lookup_memtype(PFN_PHYS(pfn)); + u64 paddr = PFN_PHYS(pfn); + enum page_cache_mode cm; + + /* + * Check MTRR type for untracked pat range since lookup_memtype() always + * returns WB for this range. + */ + if (x86_platform.is_untracked_pat_range(paddr, paddr + PAGE_SIZE)) + cm = pat_x_mtrr_type(paddr, paddr + PAGE_SIZE, _PAGE_CACHE_MODE_WB); + else + cm = lookup_memtype(paddr); return cm == _PAGE_CACHE_MODE_UC || cm == _PAGE_CACHE_MODE_UC_MINUS || -- 2.17.1