Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
cf13f0ea | 2 | /* |
a53c8fab | 3 | * Copyright IBM Corp. 2005, 2011 |
cf13f0ea | 4 | * |
c6b5b847 HC |
5 | * Author(s): Rolf Adelsberger, |
6 | * Heiko Carstens <heiko.carstens@de.ibm.com> | |
60a0c68d | 7 | * Michael Holzheu <holzheu@linux.vnet.ibm.com> |
cf13f0ea HC |
8 | */ |
9 | ||
cf13f0ea HC |
10 | #include <linux/device.h> |
11 | #include <linux/mm.h> | |
12 | #include <linux/kexec.h> | |
13 | #include <linux/delay.h> | |
2b67fc46 | 14 | #include <linux/reboot.h> |
6966727d | 15 | #include <linux/ftrace.h> |
3ab121ab | 16 | #include <linux/debug_locks.h> |
b66ac63e | 17 | #include <linux/suspend.h> |
a386fba2 HC |
18 | #include <asm/cio.h> |
19 | #include <asm/setup.h> | |
cf13f0ea HC |
20 | #include <asm/pgtable.h> |
21 | #include <asm/pgalloc.h> | |
a386fba2 | 22 | #include <asm/smp.h> |
9c9c1761 | 23 | #include <asm/ipl.h> |
60a0c68d | 24 | #include <asm/diag.h> |
6b563d8c | 25 | #include <asm/elf.h> |
60a0c68d | 26 | #include <asm/asm-offsets.h> |
4e042af4 | 27 | #include <asm/cacheflush.h> |
a9fbf1a5 | 28 | #include <asm/os_info.h> |
e6c7c630 | 29 | #include <asm/set_memory.h> |
78c98f90 | 30 | #include <asm/stacktrace.h> |
a62bc073 | 31 | #include <asm/switch_to.h> |
916cda1a | 32 | #include <asm/nmi.h> |
cf13f0ea | 33 | |
c6b5b847 | 34 | typedef void (*relocate_kernel_t)(kimage_entry_t *, unsigned long); |
cf13f0ea | 35 | |
2efe55a9 TK |
36 | extern const unsigned char relocate_kernel[]; |
37 | extern const unsigned long long relocate_kernel_len; | |
cf13f0ea | 38 | |
60a0c68d MH |
39 | #ifdef CONFIG_CRASH_DUMP |
40 | ||
b66ac63e MH |
41 | /* |
42 | * PM notifier callback for kdump | |
43 | */ | |
44 | static int machine_kdump_pm_cb(struct notifier_block *nb, unsigned long action, | |
45 | void *ptr) | |
46 | { | |
47 | switch (action) { | |
48 | case PM_SUSPEND_PREPARE: | |
49 | case PM_HIBERNATION_PREPARE: | |
7a0058ec XP |
50 | if (kexec_crash_image) |
51 | arch_kexec_unprotect_crashkres(); | |
b66ac63e MH |
52 | break; |
53 | case PM_POST_SUSPEND: | |
54 | case PM_POST_HIBERNATION: | |
7a0058ec XP |
55 | if (kexec_crash_image) |
56 | arch_kexec_protect_crashkres(); | |
b66ac63e MH |
57 | break; |
58 | default: | |
59 | return NOTIFY_DONE; | |
60 | } | |
61 | return NOTIFY_OK; | |
62 | } | |
63 | ||
64 | static int __init machine_kdump_pm_init(void) | |
65 | { | |
66 | pm_notifier(machine_kdump_pm_cb, 0); | |
67 | return 0; | |
68 | } | |
69 | arch_initcall(machine_kdump_pm_init); | |
60a0c68d MH |
70 | |
71 | /* | |
1a36a39e MS |
72 | * Reset the system, copy boot CPU registers to absolute zero, |
73 | * and jump to the kdump image | |
60a0c68d MH |
74 | */ |
75 | static void __do_machine_kdump(void *image) | |
76 | { | |
1a36a39e MS |
77 | int (*start_kdump)(int); |
78 | unsigned long prefix; | |
79 | ||
80 | /* store_status() saved the prefix register to lowcore */ | |
81 | prefix = (unsigned long) S390_lowcore.prefixreg_save_area; | |
82 | ||
83 | /* Now do the reset */ | |
84 | s390_reset_system(); | |
85 | ||
86 | /* | |
87 | * Copy dump CPU store status info to absolute zero. | |
88 | * This need to be done *after* s390_reset_system set the | |
89 | * prefix register of this CPU to zero | |
90 | */ | |
91 | memcpy((void *) __LC_FPREGS_SAVE_AREA, | |
92 | (void *)(prefix + __LC_FPREGS_SAVE_AREA), 512); | |
60a0c68d | 93 | |
fa7c0043 | 94 | __load_psw_mask(PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA); |
1a36a39e | 95 | start_kdump = (void *)((struct kimage *) image)->start; |
60a0c68d | 96 | start_kdump(1); |
1a36a39e MS |
97 | |
98 | /* Die if start_kdump returns */ | |
99 | disabled_wait((unsigned long) __builtin_return_address(0)); | |
100 | } | |
101 | ||
102 | /* | |
103 | * Start kdump: create a LGR log entry, store status of all CPUs and | |
104 | * branch to __do_machine_kdump. | |
105 | */ | |
106 | static noinline void __machine_kdump(void *image) | |
107 | { | |
916cda1a | 108 | struct mcesa *mcesa; |
ad3bc0ac | 109 | union ctlreg2 cr2_old, cr2_new; |
1a36a39e MS |
110 | int this_cpu, cpu; |
111 | ||
112 | lgr_info_log(); | |
113 | /* Get status of the other CPUs */ | |
114 | this_cpu = smp_find_processor_id(stap()); | |
115 | for_each_online_cpu(cpu) { | |
116 | if (cpu == this_cpu) | |
117 | continue; | |
118 | if (smp_store_status(cpu)) | |
119 | continue; | |
120 | } | |
121 | /* Store status of the boot CPU */ | |
916cda1a | 122 | mcesa = (struct mcesa *)(S390_lowcore.mcesad & MCESA_ORIGIN_MASK); |
1a36a39e | 123 | if (MACHINE_HAS_VX) |
916cda1a MS |
124 | save_vx_regs((__vector128 *) mcesa->vector_save_area); |
125 | if (MACHINE_HAS_GS) { | |
ad3bc0ac MS |
126 | __ctl_store(cr2_old.val, 2, 2); |
127 | cr2_new = cr2_old; | |
128 | cr2_new.gse = 1; | |
129 | __ctl_load(cr2_new.val, 2, 2); | |
916cda1a | 130 | save_gs_cb((struct gs_cb *) mcesa->guarded_storage_save_area); |
ad3bc0ac | 131 | __ctl_load(cr2_old.val, 2, 2); |
916cda1a | 132 | } |
1a36a39e MS |
133 | /* |
134 | * To create a good backchain for this CPU in the dump store_status | |
135 | * is passed the address of a function. The address is saved into | |
136 | * the PSW save area of the boot CPU and the function is invoked as | |
137 | * a tail call of store_status. The backchain in the dump will look | |
138 | * like this: | |
139 | * restart_int_handler -> __machine_kexec -> __do_machine_kdump | |
140 | * The call to store_status() will not return. | |
141 | */ | |
142 | store_status(__do_machine_kdump, image); | |
60a0c68d | 143 | } |
10ad34bc | 144 | #endif |
60a0c68d | 145 | |
ce3dc447 MS |
146 | static unsigned long do_start_kdump(unsigned long addr) |
147 | { | |
148 | struct kimage *image = (struct kimage *) addr; | |
149 | int (*start_kdump)(int) = (void *)image->start; | |
150 | int rc; | |
151 | ||
152 | __arch_local_irq_stnsm(0xfb); /* disable DAT */ | |
153 | rc = start_kdump(0); | |
154 | __arch_local_irq_stosm(0x04); /* enable DAT */ | |
155 | return rc; | |
156 | } | |
157 | ||
60a0c68d MH |
158 | /* |
159 | * Check if kdump checksums are valid: We call purgatory with parameter "0" | |
160 | */ | |
7c3eaaa3 | 161 | static bool kdump_csum_valid(struct kimage *image) |
60a0c68d MH |
162 | { |
163 | #ifdef CONFIG_CRASH_DUMP | |
60a0c68d MH |
164 | int rc; |
165 | ||
ce3dc447 | 166 | rc = CALL_ON_STACK(do_start_kdump, S390_lowcore.nodat_stack, 1, image); |
7c3eaaa3 | 167 | return rc == 0; |
60a0c68d | 168 | #else |
7c3eaaa3 | 169 | return false; |
60a0c68d MH |
170 | #endif |
171 | } | |
172 | ||
7a0058ec XP |
173 | #ifdef CONFIG_CRASH_DUMP |
174 | ||
2d0af224 HC |
175 | void crash_free_reserved_phys_range(unsigned long begin, unsigned long end) |
176 | { | |
177 | unsigned long addr, size; | |
178 | ||
179 | for (addr = begin; addr < end; addr += PAGE_SIZE) | |
180 | free_reserved_page(pfn_to_page(addr >> PAGE_SHIFT)); | |
181 | size = begin - crashk_res.start; | |
182 | if (size) | |
183 | os_info_crashkernel_add(crashk_res.start, size); | |
184 | else | |
185 | os_info_crashkernel_add(0, 0); | |
186 | } | |
187 | ||
4e042af4 | 188 | static void crash_protect_pages(int protect) |
dab7a7b1 | 189 | { |
4e042af4 | 190 | unsigned long size; |
dab7a7b1 | 191 | |
4e042af4 HC |
192 | if (!crashk_res.end) |
193 | return; | |
194 | size = resource_size(&crashk_res); | |
195 | if (protect) | |
196 | set_memory_ro(crashk_res.start, size >> PAGE_SHIFT); | |
2d0af224 | 197 | else |
4e042af4 | 198 | set_memory_rw(crashk_res.start, size >> PAGE_SHIFT); |
dab7a7b1 MH |
199 | } |
200 | ||
7a0058ec | 201 | void arch_kexec_protect_crashkres(void) |
dab7a7b1 | 202 | { |
4e042af4 | 203 | crash_protect_pages(1); |
dab7a7b1 MH |
204 | } |
205 | ||
7a0058ec | 206 | void arch_kexec_unprotect_crashkres(void) |
dab7a7b1 | 207 | { |
4e042af4 | 208 | crash_protect_pages(0); |
dab7a7b1 MH |
209 | } |
210 | ||
7a0058ec XP |
211 | #endif |
212 | ||
60a0c68d MH |
213 | /* |
214 | * Give back memory to hypervisor before new kdump is loaded | |
215 | */ | |
216 | static int machine_kexec_prepare_kdump(void) | |
217 | { | |
218 | #ifdef CONFIG_CRASH_DUMP | |
219 | if (MACHINE_IS_VM) | |
220 | diag10_range(PFN_DOWN(crashk_res.start), | |
221 | PFN_DOWN(crashk_res.end - crashk_res.start + 1)); | |
222 | return 0; | |
223 | #else | |
224 | return -EINVAL; | |
225 | #endif | |
226 | } | |
227 | ||
c6b5b847 | 228 | int machine_kexec_prepare(struct kimage *image) |
cf13f0ea | 229 | { |
c6b5b847 | 230 | void *reboot_code_buffer; |
cf13f0ea | 231 | |
60a0c68d MH |
232 | if (image->type == KEXEC_TYPE_CRASH) |
233 | return machine_kexec_prepare_kdump(); | |
234 | ||
cf13f0ea HC |
235 | /* We don't support anything but the default image type for now. */ |
236 | if (image->type != KEXEC_TYPE_DEFAULT) | |
237 | return -EINVAL; | |
238 | ||
239 | /* Get the destination where the assembler code should be copied to.*/ | |
c6b5b847 | 240 | reboot_code_buffer = (void *) page_to_phys(image->control_code_page); |
cf13f0ea HC |
241 | |
242 | /* Then copy it */ | |
c6b5b847 | 243 | memcpy(reboot_code_buffer, relocate_kernel, relocate_kernel_len); |
cf13f0ea HC |
244 | return 0; |
245 | } | |
246 | ||
c6b5b847 | 247 | void machine_kexec_cleanup(struct kimage *image) |
cf13f0ea HC |
248 | { |
249 | } | |
250 | ||
60a0c68d MH |
251 | void arch_crash_save_vmcoreinfo(void) |
252 | { | |
253 | VMCOREINFO_SYMBOL(lowcore_ptr); | |
7fe7a18c | 254 | VMCOREINFO_SYMBOL(high_memory); |
60a0c68d | 255 | VMCOREINFO_LENGTH(lowcore_ptr, NR_CPUS); |
203e9e41 | 256 | mem_assign_absolute(S390_lowcore.vmcore_info, paddr_vmcoreinfo_note()); |
a80313ff GS |
257 | vmcoreinfo_append_str("SDMA=%lx\n", __sdma); |
258 | vmcoreinfo_append_str("EDMA=%lx\n", __edma); | |
b2d24b97 | 259 | vmcoreinfo_append_str("KERNELOFFSET=%lx\n", kaslr_offset()); |
60a0c68d MH |
260 | } |
261 | ||
c6b5b847 | 262 | void machine_shutdown(void) |
cf13f0ea | 263 | { |
cf13f0ea HC |
264 | } |
265 | ||
48a8ca03 HC |
266 | void machine_crash_shutdown(struct pt_regs *regs) |
267 | { | |
3b967847 | 268 | set_os_info_reipl_block(); |
48a8ca03 HC |
269 | } |
270 | ||
60a0c68d MH |
271 | /* |
272 | * Do normal kexec | |
273 | */ | |
274 | static void __do_machine_kexec(void *data) | |
cf13f0ea | 275 | { |
cf13f0ea | 276 | relocate_kernel_t data_mover; |
2c2df118 | 277 | struct kimage *image = data; |
cf13f0ea | 278 | |
1a36a39e | 279 | s390_reset_system(); |
c6b5b847 | 280 | data_mover = (relocate_kernel_t) page_to_phys(image->control_code_page); |
cf13f0ea | 281 | |
d0e810ee | 282 | __arch_local_irq_stnsm(0xfb); /* disable DAT - avoid no-execute */ |
cf13f0ea | 283 | /* Call the moving routine */ |
c6b5b847 | 284 | (*data_mover)(&image->head, image->start); |
1a36a39e MS |
285 | |
286 | /* Die if kexec returns */ | |
287 | disabled_wait((unsigned long) __builtin_return_address(0)); | |
cf13f0ea | 288 | } |
2c2df118 | 289 | |
60a0c68d MH |
290 | /* |
291 | * Reset system and call either kdump or normal kexec | |
292 | */ | |
293 | static void __machine_kexec(void *data) | |
294 | { | |
fa7c0043 | 295 | __arch_local_irq_stosm(0x04); /* enable DAT */ |
60a0c68d | 296 | pfault_fini(); |
3ab121ab MH |
297 | tracing_off(); |
298 | debug_locks_off(); | |
10ad34bc | 299 | #ifdef CONFIG_CRASH_DUMP |
1a36a39e MS |
300 | if (((struct kimage *) data)->type == KEXEC_TYPE_CRASH) |
301 | __machine_kdump(data); | |
10ad34bc | 302 | #endif |
1a36a39e | 303 | __do_machine_kexec(data); |
60a0c68d MH |
304 | } |
305 | ||
306 | /* | |
307 | * Do either kdump or normal kexec. In case of kdump we first ask | |
308 | * purgatory, if kdump checksums are valid. | |
309 | */ | |
2c2df118 HC |
310 | void machine_kexec(struct kimage *image) |
311 | { | |
60a0c68d MH |
312 | if (image->type == KEXEC_TYPE_CRASH && !kdump_csum_valid(image)) |
313 | return; | |
6966727d | 314 | tracer_disable(); |
2c2df118 | 315 | smp_send_stop(); |
8b646bd7 | 316 | smp_call_ipl_cpu(__machine_kexec, image); |
2c2df118 | 317 | } |