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

Ariadne Conill posted 1 patch an hour ago
Patches applied successfully (tree, apply log)
git fetch https://gitlab.com/xen-project/patchew/xen tags/patchew/20260716183502.21075-1-ariadne@ariadne.space
xen/arch/x86/guest/hyperv/hyperv.c      | 19 +++++++++----------
xen/arch/x86/include/asm/guest/hyperv.h |  3 ---
2 files changed, 9 insertions(+), 13 deletions(-)
[PATCH v4] x86/hyperv: use dynamically allocated page for hypercalls
Posted by Ariadne Conill an hour ago
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 <ariadne@ariadne.space>
---
 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