aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
authorMohan Kumar M <mohan@in.ibm.com>2008-10-21 13:38:10 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2008-10-22 00:01:22 -0400
commit54622f10a6aabb8bb2bdacf3dd070046f03dc246 (patch)
tree73eb5ad4eeb7174b8c0ae1904bbe80602c5e295d /arch/powerpc/kernel
parent4792adbac9eb41cea77a45ab76258ea10d411173 (diff)
powerpc: Support for relocatable kdump kernel
This adds relocatable kernel support for kdump. With this one can use the same regular kernel to capture the kdump. A signature (0xfeed1234) is passed in r6 from panic code to the next kernel through kexec_sequence and purgatory code. The signature is used to differentiate between kdump kernel and non-kdump kernels. The purgatory code compares the signature and sets the __kdump_flag in head_64.S. During the boot up, kernel code checks __kdump_flag and if it is set, the kernel will behave as relocatable kdump kernel. This kernel will boot at the address where it was loaded by kexec-tools ie. at the address reserved through crashkernel boot parameter. CONFIG_CRASH_DUMP depends on CONFIG_RELOCATABLE option to build kdump kernel as relocatable. So the same kernel can be used as production and kdump kernel. This patch incorporates the changes suggested by Paul Mackerras to avoid GOT use and to avoid two copies of the code. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Mohan Kumar M <mohan@in.ibm.com> Signed-off-by: Michael Ellerman <michael@ellerman.id.au> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/crash_dump.c2
-rw-r--r--arch/powerpc/kernel/head_64.S39
-rw-r--r--arch/powerpc/kernel/iommu.c69
-rw-r--r--arch/powerpc/kernel/machine_kexec.c2
-rw-r--r--arch/powerpc/kernel/machine_kexec_64.c13
-rw-r--r--arch/powerpc/kernel/misc_64.S9
6 files changed, 89 insertions, 45 deletions
diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c
index 97e056379728..19671aca6591 100644
--- a/arch/powerpc/kernel/crash_dump.c
+++ b/arch/powerpc/kernel/crash_dump.c
@@ -30,6 +30,7 @@
30/* Stores the physical address of elf header of crash image. */ 30/* Stores the physical address of elf header of crash image. */
31unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX; 31unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX;
32 32
33#ifndef CONFIG_RELOCATABLE
33void __init reserve_kdump_trampoline(void) 34void __init reserve_kdump_trampoline(void)
34{ 35{
35 lmb_reserve(0, KDUMP_RESERVE_LIMIT); 36 lmb_reserve(0, KDUMP_RESERVE_LIMIT);
@@ -68,6 +69,7 @@ void __init setup_kdump_trampoline(void)
68 69
69 DBG(" <- setup_kdump_trampoline()\n"); 70 DBG(" <- setup_kdump_trampoline()\n");
70} 71}
72#endif /* CONFIG_RELOCATABLE */
71 73
72/* 74/*
73 * Note: elfcorehdr_addr is not just limited to vmcore. It is also used by 75 * Note: elfcorehdr_addr is not just limited to vmcore. It is also used by
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 84856bee33a5..69489bd3210c 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -97,6 +97,12 @@ __secondary_hold_spinloop:
97__secondary_hold_acknowledge: 97__secondary_hold_acknowledge:
98 .llong 0x0 98 .llong 0x0
99 99
100 /* This flag is set by purgatory if we should be a kdump kernel. */
101 /* Do not move this variable as purgatory knows about it. */
102 .globl __kdump_flag
103__kdump_flag:
104 .llong 0x0
105
100#ifdef CONFIG_PPC_ISERIES 106#ifdef CONFIG_PPC_ISERIES
101 /* 107 /*
102 * At offset 0x20, there is a pointer to iSeries LPAR data. 108 * At offset 0x20, there is a pointer to iSeries LPAR data.
@@ -1384,7 +1390,13 @@ _STATIC(__after_prom_start)
1384 /* process relocations for the final address of the kernel */ 1390 /* process relocations for the final address of the kernel */
1385 lis r25,PAGE_OFFSET@highest /* compute virtual base of kernel */ 1391 lis r25,PAGE_OFFSET@highest /* compute virtual base of kernel */
1386 sldi r25,r25,32 1392 sldi r25,r25,32
1387 mr r3,r25 1393#ifdef CONFIG_CRASH_DUMP
1394 ld r7,__kdump_flag-_stext(r26)
1395 cmpldi cr0,r7,1 /* kdump kernel ? - stay where we are */
1396 bne 1f
1397 add r25,r25,r26
1398#endif
13991: mr r3,r25
1388 bl .relocate 1400 bl .relocate
1389#endif 1401#endif
1390 1402
@@ -1398,11 +1410,26 @@ _STATIC(__after_prom_start)
1398 li r3,0 /* target addr */ 1410 li r3,0 /* target addr */
1399 mr. r4,r26 /* In some cases the loader may */ 1411 mr. r4,r26 /* In some cases the loader may */
1400 beq 9f /* have already put us at zero */ 1412 beq 9f /* have already put us at zero */
1401 lis r5,(copy_to_here - _stext)@ha
1402 addi r5,r5,(copy_to_here - _stext)@l /* # bytes of memory to copy */
1403 li r6,0x100 /* Start offset, the first 0x100 */ 1413 li r6,0x100 /* Start offset, the first 0x100 */
1404 /* bytes were copied earlier. */ 1414 /* bytes were copied earlier. */
1405 1415
1416#ifdef CONFIG_CRASH_DUMP
1417/*
1418 * Check if the kernel has to be running as relocatable kernel based on the
1419 * variable __kdump_flag, if it is set the kernel is treated as relocatable
1420 * kernel, otherwise it will be moved to PHYSICAL_START
1421 */
1422 ld r7,__kdump_flag-_stext(r26)
1423 cmpldi cr0,r7,1
1424 bne 3f
1425
1426 li r5,__end_interrupts - _stext /* just copy interrupts */
1427 b 5f
14283:
1429#endif
1430 lis r5,(copy_to_here - _stext)@ha
1431 addi r5,r5,(copy_to_here - _stext)@l /* # bytes of memory to copy */
1432
1406 bl .copy_and_flush /* copy the first n bytes */ 1433 bl .copy_and_flush /* copy the first n bytes */
1407 /* this includes the code being */ 1434 /* this includes the code being */
1408 /* executed here. */ 1435 /* executed here. */
@@ -1411,15 +1438,15 @@ _STATIC(__after_prom_start)
1411 mtctr r8 1438 mtctr r8
1412 bctr 1439 bctr
1413 1440
1441p_end: .llong _end - _stext
1442
14144: /* Now copy the rest of the kernel up to _end */ 14434: /* Now copy the rest of the kernel up to _end */
1415 addis r5,r26,(p_end - _stext)@ha 1444 addis r5,r26,(p_end - _stext)@ha
1416 ld r5,(p_end - _stext)@l(r5) /* get _end */ 1445 ld r5,(p_end - _stext)@l(r5) /* get _end */
1417 bl .copy_and_flush /* copy the rest */ 14465: bl .copy_and_flush /* copy the rest */
1418 1447
14199: b .start_here_multiplatform 14489: b .start_here_multiplatform
1420 1449
1421p_end: .llong _end - _stext
1422
1423/* 1450/*
1424 * Copy routine used to copy the kernel to start at physical address 0 1451 * Copy routine used to copy the kernel to start at physical address 0
1425 * and flush and invalidate the caches as needed. 1452 * and flush and invalidate the caches as needed.
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index ea1ba89f9c90..3857d7e2af0c 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -458,6 +458,42 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
458 spin_unlock_irqrestore(&(tbl->it_lock), flags); 458 spin_unlock_irqrestore(&(tbl->it_lock), flags);
459} 459}
460 460
461static void iommu_table_clear(struct iommu_table *tbl)
462{
463 if (!__kdump_flag) {
464 /* Clear the table in case firmware left allocations in it */
465 ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size);
466 return;
467 }
468
469#ifdef CONFIG_CRASH_DUMP
470 if (ppc_md.tce_get) {
471 unsigned long index, tceval, tcecount = 0;
472
473 /* Reserve the existing mappings left by the first kernel. */
474 for (index = 0; index < tbl->it_size; index++) {
475 tceval = ppc_md.tce_get(tbl, index + tbl->it_offset);
476 /*
477 * Freed TCE entry contains 0x7fffffffffffffff on JS20
478 */
479 if (tceval && (tceval != 0x7fffffffffffffffUL)) {
480 __set_bit(index, tbl->it_map);
481 tcecount++;
482 }
483 }
484
485 if ((tbl->it_size - tcecount) < KDUMP_MIN_TCE_ENTRIES) {
486 printk(KERN_WARNING "TCE table is full; freeing ");
487 printk(KERN_WARNING "%d entries for the kdump boot\n",
488 KDUMP_MIN_TCE_ENTRIES);
489 for (index = tbl->it_size - KDUMP_MIN_TCE_ENTRIES;
490 index < tbl->it_size; index++)
491 __clear_bit(index, tbl->it_map);
492 }
493 }
494#endif
495}
496
461/* 497/*
462 * Build a iommu_table structure. This contains a bit map which 498 * Build a iommu_table structure. This contains a bit map which
463 * is used to manage allocation of the tce space. 499 * is used to manage allocation of the tce space.
@@ -484,38 +520,7 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
484 tbl->it_largehint = tbl->it_halfpoint; 520 tbl->it_largehint = tbl->it_halfpoint;
485 spin_lock_init(&tbl->it_lock); 521 spin_lock_init(&tbl->it_lock);
486 522
487#ifdef CONFIG_CRASH_DUMP 523 iommu_table_clear(tbl);
488 if (ppc_md.tce_get) {
489 unsigned long index;
490 unsigned long tceval;
491 unsigned long tcecount = 0;
492
493 /*
494 * Reserve the existing mappings left by the first kernel.
495 */
496 for (index = 0; index < tbl->it_size; index++) {
497 tceval = ppc_md.tce_get(tbl, index + tbl->it_offset);
498 /*
499 * Freed TCE entry contains 0x7fffffffffffffff on JS20
500 */
501 if (tceval && (tceval != 0x7fffffffffffffffUL)) {
502 __set_bit(index, tbl->it_map);
503 tcecount++;
504 }
505 }
506 if ((tbl->it_size - tcecount) < KDUMP_MIN_TCE_ENTRIES) {
507 printk(KERN_WARNING "TCE table is full; ");
508 printk(KERN_WARNING "freeing %d entries for the kdump boot\n",
509 KDUMP_MIN_TCE_ENTRIES);
510 for (index = tbl->it_size - KDUMP_MIN_TCE_ENTRIES;
511 index < tbl->it_size; index++)
512 __clear_bit(index, tbl->it_map);
513 }
514 }
515#else
516 /* Clear the hardware table in case firmware left allocations in it */
517 ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size);
518#endif
519 524
520 if (!welcomed) { 525 if (!welcomed) {
521 printk(KERN_INFO "IOMMU table initialized, virtual merging %s\n", 526 printk(KERN_INFO "IOMMU table initialized, virtual merging %s\n",
diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c
index aab76887a842..ac2a21f45c75 100644
--- a/arch/powerpc/kernel/machine_kexec.c
+++ b/arch/powerpc/kernel/machine_kexec.c
@@ -88,11 +88,13 @@ void __init reserve_crashkernel(void)
88 88
89 crash_size = crashk_res.end - crashk_res.start + 1; 89 crash_size = crashk_res.end - crashk_res.start + 1;
90 90
91#ifndef CONFIG_RELOCATABLE
91 if (crashk_res.start != KDUMP_KERNELBASE) 92 if (crashk_res.start != KDUMP_KERNELBASE)
92 printk("Crash kernel location must be 0x%x\n", 93 printk("Crash kernel location must be 0x%x\n",
93 KDUMP_KERNELBASE); 94 KDUMP_KERNELBASE);
94 95
95 crashk_res.start = KDUMP_KERNELBASE; 96 crashk_res.start = KDUMP_KERNELBASE;
97#endif
96 crash_size = PAGE_ALIGN(crash_size); 98 crash_size = PAGE_ALIGN(crash_size);
97 crashk_res.end = crashk_res.start + crash_size - 1; 99 crashk_res.end = crashk_res.start + crash_size - 1;
98 100
diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c
index 4bd8b4f5e70d..e6efec788c4d 100644
--- a/arch/powerpc/kernel/machine_kexec_64.c
+++ b/arch/powerpc/kernel/machine_kexec_64.c
@@ -255,11 +255,14 @@ static union thread_union kexec_stack
255/* Our assembly helper, in kexec_stub.S */ 255/* Our assembly helper, in kexec_stub.S */
256extern NORET_TYPE void kexec_sequence(void *newstack, unsigned long start, 256extern NORET_TYPE void kexec_sequence(void *newstack, unsigned long start,
257 void *image, void *control, 257 void *image, void *control,
258 void (*clear_all)(void)) ATTRIB_NORET; 258 void (*clear_all)(void),
259 unsigned long kdump_flag) ATTRIB_NORET;
259 260
260/* too late to fail here */ 261/* too late to fail here */
261void default_machine_kexec(struct kimage *image) 262void default_machine_kexec(struct kimage *image)
262{ 263{
264 unsigned long kdump_flag = 0;
265
263 /* prepare control code if any */ 266 /* prepare control code if any */
264 267
265 /* 268 /*
@@ -270,8 +273,10 @@ void default_machine_kexec(struct kimage *image)
270 * using debugger IPI. 273 * using debugger IPI.
271 */ 274 */
272 275
273 if (crashing_cpu == -1) 276 if (crashing_cpu == -1)
274 kexec_prepare_cpus(); 277 kexec_prepare_cpus();
278 else
279 kdump_flag = KDUMP_SIGNATURE;
275 280
276 /* switch to a staticly allocated stack. Based on irq stack code. 281 /* switch to a staticly allocated stack. Based on irq stack code.
277 * XXX: the task struct will likely be invalid once we do the copy! 282 * XXX: the task struct will likely be invalid once we do the copy!
@@ -284,7 +289,7 @@ void default_machine_kexec(struct kimage *image)
284 */ 289 */
285 kexec_sequence(&kexec_stack, image->start, image, 290 kexec_sequence(&kexec_stack, image->start, image,
286 page_address(image->control_code_page), 291 page_address(image->control_code_page),
287 ppc_md.hpte_clear_all); 292 ppc_md.hpte_clear_all, kdump_flag);
288 /* NOTREACHED */ 293 /* NOTREACHED */
289} 294}
290 295
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index 3053fe5c62f2..a243fd072a77 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -611,10 +611,12 @@ real_mode: /* assume normal blr return */
611 611
612 612
613/* 613/*
614 * kexec_sequence(newstack, start, image, control, clear_all()) 614 * kexec_sequence(newstack, start, image, control, clear_all(), kdump_flag)
615 * 615 *
616 * does the grungy work with stack switching and real mode switches 616 * does the grungy work with stack switching and real mode switches
617 * also does simple calls to other code 617 * also does simple calls to other code
618 *
619 * kdump_flag says whether the next kernel should be a kdump kernel.
618 */ 620 */
619 621
620_GLOBAL(kexec_sequence) 622_GLOBAL(kexec_sequence)
@@ -647,7 +649,7 @@ _GLOBAL(kexec_sequence)
647 mr r29,r5 /* image (virt) */ 649 mr r29,r5 /* image (virt) */
648 mr r28,r6 /* control, unused */ 650 mr r28,r6 /* control, unused */
649 mr r27,r7 /* clear_all() fn desc */ 651 mr r27,r7 /* clear_all() fn desc */
650 mr r26,r8 /* spare */ 652 mr r26,r8 /* kdump flag */
651 lhz r25,PACAHWCPUID(r13) /* get our phys cpu from paca */ 653 lhz r25,PACAHWCPUID(r13) /* get our phys cpu from paca */
652 654
653 /* disable interrupts, we are overwriting kernel data next */ 655 /* disable interrupts, we are overwriting kernel data next */
@@ -709,5 +711,6 @@ _GLOBAL(kexec_sequence)
709 mr r4,r30 # start, aka phys mem offset 711 mr r4,r30 # start, aka phys mem offset
710 mtlr 4 712 mtlr 4
711 li r5,0 713 li r5,0
712 blr /* image->start(physid, image->start, 0); */ 714 mr r6,r26 /* kdump_flag */
715 blr /* image->start(physid, image->start, 0, kdump_flag); */
713#endif /* CONFIG_KEXEC */ 716#endif /* CONFIG_KEXEC */