diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2012-10-11 12:14:58 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2012-12-13 10:46:47 -0500 |
commit | 7aa1c8f47e7e792d11f898cbdddaf6fa21ff08cc (patch) | |
tree | e34986c087ab7a9f91c8303eda7f13736e315905 /arch | |
parent | 98cdee0eae861e8d25c147a72c5f309e883f4ed8 (diff) |
MIPS: kdump: Add support
[ralf@linux-mips.org: Original patch by Maxim Uvarov <muvarov@gmail.com>
with plenty of further shining, polishing, debugging and testing by me.]
Signed-off-by: Maxim Uvarov <muvarov@gmail.com>
Cc: linux-mips@linux-mips.org
Cc: kexec@lists.infradead.org
Cc: horms@verge.net.au
Patchwork: https://patchwork.linux-mips.org/patch/1025/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/mips/Kconfig | 23 | ||||
-rw-r--r-- | arch/mips/include/asm/kexec.h | 27 | ||||
-rw-r--r-- | arch/mips/include/asm/smp.h | 6 | ||||
-rw-r--r-- | arch/mips/kernel/Makefile | 3 | ||||
-rw-r--r-- | arch/mips/kernel/crash.c | 71 | ||||
-rw-r--r-- | arch/mips/kernel/crash_dump.c | 77 | ||||
-rw-r--r-- | arch/mips/kernel/machine_kexec.c | 33 | ||||
-rw-r--r-- | arch/mips/kernel/relocate_kernel.S | 88 | ||||
-rw-r--r-- | arch/mips/kernel/setup.c | 56 | ||||
-rw-r--r-- | arch/mips/kernel/smp.c | 17 | ||||
-rw-r--r-- | arch/mips/kernel/traps.c | 4 |
11 files changed, 396 insertions, 9 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 462f9c4fe2e5..c97fc030fdac 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig | |||
@@ -2379,6 +2379,29 @@ config KEXEC | |||
2379 | support. As of this writing the exact hardware interface is | 2379 | support. As of this writing the exact hardware interface is |
2380 | strongly in flux, so no good recommendation can be made. | 2380 | strongly in flux, so no good recommendation can be made. |
2381 | 2381 | ||
2382 | config CRASH_DUMP | ||
2383 | bool "Kernel crash dumps" | ||
2384 | help | ||
2385 | Generate crash dump after being started by kexec. | ||
2386 | This should be normally only set in special crash dump kernels | ||
2387 | which are loaded in the main kernel with kexec-tools into | ||
2388 | a specially reserved region and then later executed after | ||
2389 | a crash by kdump/kexec. The crash dump kernel must be compiled | ||
2390 | to a memory address not used by the main kernel or firmware using | ||
2391 | PHYSICAL_START. | ||
2392 | |||
2393 | config PHYSICAL_START | ||
2394 | hex "Physical address where the kernel is loaded" | ||
2395 | default "0xffffffff84000000" if 64BIT | ||
2396 | default "0x84000000" if 32BIT | ||
2397 | depends on CRASH_DUMP | ||
2398 | help | ||
2399 | This gives the CKSEG0 or KSEG0 address where the kernel is loaded. | ||
2400 | If you plan to use kernel for capturing the crash dump change | ||
2401 | this value to start of the reserved region (the "X" value as | ||
2402 | specified in the "crashkernel=YM@XM" command line boot parameter | ||
2403 | passed to the panic-ed kernel). | ||
2404 | |||
2382 | config SECCOMP | 2405 | config SECCOMP |
2383 | bool "Enable seccomp to safely compute untrusted bytecode" | 2406 | bool "Enable seccomp to safely compute untrusted bytecode" |
2384 | depends on PROC_FS | 2407 | depends on PROC_FS |
diff --git a/arch/mips/include/asm/kexec.h b/arch/mips/include/asm/kexec.h index 4314892aaebb..ee25ebbf2a28 100644 --- a/arch/mips/include/asm/kexec.h +++ b/arch/mips/include/asm/kexec.h | |||
@@ -9,22 +9,43 @@ | |||
9 | #ifndef _MIPS_KEXEC | 9 | #ifndef _MIPS_KEXEC |
10 | # define _MIPS_KEXEC | 10 | # define _MIPS_KEXEC |
11 | 11 | ||
12 | #include <asm/stacktrace.h> | ||
13 | |||
12 | /* Maximum physical address we can use pages from */ | 14 | /* Maximum physical address we can use pages from */ |
13 | #define KEXEC_SOURCE_MEMORY_LIMIT (0x20000000) | 15 | #define KEXEC_SOURCE_MEMORY_LIMIT (0x20000000) |
14 | /* Maximum address we can reach in physical address mode */ | 16 | /* Maximum address we can reach in physical address mode */ |
15 | #define KEXEC_DESTINATION_MEMORY_LIMIT (0x20000000) | 17 | #define KEXEC_DESTINATION_MEMORY_LIMIT (0x20000000) |
16 | /* Maximum address we can use for the control code buffer */ | 18 | /* Maximum address we can use for the control code buffer */ |
17 | #define KEXEC_CONTROL_MEMORY_LIMIT (0x20000000) | 19 | #define KEXEC_CONTROL_MEMORY_LIMIT (0x20000000) |
18 | 20 | /* Reserve 3*4096 bytes for board-specific info */ | |
19 | #define KEXEC_CONTROL_PAGE_SIZE 4096 | 21 | #define KEXEC_CONTROL_PAGE_SIZE (4096 + 3*4096) |
20 | 22 | ||
21 | /* The native architecture */ | 23 | /* The native architecture */ |
22 | #define KEXEC_ARCH KEXEC_ARCH_MIPS | 24 | #define KEXEC_ARCH KEXEC_ARCH_MIPS |
25 | #define MAX_NOTE_BYTES 1024 | ||
23 | 26 | ||
24 | static inline void crash_setup_regs(struct pt_regs *newregs, | 27 | static inline void crash_setup_regs(struct pt_regs *newregs, |
25 | struct pt_regs *oldregs) | 28 | struct pt_regs *oldregs) |
26 | { | 29 | { |
27 | /* Dummy implementation for now */ | 30 | if (oldregs) |
31 | memcpy(newregs, oldregs, sizeof(*newregs)); | ||
32 | else | ||
33 | prepare_frametrace(newregs); | ||
28 | } | 34 | } |
29 | 35 | ||
36 | #ifdef CONFIG_KEXEC | ||
37 | struct kimage; | ||
38 | extern unsigned long kexec_args[4]; | ||
39 | extern int (*_machine_kexec_prepare)(struct kimage *); | ||
40 | extern void (*_machine_kexec_shutdown)(void); | ||
41 | extern void (*_machine_crash_shutdown)(struct pt_regs *regs); | ||
42 | extern void default_machine_crash_shutdown(struct pt_regs *regs); | ||
43 | #ifdef CONFIG_SMP | ||
44 | extern const unsigned char kexec_smp_wait[]; | ||
45 | extern unsigned long secondary_kexec_args[4]; | ||
46 | extern void (*relocated_kexec_smp_wait) (void *); | ||
47 | extern atomic_t kexec_ready_to_reboot; | ||
48 | #endif | ||
49 | #endif | ||
50 | |||
30 | #endif /* !_MIPS_KEXEC */ | 51 | #endif /* !_MIPS_KEXEC */ |
diff --git a/arch/mips/include/asm/smp.h b/arch/mips/include/asm/smp.h index d4fb4d852a6d..f33b5fd6972b 100644 --- a/arch/mips/include/asm/smp.h +++ b/arch/mips/include/asm/smp.h | |||
@@ -40,6 +40,8 @@ extern int __cpu_logical_map[NR_CPUS]; | |||
40 | #define SMP_CALL_FUNCTION 0x2 | 40 | #define SMP_CALL_FUNCTION 0x2 |
41 | /* Octeon - Tell another core to flush its icache */ | 41 | /* Octeon - Tell another core to flush its icache */ |
42 | #define SMP_ICACHE_FLUSH 0x4 | 42 | #define SMP_ICACHE_FLUSH 0x4 |
43 | /* Used by kexec crashdump to save all cpu's state */ | ||
44 | #define SMP_DUMP 0x8 | ||
43 | 45 | ||
44 | extern volatile cpumask_t cpu_callin_map; | 46 | extern volatile cpumask_t cpu_callin_map; |
45 | 47 | ||
@@ -91,4 +93,8 @@ static inline void arch_send_call_function_ipi_mask(const struct cpumask *mask) | |||
91 | mp_ops->send_ipi_mask(mask, SMP_CALL_FUNCTION); | 93 | mp_ops->send_ipi_mask(mask, SMP_CALL_FUNCTION); |
92 | } | 94 | } |
93 | 95 | ||
96 | #if defined(CONFIG_KEXEC) | ||
97 | extern void (*dump_ipi_function_ptr)(void *); | ||
98 | void dump_send_ipi(void (*dump_ipi_callback)(void *)); | ||
99 | #endif | ||
94 | #endif /* __ASM_SMP_H */ | 100 | #endif /* __ASM_SMP_H */ |
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 8b28bc4e14ea..764597b5fb56 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile | |||
@@ -80,7 +80,8 @@ obj-$(CONFIG_I8253) += i8253.o | |||
80 | 80 | ||
81 | obj-$(CONFIG_GPIO_TXX9) += gpio_txx9.o | 81 | obj-$(CONFIG_GPIO_TXX9) += gpio_txx9.o |
82 | 82 | ||
83 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o | 83 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o |
84 | obj-$(CONFIG_CRASH_DUMP) += crash_dump.o | ||
84 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | 85 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
85 | obj-$(CONFIG_SPINLOCK_TEST) += spinlock_test.o | 86 | obj-$(CONFIG_SPINLOCK_TEST) += spinlock_test.o |
86 | obj-$(CONFIG_MIPS_MACHINE) += mips_machine.o | 87 | obj-$(CONFIG_MIPS_MACHINE) += mips_machine.o |
diff --git a/arch/mips/kernel/crash.c b/arch/mips/kernel/crash.c new file mode 100644 index 000000000000..0f53c39324bb --- /dev/null +++ b/arch/mips/kernel/crash.c | |||
@@ -0,0 +1,71 @@ | |||
1 | #include <linux/kernel.h> | ||
2 | #include <linux/smp.h> | ||
3 | #include <linux/reboot.h> | ||
4 | #include <linux/kexec.h> | ||
5 | #include <linux/bootmem.h> | ||
6 | #include <linux/crash_dump.h> | ||
7 | #include <linux/delay.h> | ||
8 | #include <linux/init.h> | ||
9 | #include <linux/irq.h> | ||
10 | #include <linux/types.h> | ||
11 | #include <linux/sched.h> | ||
12 | |||
13 | /* This keeps a track of which one is crashing cpu. */ | ||
14 | static int crashing_cpu = -1; | ||
15 | static cpumask_t cpus_in_crash = CPU_MASK_NONE; | ||
16 | |||
17 | #ifdef CONFIG_SMP | ||
18 | static void crash_shutdown_secondary(void *ignore) | ||
19 | { | ||
20 | struct pt_regs *regs; | ||
21 | int cpu = smp_processor_id(); | ||
22 | |||
23 | regs = task_pt_regs(current); | ||
24 | |||
25 | if (!cpu_online(cpu)) | ||
26 | return; | ||
27 | |||
28 | local_irq_disable(); | ||
29 | if (!cpu_isset(cpu, cpus_in_crash)) | ||
30 | crash_save_cpu(regs, cpu); | ||
31 | cpu_set(cpu, cpus_in_crash); | ||
32 | |||
33 | while (!atomic_read(&kexec_ready_to_reboot)) | ||
34 | cpu_relax(); | ||
35 | relocated_kexec_smp_wait(NULL); | ||
36 | /* NOTREACHED */ | ||
37 | } | ||
38 | |||
39 | static void crash_kexec_prepare_cpus(void) | ||
40 | { | ||
41 | unsigned int msecs; | ||
42 | |||
43 | unsigned int ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */ | ||
44 | |||
45 | dump_send_ipi(crash_shutdown_secondary); | ||
46 | smp_wmb(); | ||
47 | |||
48 | /* | ||
49 | * The crash CPU sends an IPI and wait for other CPUs to | ||
50 | * respond. Delay of at least 10 seconds. | ||
51 | */ | ||
52 | pr_emerg("Sending IPI to other cpus...\n"); | ||
53 | msecs = 10000; | ||
54 | while ((cpus_weight(cpus_in_crash) < ncpus) && (--msecs > 0)) { | ||
55 | cpu_relax(); | ||
56 | mdelay(1); | ||
57 | } | ||
58 | } | ||
59 | |||
60 | #else /* !defined(CONFIG_SMP) */ | ||
61 | static void crash_kexec_prepare_cpus(void) {} | ||
62 | #endif /* !defined(CONFIG_SMP) */ | ||
63 | |||
64 | void default_machine_crash_shutdown(struct pt_regs *regs) | ||
65 | { | ||
66 | local_irq_disable(); | ||
67 | crashing_cpu = smp_processor_id(); | ||
68 | crash_save_cpu(regs, crashing_cpu); | ||
69 | crash_kexec_prepare_cpus(); | ||
70 | cpu_set(crashing_cpu, cpus_in_crash); | ||
71 | } | ||
diff --git a/arch/mips/kernel/crash_dump.c b/arch/mips/kernel/crash_dump.c new file mode 100644 index 000000000000..d9ec3898f9fa --- /dev/null +++ b/arch/mips/kernel/crash_dump.c | |||
@@ -0,0 +1,77 @@ | |||
1 | #include <linux/highmem.h> | ||
2 | #include <linux/bootmem.h> | ||
3 | #include <linux/crash_dump.h> | ||
4 | #include <asm/uaccess.h> | ||
5 | |||
6 | unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX; | ||
7 | |||
8 | static int __init parse_savemaxmem(char *p) | ||
9 | { | ||
10 | if (p) | ||
11 | saved_max_pfn = (memparse(p, &p) >> PAGE_SHIFT) - 1; | ||
12 | |||
13 | return 1; | ||
14 | } | ||
15 | __setup("savemaxmem=", parse_savemaxmem); | ||
16 | |||
17 | |||
18 | static void *kdump_buf_page; | ||
19 | |||
20 | /** | ||
21 | * copy_oldmem_page - copy one page from "oldmem" | ||
22 | * @pfn: page frame number to be copied | ||
23 | * @buf: target memory address for the copy; this can be in kernel address | ||
24 | * space or user address space (see @userbuf) | ||
25 | * @csize: number of bytes to copy | ||
26 | * @offset: offset in bytes into the page (based on pfn) to begin the copy | ||
27 | * @userbuf: if set, @buf is in user address space, use copy_to_user(), | ||
28 | * otherwise @buf is in kernel address space, use memcpy(). | ||
29 | * | ||
30 | * Copy a page from "oldmem". For this page, there is no pte mapped | ||
31 | * in the current kernel. | ||
32 | * | ||
33 | * Calling copy_to_user() in atomic context is not desirable. Hence first | ||
34 | * copying the data to a pre-allocated kernel page and then copying to user | ||
35 | * space in non-atomic context. | ||
36 | */ | ||
37 | ssize_t copy_oldmem_page(unsigned long pfn, char *buf, | ||
38 | size_t csize, unsigned long offset, int userbuf) | ||
39 | { | ||
40 | void *vaddr; | ||
41 | |||
42 | if (!csize) | ||
43 | return 0; | ||
44 | |||
45 | vaddr = kmap_atomic_pfn(pfn); | ||
46 | |||
47 | if (!userbuf) { | ||
48 | memcpy(buf, (vaddr + offset), csize); | ||
49 | kunmap_atomic(vaddr); | ||
50 | } else { | ||
51 | if (!kdump_buf_page) { | ||
52 | pr_warning("Kdump: Kdump buffer page not allocated\n"); | ||
53 | |||
54 | return -EFAULT; | ||
55 | } | ||
56 | copy_page(kdump_buf_page, vaddr); | ||
57 | kunmap_atomic(vaddr); | ||
58 | if (copy_to_user(buf, (kdump_buf_page + offset), csize)) | ||
59 | return -EFAULT; | ||
60 | } | ||
61 | |||
62 | return csize; | ||
63 | } | ||
64 | |||
65 | static int __init kdump_buf_page_init(void) | ||
66 | { | ||
67 | int ret = 0; | ||
68 | |||
69 | kdump_buf_page = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
70 | if (!kdump_buf_page) { | ||
71 | pr_warning("Kdump: Failed to allocate kdump buffer page\n"); | ||
72 | ret = -ENOMEM; | ||
73 | } | ||
74 | |||
75 | return ret; | ||
76 | } | ||
77 | arch_initcall(kdump_buf_page_init); | ||
diff --git a/arch/mips/kernel/machine_kexec.c b/arch/mips/kernel/machine_kexec.c index 85beb9b0b2d0..992e18474da5 100644 --- a/arch/mips/kernel/machine_kexec.c +++ b/arch/mips/kernel/machine_kexec.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * This source code is licensed under the GNU General Public License, | 5 | * This source code is licensed under the GNU General Public License, |
6 | * Version 2. See the file COPYING for more details. | 6 | * Version 2. See the file COPYING for more details. |
7 | */ | 7 | */ |
8 | 8 | #include <linux/compiler.h> | |
9 | #include <linux/kexec.h> | 9 | #include <linux/kexec.h> |
10 | #include <linux/mm.h> | 10 | #include <linux/mm.h> |
11 | #include <linux/delay.h> | 11 | #include <linux/delay.h> |
@@ -19,9 +19,19 @@ extern const size_t relocate_new_kernel_size; | |||
19 | extern unsigned long kexec_start_address; | 19 | extern unsigned long kexec_start_address; |
20 | extern unsigned long kexec_indirection_page; | 20 | extern unsigned long kexec_indirection_page; |
21 | 21 | ||
22 | int (*_machine_kexec_prepare)(struct kimage *) = NULL; | ||
23 | void (*_machine_kexec_shutdown)(void) = NULL; | ||
24 | void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL; | ||
25 | #ifdef CONFIG_SMP | ||
26 | void (*relocated_kexec_smp_wait) (void *); | ||
27 | atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0); | ||
28 | #endif | ||
29 | |||
22 | int | 30 | int |
23 | machine_kexec_prepare(struct kimage *kimage) | 31 | machine_kexec_prepare(struct kimage *kimage) |
24 | { | 32 | { |
33 | if (_machine_kexec_prepare) | ||
34 | return _machine_kexec_prepare(kimage); | ||
25 | return 0; | 35 | return 0; |
26 | } | 36 | } |
27 | 37 | ||
@@ -33,14 +43,20 @@ machine_kexec_cleanup(struct kimage *kimage) | |||
33 | void | 43 | void |
34 | machine_shutdown(void) | 44 | machine_shutdown(void) |
35 | { | 45 | { |
46 | if (_machine_kexec_shutdown) | ||
47 | _machine_kexec_shutdown(); | ||
36 | } | 48 | } |
37 | 49 | ||
38 | void | 50 | void |
39 | machine_crash_shutdown(struct pt_regs *regs) | 51 | machine_crash_shutdown(struct pt_regs *regs) |
40 | { | 52 | { |
53 | if (_machine_crash_shutdown) | ||
54 | _machine_crash_shutdown(regs); | ||
55 | else | ||
56 | default_machine_crash_shutdown(regs); | ||
41 | } | 57 | } |
42 | 58 | ||
43 | typedef void (*noretfun_t)(void) __attribute__((noreturn)); | 59 | typedef void (*noretfun_t)(void) __noreturn; |
44 | 60 | ||
45 | void | 61 | void |
46 | machine_kexec(struct kimage *image) | 62 | machine_kexec(struct kimage *image) |
@@ -52,7 +68,9 @@ machine_kexec(struct kimage *image) | |||
52 | reboot_code_buffer = | 68 | reboot_code_buffer = |
53 | (unsigned long)page_address(image->control_code_page); | 69 | (unsigned long)page_address(image->control_code_page); |
54 | 70 | ||
55 | kexec_start_address = image->start; | 71 | kexec_start_address = |
72 | (unsigned long) phys_to_virt(image->start); | ||
73 | |||
56 | kexec_indirection_page = | 74 | kexec_indirection_page = |
57 | (unsigned long) phys_to_virt(image->head & PAGE_MASK); | 75 | (unsigned long) phys_to_virt(image->head & PAGE_MASK); |
58 | 76 | ||
@@ -63,7 +81,7 @@ machine_kexec(struct kimage *image) | |||
63 | * The generic kexec code builds a page list with physical | 81 | * The generic kexec code builds a page list with physical |
64 | * addresses. they are directly accessible through KSEG0 (or | 82 | * addresses. they are directly accessible through KSEG0 (or |
65 | * CKSEG0 or XPHYS if on 64bit system), hence the | 83 | * CKSEG0 or XPHYS if on 64bit system), hence the |
66 | * pys_to_virt() call. | 84 | * phys_to_virt() call. |
67 | */ | 85 | */ |
68 | for (ptr = &image->head; (entry = *ptr) && !(entry &IND_DONE); | 86 | for (ptr = &image->head; (entry = *ptr) && !(entry &IND_DONE); |
69 | ptr = (entry & IND_INDIRECTION) ? | 87 | ptr = (entry & IND_INDIRECTION) ? |
@@ -81,5 +99,12 @@ machine_kexec(struct kimage *image) | |||
81 | printk("Will call new kernel at %08lx\n", image->start); | 99 | printk("Will call new kernel at %08lx\n", image->start); |
82 | printk("Bye ...\n"); | 100 | printk("Bye ...\n"); |
83 | __flush_cache_all(); | 101 | __flush_cache_all(); |
102 | #ifdef CONFIG_SMP | ||
103 | /* All secondary cpus now may jump to kexec_wait cycle */ | ||
104 | relocated_kexec_smp_wait = reboot_code_buffer + | ||
105 | (void *)(kexec_smp_wait - relocate_new_kernel); | ||
106 | smp_wmb(); | ||
107 | atomic_set(&kexec_ready_to_reboot, 1); | ||
108 | #endif | ||
84 | ((noretfun_t) reboot_code_buffer)(); | 109 | ((noretfun_t) reboot_code_buffer)(); |
85 | } | 110 | } |
diff --git a/arch/mips/kernel/relocate_kernel.S b/arch/mips/kernel/relocate_kernel.S index 87481f916a61..0b108587f065 100644 --- a/arch/mips/kernel/relocate_kernel.S +++ b/arch/mips/kernel/relocate_kernel.S | |||
@@ -15,6 +15,11 @@ | |||
15 | #include <asm/addrspace.h> | 15 | #include <asm/addrspace.h> |
16 | 16 | ||
17 | LEAF(relocate_new_kernel) | 17 | LEAF(relocate_new_kernel) |
18 | PTR_L a0, arg0 | ||
19 | PTR_L a1, arg1 | ||
20 | PTR_L a2, arg2 | ||
21 | PTR_L a3, arg3 | ||
22 | |||
18 | PTR_L s0, kexec_indirection_page | 23 | PTR_L s0, kexec_indirection_page |
19 | PTR_L s1, kexec_start_address | 24 | PTR_L s1, kexec_start_address |
20 | 25 | ||
@@ -26,7 +31,6 @@ process_entry: | |||
26 | and s3, s2, 0x1 | 31 | and s3, s2, 0x1 |
27 | beq s3, zero, 1f | 32 | beq s3, zero, 1f |
28 | and s4, s2, ~0x1 /* store destination addr in s4 */ | 33 | and s4, s2, ~0x1 /* store destination addr in s4 */ |
29 | move a0, s4 | ||
30 | b process_entry | 34 | b process_entry |
31 | 35 | ||
32 | 1: | 36 | 1: |
@@ -60,10 +64,92 @@ copy_word: | |||
60 | b process_entry | 64 | b process_entry |
61 | 65 | ||
62 | done: | 66 | done: |
67 | #ifdef CONFIG_SMP | ||
68 | /* kexec_flag reset is signal to other CPUs what kernel | ||
69 | was moved to it's location. Note - we need relocated address | ||
70 | of kexec_flag. */ | ||
71 | |||
72 | bal 1f | ||
73 | 1: move t1,ra; | ||
74 | PTR_LA t2,1b | ||
75 | PTR_LA t0,kexec_flag | ||
76 | PTR_SUB t0,t0,t2; | ||
77 | PTR_ADD t0,t1,t0; | ||
78 | LONG_S zero,(t0) | ||
79 | #endif | ||
80 | |||
81 | sync | ||
63 | /* jump to kexec_start_address */ | 82 | /* jump to kexec_start_address */ |
64 | j s1 | 83 | j s1 |
65 | END(relocate_new_kernel) | 84 | END(relocate_new_kernel) |
66 | 85 | ||
86 | #ifdef CONFIG_SMP | ||
87 | /* | ||
88 | * Other CPUs should wait until code is relocated and | ||
89 | * then start at entry (?) point. | ||
90 | */ | ||
91 | LEAF(kexec_smp_wait) | ||
92 | PTR_L a0, s_arg0 | ||
93 | PTR_L a1, s_arg1 | ||
94 | PTR_L a2, s_arg2 | ||
95 | PTR_L a3, s_arg3 | ||
96 | PTR_L s1, kexec_start_address | ||
97 | |||
98 | /* Non-relocated address works for args and kexec_start_address ( old | ||
99 | * kernel is not overwritten). But we need relocated address of | ||
100 | * kexec_flag. | ||
101 | */ | ||
102 | |||
103 | bal 1f | ||
104 | 1: move t1,ra; | ||
105 | PTR_LA t2,1b | ||
106 | PTR_LA t0,kexec_flag | ||
107 | PTR_SUB t0,t0,t2; | ||
108 | PTR_ADD t0,t1,t0; | ||
109 | |||
110 | 1: LONG_L s0, (t0) | ||
111 | bne s0, zero,1b | ||
112 | |||
113 | sync | ||
114 | j s1 | ||
115 | END(kexec_smp_wait) | ||
116 | #endif | ||
117 | |||
118 | #ifdef __mips64 | ||
119 | /* all PTR's must be aligned to 8 byte in 64-bit mode */ | ||
120 | .align 3 | ||
121 | #endif | ||
122 | |||
123 | /* All parameters to new kernel are passed in registers a0-a3. | ||
124 | * kexec_args[0..3] are uses to prepare register values. | ||
125 | */ | ||
126 | |||
127 | kexec_args: | ||
128 | EXPORT(kexec_args) | ||
129 | arg0: PTR 0x0 | ||
130 | arg1: PTR 0x0 | ||
131 | arg2: PTR 0x0 | ||
132 | arg3: PTR 0x0 | ||
133 | .size kexec_args,PTRSIZE*4 | ||
134 | |||
135 | #ifdef CONFIG_SMP | ||
136 | /* | ||
137 | * Secondary CPUs may have different kernel parameters in | ||
138 | * their registers a0-a3. secondary_kexec_args[0..3] are used | ||
139 | * to prepare register values. | ||
140 | */ | ||
141 | secondary_kexec_args: | ||
142 | EXPORT(secondary_kexec_args) | ||
143 | s_arg0: PTR 0x0 | ||
144 | s_arg1: PTR 0x0 | ||
145 | s_arg2: PTR 0x0 | ||
146 | s_arg3: PTR 0x0 | ||
147 | .size secondary_kexec_args,PTRSIZE*4 | ||
148 | kexec_flag: | ||
149 | LONG 0x1 | ||
150 | |||
151 | #endif | ||
152 | |||
67 | kexec_start_address: | 153 | kexec_start_address: |
68 | EXPORT(kexec_start_address) | 154 | EXPORT(kexec_start_address) |
69 | PTR 0x0 | 155 | PTR 0x0 |
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 290dc6a1d7a3..8c41187801ce 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/console.h> | 22 | #include <linux/console.h> |
23 | #include <linux/pfn.h> | 23 | #include <linux/pfn.h> |
24 | #include <linux/debugfs.h> | 24 | #include <linux/debugfs.h> |
25 | #include <linux/kexec.h> | ||
25 | 26 | ||
26 | #include <asm/addrspace.h> | 27 | #include <asm/addrspace.h> |
27 | #include <asm/bootinfo.h> | 28 | #include <asm/bootinfo.h> |
@@ -536,12 +537,64 @@ static void __init arch_mem_init(char **cmdline_p) | |||
536 | } | 537 | } |
537 | 538 | ||
538 | bootmem_init(); | 539 | bootmem_init(); |
540 | #ifdef CONFIG_KEXEC | ||
541 | if (crashk_res.start != crashk_res.end) | ||
542 | reserve_bootmem(crashk_res.start, | ||
543 | crashk_res.end - crashk_res.start + 1, | ||
544 | BOOTMEM_DEFAULT); | ||
545 | #endif | ||
539 | device_tree_init(); | 546 | device_tree_init(); |
540 | sparse_init(); | 547 | sparse_init(); |
541 | plat_swiotlb_setup(); | 548 | plat_swiotlb_setup(); |
542 | paging_init(); | 549 | paging_init(); |
543 | } | 550 | } |
544 | 551 | ||
552 | #ifdef CONFIG_KEXEC | ||
553 | static inline unsigned long long get_total_mem(void) | ||
554 | { | ||
555 | unsigned long long total; | ||
556 | |||
557 | total = max_pfn - min_low_pfn; | ||
558 | return total << PAGE_SHIFT; | ||
559 | } | ||
560 | |||
561 | static void __init mips_parse_crashkernel(void) | ||
562 | { | ||
563 | unsigned long long total_mem; | ||
564 | unsigned long long crash_size, crash_base; | ||
565 | int ret; | ||
566 | |||
567 | total_mem = get_total_mem(); | ||
568 | ret = parse_crashkernel(boot_command_line, total_mem, | ||
569 | &crash_size, &crash_base); | ||
570 | if (ret != 0 || crash_size <= 0) | ||
571 | return; | ||
572 | |||
573 | crashk_res.start = crash_base; | ||
574 | crashk_res.end = crash_base + crash_size - 1; | ||
575 | } | ||
576 | |||
577 | static void __init request_crashkernel(struct resource *res) | ||
578 | { | ||
579 | int ret; | ||
580 | |||
581 | ret = request_resource(res, &crashk_res); | ||
582 | if (!ret) | ||
583 | pr_info("Reserving %ldMB of memory at %ldMB for crashkernel\n", | ||
584 | (unsigned long)((crashk_res.end - | ||
585 | crashk_res.start + 1) >> 20), | ||
586 | (unsigned long)(crashk_res.start >> 20)); | ||
587 | } | ||
588 | #else /* !defined(CONFIG_KEXEC) */ | ||
589 | static void __init mips_parse_crashkernel(void) | ||
590 | { | ||
591 | } | ||
592 | |||
593 | static void __init request_crashkernel(struct resource *res) | ||
594 | { | ||
595 | } | ||
596 | #endif /* !defined(CONFIG_KEXEC) */ | ||
597 | |||
545 | static void __init resource_init(void) | 598 | static void __init resource_init(void) |
546 | { | 599 | { |
547 | int i; | 600 | int i; |
@@ -557,6 +610,8 @@ static void __init resource_init(void) | |||
557 | /* | 610 | /* |
558 | * Request address space for all standard RAM. | 611 | * Request address space for all standard RAM. |
559 | */ | 612 | */ |
613 | mips_parse_crashkernel(); | ||
614 | |||
560 | for (i = 0; i < boot_mem_map.nr_map; i++) { | 615 | for (i = 0; i < boot_mem_map.nr_map; i++) { |
561 | struct resource *res; | 616 | struct resource *res; |
562 | unsigned long start, end; | 617 | unsigned long start, end; |
@@ -593,6 +648,7 @@ static void __init resource_init(void) | |||
593 | */ | 648 | */ |
594 | request_resource(res, &code_resource); | 649 | request_resource(res, &code_resource); |
595 | request_resource(res, &data_resource); | 650 | request_resource(res, &data_resource); |
651 | request_crashkernel(res); | ||
596 | } | 652 | } |
597 | } | 653 | } |
598 | 654 | ||
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 9005bf9fb859..2e6374a589ec 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c | |||
@@ -386,3 +386,20 @@ void flush_tlb_one(unsigned long vaddr) | |||
386 | 386 | ||
387 | EXPORT_SYMBOL(flush_tlb_page); | 387 | EXPORT_SYMBOL(flush_tlb_page); |
388 | EXPORT_SYMBOL(flush_tlb_one); | 388 | EXPORT_SYMBOL(flush_tlb_one); |
389 | |||
390 | #if defined(CONFIG_KEXEC) | ||
391 | void (*dump_ipi_function_ptr)(void *) = NULL; | ||
392 | void dump_send_ipi(void (*dump_ipi_callback)(void *)) | ||
393 | { | ||
394 | int i; | ||
395 | int cpu = smp_processor_id(); | ||
396 | |||
397 | dump_ipi_function_ptr = dump_ipi_callback; | ||
398 | smp_mb(); | ||
399 | for_each_online_cpu(i) | ||
400 | if (i != cpu) | ||
401 | mp_ops->send_ipi_single(i, SMP_DUMP); | ||
402 | |||
403 | } | ||
404 | EXPORT_SYMBOL(dump_send_ipi); | ||
405 | #endif | ||
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 9be3df1fa8a4..da0c29422cf2 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
@@ -13,6 +13,7 @@ | |||
13 | */ | 13 | */ |
14 | #include <linux/bug.h> | 14 | #include <linux/bug.h> |
15 | #include <linux/compiler.h> | 15 | #include <linux/compiler.h> |
16 | #include <linux/kexec.h> | ||
16 | #include <linux/init.h> | 17 | #include <linux/init.h> |
17 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
18 | #include <linux/module.h> | 19 | #include <linux/module.h> |
@@ -409,6 +410,9 @@ void __noreturn die(const char *str, struct pt_regs *regs) | |||
409 | panic("Fatal exception"); | 410 | panic("Fatal exception"); |
410 | } | 411 | } |
411 | 412 | ||
413 | if (regs && kexec_should_crash(current)) | ||
414 | crash_kexec(regs); | ||
415 | |||
412 | do_exit(sig); | 416 | do_exit(sig); |
413 | } | 417 | } |
414 | 418 | ||