Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

x86/hyperv: Use __naked attribute to fix stackless C function

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.

Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com> # asm parts, not hv parts
Reviewed-by: Mukesh Rathor <mrathor@linux.microsoft.com>
Acked-by: Uros Bizjak <ubizjak@gmail.com>
Cc: Wei Liu <wei.liu@kernel.org>
Cc: linux-hyperv@vger.kernel.org
Fixes: 94212d34618c ("x86/hyperv: Implement hypervisor RAM collection into vmcore")
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Wei Liu <wei.liu@kernel.org>

authored by

Ard Biesheuvel and committed by
Wei Liu
3fde5281 edd20cb6

+52 -48
+52 -48
arch/x86/hyperv/hv_crash.c
··· 107 107 cpu_relax(); 108 108 } 109 109 110 - /* This cannot be inlined as it needs stack */ 111 - static noinline __noclone void hv_crash_restore_tss(void) 110 + static void hv_crash_restore_tss(void) 112 111 { 113 112 load_TR_desc(); 114 113 } 115 114 116 - /* This cannot be inlined as it needs stack */ 117 - static noinline void hv_crash_clear_kernpt(void) 115 + static void hv_crash_clear_kernpt(void) 118 116 { 119 117 pgd_t *pgd; 120 118 p4d_t *p4d; ··· 123 125 native_p4d_clear(p4d); 124 126 } 125 127 126 - /* 127 - * This is the C entry point from the asm glue code after the disable hypercall. 128 - * We enter here in IA32-e long mode, ie, full 64bit mode running on kernel 129 - * page tables with our below 4G page identity mapped, but using a temporary 130 - * GDT. ds/fs/gs/es are null. ss is not usable. bp is null. stack is not 131 - * available. We restore kernel GDT, and rest of the context, and continue 132 - * to kexec. 133 - */ 134 - static asmlinkage void __noreturn hv_crash_c_entry(void) 128 + 129 + static void __noreturn hv_crash_handle(void) 135 130 { 136 - struct hv_crash_ctxt *ctxt = &hv_crash_ctxt; 137 - 138 - /* first thing, restore kernel gdt */ 139 - native_load_gdt(&ctxt->gdtr); 140 - 141 - asm volatile("movw %%ax, %%ss" : : "a"(ctxt->ss)); 142 - asm volatile("movq %0, %%rsp" : : "m"(ctxt->rsp)); 143 - 144 - asm volatile("movw %%ax, %%ds" : : "a"(ctxt->ds)); 145 - asm volatile("movw %%ax, %%es" : : "a"(ctxt->es)); 146 - asm volatile("movw %%ax, %%fs" : : "a"(ctxt->fs)); 147 - asm volatile("movw %%ax, %%gs" : : "a"(ctxt->gs)); 148 - 149 - native_wrmsrq(MSR_IA32_CR_PAT, ctxt->pat); 150 - asm volatile("movq %0, %%cr0" : : "r"(ctxt->cr0)); 151 - 152 - asm volatile("movq %0, %%cr8" : : "r"(ctxt->cr8)); 153 - asm volatile("movq %0, %%cr4" : : "r"(ctxt->cr4)); 154 - asm volatile("movq %0, %%cr2" : : "r"(ctxt->cr4)); 155 - 156 - native_load_idt(&ctxt->idtr); 157 - native_wrmsrq(MSR_GS_BASE, ctxt->gsbase); 158 - native_wrmsrq(MSR_EFER, ctxt->efer); 159 - 160 - /* restore the original kernel CS now via far return */ 161 - asm volatile("movzwq %0, %%rax\n\t" 162 - "pushq %%rax\n\t" 163 - "pushq $1f\n\t" 164 - "lretq\n\t" 165 - "1:nop\n\t" : : "m"(ctxt->cs) : "rax"); 166 - 167 - /* We are in asmlinkage without stack frame, hence make C function 168 - * calls which will buy stack frames. 169 - */ 170 131 hv_crash_restore_tss(); 171 132 hv_crash_clear_kernpt(); 172 133 ··· 134 177 135 178 hv_panic_timeout_reboot(); 136 179 } 137 - /* Tell gcc we are using lretq long jump in the above function intentionally */ 180 + 181 + /* 182 + * __naked functions do not permit function calls, not even to __always_inline 183 + * functions that only contain asm() blocks themselves. So use a macro instead. 184 + */ 185 + #define hv_wrmsr(msr, val) \ 186 + asm volatile("wrmsr" :: "c"(msr), "a"((u32)val), "d"((u32)(val >> 32)) : "memory") 187 + 188 + /* 189 + * This is the C entry point from the asm glue code after the disable hypercall. 190 + * We enter here in IA32-e long mode, ie, full 64bit mode running on kernel 191 + * page tables with our below 4G page identity mapped, but using a temporary 192 + * GDT. ds/fs/gs/es are null. ss is not usable. bp is null. stack is not 193 + * available. We restore kernel GDT, and rest of the context, and continue 194 + * to kexec. 195 + */ 196 + static void __naked hv_crash_c_entry(void) 197 + { 198 + /* first thing, restore kernel gdt */ 199 + asm volatile("lgdt %0" : : "m" (hv_crash_ctxt.gdtr)); 200 + 201 + asm volatile("movw %0, %%ss\n\t" 202 + "movq %1, %%rsp" 203 + :: "m"(hv_crash_ctxt.ss), "m"(hv_crash_ctxt.rsp)); 204 + 205 + asm volatile("movw %0, %%ds" : : "m"(hv_crash_ctxt.ds)); 206 + asm volatile("movw %0, %%es" : : "m"(hv_crash_ctxt.es)); 207 + asm volatile("movw %0, %%fs" : : "m"(hv_crash_ctxt.fs)); 208 + asm volatile("movw %0, %%gs" : : "m"(hv_crash_ctxt.gs)); 209 + 210 + hv_wrmsr(MSR_IA32_CR_PAT, hv_crash_ctxt.pat); 211 + asm volatile("movq %0, %%cr0" : : "r"(hv_crash_ctxt.cr0)); 212 + 213 + asm volatile("movq %0, %%cr8" : : "r"(hv_crash_ctxt.cr8)); 214 + asm volatile("movq %0, %%cr4" : : "r"(hv_crash_ctxt.cr4)); 215 + asm volatile("movq %0, %%cr2" : : "r"(hv_crash_ctxt.cr2)); 216 + 217 + asm volatile("lidt %0" : : "m" (hv_crash_ctxt.idtr)); 218 + hv_wrmsr(MSR_GS_BASE, hv_crash_ctxt.gsbase); 219 + hv_wrmsr(MSR_EFER, hv_crash_ctxt.efer); 220 + 221 + /* restore the original kernel CS now via far return */ 222 + asm volatile("pushq %q0\n\t" 223 + "pushq %q1\n\t" 224 + "lretq" 225 + :: "r"(hv_crash_ctxt.cs), "r"(hv_crash_handle)); 226 + } 227 + /* Tell objtool we are using lretq long jump in the above function intentionally */ 138 228 STACK_FRAME_NON_STANDARD(hv_crash_c_entry); 139 229 140 230 static void hv_mark_tss_not_busy(void)