[PATCH v4] x86/hyperv: use dynamically allocated page for hypercalls

Ariadne Conill <[email protected]>
Newsgroups org.xenproject.lists.xen-devel
Message-ID <[email protected]>
Previously, the Hyper-V guest code placed the hypercall page at a
fixed, hardcoded location: the top-most MFN of the guest physical
address space (HV_HCALL_MFN). To make this work, an e820_fixup hook
reserved that range as E820_RESERVED so nothing else would claim it.

This assumes the top-most physical frame is actually backed by RAM (or
at least mapped to something), which is not guaranteed. On Azure
compute guests it is not: the top-most MFN is not physically mapped to
anything. When we program HV_X64_MSR_HYPERCALL to point at that frame
and subsequently execute through the hypercall page via the fixmap, the
access faults and Xen panics during early boot.

Instead of guessing at a physical address, allocate a real xenheap page
and use its MFN for the hypercall page. This frame is always backed and
mapped, so the fault no longer occurs. The e820_fixup hook and the
HV_HCALL_MFN definition are no longer needed and are removed.

Signed-off-by: Ariadne Conill <[email protected]>
---
 xen/arch/x86/guest/hyperv/hyperv.c      | 19 +++++++++----------
 xen/arch/x86/include/asm/guest/hyperv.h |  3 ---
 2 files changed, 9 insertions(+), 13 deletions(-)

diff --git a/xen/arch/x86/guest/hyperv/hyperv.c b/xen/arch/x86/guest/hyperv/hyperv.c
index 90757e0793..d98d02fb80 100644
--- a/xen/arch/x86/guest/hyperv/hyperv.c
+++ b/xen/arch/x86/guest/hyperv/hyperv.c
@@ -99,10 +99,18 @@ static void __init setup_hypercall_page(void)
     rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
     if ( !hypercall_msr.enable )
     {
-        mfn = HV_HCALL_MFN;
+        void *hcall_page = alloc_xenheap_page();
+
+        if ( !hcall_page )
+            panic("Hyper-V: Failed to allocate hypercall trampoline page\n");
+
+        mfn = virt_to_mfn(hcall_page);
         hypercall_msr.enable = 1;
         hypercall_msr.guest_physical_address = mfn;
         wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
+
+        dprintk(XENLOG_INFO,
+                "Hyper-V: Allocated hypercall page at MFN %lx\n", mfn);
     }
     else
         mfn = hypercall_msr.guest_physical_address;
@@ -188,14 +196,6 @@ static int cf_check ap_setup(void)
     return setup_vp_assist();
 }
 
-static void __init cf_check e820_fixup(void)
-{
-    uint64_t s = HV_HCALL_MFN << PAGE_SHIFT;
-
-    if ( !e820_add_range(s, s + PAGE_SIZE, E820_RESERVED) )
-        panic("Unable to reserve Hyper-V hypercall range\n");
-}
-
 static int cf_check flush_tlb(
     const cpumask_t *mask, const void *va, unsigned int flags)
 {
@@ -212,7 +212,6 @@ static const struct hypervisor_ops __initconst_cf_clobber ops = {
     .name = "Hyper-V",
     .setup = setup,
     .ap_setup = ap_setup,
-    .e820_fixup = e820_fixup,
     .flush_tlb = flush_tlb,
 };
 
diff --git a/xen/arch/x86/include/asm/guest/hyperv.h b/xen/arch/x86/include/asm/guest/hyperv.h
index dabc62727b..5792e77104 100644
--- a/xen/arch/x86/include/asm/guest/hyperv.h
+++ b/xen/arch/x86/include/asm/guest/hyperv.h
@@ -10,9 +10,6 @@
 
 #include <xen/types.h>
 
-/* Use top-most MFN for hypercall page */
-#define HV_HCALL_MFN   (((1ULL << paddr_bits) - 1) >> HV_HYP_PAGE_SHIFT)
-
 /*
  * The specification says: "The partition reference time is computed
  * by the following formula:
-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.