On Thu, Feb 26, 2026 at 11:48 AM Ard Biesheuvel <[email protected]> wrote:
>
> Hi Uros,
>
> On Thu, 26 Feb 2026, at 11:35, Uros Bizjak wrote:
> > 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).
> >
>
> Nice.
>
> >> +                    "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.
> >
>
> Right, so the compiler knows that the register will be updated by the asm() 
> block. But what is preventing it from writing back this value to 
> hv_crash_ctxt.cs? The generated code doesn't seem to do so, but the semantics 
> of "+r" suggest otherwise AIUI.
>
> The code following the asm() block is unreachable anyway, so it doesn't 
> really matter either way in practice. Just curious ...

Oh, you just need a temporary here... the original is OK. Indeed, "+r"
will write back the value to the memory location, and this is not what
we want here.

Uros.

Reply via email to