On Sun, Sep 27, 2026 at 08:26:45PM +0000, Michael Kelley wrote:
> 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
>

Thanks, Michael.

I initially kept the implementation ARM64-specific to avoid changing
the existing x86 shutdown path. Using the common syscore callback would
require moving the x86 VMBus teardown out of hv_machine_shutdown(),
including changing the established ordering where
hv_stimer_global_cleanup() runs before VMBus UNLOAD.

Commit be0cfab740e5 ("clocksource: hyper-v: Remove support for stimer
interrupts in message mode") has since removed that dependency. With
this ordering constraint gone, the architecture-independent
implementation is now the cleaner approach, and I will rework the patch
accordingly.

For stable backports to kernels that still support message-mode
stimers, I will prepare an ARM64-specific adaptation that preserves the
existing x86 ordering.

Regarding the Fixes tag, I used 9d7cf2c96758 because it introduced the
weak no-op handlers used by ARM64. However, I agree that it made no
functional change and did not introduce the failure. I will change the
tag to:

Fixes: 9bbb888824e3 ("arm64: hyperv: Initialize hypervisor on boot")

Thanks,
Shradha
 
> > 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