* [RFT PATCH] x86/hyperv: Use __naked attribute to fix stackless C function
@ 2026-02-26 9:50 Ard Biesheuvel
2026-02-26 10:35 ` Uros Bizjak
` (2 more replies)
0 siblings, 3 replies; 10+ messages in thread
From: Ard Biesheuvel @ 2026-02-26 9:50 UTC (permalink / raw)
To: linux-kernel
Cc: Ard Biesheuvel, Mukesh Rathor, K. Y. Srinivasan, Haiyang Zhang,
Wei Liu, Dexuan Cui, Long Li, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, H. Peter Anvin, Uros Bizjak,
linux-hyperv
From: Ard Biesheuvel <ardb@kernel.org>
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 <ardb@kernel.org>
---
Build tested only.
Cc: Mukesh Rathor <mrathor@linux.microsoft.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Haiyang Zhang <haiyangz@microsoft.com>
Cc: Wei Liu <wei.liu@kernel.org>
Cc: Dexuan Cui <decui@microsoft.com>
Cc: Long Li <longli@microsoft.com>
Cc: Thomas Gleixner <tglx@kernel.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Uros Bizjak <ubizjak@gmail.com>
Cc: linux-hyperv@vger.kernel.org
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"
+ "pushq %q0 \n\t"
+ "lretq \n\t"
+ :: "a"(hv_crash_ctxt.cs), "i"(hv_crash_handle));
}
/* Tell gcc we are using lretq long jump in the above function intentionally */
STACK_FRAME_NON_STANDARD(hv_crash_c_entry);
--
2.53.0.414.gf7e9f6c205-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [RFT PATCH] x86/hyperv: Use __naked attribute to fix stackless C function 2026-02-26 9:50 [RFT PATCH] x86/hyperv: Use __naked attribute to fix stackless C function Ard Biesheuvel @ 2026-02-26 10:35 ` Uros Bizjak 2026-02-26 10:48 ` Ard Biesheuvel 2026-02-26 12:01 ` Andrew Cooper 2026-02-27 21:50 ` Wei Liu 2 siblings, 1 reply; 10+ messages in thread From: Uros Bizjak @ 2026-02-26 10:35 UTC (permalink / raw) To: Ard Biesheuvel Cc: linux-kernel, Ard Biesheuvel, Mukesh Rathor, K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui, Long Li, Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, H. Peter Anvin, linux-hyperv On Thu, Feb 26, 2026 at 10:51 AM Ard Biesheuvel <ardb+git@google.com> wrote: > > From: Ard Biesheuvel <ardb@kernel.org> > > 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 <ardb@kernel.org> > --- > Build tested only. > > Cc: Mukesh Rathor <mrathor@linux.microsoft.com> > Cc: "K. Y. Srinivasan" <kys@microsoft.com> > Cc: Haiyang Zhang <haiyangz@microsoft.com> > Cc: Wei Liu <wei.liu@kernel.org> > Cc: Dexuan Cui <decui@microsoft.com> > Cc: Long Li <longli@microsoft.com> > Cc: Thomas Gleixner <tglx@kernel.org> > Cc: Ingo Molnar <mingo@redhat.com> > Cc: Borislav Petkov <bp@alien8.de> > Cc: Dave Hansen <dave.hansen@linux.intel.com> > Cc: "H. Peter Anvin" <hpa@zytor.com> > Cc: Uros Bizjak <ubizjak@gmail.com> > Cc: linux-hyperv@vger.kernel.org > > 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. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFT PATCH] x86/hyperv: Use __naked attribute to fix stackless C function 2026-02-26 10:35 ` Uros Bizjak @ 2026-02-26 10:48 ` Ard Biesheuvel 2026-02-26 10:51 ` Uros Bizjak 0 siblings, 1 reply; 10+ messages in thread From: Ard Biesheuvel @ 2026-02-26 10:48 UTC (permalink / raw) To: Uros Bizjak, Ard Biesheuvel Cc: linux-kernel, Mukesh Rathor, K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui, Long Li, Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, H . Peter Anvin, linux-hyperv Hi Uros, On Thu, 26 Feb 2026, at 11:35, Uros Bizjak wrote: > On Thu, Feb 26, 2026 at 10:51 AM Ard Biesheuvel <ardb+git@google.com> wrote: >> >> From: Ard Biesheuvel <ardb@kernel.org> >> >> 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 <ardb@kernel.org> >> --- >> Build tested only. >> >> Cc: Mukesh Rathor <mrathor@linux.microsoft.com> >> Cc: "K. Y. Srinivasan" <kys@microsoft.com> >> Cc: Haiyang Zhang <haiyangz@microsoft.com> >> Cc: Wei Liu <wei.liu@kernel.org> >> Cc: Dexuan Cui <decui@microsoft.com> >> Cc: Long Li <longli@microsoft.com> >> Cc: Thomas Gleixner <tglx@kernel.org> >> Cc: Ingo Molnar <mingo@redhat.com> >> Cc: Borislav Petkov <bp@alien8.de> >> Cc: Dave Hansen <dave.hansen@linux.intel.com> >> Cc: "H. Peter Anvin" <hpa@zytor.com> >> Cc: Uros Bizjak <ubizjak@gmail.com> >> Cc: linux-hyperv@vger.kernel.org >> >> 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 ... ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFT PATCH] x86/hyperv: Use __naked attribute to fix stackless C function 2026-02-26 10:48 ` Ard Biesheuvel @ 2026-02-26 10:51 ` Uros Bizjak 0 siblings, 0 replies; 10+ messages in thread From: Uros Bizjak @ 2026-02-26 10:51 UTC (permalink / raw) To: Ard Biesheuvel Cc: Ard Biesheuvel, linux-kernel, Mukesh Rathor, K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui, Long Li, Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, H . Peter Anvin, linux-hyperv On Thu, Feb 26, 2026 at 11:48 AM Ard Biesheuvel <ardb@kernel.org> 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 <ardb+git@google.com> wrote: > >> > >> From: Ard Biesheuvel <ardb@kernel.org> > >> > >> 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 <ardb@kernel.org> > >> --- > >> Build tested only. > >> > >> Cc: Mukesh Rathor <mrathor@linux.microsoft.com> > >> Cc: "K. Y. Srinivasan" <kys@microsoft.com> > >> Cc: Haiyang Zhang <haiyangz@microsoft.com> > >> Cc: Wei Liu <wei.liu@kernel.org> > >> Cc: Dexuan Cui <decui@microsoft.com> > >> Cc: Long Li <longli@microsoft.com> > >> Cc: Thomas Gleixner <tglx@kernel.org> > >> Cc: Ingo Molnar <mingo@redhat.com> > >> Cc: Borislav Petkov <bp@alien8.de> > >> Cc: Dave Hansen <dave.hansen@linux.intel.com> > >> Cc: "H. Peter Anvin" <hpa@zytor.com> > >> Cc: Uros Bizjak <ubizjak@gmail.com> > >> Cc: linux-hyperv@vger.kernel.org > >> > >> 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. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFT PATCH] x86/hyperv: Use __naked attribute to fix stackless C function 2026-02-26 9:50 [RFT PATCH] x86/hyperv: Use __naked attribute to fix stackless C function Ard Biesheuvel 2026-02-26 10:35 ` Uros Bizjak @ 2026-02-26 12:01 ` Andrew Cooper 2026-02-26 13:07 ` Ard Biesheuvel 2026-02-27 21:50 ` Wei Liu 2 siblings, 1 reply; 10+ messages in thread From: Andrew Cooper @ 2026-02-26 12:01 UTC (permalink / raw) To: Ard Biesheuvel Cc: Andrew Cooper, ardb, bp, dave.hansen, decui, haiyangz, hpa, kys, linux-hyperv, linux-kernel, longli, mingo, mrathor, tglx, ubizjak, wei.liu > @@ -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)); I know this is pre-existing, but the asm here is poor. All segment registers loads can have a memory operand, rather than forcing through %eax, which in turn reduces the setup logic the compiler needs to emit. Something like this: "movl %0, %%ss" : : "m"(hv_crash_ctxt.ss) ought to do. > > - 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" + "pushq %q0 \n\t" + "lretq \n\t" + :: > "a"(hv_crash_ctxt.cs), "i"(hv_crash_handle)); As Uros notes, "a" is clobbered here but the compiler is not informed. But, it's not necessary. As a naked function you could even use 3x asm() statements, but you can get the compiler to sort out the function reference automatically with: asm volatile ("push %q0\n\t" "push %q1\n\t" "lretq" :: "r"(hv_crash_ctxt.cs), "r"(hv_crash_handle)); (Only tested in godbolt) ~Andrew ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFT PATCH] x86/hyperv: Use __naked attribute to fix stackless C function 2026-02-26 12:01 ` Andrew Cooper @ 2026-02-26 13:07 ` Ard Biesheuvel 2026-02-26 13:24 ` Andrew Cooper 0 siblings, 1 reply; 10+ messages in thread From: Ard Biesheuvel @ 2026-02-26 13:07 UTC (permalink / raw) To: Andrew Cooper Cc: Borislav Petkov, dave.hansen, decui, haiyangz, H . Peter Anvin, kys, linux-hyperv, linux-kernel, Long Li, Ingo Molnar, Mukesh Rathor, Thomas Gleixner, Uros Bizjak, wei.liu On Thu, 26 Feb 2026, at 13:01, Andrew Cooper wrote: >> @@ -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)); > > I know this is pre-existing, but the asm here is poor. > > All segment registers loads can have a memory operand, rather than > forcing through %eax, which in turn reduces the setup logic the compiler > needs to emit. > > Something like this: > > "movl %0, %%ss" : : "m"(hv_crash_ctxt.ss) > > ought to do. > 'movw' seems to work, yes. ... > > As Uros notes, "a" is clobbered here but the compiler is not informed. > But, it's not necessary. > > As a naked function you could even use 3x asm() statements, but you can > get the compiler to sort out the function reference automatically with: > > asm volatile ("push %q0\n\t" > "push %q1\n\t" > "lretq" > :: "r"(hv_crash_ctxt.cs), "r"(hv_crash_handle)); > > Yeah much better - thanks. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFT PATCH] x86/hyperv: Use __naked attribute to fix stackless C function 2026-02-26 13:07 ` Ard Biesheuvel @ 2026-02-26 13:24 ` Andrew Cooper 2026-02-26 13:29 ` Ard Biesheuvel 0 siblings, 1 reply; 10+ messages in thread From: Andrew Cooper @ 2026-02-26 13:24 UTC (permalink / raw) To: Ard Biesheuvel Cc: Andrew Cooper, Borislav Petkov, dave.hansen, decui, haiyangz, H . Peter Anvin, kys, linux-hyperv, linux-kernel, Long Li, Ingo Molnar, Mukesh Rathor, Thomas Gleixner, Uros Bizjak, wei.liu On 26/02/2026 1:07 pm, Ard Biesheuvel wrote: > > On Thu, 26 Feb 2026, at 13:01, Andrew Cooper wrote: >>> @@ -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)); >> I know this is pre-existing, but the asm here is poor. >> >> All segment registers loads can have a memory operand, rather than >> forcing through %eax, which in turn reduces the setup logic the compiler >> needs to emit. >> >> Something like this: >> >> "movl %0, %%ss" : : "m"(hv_crash_ctxt.ss) >> >> ought to do. >> > 'movw' seems to work, yes. movw works, but is sub-optimal. The segment register instructions are somewhat weird even by x86 standards. They should always be written as 32-bit operations (movl, and %eax), removing the operand size prefix which is not necessary for these instructions to function correctly. It's absolutely marginal, but it does always pain me to read asm like this and see the myth of how to access segment selectors being repeated time and time again. ~Andrew ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFT PATCH] x86/hyperv: Use __naked attribute to fix stackless C function 2026-02-26 13:24 ` Andrew Cooper @ 2026-02-26 13:29 ` Ard Biesheuvel 2026-02-26 13:52 ` Andrew Cooper 0 siblings, 1 reply; 10+ messages in thread From: Ard Biesheuvel @ 2026-02-26 13:29 UTC (permalink / raw) To: Andrew Cooper Cc: Borislav Petkov, dave.hansen, decui, haiyangz, H . Peter Anvin, kys, linux-hyperv, linux-kernel, Long Li, Ingo Molnar, Mukesh Rathor, Thomas Gleixner, Uros Bizjak, wei.liu On Thu, 26 Feb 2026, at 14:24, Andrew Cooper wrote: > On 26/02/2026 1:07 pm, Ard Biesheuvel wrote: >> >> On Thu, 26 Feb 2026, at 13:01, Andrew Cooper wrote: >>>> @@ -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)); >>> I know this is pre-existing, but the asm here is poor. >>> >>> All segment registers loads can have a memory operand, rather than >>> forcing through %eax, which in turn reduces the setup logic the compiler >>> needs to emit. >>> >>> Something like this: >>> >>> "movl %0, %%ss" : : "m"(hv_crash_ctxt.ss) >>> >>> ought to do. >>> >> 'movw' seems to work, yes. > > movw works, but is sub-optimal. > Can you give an asm example where movl with a segment register is accepted by the assembler? I only managed that with movw, hence my comment. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFT PATCH] x86/hyperv: Use __naked attribute to fix stackless C function 2026-02-26 13:29 ` Ard Biesheuvel @ 2026-02-26 13:52 ` Andrew Cooper 0 siblings, 0 replies; 10+ messages in thread From: Andrew Cooper @ 2026-02-26 13:52 UTC (permalink / raw) To: Ard Biesheuvel Cc: Andrew Cooper, Borislav Petkov, dave.hansen, decui, haiyangz, H . Peter Anvin, kys, linux-hyperv, linux-kernel, Long Li, Ingo Molnar, Mukesh Rathor, Thomas Gleixner, Uros Bizjak, wei.liu On 26/02/2026 1:29 pm, Ard Biesheuvel wrote: > > On Thu, 26 Feb 2026, at 14:24, Andrew Cooper wrote: >> On 26/02/2026 1:07 pm, Ard Biesheuvel wrote: >>> On Thu, 26 Feb 2026, at 13:01, Andrew Cooper wrote: >>>>> @@ -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)); >>>> I know this is pre-existing, but the asm here is poor. >>>> >>>> All segment registers loads can have a memory operand, rather than >>>> forcing through %eax, which in turn reduces the setup logic the compiler >>>> needs to emit. >>>> >>>> Something like this: >>>> >>>> "movl %0, %%ss" : : "m"(hv_crash_ctxt.ss) >>>> >>>> ought to do. >>>> >>> 'movw' seems to work, yes. >> movw works, but is sub-optimal. >> > Can you give an asm example where movl with a segment register is accepted by the assembler? I only managed that with movw, hence my comment. Oh lovely, that looks like a binutils bug, but I bet it comes from not realising that `mov sreg` is different to the more general mov forms. Using no suffix will emit the optimal instruction without a warning. https://godbolt.org/z/GYKs31Gqn ~Andrew ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFT PATCH] x86/hyperv: Use __naked attribute to fix stackless C function 2026-02-26 9:50 [RFT PATCH] x86/hyperv: Use __naked attribute to fix stackless C function Ard Biesheuvel 2026-02-26 10:35 ` Uros Bizjak 2026-02-26 12:01 ` Andrew Cooper @ 2026-02-27 21:50 ` Wei Liu 2 siblings, 0 replies; 10+ messages in thread From: Wei Liu @ 2026-02-27 21:50 UTC (permalink / raw) To: Ard Biesheuvel Cc: linux-kernel, Ard Biesheuvel, Mukesh Rathor, K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui, Long Li, Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, H. Peter Anvin, Uros Bizjak, linux-hyperv On Thu, Feb 26, 2026 at 10:50:57AM +0100, Ard Biesheuvel wrote: > From: Ard Biesheuvel <ardb@kernel.org> > > 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 <ardb@kernel.org> Ard, thank you for the patch. For avoidance of doubt, I expect another version to be sent. We will review and test the new version on our side. Wei ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-02-27 21:50 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-02-26 9:50 [RFT PATCH] x86/hyperv: Use __naked attribute to fix stackless C function Ard Biesheuvel 2026-02-26 10:35 ` Uros Bizjak 2026-02-26 10:48 ` Ard Biesheuvel 2026-02-26 10:51 ` Uros Bizjak 2026-02-26 12:01 ` Andrew Cooper 2026-02-26 13:07 ` Ard Biesheuvel 2026-02-26 13:24 ` Andrew Cooper 2026-02-26 13:29 ` Ard Biesheuvel 2026-02-26 13:52 ` Andrew Cooper 2026-02-27 21:50 ` Wei Liu
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox