On Fri, Mar 27, 2026 at 01:19:14PM -0700, Jork Loeser wrote: > After a kexec the logical processors and virtual processors already > exist in the hypervisor because they were created by the previous > kernel. Attempting to add them again causes either a BUG_ON or > corrupted VP state leading to MCEs in the new kernel. > > Add hv_lp_exists() to probe whether an LP is already present by > calling HVCALL_GET_LOGICAL_PROCESSOR_RUN_TIME. When it succeeds the > LP exists and we skip the add-LP and create-VP loops entirely. > > Also add hv_call_notify_all_processors_started() which informs the > hypervisor that all processors are online. This is required after > adding LPs (fresh boot) and is a no-op on kexec since we skip that > path. > > Co-developed-by: Anirudh Rayabharam <[email protected]> > Signed-off-by: Anirudh Rayabharam <[email protected]> > Co-developed-by: Stanislav Kinsburskii <[email protected]> > Signed-off-by: Stanislav Kinsburskii <[email protected]> > Co-developed-by: Mukesh Rathor <[email protected]> > Signed-off-by: Mukesh Rathor <[email protected]> > Signed-off-by: Jork Loeser <[email protected]> > --- > arch/x86/kernel/cpu/mshyperv.c | 7 +++++ > drivers/hv/hv_proc.c | 47 ++++++++++++++++++++++++++++++++++ > include/asm-generic/mshyperv.h | 10 ++++++++ > include/hyperv/hvgdk_mini.h | 1 + > include/hyperv/hvhdk_mini.h | 12 +++++++++ > 5 files changed, 77 insertions(+) > > diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c > index 235087456bdf..f653feea880b 100644 > --- a/arch/x86/kernel/cpu/mshyperv.c > +++ b/arch/x86/kernel/cpu/mshyperv.c > @@ -429,6 +429,10 @@ static void __init hv_smp_prepare_cpus(unsigned int > max_cpus) > } > > #ifdef CONFIG_X86_64 > + /* If AP LPs exist, we are in a kexec'd kernel and VPs already exist */ > + if (num_present_cpus() == 1 || hv_lp_exists(1)) > + return; > + > for_each_present_cpu(i) { > if (i == 0) > continue; > @@ -436,6 +440,9 @@ static void __init hv_smp_prepare_cpus(unsigned int > max_cpus) > BUG_ON(ret); > } > > + ret = hv_call_notify_all_processors_started(); > + WARN_ON(ret); > + > for_each_present_cpu(i) { > if (i == 0) > continue; > diff --git a/drivers/hv/hv_proc.c b/drivers/hv/hv_proc.c > index 5f4fd9c3231c..63a48e5a02c5 100644 > --- a/drivers/hv/hv_proc.c > +++ b/drivers/hv/hv_proc.c > @@ -239,3 +239,50 @@ int hv_call_create_vp(int node, u64 partition_id, u32 > vp_index, u32 flags) > return ret; > } > EXPORT_SYMBOL_GPL(hv_call_create_vp); > + > +int hv_call_notify_all_processors_started(void) > +{ > + struct hv_input_notify_partition_event *input; > + u64 status; > + unsigned long irq_flags; > + int ret = 0; > + > + local_irq_save(irq_flags); > + input = *this_cpu_ptr(hyperv_pcpu_input_arg); > + memset(input, 0, sizeof(*input)); > + input->event = HV_PARTITION_ALL_LOGICAL_PROCESSORS_STARTED; > + status = hv_do_hypercall(HVCALL_NOTIFY_PARTITION_EVENT, > + input, NULL);
nit: hv_do_fast_hypercall8 should do here as this would simplify the code. Reviewed-by: Stanislav Kinsburskii <[email protected]> > + local_irq_restore(irq_flags); > + > + if (!hv_result_success(status)) { > + hv_status_err(status, "\n"); > + ret = hv_result_to_errno(status); > + } > + return ret; > +} > + > +bool hv_lp_exists(u32 lp_index) > +{ > + struct hv_input_get_logical_processor_run_time *input; > + struct hv_output_get_logical_processor_run_time *output; > + unsigned long flags; > + u64 status; > + > + local_irq_save(flags); > + input = *this_cpu_ptr(hyperv_pcpu_input_arg); > + output = *this_cpu_ptr(hyperv_pcpu_output_arg); > + > + input->lp_index = lp_index; > + status = hv_do_hypercall(HVCALL_GET_LOGICAL_PROCESSOR_RUN_TIME, > + input, output); > + local_irq_restore(flags); > + > + if (!hv_result_success(status) && > + hv_result(status) != HV_STATUS_INVALID_LP_INDEX) { > + hv_status_err(status, "\n"); > + BUG(); > + } > + > + return hv_result_success(status); > +} > diff --git a/include/asm-generic/mshyperv.h b/include/asm-generic/mshyperv.h > index d37b68238c97..bf601d67cecb 100644 > --- a/include/asm-generic/mshyperv.h > +++ b/include/asm-generic/mshyperv.h > @@ -347,6 +347,8 @@ bool hv_result_needs_memory(u64 status); > int hv_deposit_memory_node(int node, u64 partition_id, u64 status); > int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages); > int hv_call_add_logical_proc(int node, u32 lp_index, u32 acpi_id); > +int hv_call_notify_all_processors_started(void); > +bool hv_lp_exists(u32 lp_index); > int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags); > > #else /* CONFIG_MSHV_ROOT */ > @@ -366,6 +368,14 @@ static inline int hv_call_add_logical_proc(int node, u32 > lp_index, u32 acpi_id) > { > return -EOPNOTSUPP; > } > +static inline int hv_call_notify_all_processors_started(void) > +{ > + return -EOPNOTSUPP; > +} > +static inline bool hv_lp_exists(u32 lp_index) > +{ > + return false; > +} > static inline int hv_call_create_vp(int node, u64 partition_id, u32 > vp_index, u32 flags) > { > return -EOPNOTSUPP; > diff --git a/include/hyperv/hvgdk_mini.h b/include/hyperv/hvgdk_mini.h > index 056ef7b6b360..f2598e186550 100644 > --- a/include/hyperv/hvgdk_mini.h > +++ b/include/hyperv/hvgdk_mini.h > @@ -435,6 +435,7 @@ union hv_vp_assist_msr_contents { /* > HV_REGISTER_VP_ASSIST_PAGE */ > /* HV_CALL_CODE */ > #define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE 0x0002 > #define HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST 0x0003 > +#define HVCALL_GET_LOGICAL_PROCESSOR_RUN_TIME 0x0004 > #define HVCALL_NOTIFY_LONG_SPIN_WAIT 0x0008 > #define HVCALL_SEND_IPI 0x000b > #define HVCALL_ENABLE_VP_VTL 0x000f > diff --git a/include/hyperv/hvhdk_mini.h b/include/hyperv/hvhdk_mini.h > index 091c03e26046..b4cb2fa26e9b 100644 > --- a/include/hyperv/hvhdk_mini.h > +++ b/include/hyperv/hvhdk_mini.h > @@ -362,6 +362,7 @@ union hv_partition_event_input { > > enum hv_partition_event { > HV_PARTITION_EVENT_ROOT_CRASHDUMP = 2, > + HV_PARTITION_ALL_LOGICAL_PROCESSORS_STARTED = 4, > }; > > struct hv_input_notify_partition_event { > @@ -369,6 +370,17 @@ struct hv_input_notify_partition_event { > union hv_partition_event_input input; > } __packed; > > +struct hv_input_get_logical_processor_run_time { > + u32 lp_index; > +} __packed; > + > +struct hv_output_get_logical_processor_run_time { > + u64 global_time; > + u64 local_run_time; > + u64 rsvdz0; > + u64 hypervisor_time; > +} __packed; > + > struct hv_lp_startup_status { > u64 hv_status; > u64 substatus1; > -- > 2.43.0 >

