xref: /openbmc/linux/arch/ia64/kernel/machine_kexec.c (revision 8be98d2f2a0a262f8bf8a0bc1fdf522b3c7aab17)
140b0b3f8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2a7956113SZou Nan hai /*
3a7956113SZou Nan hai  * arch/ia64/kernel/machine_kexec.c
4a7956113SZou Nan hai  *
5a7956113SZou Nan hai  * Handle transition of Linux booting another kernel
6a7956113SZou Nan hai  * Copyright (C) 2005 Hewlett-Packard Development Comapny, L.P.
7a7956113SZou Nan hai  * Copyright (C) 2005 Khalid Aziz <khalid.aziz@hp.com>
8a7956113SZou Nan hai  * Copyright (C) 2006 Intel Corp, Zou Nan hai <nanhai.zou@intel.com>
9a7956113SZou Nan hai  */
10a7956113SZou Nan hai 
11a7956113SZou Nan hai #include <linux/mm.h>
12a7956113SZou Nan hai #include <linux/kexec.h>
13a7956113SZou Nan hai #include <linux/cpu.h>
14a7956113SZou Nan hai #include <linux/irq.h>
15abac08dbSHorms #include <linux/efi.h>
16fd59d231SKen'ichi Ohmichi #include <linux/numa.h>
17fd59d231SKen'ichi Ohmichi #include <linux/mmzone.h>
187259888eSAndrew Morton 
198ff059b8SArd Biesheuvel #include <asm/efi.h>
207259888eSAndrew Morton #include <asm/numa.h>
21a7956113SZou Nan hai #include <asm/mmu_context.h>
22a7956113SZou Nan hai #include <asm/setup.h>
23a7956113SZou Nan hai #include <asm/delay.h>
24a7956113SZou Nan hai #include <asm/meminit.h>
2500cab92fSKen'ichi Ohmichi #include <asm/processor.h>
2607a6a4aeSHidetoshi Seto #include <asm/sal.h>
2707a6a4aeSHidetoshi Seto #include <asm/mca.h>
28a7956113SZou Nan hai 
299402c95fSJoe Perches typedef void (*relocate_new_kernel_t)(
3053da5763SHorms 					unsigned long indirection_page,
3153da5763SHorms 					unsigned long start_address,
3253da5763SHorms 					struct ia64_boot_param *boot_param,
33ff2d8b19SJoe Perches 					unsigned long pal_addr) __noreturn;
34a7956113SZou Nan hai 
35a7956113SZou Nan hai struct kimage *ia64_kimage;
36a7956113SZou Nan hai 
37a7956113SZou Nan hai struct resource efi_memmap_res = {
38a7956113SZou Nan hai         .name  = "EFI Memory Map",
39a7956113SZou Nan hai         .start = 0,
40a7956113SZou Nan hai         .end   = 0,
41a7956113SZou Nan hai         .flags = IORESOURCE_BUSY | IORESOURCE_MEM
42a7956113SZou Nan hai };
43a7956113SZou Nan hai 
44a7956113SZou Nan hai struct resource boot_param_res = {
45a7956113SZou Nan hai         .name  = "Boot parameter",
46a7956113SZou Nan hai         .start = 0,
47a7956113SZou Nan hai         .end   = 0,
48a7956113SZou Nan hai         .flags = IORESOURCE_BUSY | IORESOURCE_MEM
49a7956113SZou Nan hai };
50a7956113SZou Nan hai 
51a7956113SZou Nan hai 
52a7956113SZou Nan hai /*
53a7956113SZou Nan hai  * Do what every setup is needed on image and the
54a7956113SZou Nan hai  * reboot code buffer to allow us to avoid allocations
55a7956113SZou Nan hai  * later.
56a7956113SZou Nan hai  */
machine_kexec_prepare(struct kimage * image)57a7956113SZou Nan hai int machine_kexec_prepare(struct kimage *image)
58a7956113SZou Nan hai {
59a7956113SZou Nan hai 	void *control_code_buffer;
60a7956113SZou Nan hai 	const unsigned long *func;
61a7956113SZou Nan hai 
62a7956113SZou Nan hai 	func = (unsigned long *)&relocate_new_kernel;
63a7956113SZou Nan hai 	/* Pre-load control code buffer to minimize work in kexec path */
64a7956113SZou Nan hai 	control_code_buffer = page_address(image->control_code_page);
65a7956113SZou Nan hai 	memcpy((void *)control_code_buffer, (const void *)func[0],
66a7956113SZou Nan hai 			relocate_new_kernel_size);
67a7956113SZou Nan hai 	flush_icache_range((unsigned long)control_code_buffer,
68a7956113SZou Nan hai 			(unsigned long)control_code_buffer + relocate_new_kernel_size);
69a7956113SZou Nan hai 	ia64_kimage = image;
70a7956113SZou Nan hai 
71a7956113SZou Nan hai 	return 0;
72a7956113SZou Nan hai }
73a7956113SZou Nan hai 
machine_kexec_cleanup(struct kimage * image)74a7956113SZou Nan hai void machine_kexec_cleanup(struct kimage *image)
75a7956113SZou Nan hai {
76a7956113SZou Nan hai }
77a7956113SZou Nan hai 
78a7956113SZou Nan hai /*
79a7956113SZou Nan hai  * Do not allocate memory (or fail in any way) in machine_kexec().
80a7956113SZou Nan hai  * We are past the point of no return, committed to rebooting now.
81a7956113SZou Nan hai  */
ia64_machine_kexec(struct unw_frame_info * info,void * arg)82a7956113SZou Nan hai static void ia64_machine_kexec(struct unw_frame_info *info, void *arg)
83a7956113SZou Nan hai {
84a7956113SZou Nan hai 	struct kimage *image = arg;
85a7956113SZou Nan hai 	relocate_new_kernel_t rnk;
86a7956113SZou Nan hai 	void *pal_addr = efi_get_pal_addr();
8736a45e74SWei Yongjun 	unsigned long code_addr;
88a7956113SZou Nan hai 	int ii;
8907a6a4aeSHidetoshi Seto 	u64 fp, gp;
9007a6a4aeSHidetoshi Seto 	ia64_fptr_t *init_handler = (ia64_fptr_t *)ia64_os_init_on_kdump;
91a7956113SZou Nan hai 
92c2c77fe8SBernhard Walle 	BUG_ON(!image);
9336a45e74SWei Yongjun 	code_addr = (unsigned long)page_address(image->control_code_page);
94a7956113SZou Nan hai 	if (image->type == KEXEC_TYPE_CRASH) {
95a7956113SZou Nan hai 		crash_save_this_cpu();
96a7956113SZou Nan hai 		current->thread.ksp = (__u64)info->sw - 16;
9707a6a4aeSHidetoshi Seto 
9807a6a4aeSHidetoshi Seto 		/* Register noop init handler */
9907a6a4aeSHidetoshi Seto 		fp = ia64_tpa(init_handler->fp);
10007a6a4aeSHidetoshi Seto 		gp = ia64_tpa(ia64_getreg(_IA64_REG_GP));
10107a6a4aeSHidetoshi Seto 		ia64_sal_set_vectors(SAL_VECTOR_OS_INIT, fp, gp, 0, fp, gp, 0);
10207a6a4aeSHidetoshi Seto 	} else {
10307a6a4aeSHidetoshi Seto 		/* Unregister init handlers of current kernel */
10407a6a4aeSHidetoshi Seto 		ia64_sal_set_vectors(SAL_VECTOR_OS_INIT, 0, 0, 0, 0, 0, 0);
105a7956113SZou Nan hai 	}
106a7956113SZou Nan hai 
1076cc3efcdSHidetoshi Seto 	/* Unregister mca handler - No more recovery on current kernel */
1086cc3efcdSHidetoshi Seto 	ia64_sal_set_vectors(SAL_VECTOR_OS_MCA, 0, 0, 0, 0, 0, 0);
1096cc3efcdSHidetoshi Seto 
110a7956113SZou Nan hai 	/* Interrupts aren't acceptable while we reboot */
111a7956113SZou Nan hai 	local_irq_disable();
112a7956113SZou Nan hai 
113a7956113SZou Nan hai 	/* Mask CMC and Performance Monitor interrupts */
114a7956113SZou Nan hai 	ia64_setreg(_IA64_REG_CR_PMV, 1 << 16);
115a7956113SZou Nan hai 	ia64_setreg(_IA64_REG_CR_CMCV, 1 << 16);
116a7956113SZou Nan hai 
117a7956113SZou Nan hai 	/* Mask ITV and Local Redirect Registers */
118a7956113SZou Nan hai 	ia64_set_itv(1 << 16);
119a7956113SZou Nan hai 	ia64_set_lrr0(1 << 16);
120a7956113SZou Nan hai 	ia64_set_lrr1(1 << 16);
121a7956113SZou Nan hai 
122a7956113SZou Nan hai 	/* terminate possible nested in-service interrupts */
123a7956113SZou Nan hai 	for (ii = 0; ii < 16; ii++)
124a7956113SZou Nan hai 		ia64_eoi();
125a7956113SZou Nan hai 
126a7956113SZou Nan hai 	/* unmask TPR and clear any pending interrupts */
127a7956113SZou Nan hai 	ia64_setreg(_IA64_REG_CR_TPR, 0);
128a7956113SZou Nan hai 	ia64_srlz_d();
129a62c9fe4SSimon Horman 	while (ia64_get_ivr() != IA64_SPURIOUS_INT_VECTOR)
130a7956113SZou Nan hai 		ia64_eoi();
131a7956113SZou Nan hai 	rnk = (relocate_new_kernel_t)&code_addr;
132a7956113SZou Nan hai 	(*rnk)(image->head, image->start, ia64_boot_param,
133a7956113SZou Nan hai 		     GRANULEROUNDDOWN((unsigned long) pal_addr));
134a7956113SZou Nan hai 	BUG();
135a7956113SZou Nan hai }
136a7956113SZou Nan hai 
machine_kexec(struct kimage * image)137a7956113SZou Nan hai void machine_kexec(struct kimage *image)
138a7956113SZou Nan hai {
139c2c77fe8SBernhard Walle 	BUG_ON(!image);
140a7956113SZou Nan hai 	unw_init_running(ia64_machine_kexec, image);
141a7956113SZou Nan hai 	for(;;);
142a7956113SZou Nan hai }
143fd59d231SKen'ichi Ohmichi 
arch_crash_save_vmcoreinfo(void)144fd59d231SKen'ichi Ohmichi void arch_crash_save_vmcoreinfo(void)
145fd59d231SKen'ichi Ohmichi {
146*9187592bSSergei Trofimovich #if defined(CONFIG_SPARSEMEM)
147bcbba6c1SKen'ichi Ohmichi 	VMCOREINFO_SYMBOL(pgdat_list);
148bcbba6c1SKen'ichi Ohmichi 	VMCOREINFO_LENGTH(pgdat_list, MAX_NUMNODES);
14992df5c3eSKen'ichi Ohmichi #endif
15092df5c3eSKen'ichi Ohmichi #ifdef CONFIG_NUMA
151bcbba6c1SKen'ichi Ohmichi 	VMCOREINFO_SYMBOL(node_memblk);
152bcbba6c1SKen'ichi Ohmichi 	VMCOREINFO_LENGTH(node_memblk, NR_NODE_MEMBLKS);
153c76f860cSKen'ichi Ohmichi 	VMCOREINFO_STRUCT_SIZE(node_memblk_s);
154bcbba6c1SKen'ichi Ohmichi 	VMCOREINFO_OFFSET(node_memblk_s, start_paddr);
155bcbba6c1SKen'ichi Ohmichi 	VMCOREINFO_OFFSET(node_memblk_s, size);
156fd59d231SKen'ichi Ohmichi #endif
1574d66bcc7SKirill A. Shutemov #if CONFIG_PGTABLE_LEVELS == 3
158bcbba6c1SKen'ichi Ohmichi 	VMCOREINFO_CONFIG(PGTABLE_3);
1594d66bcc7SKirill A. Shutemov #elif CONFIG_PGTABLE_LEVELS == 4
160bcbba6c1SKen'ichi Ohmichi 	VMCOREINFO_CONFIG(PGTABLE_4);
161fd59d231SKen'ichi Ohmichi #endif
162fd59d231SKen'ichi Ohmichi }
163fd59d231SKen'ichi Ohmichi 
164