FILE
hv_crash.c
File preview with syntax highlighting.
linux-6.19.14/arch/x86/hyperv/hv_crash.c
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * X86 specific Hyper-V root partition kdump/crash support module 4 * 5 * Copyright (C) 2025, Microsoft, Inc. 6 * 7 * This module implements hypervisor RAM collection into vmcore for both 8 * cases of the hypervisor crash and Linux root crash. Hyper-V implements 9 * a disable hypercall with a 32bit protected mode ABI callback. This 10 * mechanism must be used to unlock hypervisor RAM. Since the hypervisor RAM 11 * is already mapped in Linux, it is automatically collected into Linux vmcore, 12 * and can be examined by the crash command (raw RAM dump) or windbg. 13 * 14 * At a high level: 15 * 16 * Hypervisor Crash: 17 * Upon crash, hypervisor goes into an emergency minimal dispatch loop, a 18 * restrictive mode with very limited hypercall and MSR support. Each cpu 19 * then injects NMIs into root vcpus. A shared page is used to check 20 * by Linux in the NMI handler if the hypervisor has crashed. This shared 21 * page is setup in hv_root_crash_init during boot. 22 * 23 * Linux Crash: 24 * In case of Linux crash, the callback hv_crash_stop_other_cpus will send 25 * NMIs to all cpus, then proceed to the crash_nmi_callback where it waits 26 * for all cpus to be in NMI. 27 * 28 * NMI Handler (upon quorum): 29 * Eventually, in both cases, all cpus will end up in the NMI handler. 30 * Hyper-V requires the disable hypervisor must be done from the BSP. So 31 * the BSP NMI handler saves current context, does some fixups and makes 32 * the hypercall to disable the hypervisor, ie, devirtualize. Hypervisor 33 * at that point will suspend all vcpus (except the BSP), unlock all its 34 * RAM, and return to Linux at the 32bit mode entry RIP. 35 * 36 * Linux 32bit entry trampoline will then restore long mode and call C 37 * function here to restore context and continue execution to crash kexec. 38 */ 39 40#include <linux/delay.h> 41#include <linux/kexec.h> 42#include <linux/crash_dump.h> 43#include <linux/panic.h> 44#include <asm/apic.h> 45#include <asm/desc.h> 46#include <asm/page.h> 47#include <asm/pgalloc.h> 48#include <asm/mshyperv.h> 49#include <asm/nmi.h> 50#include <asm/idtentry.h> 51#include <asm/reboot.h> 52#include <asm/intel_pt.h> 53 54bool hv_crash_enabled; 55EXPORT_SYMBOL_GPL(hv_crash_enabled); 56 57struct hv_crash_ctxt { 58 ulong rsp; 59 ulong cr0; 60 ulong cr2; 61 ulong cr4; 62 ulong cr8; 63 64 u16 cs; 65 u16 ss; 66 u16 ds; 67 u16 es; 68 u16 fs; 69 u16 gs; 70 71 u16 gdt_fill; 72 struct desc_ptr gdtr; 73 char idt_fill[6]; 74 struct desc_ptr idtr; 75 76 u64 gsbase; 77 u64 efer; 78 u64 pat; 79}; 80static struct hv_crash_ctxt hv_crash_ctxt; 81 82/* Shared hypervisor page that contains crash dump area we peek into. 83 * NB: windbg looks for "hv_cda" symbol so don't change it. 84 */ 85static struct hv_crashdump_area *hv_cda; 86 87static u32 trampoline_pa, devirt_arg; 88static atomic_t crash_cpus_wait; 89static void *hv_crash_ptpgs[4]; 90static bool hv_has_crashed, lx_has_crashed; 91 92static void __noreturn hv_panic_timeout_reboot(void) 93{ 94 #define PANIC_TIMER_STEP 100 95 96 if (panic_timeout > 0) { 97 int i; 98 99 for (i = 0; i < panic_timeout * 1000; i += PANIC_TIMER_STEP) 100 mdelay(PANIC_TIMER_STEP); 101 } 102 103 if (panic_timeout) 104 native_wrmsrq(HV_X64_MSR_RESET, 1); /* get hyp to reboot */ 105 106 for (;;) 107 cpu_relax(); 108} 109 110static void hv_crash_restore_tss(void) 111{ 112 load_TR_desc(); 113} 114 115static void hv_crash_clear_kernpt(void) 116{ 117 pgd_t *pgd; 118 p4d_t *p4d; 119 120 /* Clear entry so it's not confusing to someone looking at the core */ 121 pgd = pgd_offset_k(trampoline_pa); 122 p4d = p4d_offset(pgd, trampoline_pa); 123 native_p4d_clear(p4d); 124} 125 126 127static void __noreturn hv_crash_handle(void) 128{ 129 hv_crash_restore_tss(); 130 hv_crash_clear_kernpt(); 131 132 /* we are now fully in devirtualized normal kernel mode */ 133 __crash_kexec(NULL); 134 135 hv_panic_timeout_reboot(); 136} 137 138/* 139 * __naked functions do not permit function calls, not even to __always_inline 140 * functions that only contain asm() blocks themselves. So use a macro instead. 141 */ 142#define hv_wrmsr(msr, val) \ 143 asm volatile("wrmsr" :: "c"(msr), "a"((u32)val), "d"((u32)(val >> 32)) : "memory") 144 145/* 146 * This is the C entry point from the asm glue code after the disable hypercall. 147 * We enter here in IA32-e long mode, ie, full 64bit mode running on kernel 148 * page tables with our below 4G page identity mapped, but using a temporary 149 * GDT. ds/fs/gs/es are null. ss is not usable. bp is null. stack is not 150 * available. We restore kernel GDT, and rest of the context, and continue 151 * to kexec. 152 */ 153static void __naked hv_crash_c_entry(void) 154{ 155 /* first thing, restore kernel gdt */ 156 asm volatile("lgdt %0" : : "m" (hv_crash_ctxt.gdtr)); 157 158 asm volatile("movw %0, %%ss\n\t" 159 "movq %1, %%rsp" 160 :: "m"(hv_crash_ctxt.ss), "m"(hv_crash_ctxt.rsp)); 161 162 asm volatile("movw %0, %%ds" : : "m"(hv_crash_ctxt.ds)); 163 asm volatile("movw %0, %%es" : : "m"(hv_crash_ctxt.es)); 164 asm volatile("movw %0, %%fs" : : "m"(hv_crash_ctxt.fs)); 165 asm volatile("movw %0, %%gs" : : "m"(hv_crash_ctxt.gs)); 166 167 hv_wrmsr(MSR_IA32_CR_PAT, hv_crash_ctxt.pat); 168 asm volatile("movq %0, %%cr0" : : "r"(hv_crash_ctxt.cr0)); 169 170 asm volatile("movq %0, %%cr8" : : "r"(hv_crash_ctxt.cr8)); 171 asm volatile("movq %0, %%cr4" : : "r"(hv_crash_ctxt.cr4)); 172 asm volatile("movq %0, %%cr2" : : "r"(hv_crash_ctxt.cr2)); 173 174 asm volatile("lidt %0" : : "m" (hv_crash_ctxt.idtr)); 175 hv_wrmsr(MSR_GS_BASE, hv_crash_ctxt.gsbase); 176 hv_wrmsr(MSR_EFER, hv_crash_ctxt.efer); 177 178 /* restore the original kernel CS now via far return */ 179 asm volatile("pushq %q0\n\t" 180 "pushq %q1\n\t" 181 "lretq" 182 :: "r"(hv_crash_ctxt.cs), "r"(hv_crash_handle)); 183} 184/* Tell objtool we are using lretq long jump in the above function intentionally */ 185STACK_FRAME_NON_STANDARD(hv_crash_c_entry); 186 187static void hv_mark_tss_not_busy(void) 188{ 189 struct desc_struct *desc = get_current_gdt_rw(); 190 tss_desc tss; 191 192 memcpy(&tss, &desc[GDT_ENTRY_TSS], sizeof(tss_desc)); 193 tss.type = 0x9; /* available 64-bit TSS. 0xB is busy TSS */ 194 write_gdt_entry(desc, GDT_ENTRY_TSS, &tss, DESC_TSS); 195} 196 197/* Save essential context */ 198static void hv_hvcrash_ctxt_save(void) 199{ 200 struct hv_crash_ctxt *ctxt = &hv_crash_ctxt; 201 202 asm volatile("movq %%rsp,%0" : "=m"(ctxt->rsp)); 203 204 ctxt->cr0 = native_read_cr0(); 205 ctxt->cr4 = native_read_cr4(); 206 207 asm volatile("movq %%cr2, %0" : "=a"(ctxt->cr2)); 208 asm volatile("movq %%cr8, %0" : "=a"(ctxt->cr8)); 209 210 asm volatile("movl %%cs, %%eax" : "=a"(ctxt->cs)); 211 asm volatile("movl %%ss, %%eax" : "=a"(ctxt->ss)); 212 asm volatile("movl %%ds, %%eax" : "=a"(ctxt->ds)); 213 asm volatile("movl %%es, %%eax" : "=a"(ctxt->es)); 214 asm volatile("movl %%fs, %%eax" : "=a"(ctxt->fs)); 215 asm volatile("movl %%gs, %%eax" : "=a"(ctxt->gs)); 216 217 native_store_gdt(&ctxt->gdtr); 218 store_idt(&ctxt->idtr); 219 220 ctxt->gsbase = __rdmsr(MSR_GS_BASE); 221 ctxt->efer = __rdmsr(MSR_EFER); 222 ctxt->pat = __rdmsr(MSR_IA32_CR_PAT); 223} 224 225/* Add trampoline page to the kernel pagetable for transition to kernel PT */ 226static void hv_crash_fixup_kernpt(void) 227{ 228 pgd_t *pgd; 229 p4d_t *p4d; 230 231 pgd = pgd_offset_k(trampoline_pa); 232 p4d = p4d_offset(pgd, trampoline_pa); 233 234 /* trampoline_pa is below 4G, so no pre-existing entry to clobber */ 235 p4d_populate(&init_mm, p4d, (pud_t *)hv_crash_ptpgs[1]); 236 p4d->p4d = p4d->p4d & ~(_PAGE_NX); /* enable execute */ 237} 238 239/* 240 * Notify the hyp that Linux has crashed. This will cause the hyp to quiesce 241 * and suspend all guest VPs. 242 */ 243static void hv_notify_prepare_hyp(void) 244{ 245 u64 status; 246 struct hv_input_notify_partition_event *input; 247 struct hv_partition_event_root_crashdump_input *cda; 248 249 input = *this_cpu_ptr(hyperv_pcpu_input_arg); 250 cda = &input->input.crashdump_input; 251 memset(input, 0, sizeof(*input)); 252 input->event = HV_PARTITION_EVENT_ROOT_CRASHDUMP; 253 254 cda->crashdump_action = HV_CRASHDUMP_ENTRY; 255 status = hv_do_hypercall(HVCALL_NOTIFY_PARTITION_EVENT, input, NULL); 256 if (!hv_result_success(status)) 257 return; 258 259 cda->crashdump_action = HV_CRASHDUMP_SUSPEND_ALL_VPS; 260 hv_do_hypercall(HVCALL_NOTIFY_PARTITION_EVENT, input, NULL); 261} 262 263/* 264 * Common function for all cpus before devirtualization. 265 * 266 * Hypervisor crash: all cpus get here in NMI context. 267 * Linux crash: the panicing cpu gets here at base level, all others in NMI 268 * context. Note, panicing cpu may not be the BSP. 269 * 270 * The function is not inlined so it will show on the stack. It is named so 271 * because the crash cmd looks for certain well known function names on the 272 * stack before looking into the cpu saved note in the elf section, and 273 * that work is currently incomplete. 274 * 275 * Notes: 276 * Hypervisor crash: 277 * - the hypervisor is in a very restrictive mode at this point and any 278 * vmexit it cannot handle would result in reboot. So, no mumbo jumbo, 279 * just get to kexec as quickly as possible. 280 * 281 * Devirtualization is supported from the BSP only at present. 282 */ 283static noinline __noclone void crash_nmi_callback(struct pt_regs *regs) 284{ 285 struct hv_input_disable_hyp_ex *input; 286 u64 status; 287 int msecs = 1000, ccpu = smp_processor_id(); 288 289 if (ccpu == 0) { 290 /* crash_save_cpu() will be done in the kexec path */ 291 cpu_emergency_stop_pt(); /* disable performance trace */ 292 atomic_inc(&crash_cpus_wait); 293 } else { 294 crash_save_cpu(regs, ccpu); 295 cpu_emergency_stop_pt(); /* disable performance trace */ 296 atomic_inc(&crash_cpus_wait); 297 for (;;) 298 cpu_relax(); 299 } 300 301 while (atomic_read(&crash_cpus_wait) < num_online_cpus() && msecs--) 302 mdelay(1); 303 304 stop_nmi(); 305 if (!hv_has_crashed) 306 hv_notify_prepare_hyp(); 307 308 if (crashing_cpu == -1) 309 crashing_cpu = ccpu; /* crash cmd uses this */ 310 311 hv_hvcrash_ctxt_save(); 312 hv_mark_tss_not_busy(); 313 hv_crash_fixup_kernpt(); 314 315 input = *this_cpu_ptr(hyperv_pcpu_input_arg); 316 memset(input, 0, sizeof(*input)); 317 input->rip = trampoline_pa; 318 input->arg = devirt_arg; 319 320 status = hv_do_hypercall(HVCALL_DISABLE_HYP_EX, input, NULL); 321 322 hv_panic_timeout_reboot(); 323} 324 325 326static DEFINE_SPINLOCK(hv_crash_reboot_lk); 327 328/* 329 * Generic NMI callback handler: could be called without any crash also. 330 * hv crash: hypervisor injects NMI's into all cpus 331 * lx crash: panicing cpu sends NMI to all but self via crash_stop_other_cpus 332 */ 333static int hv_crash_nmi_local(unsigned int cmd, struct pt_regs *regs) 334{ 335 if (!hv_has_crashed && hv_cda && hv_cda->cda_valid) 336 hv_has_crashed = true; 337 338 if (!hv_has_crashed && !lx_has_crashed) 339 return NMI_DONE; /* ignore the NMI */ 340 341 if (hv_has_crashed && !kexec_crash_loaded()) { 342 if (spin_trylock(&hv_crash_reboot_lk)) 343 hv_panic_timeout_reboot(); 344 else 345 for (;;) 346 cpu_relax(); 347 } 348 349 crash_nmi_callback(regs); 350 351 return NMI_DONE; 352} 353 354/* 355 * hv_crash_stop_other_cpus() == smp_ops.crash_stop_other_cpus 356 * 357 * On normal Linux panic, this is called twice: first from panic and then again 358 * from native_machine_crash_shutdown. 359 * 360 * In case of hyperv, 3 ways to get here: 361 * 1. hv crash (only BSP will get here): 362 * BSP : NMI callback -> DisableHv -> hv_crash_asm32 -> hv_crash_c_entry 363 * -> __crash_kexec -> native_machine_crash_shutdown 364 * -> crash_smp_send_stop -> smp_ops.crash_stop_other_cpus 365 * Linux panic: 366 * 2. panic cpu x: panic() -> crash_smp_send_stop 367 * -> smp_ops.crash_stop_other_cpus 368 * 3. BSP: native_machine_crash_shutdown -> crash_smp_send_stop 369 * 370 * NB: noclone and non standard stack because of call to crash_setup_regs(). 371 */ 372static void __noclone hv_crash_stop_other_cpus(void) 373{ 374 static bool crash_stop_done; 375 struct pt_regs lregs; 376 int ccpu = smp_processor_id(); 377 378 if (hv_has_crashed) 379 return; /* all cpus already in NMI handler path */ 380 381 if (!kexec_crash_loaded()) { 382 hv_notify_prepare_hyp(); 383 hv_panic_timeout_reboot(); /* no return */ 384 } 385 386 /* If the hv crashes also, we could come here again before cpus_stopped 387 * is set in crash_smp_send_stop(). So use our own check. 388 */ 389 if (crash_stop_done) 390 return; 391 crash_stop_done = true; 392 393 /* Linux has crashed: hv is healthy, we can IPI safely */ 394 lx_has_crashed = true; 395 wmb(); /* NMI handlers look at lx_has_crashed */ 396 397 apic->send_IPI_allbutself(NMI_VECTOR); 398 399 if (crashing_cpu == -1) 400 crashing_cpu = ccpu; /* crash cmd uses this */ 401 402 /* crash_setup_regs() happens in kexec also, but for the kexec cpu which 403 * is the BSP. We could be here on non-BSP cpu, collect regs if so. 404 */ 405 if (ccpu) 406 crash_setup_regs(&lregs, NULL); 407 408 crash_nmi_callback(&lregs); 409} 410STACK_FRAME_NON_STANDARD(hv_crash_stop_other_cpus); 411 412/* This GDT is accessed in IA32-e compat mode which uses 32bits addresses */ 413struct hv_gdtreg_32 { 414 u16 fill; 415 u16 limit; 416 u32 address; 417} __packed; 418 419/* We need a CS with L bit to goto IA32-e long mode from 32bit compat mode */ 420struct hv_crash_tramp_gdt { 421 u64 null; /* index 0, selector 0, null selector */ 422 u64 cs64; /* index 1, selector 8, cs64 selector */ 423} __packed; 424 425/* No stack, so jump via far ptr in memory to load the 64bit CS */ 426struct hv_cs_jmptgt { 427 u32 address; 428 u16 csval; 429 u16 fill; 430} __packed; 431 432/* Linux use only, hypervisor doesn't look at this struct */ 433struct hv_crash_tramp_data { 434 u64 tramp32_cr3; 435 u64 kernel_cr3; 436 struct hv_gdtreg_32 gdtr32; 437 struct hv_crash_tramp_gdt tramp_gdt; 438 struct hv_cs_jmptgt cs_jmptgt; 439 u64 c_entry_addr; 440} __packed; 441 442/* 443 * Setup a temporary gdt to allow the asm code to switch to the long mode. 444 * Since the asm code is relocated/copied to a below 4G page, it cannot use rip 445 * relative addressing, hence we must use trampoline_pa here. Also, save other 446 * info like jmp and C entry targets for same reasons. 447 * 448 * Returns: 0 on success, -1 on error 449 */ 450static int hv_crash_setup_trampdata(u64 trampoline_va) 451{ 452 int size, offs; 453 void *dest; 454 struct hv_crash_tramp_data *tramp; 455 456 /* These must match exactly the ones in the corresponding asm file */ 457 BUILD_BUG_ON(offsetof(struct hv_crash_tramp_data, tramp32_cr3) != 0); 458 BUILD_BUG_ON(offsetof(struct hv_crash_tramp_data, kernel_cr3) != 8); 459 BUILD_BUG_ON(offsetof(struct hv_crash_tramp_data, gdtr32.limit) != 18); 460 BUILD_BUG_ON(offsetof(struct hv_crash_tramp_data, 461 cs_jmptgt.address) != 40); 462 BUILD_BUG_ON(offsetof(struct hv_crash_tramp_data, c_entry_addr) != 48); 463 464 /* hv_crash_asm_end is beyond last byte by 1 */ 465 size = &hv_crash_asm_end - &hv_crash_asm32; 466 if (size + sizeof(struct hv_crash_tramp_data) > PAGE_SIZE) { 467 pr_err("%s: trampoline page overflow\n", __func__); 468 return -1; 469 } 470 471 dest = (void *)trampoline_va; 472 memcpy(dest, &hv_crash_asm32, size); 473 474 dest += size; 475 dest = (void *)round_up((ulong)dest, 16); 476 tramp = (struct hv_crash_tramp_data *)dest; 477 478 /* see MAX_ASID_AVAILABLE in tlb.c: "PCID 0 is reserved for use by 479 * non-PCID-aware users". Build cr3 with pcid 0 480 */ 481 tramp->tramp32_cr3 = __sme_pa(hv_crash_ptpgs[0]); 482 483 /* Note, when restoring X86_CR4_PCIDE, cr3[11:0] must be zero */ 484 tramp->kernel_cr3 = __sme_pa(init_mm.pgd); 485 486 tramp->gdtr32.limit = sizeof(struct hv_crash_tramp_gdt); 487 tramp->gdtr32.address = trampoline_pa + 488 (ulong)&tramp->tramp_gdt - trampoline_va; 489 490 /* base:0 limit:0xfffff type:b dpl:0 P:1 L:1 D:0 avl:0 G:1 */ 491 tramp->tramp_gdt.cs64 = 0x00af9a000000ffff; 492 493 tramp->cs_jmptgt.csval = 0x8; 494 offs = (ulong)&hv_crash_asm64 - (ulong)&hv_crash_asm32; 495 tramp->cs_jmptgt.address = trampoline_pa + offs; 496 497 tramp->c_entry_addr = (u64)&hv_crash_c_entry; 498 499 devirt_arg = trampoline_pa + (ulong)dest - trampoline_va; 500 501 return 0; 502} 503 504/* 505 * Build 32bit trampoline page table for transition from protected mode 506 * non-paging to long-mode paging. This transition needs pagetables below 4G. 507 */ 508static void hv_crash_build_tramp_pt(void) 509{ 510 p4d_t *p4d; 511 pud_t *pud; 512 pmd_t *pmd; 513 pte_t *pte; 514 u64 pa, addr = trampoline_pa; 515 516 p4d = hv_crash_ptpgs[0] + pgd_index(addr) * sizeof(p4d); 517 pa = virt_to_phys(hv_crash_ptpgs[1]); 518 set_p4d(p4d, __p4d(_PAGE_TABLE | pa)); 519 p4d->p4d &= ~(_PAGE_NX); /* enable execute */ 520 521 pud = hv_crash_ptpgs[1] + pud_index(addr) * sizeof(pud); 522 pa = virt_to_phys(hv_crash_ptpgs[2]); 523 set_pud(pud, __pud(_PAGE_TABLE | pa)); 524 525 pmd = hv_crash_ptpgs[2] + pmd_index(addr) * sizeof(pmd); 526 pa = virt_to_phys(hv_crash_ptpgs[3]); 527 set_pmd(pmd, __pmd(_PAGE_TABLE | pa)); 528 529 pte = hv_crash_ptpgs[3] + pte_index(addr) * sizeof(pte); 530 set_pte(pte, pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL_EXEC)); 531} 532 533/* 534 * Setup trampoline for devirtualization: 535 * - a page below 4G, ie 32bit addr containing asm glue code that hyp jmps to 536 * in protected mode. 537 * - 4 pages for a temporary page table that asm code uses to turn paging on 538 * - a temporary gdt to use in the compat mode. 539 * 540 * Returns: 0 on success 541 */ 542static int hv_crash_trampoline_setup(void) 543{ 544 int i, rc, order; 545 struct page *page; 546 u64 trampoline_va; 547 gfp_t flags32 = GFP_KERNEL | GFP_DMA32 | __GFP_ZERO; 548 549 /* page for 32bit trampoline assembly code + hv_crash_tramp_data */ 550 page = alloc_page(flags32); 551 if (page == NULL) { 552 pr_err("%s: failed to alloc asm stub page\n", __func__); 553 return -1; 554 } 555 556 trampoline_va = (u64)page_to_virt(page); 557 trampoline_pa = (u32)page_to_phys(page); 558 559 order = 2; /* alloc 2^2 pages */ 560 page = alloc_pages(flags32, order); 561 if (page == NULL) { 562 pr_err("%s: failed to alloc pt pages\n", __func__); 563 free_page(trampoline_va); 564 return -1; 565 } 566 567 for (i = 0; i < 4; i++, page++) 568 hv_crash_ptpgs[i] = page_to_virt(page); 569 570 hv_crash_build_tramp_pt(); 571 572 rc = hv_crash_setup_trampdata(trampoline_va); 573 if (rc) 574 goto errout; 575 576 return 0; 577 578errout: 579 free_page(trampoline_va); 580 free_pages((ulong)hv_crash_ptpgs[0], order); 581 582 return rc; 583} 584 585/* Setup for kdump kexec to collect hypervisor RAM when running as root */ 586void hv_root_crash_init(void) 587{ 588 int rc; 589 struct hv_input_get_system_property *input; 590 struct hv_output_get_system_property *output; 591 unsigned long flags; 592 u64 status; 593 union hv_pfn_range cda_info; 594 595 if (pgtable_l5_enabled()) { 596 pr_err("Hyper-V: crash dump not yet supported on 5level PTs\n"); 597 return; 598 } 599 600 rc = register_nmi_handler(NMI_LOCAL, hv_crash_nmi_local, NMI_FLAG_FIRST, 601 "hv_crash_nmi"); 602 if (rc) { 603 pr_err("Hyper-V: failed to register crash nmi handler\n"); 604 return; 605 } 606 607 local_irq_save(flags); 608 input = *this_cpu_ptr(hyperv_pcpu_input_arg); 609 output = *this_cpu_ptr(hyperv_pcpu_output_arg); 610 611 memset(input, 0, sizeof(*input)); 612 input->property_id = HV_SYSTEM_PROPERTY_CRASHDUMPAREA; 613 614 status = hv_do_hypercall(HVCALL_GET_SYSTEM_PROPERTY, input, output); 615 cda_info.as_uint64 = output->hv_cda_info.as_uint64; 616 local_irq_restore(flags); 617 618 if (!hv_result_success(status)) { 619 pr_err("Hyper-V: %s: property:%d %s\n", __func__, 620 input->property_id, hv_result_to_string(status)); 621 goto err_out; 622 } 623 624 if (cda_info.base_pfn == 0) { 625 pr_err("Hyper-V: hypervisor crash dump area pfn is 0\n"); 626 goto err_out; 627 } 628 629 hv_cda = phys_to_virt(cda_info.base_pfn << HV_HYP_PAGE_SHIFT); 630 631 rc = hv_crash_trampoline_setup(); 632 if (rc) 633 goto err_out; 634 635#ifdef CONFIG_SMP 636 smp_ops.crash_stop_other_cpus = hv_crash_stop_other_cpus; 637#endif 638 639 crash_kexec_post_notifiers = true; 640 hv_crash_enabled = true; 641 pr_info("Hyper-V: both linux and hypervisor kdump support enabled\n"); 642 643 return; 644 645err_out: 646 unregister_nmi_handler(NMI_LOCAL, "hv_crash_nmi"); 647 pr_err("Hyper-V: only linux root kdump support enabled\n"); 648}
~/
Read-only file preview.