From: Wei Hu <[email protected]>

Upstream mshv_synic_cpu_init()/_exit() skip programming the SynIC
SIMP/SIEFP/SCONTROL registers when VMBus is active (hv_vmbus_exists()),
assuming VMBus's hv_hyp_synic_enable_regs() already provisioned them.

That assumption is wrong for a nested root partition. There, VMBus
programs the nested SynIC MSRs (HV_X64_MSR_NESTED_SIMP, ...) through
hv_set_msr()'s nested remap, while mshv_synic reads and writes the
non-nested SynIC MSRs. As a result MSHV maps the wrong message page and
never receives the async hypercall completion, hanging guest creation.

Gate the "VMBus owns the SynIC registers" optimization on !hv_nested so
a nested root partition programs its own non-nested SynIC registers.
There is no behavior change for a non-nested root.

Map hypervisor-provided SIMP, SIEFP, and root SIRBP pages with the shared
GPA boundary removed and MEMREMAP_DEC, matching drivers/hv/hv.c for
confidential hosts. The L1VH SIRBP remains locally allocated.

Signed-off-by: Wei Hu <[email protected]>
---
 drivers/hv/mshv_synic.c | 38 +++++++++++++++++++++++++-------------
 1 file changed, 25 insertions(+), 13 deletions(-)

diff --git a/drivers/hv/mshv_synic.c b/drivers/hv/mshv_synic.c
index 0fdbae1e053c..8470cf958f21 100644
--- a/drivers/hv/mshv_synic.c
+++ b/drivers/hv/mshv_synic.c
@@ -458,6 +458,25 @@ void mshv_isr(void)
        }
 }
 
+static bool mshv_synic_vmbus_owns_registers(void)
+{
+       /* Nested VMBus programs nested MSRs, while MSHV uses non-nested MSRs. 
*/
+       return hv_vmbus_exists() && !hv_nested;
+}
+
+static void *mshv_synic_map_shared_page(u64 pfn)
+{
+       u64 base;
+
+       if (!pfn)
+               return NULL;
+
+       /* Match Hyper-V's established confidential SynIC mapping convention. */
+       base = (pfn << HV_HYP_PAGE_SHIFT) &
+               ~ms_hyperv.shared_gpa_boundary;
+       return memremap(base, HV_HYP_PAGE_SIZE, MEMREMAP_WB | MEMREMAP_DEC);
+}
+
 static int mshv_synic_cpu_init(unsigned int cpu)
 {
        union hv_synic_simp simp;
@@ -468,11 +487,7 @@ static int mshv_synic_cpu_init(unsigned int cpu)
        struct hv_message_page *msg_page;
        struct hv_synic_event_flags_page *event_flags_page;
        struct hv_synic_event_ring_page *event_ring_page;
-       /*
-        * VMBus owns SIMP/SIEFP/SCONTROL when it is active.
-        * See hv_hyp_synic_enable_regs() for that initialization.
-        */
-       bool vmbus_active = hv_vmbus_exists();
+       bool vmbus_active = mshv_synic_vmbus_owns_registers();
 
        /*
         * Map the SYNIC message page. When VMBus is not active the
@@ -484,8 +499,7 @@ static int mshv_synic_cpu_init(unsigned int cpu)
                simp.simp_enabled = true;
                hv_set_non_nested_msr(HV_MSR_SIMP, simp.as_uint64);
        }
-       msg_page = memremap(simp.base_simp_gpa << HV_HYP_PAGE_SHIFT,
-                           HV_HYP_PAGE_SIZE, MEMREMAP_WB);
+       msg_page = mshv_synic_map_shared_page(simp.base_simp_gpa);
        WRITE_ONCE(spages->hyp_synic_message_page, msg_page);
 
        if (!msg_page)
@@ -500,8 +514,7 @@ static int mshv_synic_cpu_init(unsigned int cpu)
                siefp.siefp_enabled = true;
                hv_set_non_nested_msr(HV_MSR_SIEFP, siefp.as_uint64);
        }
-       event_flags_page = memremap(siefp.base_siefp_gpa << HV_HYP_PAGE_SHIFT,
-                                   HV_HYP_PAGE_SIZE, MEMREMAP_WB);
+       event_flags_page = mshv_synic_map_shared_page(siefp.base_siefp_gpa);
        WRITE_ONCE(spages->synic_event_flags_page, event_flags_page);
 
        if (!event_flags_page)
@@ -511,8 +524,8 @@ static int mshv_synic_cpu_init(unsigned int cpu)
        sirbp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIRBP);
 
        if (hv_root_partition()) {
-               event_ring_page = memremap(sirbp.base_sirbp_gpa << 
HV_HYP_PAGE_SHIFT,
-                                          HV_HYP_PAGE_SIZE, MEMREMAP_WB);
+               event_ring_page =
+                       mshv_synic_map_shared_page(sirbp.base_sirbp_gpa);
 
                if (!event_ring_page)
                        goto cleanup_siefp;
@@ -595,8 +608,7 @@ static int mshv_synic_cpu_exit(unsigned int cpu)
        struct hv_message_page *msg_page;
        struct hv_synic_event_flags_page *event_flags_page;
        struct hv_synic_event_ring_page *event_ring_page;
-       /* VMBus owns SIMP/SIEFP/SCONTROL when it is active */
-       bool vmbus_active = hv_vmbus_exists();
+       bool vmbus_active = mshv_synic_vmbus_owns_registers();
 
        msg_page = READ_ONCE(spages->hyp_synic_message_page);
        event_flags_page = READ_ONCE(spages->synic_event_flags_page);
-- 
2.43.0


Reply via email to