From: Shradha Gupta <[email protected]> Sent: Monday, September 
7, 2026 2:26 AM
> 
> On ARM64, machine_shutdown() does not provide a platform hook between
> device_shutdown() and smp_shutdown_nonboot_cpus(), unlike x86's
> machine_ops.shutdown. This prevents the Hyper-V VMBus kexec handler
> from running at the correct point during kexec shutdown, causing
> kexec reboot to fail on ARM64 Hyper-V guests.
> 
> Use syscore_ops.shutdown instead: syscore_shutdown() runs in the same
> window (after device_shutdown(), before CPUs are taken offline) where
> VMBus UNLOAD and cpuhp_remove_state() must execute.
> 
> Provide ARM64-specific overrides of hv_setup_kexec_handler() and
> hv_remove_kexec_handler() that register/unregister a syscore_ops
> shutdown callback, replacing the __weak no-op stubs in hv_common.c.
> On x86, the existing machine_ops.shutdown mechanism is unchanged.

Reviewing the code, I think this patch works as intended to provide the
missing functionality on arm64. But it adds to code sprawl by having
separate implementations on x86 and arm64, and there's an
opportunity to combine into a single arch independent implementation
based on syscore_ops.shutdown. Here's an outline of that approach:

1) Move the current kexec_handler setup functions from
arch/x86/kernel/cpu/mshyperv.c to vmbus_drv.c. (Or maybe
they all just go away per my #4 below.)

2) There's already hv_synic_syscore_ops defined and registered
in vmbus_drv.c. Add the .shutdown function to that syscore_ops.
(And perhaps rename it to hv_vmbus_syscore_ops as it is no
longer specific to synic.)

3) Remove the hv_kexec_handler code from hv_machine_shutdown().
The new syscore_ops.shutdown path will run before
hv_machine_shutdown(), which mean it happens before the call
to hv_stimer_global_cleanup() instead of after. Until just recently,
that would have been an ordering problem. But with support for
Windows Server 2012 Hyper-V having been removed along with
the legacy message-based path for stimer interrupts,  it's now
OK for hv_stimer_global_cleanup() to run after the kexec handler
has done the VMBus unload.

4) With all the above code now in vmbus_drv.c, the kexec handler
functions and data can be static. The __weak stubs for the kexec
handler can be removed from hv_common.c. And having a
global variable to store the pointer to hv_kexec_handler()
is probably unnecessary -- it can just be called directly.

Net, overall there might be a few less lines of code, instead
of adding 40 lines. I haven't coded this up, so maybe there's
an issue I'm missing, but hopefully it could be worked out.
When possible, having a single arch independent
implementation is almost always better than separate
implementations for each architecture.

One issue: The arch independent approach I've proposed
wouldn't backport very well. If a backport is important, it
might have to be the arm64 specific implementation that
you have in this version of the patch. Then supersede it
with the arch independent version for simplicity going
forward.

> 
> Fixes: 9d7cf2c96758 ("Drivers: hv: Add arch independent default functions for 
> some Hyper-V handlers")

I'm not clear on how this commit is related to fixing/adding
the kexec support on arm64.

Michael

> Link: 
> https://lore.kernel.org/all/[email protected]/
> Suggested-by: Catalin Marinas <[email protected]>
> Signed-off-by: Shradha Gupta <[email protected]>
> Reviewed-by: Naman Jain <[email protected]>
> ---
>  Changes in V2
>  * Use syscore_ops.shutdown instead of a bare function pointer hook in
>    machine_shutdown(), per Catalin's suggestion.
> ---
>  arch/arm64/hyperv/mshyperv.c | 40 ++++++++++++++++++++++++++++++++++++
>  1 file changed, 40 insertions(+)
> 
> diff --git a/arch/arm64/hyperv/mshyperv.c b/arch/arm64/hyperv/mshyperv.c
> index 4fdc26ade1d7..e608e546a395 100644
> --- a/arch/arm64/hyperv/mshyperv.c
> +++ b/arch/arm64/hyperv/mshyperv.c
> @@ -15,10 +15,50 @@
>  #include <linux/errno.h>
>  #include <linux/version.h>
>  #include <linux/cpuhotplug.h>
> +#include <linux/kexec.h>
> +#include <linux/syscore_ops.h>
>  #include <asm/mshyperv.h>
> 
>  static bool hyperv_initialized;
> 
> +/*
> + * Kexec handler registered by VMBus.
> + *
> + * On ARM64, machine_shutdown() does not provide a platform hook between
> + * device_shutdown() and smp_shutdown_nonboot_cpus(), unlike the
> + * machine_ops.shutdown mechanism used on x86.  Use a syscore_ops shutdown
> + * callback instead: syscore_shutdown() runs after device_shutdown() and
> + * before CPUs are taken offline, which is the same window VMBus needs to
> + * run its UNLOAD message and cpuhp_remove_state() during kexec.
> + */
> +static void (*hv_kexec_handler_fn)(void);
> +
> +static void hv_kexec_syscore_shutdown(void *data)
> +{
> +     if (kexec_in_progress && hv_kexec_handler_fn)
> +             hv_kexec_handler_fn();
> +}
> +
> +static const struct syscore_ops hv_kexec_syscore_ops = {
> +     .shutdown       = hv_kexec_syscore_shutdown,
> +};
> +
> +static struct syscore hv_kexec_syscore = {
> +     .ops            = &hv_kexec_syscore_ops,
> +};
> +
> +void hv_setup_kexec_handler(void (*handler)(void))
> +{
> +     hv_kexec_handler_fn = handler;
> +     register_syscore(&hv_kexec_syscore);
> +}
> +
> +void hv_remove_kexec_handler(void)
> +{
> +     unregister_syscore(&hv_kexec_syscore);
> +     hv_kexec_handler_fn = NULL;
> +}
> +
>  int hv_get_hypervisor_version(union hv_hypervisor_version_info *info)
>  {
>       hv_get_vpreg_128(HV_REGISTER_HYPERVISOR_VERSION,
> --
> 2.43.0
> 


Reply via email to