On Tue, May 07, 2024 at 04:51:31PM +0800, Tian, Kevin wrote: > > From: Zhao, Yan Y <yan.y.zhao@xxxxxxxxx> > > Sent: Tuesday, May 7, 2024 2:21 PM > > > > + > > +/* > > + * Flush a reserved page or !pfn_valid() PFN. > > + * Flush is not performed if the PFN is accessed in uncacheable type. i.e. > > + * - PAT type is UC/UC-/WC when PAT is enabled > > + * - MTRR type is UC/WC/WT/WP when PAT is not enabled. > > + * (no need to do CLFLUSH though WT/WP is cacheable). > > + */ > > As long as a page is cacheable (being WB/WT/WP) the malicious > guest can always use non-coherent DMA to make cache/memory > inconsistent, hence clflush is still required after unmapping such > page from the IOMMU page table to avoid leaking the inconsistency > state back to the host. You are right. I should only check MTRR type is UC or WC, as below. static void clflush_reserved_or_invalid_pfn(unsigned long pfn) { const int size = boot_cpu_data.x86_clflush_size; unsigned int i; void *va; if (!pat_enabled()) { u64 start = PFN_PHYS(pfn), end = start + PAGE_SIZE; u8 mtrr_type, uniform; mtrr_type = mtrr_type_lookup(start, end, &uniform); if ((mtrr_type == MTRR_TYPE_UNCACHABLE) ||( mtrry_type == MTRR_TYPE_WRCOMB)) return; } else if (pat_pfn_immune_to_uc_mtrr(pfn)) { return; } ... } Also for the pat_enabled() case where pat_pfn_immune_to_uc_mtrr() is called, maybe pat_x_mtrr_type() cannot be called in patch 1 for untracked PAT range, because pat_x_mtrr_type() will return UC- if MTRR type is WT/WP, which will cause pat_pfn_immune_to_uc_mtrr() to return true and CLFLUSH would be skipped. static unsigned long pat_x_mtrr_type(u64 start, u64 end, enum page_cache_mode req_type) { /* * Look for MTRR hint to get the effective type in case where PAT * request is for WB. */ if (req_type == _PAGE_CACHE_MODE_WB) { u8 mtrr_type, uniform; mtrr_type = mtrr_type_lookup(start, end, &uniform); if (mtrr_type != MTRR_TYPE_WRBACK) return _PAGE_CACHE_MODE_UC_MINUS; return _PAGE_CACHE_MODE_WB; } return req_type; } > > > + > > +/** > > + * arch_clean_nonsnoop_dma - flush a cache range for non-coherent DMAs > > + * (DMAs that lack CPU cache snooping). > > + * @phys_addr: physical address start > > + * @length: number of bytes to flush > > + */ > > +void arch_clean_nonsnoop_dma(phys_addr_t phys_addr, size_t length) > > +{ > > + unsigned long nrpages, pfn; > > + unsigned long i; > > + > > + pfn = PHYS_PFN(phys_addr); > > + nrpages = PAGE_ALIGN((phys_addr & ~PAGE_MASK) + length) >> > > PAGE_SHIFT; > > + > > + for (i = 0; i < nrpages; i++, pfn++) > > + clflush_pfn(pfn); > > +} > > +EXPORT_SYMBOL_GPL(arch_clean_nonsnoop_dma); > > this is not a good name. The code has nothing to do with nonsnoop > dma aspect. It's just a general helper accepting a physical pfn to flush > CPU cache, with nonsnoop dma as one potential caller usage. > > It's clearer to be arch_flush_cache_phys(). > > and probably drm_clflush_pages() can be converted to use this > helper too. Yes. I agree, though arch_clean_nonsnoop_dma() might have its merit if its implementation in other platforms would do some nonsnoop_dma specific implementations.