On Thu, Feb 26, 2026 at 10:51 AM Ard Biesheuvel <[email protected]> wrote:
>
> From: Ard Biesheuvel <[email protected]>
>
> hv_crash_c_entry() is a C function that is entered without a stack,
> and this is only allowed for functions that have the __naked attribute,
> which informs the compiler that it must not emit the usual prologue and
> epilogue or emit any other kind of instrumentation that relies on a
> stack frame.
>
> So split up the function, and set the __naked attribute on the initial
> part that sets up the stack, GDT, IDT and other pieces that are needed
> for ordinary C execution. Given that function calls are not permitted
> either, use the existing long return coded in an asm() block to call the
> second part of the function, which is an ordinary function that is
> permitted to call other functions as usual.
>
> Fixes: 94212d34618c ("x86/hyperv: Implement hypervisor RAM collection into 
> vmcore")
> Signed-off-by: Ard Biesheuvel <[email protected]>
> ---
> Build tested only.
>
> Cc: Mukesh Rathor <[email protected]>
> Cc: "K. Y. Srinivasan" <[email protected]>
> Cc: Haiyang Zhang <[email protected]>
> Cc: Wei Liu <[email protected]>
> Cc: Dexuan Cui <[email protected]>
> Cc: Long Li <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> Cc: Ingo Molnar <[email protected]>
> Cc: Borislav Petkov <[email protected]>
> Cc: Dave Hansen <[email protected]>
> Cc: "H. Peter Anvin" <[email protected]>
> Cc: Uros Bizjak <[email protected]>
> Cc: [email protected]
>
>  arch/x86/hyperv/hv_crash.c | 80 ++++++++++----------
>  1 file changed, 42 insertions(+), 38 deletions(-)
>
> diff --git a/arch/x86/hyperv/hv_crash.c b/arch/x86/hyperv/hv_crash.c
> index a78e4fed5720..d77766e8d37e 100644
> --- a/arch/x86/hyperv/hv_crash.c
> +++ b/arch/x86/hyperv/hv_crash.c
> @@ -107,14 +107,12 @@ static void __noreturn hv_panic_timeout_reboot(void)
>                 cpu_relax();
>  }
>
> -/* This cannot be inlined as it needs stack */
> -static noinline __noclone void hv_crash_restore_tss(void)
> +static void hv_crash_restore_tss(void)
>  {
>         load_TR_desc();
>  }
>
> -/* This cannot be inlined as it needs stack */
> -static noinline void hv_crash_clear_kernpt(void)
> +static void hv_crash_clear_kernpt(void)
>  {
>         pgd_t *pgd;
>         p4d_t *p4d;
> @@ -125,6 +123,25 @@ static noinline void hv_crash_clear_kernpt(void)
>         native_p4d_clear(p4d);
>  }
>
> +
> +static void __noreturn hv_crash_handle(void)
> +{
> +       hv_crash_restore_tss();
> +       hv_crash_clear_kernpt();
> +
> +       /* we are now fully in devirtualized normal kernel mode */
> +       __crash_kexec(NULL);
> +
> +       hv_panic_timeout_reboot();
> +}
> +
> +/*
> + * __naked functions do not permit function calls, not even to 
> __always_inline
> + * functions that only contain asm() blocks themselves. So use a macro 
> instead.
> + */
> +#define hv_wrmsr(msr, val) \
> +       asm("wrmsr" :: "c"(msr), "a"((u32)val), "d"((u32)(val >> 32)) : 
> "memory")
> +
>  /*
>   * This is the C entry point from the asm glue code after the disable 
> hypercall.
>   * We enter here in IA32-e long mode, ie, full 64bit mode running on kernel
> @@ -133,49 +150,36 @@ static noinline void hv_crash_clear_kernpt(void)
>   * available. We restore kernel GDT, and rest of the context, and continue
>   * to kexec.
>   */
> -static asmlinkage void __noreturn hv_crash_c_entry(void)
> +static void __naked hv_crash_c_entry(void)
>  {
> -       struct hv_crash_ctxt *ctxt = &hv_crash_ctxt;
> -
>         /* first thing, restore kernel gdt */
> -       native_load_gdt(&ctxt->gdtr);
> +       asm volatile("lgdt %0" : : "m" (hv_crash_ctxt.gdtr));
>
> -       asm volatile("movw %%ax, %%ss" : : "a"(ctxt->ss));
> -       asm volatile("movq %0, %%rsp" : : "m"(ctxt->rsp));
> +       asm volatile("movw %%ax, %%ss" : : "a"(hv_crash_ctxt.ss));
> +       asm volatile("movq %0, %%rsp" : : "m"(hv_crash_ctxt.rsp));
>
> -       asm volatile("movw %%ax, %%ds" : : "a"(ctxt->ds));
> -       asm volatile("movw %%ax, %%es" : : "a"(ctxt->es));
> -       asm volatile("movw %%ax, %%fs" : : "a"(ctxt->fs));
> -       asm volatile("movw %%ax, %%gs" : : "a"(ctxt->gs));
> +       asm volatile("movw %%ax, %%ds" : : "a"(hv_crash_ctxt.ds));
> +       asm volatile("movw %%ax, %%es" : : "a"(hv_crash_ctxt.es));
> +       asm volatile("movw %%ax, %%fs" : : "a"(hv_crash_ctxt.fs));
> +       asm volatile("movw %%ax, %%gs" : : "a"(hv_crash_ctxt.gs));
>
> -       native_wrmsrq(MSR_IA32_CR_PAT, ctxt->pat);
> -       asm volatile("movq %0, %%cr0" : : "r"(ctxt->cr0));
> +       hv_wrmsr(MSR_IA32_CR_PAT, hv_crash_ctxt.pat);
> +       asm volatile("movq %0, %%cr0" : : "r"(hv_crash_ctxt.cr0));
>
> -       asm volatile("movq %0, %%cr8" : : "r"(ctxt->cr8));
> -       asm volatile("movq %0, %%cr4" : : "r"(ctxt->cr4));
> -       asm volatile("movq %0, %%cr2" : : "r"(ctxt->cr4));
> +       asm volatile("movq %0, %%cr8" : : "r"(hv_crash_ctxt.cr8));
> +       asm volatile("movq %0, %%cr4" : : "r"(hv_crash_ctxt.cr4));
> +       asm volatile("movq %0, %%cr2" : : "r"(hv_crash_ctxt.cr4));
>
> -       native_load_idt(&ctxt->idtr);
> -       native_wrmsrq(MSR_GS_BASE, ctxt->gsbase);
> -       native_wrmsrq(MSR_EFER, ctxt->efer);
> +       asm volatile("lidt %0" : : "m" (hv_crash_ctxt.idtr));
> +       hv_wrmsr(MSR_GS_BASE, hv_crash_ctxt.gsbase);
> +       hv_wrmsr(MSR_EFER, hv_crash_ctxt.efer);
>
>         /* restore the original kernel CS now via far return */
> -       asm volatile("movzwq %0, %%rax\n\t"
> -                    "pushq %%rax\n\t"
> -                    "pushq $1f\n\t"
> -                    "lretq\n\t"
> -                    "1:nop\n\t" : : "m"(ctxt->cs) : "rax");
> -
> -       /* We are in asmlinkage without stack frame, hence make C function
> -        * calls which will buy stack frames.
> -        */
> -       hv_crash_restore_tss();
> -       hv_crash_clear_kernpt();
> -
> -       /* we are now fully in devirtualized normal kernel mode */
> -       __crash_kexec(NULL);
> -
> -       hv_panic_timeout_reboot();
> +       asm volatile("pushq     %q0             \n\t"
> +                    "leaq      %c1(%%rip), %q0 \n\t"

You can use %a1 instead of %c1(%%rip).

> +                    "pushq     %q0             \n\t"
> +                    "lretq                     \n\t"

No need for terminating \n\t after the last insn in the asm template.

> +                    :: "a"(hv_crash_ctxt.cs), "i"(hv_crash_handle));

Pedantically, you need ': "+a"(...) : "i"(...)' here.

Uros.

Reply via email to