File Index
Files and directories
Sign in
FILE

hv_crash.c

File preview with syntax highlighting.

linux-6.19.14/arch/x86/hyperv/hv_crash.c 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.