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