]>
Commit | Line | Data |
---|---|---|
cf13f0ea | 1 | /* |
a53c8fab | 2 | * Copyright IBM Corp. 2005, 2011 |
cf13f0ea | 3 | * |
c6b5b847 HC |
4 | * Author(s): Rolf Adelsberger, |
5 | * Heiko Carstens <heiko.carstens@de.ibm.com> | |
60a0c68d | 6 | * Michael Holzheu <holzheu@linux.vnet.ibm.com> |
cf13f0ea HC |
7 | */ |
8 | ||
cf13f0ea HC |
9 | #include <linux/device.h> |
10 | #include <linux/mm.h> | |
11 | #include <linux/kexec.h> | |
12 | #include <linux/delay.h> | |
2b67fc46 | 13 | #include <linux/reboot.h> |
6966727d | 14 | #include <linux/ftrace.h> |
3ab121ab | 15 | #include <linux/debug_locks.h> |
a386fba2 HC |
16 | #include <asm/cio.h> |
17 | #include <asm/setup.h> | |
cf13f0ea HC |
18 | #include <asm/pgtable.h> |
19 | #include <asm/pgalloc.h> | |
a386fba2 | 20 | #include <asm/smp.h> |
15e9b586 | 21 | #include <asm/reset.h> |
9c9c1761 | 22 | #include <asm/ipl.h> |
60a0c68d MH |
23 | #include <asm/diag.h> |
24 | #include <asm/asm-offsets.h> | |
a9fbf1a5 | 25 | #include <asm/os_info.h> |
cf13f0ea | 26 | |
c6b5b847 | 27 | typedef void (*relocate_kernel_t)(kimage_entry_t *, unsigned long); |
cf13f0ea | 28 | |
2efe55a9 TK |
29 | extern const unsigned char relocate_kernel[]; |
30 | extern const unsigned long long relocate_kernel_len; | |
cf13f0ea | 31 | |
60a0c68d MH |
32 | #ifdef CONFIG_CRASH_DUMP |
33 | ||
34 | void *fill_cpu_elf_notes(void *ptr, struct save_area *sa); | |
35 | ||
36 | /* | |
37 | * Create ELF notes for one CPU | |
38 | */ | |
39 | static void add_elf_notes(int cpu) | |
40 | { | |
41 | struct save_area *sa = (void *) 4608 + store_prefix(); | |
42 | void *ptr; | |
43 | ||
44 | memcpy((void *) (4608UL + sa->pref_reg), sa, sizeof(*sa)); | |
45 | ptr = (u64 *) per_cpu_ptr(crash_notes, cpu); | |
46 | ptr = fill_cpu_elf_notes(ptr, sa); | |
47 | memset(ptr, 0, sizeof(struct elf_note)); | |
48 | } | |
49 | ||
60a0c68d MH |
50 | /* |
51 | * Initialize CPU ELF notes | |
52 | */ | |
53 | void setup_regs(void) | |
54 | { | |
55 | unsigned long sa = S390_lowcore.prefixreg_save_area + SAVE_AREA_BASE; | |
8b646bd7 | 56 | int cpu, this_cpu; |
60a0c68d | 57 | |
8b646bd7 MS |
58 | this_cpu = smp_find_processor_id(stap()); |
59 | add_elf_notes(this_cpu); | |
60a0c68d | 60 | for_each_online_cpu(cpu) { |
8b646bd7 MS |
61 | if (cpu == this_cpu) |
62 | continue; | |
63 | if (smp_store_status(cpu)) | |
60a0c68d | 64 | continue; |
60a0c68d | 65 | add_elf_notes(cpu); |
60a0c68d MH |
66 | } |
67 | /* Copy dump CPU store status info to absolute zero */ | |
68 | memcpy((void *) SAVE_AREA_BASE, (void *) sa, sizeof(struct save_area)); | |
69 | } | |
70 | ||
71 | #endif | |
72 | ||
73 | /* | |
74 | * Start kdump: We expect here that a store status has been done on our CPU | |
75 | */ | |
76 | static void __do_machine_kdump(void *image) | |
77 | { | |
78 | #ifdef CONFIG_CRASH_DUMP | |
79 | int (*start_kdump)(int) = (void *)((struct kimage *) image)->start; | |
80 | ||
60a0c68d | 81 | setup_regs(); |
fa7c0043 | 82 | __load_psw_mask(PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA); |
60a0c68d MH |
83 | start_kdump(1); |
84 | #endif | |
85 | } | |
86 | ||
87 | /* | |
88 | * Check if kdump checksums are valid: We call purgatory with parameter "0" | |
89 | */ | |
90 | static int kdump_csum_valid(struct kimage *image) | |
91 | { | |
92 | #ifdef CONFIG_CRASH_DUMP | |
93 | int (*start_kdump)(int) = (void *)image->start; | |
94 | int rc; | |
95 | ||
96 | __arch_local_irq_stnsm(0xfb); /* disable DAT */ | |
97 | rc = start_kdump(0); | |
98 | __arch_local_irq_stosm(0x04); /* enable DAT */ | |
99 | return rc ? 0 : -EINVAL; | |
100 | #else | |
101 | return -EINVAL; | |
102 | #endif | |
103 | } | |
104 | ||
dab7a7b1 MH |
105 | /* |
106 | * Map or unmap crashkernel memory | |
107 | */ | |
108 | static void crash_map_pages(int enable) | |
109 | { | |
110 | unsigned long size = resource_size(&crashk_res); | |
111 | ||
112 | BUG_ON(crashk_res.start % KEXEC_CRASH_MEM_ALIGN || | |
113 | size % KEXEC_CRASH_MEM_ALIGN); | |
114 | if (enable) | |
115 | vmem_add_mapping(crashk_res.start, size); | |
a9fbf1a5 | 116 | else { |
dab7a7b1 | 117 | vmem_remove_mapping(crashk_res.start, size); |
a9fbf1a5 MH |
118 | if (size) |
119 | os_info_crashkernel_add(crashk_res.start, size); | |
120 | else | |
121 | os_info_crashkernel_add(0, 0); | |
122 | } | |
dab7a7b1 MH |
123 | } |
124 | ||
125 | /* | |
126 | * Map crashkernel memory | |
127 | */ | |
128 | void crash_map_reserved_pages(void) | |
129 | { | |
130 | crash_map_pages(1); | |
131 | } | |
132 | ||
133 | /* | |
134 | * Unmap crashkernel memory | |
135 | */ | |
136 | void crash_unmap_reserved_pages(void) | |
137 | { | |
138 | crash_map_pages(0); | |
139 | } | |
140 | ||
60a0c68d MH |
141 | /* |
142 | * Give back memory to hypervisor before new kdump is loaded | |
143 | */ | |
144 | static int machine_kexec_prepare_kdump(void) | |
145 | { | |
146 | #ifdef CONFIG_CRASH_DUMP | |
147 | if (MACHINE_IS_VM) | |
148 | diag10_range(PFN_DOWN(crashk_res.start), | |
149 | PFN_DOWN(crashk_res.end - crashk_res.start + 1)); | |
150 | return 0; | |
151 | #else | |
152 | return -EINVAL; | |
153 | #endif | |
154 | } | |
155 | ||
c6b5b847 | 156 | int machine_kexec_prepare(struct kimage *image) |
cf13f0ea | 157 | { |
c6b5b847 | 158 | void *reboot_code_buffer; |
cf13f0ea | 159 | |
9c9c1761 HC |
160 | /* Can't replace kernel image since it is read-only. */ |
161 | if (ipl_flags & IPL_NSS_VALID) | |
162 | return -ENOSYS; | |
163 | ||
60a0c68d MH |
164 | if (image->type == KEXEC_TYPE_CRASH) |
165 | return machine_kexec_prepare_kdump(); | |
166 | ||
cf13f0ea HC |
167 | /* We don't support anything but the default image type for now. */ |
168 | if (image->type != KEXEC_TYPE_DEFAULT) | |
169 | return -EINVAL; | |
170 | ||
171 | /* Get the destination where the assembler code should be copied to.*/ | |
c6b5b847 | 172 | reboot_code_buffer = (void *) page_to_phys(image->control_code_page); |
cf13f0ea HC |
173 | |
174 | /* Then copy it */ | |
c6b5b847 | 175 | memcpy(reboot_code_buffer, relocate_kernel, relocate_kernel_len); |
cf13f0ea HC |
176 | return 0; |
177 | } | |
178 | ||
c6b5b847 | 179 | void machine_kexec_cleanup(struct kimage *image) |
cf13f0ea HC |
180 | { |
181 | } | |
182 | ||
60a0c68d MH |
183 | void arch_crash_save_vmcoreinfo(void) |
184 | { | |
185 | VMCOREINFO_SYMBOL(lowcore_ptr); | |
7fe7a18c | 186 | VMCOREINFO_SYMBOL(high_memory); |
60a0c68d MH |
187 | VMCOREINFO_LENGTH(lowcore_ptr, NR_CPUS); |
188 | } | |
189 | ||
c6b5b847 | 190 | void machine_shutdown(void) |
cf13f0ea | 191 | { |
cf13f0ea HC |
192 | } |
193 | ||
48a8ca03 HC |
194 | void machine_crash_shutdown(struct pt_regs *regs) |
195 | { | |
196 | } | |
197 | ||
60a0c68d MH |
198 | /* |
199 | * Do normal kexec | |
200 | */ | |
201 | static void __do_machine_kexec(void *data) | |
cf13f0ea | 202 | { |
cf13f0ea | 203 | relocate_kernel_t data_mover; |
2c2df118 | 204 | struct kimage *image = data; |
cf13f0ea | 205 | |
c6b5b847 | 206 | data_mover = (relocate_kernel_t) page_to_phys(image->control_code_page); |
cf13f0ea HC |
207 | |
208 | /* Call the moving routine */ | |
c6b5b847 | 209 | (*data_mover)(&image->head, image->start); |
cf13f0ea | 210 | } |
2c2df118 | 211 | |
60a0c68d MH |
212 | /* |
213 | * Reset system and call either kdump or normal kexec | |
214 | */ | |
215 | static void __machine_kexec(void *data) | |
216 | { | |
217 | struct kimage *image = data; | |
218 | ||
fa7c0043 | 219 | __arch_local_irq_stosm(0x04); /* enable DAT */ |
60a0c68d | 220 | pfault_fini(); |
3ab121ab MH |
221 | tracing_off(); |
222 | debug_locks_off(); | |
223 | if (image->type == KEXEC_TYPE_CRASH) { | |
224 | lgr_info_log(); | |
60a0c68d | 225 | s390_reset_system(__do_machine_kdump, data); |
3ab121ab | 226 | } else { |
60a0c68d | 227 | s390_reset_system(__do_machine_kexec, data); |
3ab121ab | 228 | } |
60a0c68d MH |
229 | disabled_wait((unsigned long) __builtin_return_address(0)); |
230 | } | |
231 | ||
232 | /* | |
233 | * Do either kdump or normal kexec. In case of kdump we first ask | |
234 | * purgatory, if kdump checksums are valid. | |
235 | */ | |
2c2df118 HC |
236 | void machine_kexec(struct kimage *image) |
237 | { | |
60a0c68d MH |
238 | if (image->type == KEXEC_TYPE_CRASH && !kdump_csum_valid(image)) |
239 | return; | |
6966727d | 240 | tracer_disable(); |
2c2df118 | 241 | smp_send_stop(); |
8b646bd7 | 242 | smp_call_ipl_cpu(__machine_kexec, image); |
2c2df118 | 243 | } |