1
2
3
4
5
6
7
8
9
10
11#include <linux/kexec.h>
12#include <linux/smp.h>
13#include <linux/thread_info.h>
14#include <linux/init_task.h>
15#include <linux/errno.h>
16#include <linux/kernel.h>
17#include <linux/cpu.h>
18#include <linux/hardirq.h>
19
20#include <asm/page.h>
21#include <asm/current.h>
22#include <asm/machdep.h>
23#include <asm/cacheflush.h>
24#include <asm/firmware.h>
25#include <asm/paca.h>
26#include <asm/mmu.h>
27#include <asm/sections.h>
28#include <asm/prom.h>
29#include <asm/smp.h>
30#include <asm/hw_breakpoint.h>
31#include <asm/asm-prototypes.h>
32#include <asm/svm.h>
33#include <asm/ultravisor.h>
34
35int default_machine_kexec_prepare(struct kimage *image)
36{
37 int i;
38 unsigned long begin, end;
39 unsigned long low, high;
40 struct device_node *node;
41 const unsigned long *basep;
42 const unsigned int *sizep;
43
44
45
46
47
48
49 for (i = 0; i < image->nr_segments; i++)
50 if (image->segment[i].mem < __pa(_end))
51 return -ETXTBSY;
52
53
54 for_each_node_by_type(node, "pci") {
55 basep = of_get_property(node, "linux,tce-base", NULL);
56 sizep = of_get_property(node, "linux,tce-size", NULL);
57 if (basep == NULL || sizep == NULL)
58 continue;
59
60 low = *basep;
61 high = low + (*sizep);
62
63 for (i = 0; i < image->nr_segments; i++) {
64 begin = image->segment[i].mem;
65 end = begin + image->segment[i].memsz;
66
67 if ((begin < high) && (end > low)) {
68 of_node_put(node);
69 return -ETXTBSY;
70 }
71 }
72 }
73
74 return 0;
75}
76
77
78static notrace void copy_segments(unsigned long ind)
79{
80 unsigned long entry;
81 unsigned long *ptr;
82 void *dest;
83 void *addr;
84
85
86
87
88
89
90
91 ptr = NULL;
92 dest = NULL;
93
94 for (entry = ind; !(entry & IND_DONE); entry = *ptr++) {
95 addr = __va(entry & PAGE_MASK);
96
97 switch (entry & IND_FLAGS) {
98 case IND_DESTINATION:
99 dest = addr;
100 break;
101 case IND_INDIRECTION:
102 ptr = addr;
103 break;
104 case IND_SOURCE:
105 copy_page(dest, addr);
106 dest += PAGE_SIZE;
107 }
108 }
109}
110
111
112notrace void kexec_copy_flush(struct kimage *image)
113{
114 long i, nr_segments = image->nr_segments;
115 struct kexec_segment ranges[KEXEC_SEGMENT_MAX];
116
117
118 memcpy(ranges, image->segment, sizeof(ranges));
119
120
121
122
123
124
125
126 copy_segments(image->head);
127
128
129
130
131
132 for (i = 0; i < nr_segments; i++)
133 flush_icache_range((unsigned long)__va(ranges[i].mem),
134 (unsigned long)__va(ranges[i].mem + ranges[i].memsz));
135}
136
137#ifdef CONFIG_SMP
138
139static int kexec_all_irq_disabled = 0;
140
141static void kexec_smp_down(void *arg)
142{
143 local_irq_disable();
144 hard_irq_disable();
145
146 mb();
147 get_paca()->kexec_state = KEXEC_STATE_IRQS_OFF;
148 while(kexec_all_irq_disabled == 0)
149 cpu_relax();
150 mb();
151 hw_breakpoint_disable();
152
153
154
155
156 if (ppc_md.kexec_cpu_down)
157 ppc_md.kexec_cpu_down(0, 1);
158
159 reset_sprs();
160
161 kexec_smp_wait();
162
163}
164
165static void kexec_prepare_cpus_wait(int wait_state)
166{
167 int my_cpu, i, notified=-1;
168
169 hw_breakpoint_disable();
170 my_cpu = get_cpu();
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186 for_each_online_cpu(i) {
187 if (i == my_cpu)
188 continue;
189
190 while (paca_ptrs[i]->kexec_state < wait_state) {
191 barrier();
192 if (i != notified) {
193 printk(KERN_INFO "kexec: waiting for cpu %d "
194 "(physical %d) to enter %i state\n",
195 i, paca_ptrs[i]->hw_cpu_id, wait_state);
196 notified = i;
197 }
198 }
199 }
200 mb();
201}
202
203
204
205
206
207
208
209
210
211
212
213static void wake_offline_cpus(void)
214{
215 int cpu = 0;
216
217 for_each_present_cpu(cpu) {
218 if (!cpu_online(cpu)) {
219 printk(KERN_INFO "kexec: Waking offline cpu %d.\n",
220 cpu);
221 WARN_ON(add_cpu(cpu));
222 }
223 }
224}
225
226static void kexec_prepare_cpus(void)
227{
228 wake_offline_cpus();
229 smp_call_function(kexec_smp_down, NULL, 0);
230 local_irq_disable();
231 hard_irq_disable();
232
233 mb();
234 get_paca()->kexec_state = KEXEC_STATE_IRQS_OFF;
235
236 kexec_prepare_cpus_wait(KEXEC_STATE_IRQS_OFF);
237
238 kexec_all_irq_disabled = 1;
239
240
241
242
243
244 kexec_prepare_cpus_wait(KEXEC_STATE_REAL_MODE);
245
246
247 if (ppc_md.kexec_cpu_down)
248 ppc_md.kexec_cpu_down(0, 0);
249
250 put_cpu();
251}
252
253#else
254
255static void kexec_prepare_cpus(void)
256{
257
258
259
260
261
262
263
264
265
266 smp_release_cpus();
267 if (ppc_md.kexec_cpu_down)
268 ppc_md.kexec_cpu_down(0, 0);
269 local_irq_disable();
270 hard_irq_disable();
271}
272
273#endif
274
275
276
277
278
279
280
281
282
283
284
285
286
287static union thread_union kexec_stack __init_task_data =
288 { };
289
290
291
292
293
294struct paca_struct kexec_paca;
295
296
297extern void kexec_sequence(void *newstack, unsigned long start,
298 void *image, void *control,
299 void (*clear_all)(void),
300 bool copy_with_mmu_off) __noreturn;
301
302
303void default_machine_kexec(struct kimage *image)
304{
305 bool copy_with_mmu_off;
306
307
308
309
310
311
312
313
314
315
316
317 if (!kdump_in_progress())
318 kexec_prepare_cpus();
319
320 printk("kexec: Starting switchover sequence.\n");
321
322
323
324
325
326 current_thread_info()->flags = 0;
327 current_thread_info()->preempt_count = HARDIRQ_OFFSET;
328
329
330
331
332
333 memcpy(&kexec_paca, get_paca(), sizeof(struct paca_struct));
334 kexec_paca.data_offset = 0xedeaddeadeeeeeeeUL;
335#ifdef CONFIG_PPC_PSERIES
336 kexec_paca.lppaca_ptr = NULL;
337#endif
338
339 if (is_secure_guest() && !(image->preserve_context ||
340 image->type == KEXEC_TYPE_CRASH)) {
341 uv_unshare_all_pages();
342 printk("kexec: Unshared all shared pages.\n");
343 }
344
345 paca_ptrs[kexec_paca.paca_index] = &kexec_paca;
346
347 setup_paca(&kexec_paca);
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364#ifdef CONFIG_PPC_BOOK3E
365 copy_with_mmu_off = false;
366#else
367 copy_with_mmu_off = radix_enabled() ||
368 !(firmware_has_feature(FW_FEATURE_LPAR) ||
369 firmware_has_feature(FW_FEATURE_PS3_LV1));
370#endif
371
372
373
374
375 kexec_sequence(&kexec_stack, image->start, image,
376 page_address(image->control_code_page),
377 mmu_cleanup_all, copy_with_mmu_off);
378
379}
380
381#ifdef CONFIG_PPC_BOOK3S_64
382
383static unsigned long htab_base;
384static unsigned long htab_size;
385
386static struct property htab_base_prop = {
387 .name = "linux,htab-base",
388 .length = sizeof(unsigned long),
389 .value = &htab_base,
390};
391
392static struct property htab_size_prop = {
393 .name = "linux,htab-size",
394 .length = sizeof(unsigned long),
395 .value = &htab_size,
396};
397
398static int __init export_htab_values(void)
399{
400 struct device_node *node;
401
402
403 if (!htab_address)
404 return -ENODEV;
405
406 node = of_find_node_by_path("/chosen");
407 if (!node)
408 return -ENODEV;
409
410
411 of_remove_property(node, of_find_property(node, htab_base_prop.name, NULL));
412 of_remove_property(node, of_find_property(node, htab_size_prop.name, NULL));
413
414 htab_base = cpu_to_be64(__pa(htab_address));
415 of_add_property(node, &htab_base_prop);
416 htab_size = cpu_to_be64(htab_size_bytes);
417 of_add_property(node, &htab_size_prop);
418
419 of_node_put(node);
420 return 0;
421}
422late_initcall(export_htab_values);
423#endif
424