[PATCH v1] KVM: x86/mmu: Prepare kvm_is_mmio_pfn() for PG_reserved changes

From: David Hildenbrand
Date: Tue Oct 22 2019 - 04:08:04 EST


Right now, ZONE_DEVICE memory is always set PG_reserved. We want to
change that in the future.

KVM has this weird use case that you can map anything from /dev/mem
into the guest. pfn_valid() is not a reliable check whether the memmap
was initialized and can be touched. pfn_to_online_page() makes sure
that we have an initialized memmap - however, there is no reliable and
fast check to detect memmaps that were initialized and are ZONE_DEVICE.

Let's rewrite kvm_is_mmio_pfn() so we really only touch initialized
memmaps that are guaranteed to not contain garbage. Make sure that
RAM without a memmap is still not detected as MMIO and that ZONE_DEVICE
that is not UC/UC-/WC is not detected as MMIO.

Signed-off-by: David Hildenbrand <david@xxxxxxxxxx>
---
arch/x86/kvm/mmu.c | 38 ++++++++++++++++++++++----------------
1 file changed, 22 insertions(+), 16 deletions(-)

diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 24c23c66b226..c91c9a5d14dc 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -2962,23 +2962,29 @@ static bool mmu_need_write_protect(struct kvm_vcpu =
*vcpu, gfn_t gfn,
=20
static bool kvm_is_mmio_pfn(kvm_pfn_t pfn)
{
-=09if (pfn_valid(pfn))
-=09=09return !is_zero_pfn(pfn) && PageReserved(pfn_to_page(pfn)) &&
-=09=09=09/*
-=09=09=09 * Some reserved pages, such as those from NVDIMM
-=09=09=09 * DAX devices, are not for MMIO, and can be mapped
-=09=09=09 * with cached memory type for better performance.
-=09=09=09 * However, the above check misconceives those pages
-=09=09=09 * as MMIO, and results in KVM mapping them with UC
-=09=09=09 * memory type, which would hurt the performance.
-=09=09=09 * Therefore, we check the host memory type in addition
-=09=09=09 * and only treat UC/UC-/WC pages as MMIO.
-=09=09=09 */
-=09=09=09(!pat_enabled() || pat_pfn_immune_to_uc_mtrr(pfn));
+=09struct page *page =3D pfn_to_online_page(pfn);
+
+=09/*
+=09 * Online pages consist of pages managed by the buddy. Especially,
+=09 * ZONE_DEVICE pages are never online. Online pages that are reserved
+=09 * indicate the zero page and MMIO pages.
+=09 */
+=09if (page)
+=09=09return !is_zero_pfn(pfn) && PageReserved(pfn_to_page(pfn));
=20
-=09return !e820__mapped_raw_any(pfn_to_hpa(pfn),
-=09=09=09=09 pfn_to_hpa(pfn + 1) - 1,
-=09=09=09=09 E820_TYPE_RAM);
+=09/*
+=09 * Any RAM that is not online (e.g., mapped via /dev/mem without
+=09 * a memmap or with an uninitialized memmap) is not MMIO.
+=09 */
+=09if (e820__mapped_raw_any(pfn_to_hpa(pfn), pfn_to_hpa(pfn + 1) - 1,
+=09=09=09=09 E820_TYPE_RAM))
+=09=09return false;
+
+=09/*
+=09 * Finally, anything with a valid memmap could be ZONE_DEVICE - or the
+=09 * memmap could be uninitialized. Treat only UC/UC-/WC pages as MMIO.
+=09 */
+=09return pfn_valid() && !pat_enabled() || pat_pfn_immune_to_uc_mtrr(pfn);
}
=20
/* Bits which may be returned by set_spte() */
--=20
2.21.0




And also virt/kvm/kvm_main.c:kvm_is_reserved_pfn()