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