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

