diff options
-rw-r--r-- | arch/i386/kernel/crash.c | 66 | ||||
-rw-r--r-- | arch/powerpc/kernel/crash.c | 59 | ||||
-rw-r--r-- | arch/x86_64/kernel/crash.c | 69 | ||||
-rw-r--r-- | include/linux/kexec.h | 1 | ||||
-rw-r--r-- | kernel/kexec.c | 56 |
5 files changed, 63 insertions, 188 deletions
diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash.c index 144b43288965..a5e0e990ea95 100644 --- a/arch/i386/kernel/crash.c +++ b/arch/i386/kernel/crash.c | |||
@@ -31,68 +31,6 @@ | |||
31 | /* This keeps a track of which one is crashing cpu. */ | 31 | /* This keeps a track of which one is crashing cpu. */ |
32 | static int crashing_cpu; | 32 | static int crashing_cpu; |
33 | 33 | ||
34 | static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data, | ||
35 | size_t data_len) | ||
36 | { | ||
37 | struct elf_note note; | ||
38 | |||
39 | note.n_namesz = strlen(name) + 1; | ||
40 | note.n_descsz = data_len; | ||
41 | note.n_type = type; | ||
42 | memcpy(buf, ¬e, sizeof(note)); | ||
43 | buf += (sizeof(note) +3)/4; | ||
44 | memcpy(buf, name, note.n_namesz); | ||
45 | buf += (note.n_namesz + 3)/4; | ||
46 | memcpy(buf, data, note.n_descsz); | ||
47 | buf += (note.n_descsz + 3)/4; | ||
48 | |||
49 | return buf; | ||
50 | } | ||
51 | |||
52 | static void final_note(u32 *buf) | ||
53 | { | ||
54 | struct elf_note note; | ||
55 | |||
56 | note.n_namesz = 0; | ||
57 | note.n_descsz = 0; | ||
58 | note.n_type = 0; | ||
59 | memcpy(buf, ¬e, sizeof(note)); | ||
60 | } | ||
61 | |||
62 | static void crash_save_this_cpu(struct pt_regs *regs, int cpu) | ||
63 | { | ||
64 | struct elf_prstatus prstatus; | ||
65 | u32 *buf; | ||
66 | |||
67 | if ((cpu < 0) || (cpu >= NR_CPUS)) | ||
68 | return; | ||
69 | |||
70 | /* Using ELF notes here is opportunistic. | ||
71 | * I need a well defined structure format | ||
72 | * for the data I pass, and I need tags | ||
73 | * on the data to indicate what information I have | ||
74 | * squirrelled away. ELF notes happen to provide | ||
75 | * all of that, so there is no need to invent something new. | ||
76 | */ | ||
77 | buf = (u32*)per_cpu_ptr(crash_notes, cpu); | ||
78 | if (!buf) | ||
79 | return; | ||
80 | memset(&prstatus, 0, sizeof(prstatus)); | ||
81 | prstatus.pr_pid = current->pid; | ||
82 | elf_core_copy_regs(&prstatus.pr_reg, regs); | ||
83 | buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus, | ||
84 | sizeof(prstatus)); | ||
85 | final_note(buf); | ||
86 | } | ||
87 | |||
88 | static void crash_save_self(struct pt_regs *regs) | ||
89 | { | ||
90 | int cpu; | ||
91 | |||
92 | cpu = safe_smp_processor_id(); | ||
93 | crash_save_this_cpu(regs, cpu); | ||
94 | } | ||
95 | |||
96 | #if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) | 34 | #if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) |
97 | static atomic_t waiting_for_crash_ipi; | 35 | static atomic_t waiting_for_crash_ipi; |
98 | 36 | ||
@@ -121,7 +59,7 @@ static int crash_nmi_callback(struct notifier_block *self, | |||
121 | crash_fixup_ss_esp(&fixed_regs, regs); | 59 | crash_fixup_ss_esp(&fixed_regs, regs); |
122 | regs = &fixed_regs; | 60 | regs = &fixed_regs; |
123 | } | 61 | } |
124 | crash_save_this_cpu(regs, cpu); | 62 | crash_save_cpu(regs, cpu); |
125 | disable_local_APIC(); | 63 | disable_local_APIC(); |
126 | atomic_dec(&waiting_for_crash_ipi); | 64 | atomic_dec(&waiting_for_crash_ipi); |
127 | /* Assume hlt works */ | 65 | /* Assume hlt works */ |
@@ -195,5 +133,5 @@ void machine_crash_shutdown(struct pt_regs *regs) | |||
195 | #if defined(CONFIG_X86_IO_APIC) | 133 | #if defined(CONFIG_X86_IO_APIC) |
196 | disable_IO_APIC(); | 134 | disable_IO_APIC(); |
197 | #endif | 135 | #endif |
198 | crash_save_self(regs); | 136 | crash_save_cpu(regs, safe_smp_processor_id()); |
199 | } | 137 | } |
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index 89b03c8da9d2..d3f2080d2eee 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c | |||
@@ -46,61 +46,6 @@ int crashing_cpu = -1; | |||
46 | static cpumask_t cpus_in_crash = CPU_MASK_NONE; | 46 | static cpumask_t cpus_in_crash = CPU_MASK_NONE; |
47 | cpumask_t cpus_in_sr = CPU_MASK_NONE; | 47 | cpumask_t cpus_in_sr = CPU_MASK_NONE; |
48 | 48 | ||
49 | static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data, | ||
50 | size_t data_len) | ||
51 | { | ||
52 | struct elf_note note; | ||
53 | |||
54 | note.n_namesz = strlen(name) + 1; | ||
55 | note.n_descsz = data_len; | ||
56 | note.n_type = type; | ||
57 | memcpy(buf, ¬e, sizeof(note)); | ||
58 | buf += (sizeof(note) +3)/4; | ||
59 | memcpy(buf, name, note.n_namesz); | ||
60 | buf += (note.n_namesz + 3)/4; | ||
61 | memcpy(buf, data, note.n_descsz); | ||
62 | buf += (note.n_descsz + 3)/4; | ||
63 | |||
64 | return buf; | ||
65 | } | ||
66 | |||
67 | static void final_note(u32 *buf) | ||
68 | { | ||
69 | struct elf_note note; | ||
70 | |||
71 | note.n_namesz = 0; | ||
72 | note.n_descsz = 0; | ||
73 | note.n_type = 0; | ||
74 | memcpy(buf, ¬e, sizeof(note)); | ||
75 | } | ||
76 | |||
77 | static void crash_save_this_cpu(struct pt_regs *regs, int cpu) | ||
78 | { | ||
79 | struct elf_prstatus prstatus; | ||
80 | u32 *buf; | ||
81 | |||
82 | if ((cpu < 0) || (cpu >= NR_CPUS)) | ||
83 | return; | ||
84 | |||
85 | /* Using ELF notes here is opportunistic. | ||
86 | * I need a well defined structure format | ||
87 | * for the data I pass, and I need tags | ||
88 | * on the data to indicate what information I have | ||
89 | * squirrelled away. ELF notes happen to provide | ||
90 | * all of that that no need to invent something new. | ||
91 | */ | ||
92 | buf = (u32*)per_cpu_ptr(crash_notes, cpu); | ||
93 | if (!buf) | ||
94 | return; | ||
95 | |||
96 | memset(&prstatus, 0, sizeof(prstatus)); | ||
97 | prstatus.pr_pid = current->pid; | ||
98 | elf_core_copy_regs(&prstatus.pr_reg, regs); | ||
99 | buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus, | ||
100 | sizeof(prstatus)); | ||
101 | final_note(buf); | ||
102 | } | ||
103 | |||
104 | #ifdef CONFIG_SMP | 49 | #ifdef CONFIG_SMP |
105 | static atomic_t enter_on_soft_reset = ATOMIC_INIT(0); | 50 | static atomic_t enter_on_soft_reset = ATOMIC_INIT(0); |
106 | 51 | ||
@@ -113,7 +58,7 @@ void crash_ipi_callback(struct pt_regs *regs) | |||
113 | 58 | ||
114 | hard_irq_disable(); | 59 | hard_irq_disable(); |
115 | if (!cpu_isset(cpu, cpus_in_crash)) | 60 | if (!cpu_isset(cpu, cpus_in_crash)) |
116 | crash_save_this_cpu(regs, cpu); | 61 | crash_save_cpu(regs, cpu); |
117 | cpu_set(cpu, cpus_in_crash); | 62 | cpu_set(cpu, cpus_in_crash); |
118 | 63 | ||
119 | /* | 64 | /* |
@@ -306,7 +251,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs) | |||
306 | * such that another IPI will not be sent. | 251 | * such that another IPI will not be sent. |
307 | */ | 252 | */ |
308 | crashing_cpu = smp_processor_id(); | 253 | crashing_cpu = smp_processor_id(); |
309 | crash_save_this_cpu(regs, crashing_cpu); | 254 | crash_save_cpu(regs, crashing_cpu); |
310 | crash_kexec_prepare_cpus(crashing_cpu); | 255 | crash_kexec_prepare_cpus(crashing_cpu); |
311 | cpu_set(crashing_cpu, cpus_in_crash); | 256 | cpu_set(crashing_cpu, cpus_in_crash); |
312 | if (ppc_md.kexec_cpu_down) | 257 | if (ppc_md.kexec_cpu_down) |
diff --git a/arch/x86_64/kernel/crash.c b/arch/x86_64/kernel/crash.c index 3525f884af82..95a7a2c13131 100644 --- a/arch/x86_64/kernel/crash.c +++ b/arch/x86_64/kernel/crash.c | |||
@@ -28,71 +28,6 @@ | |||
28 | /* This keeps a track of which one is crashing cpu. */ | 28 | /* This keeps a track of which one is crashing cpu. */ |
29 | static int crashing_cpu; | 29 | static int crashing_cpu; |
30 | 30 | ||
31 | static u32 *append_elf_note(u32 *buf, char *name, unsigned type, | ||
32 | void *data, size_t data_len) | ||
33 | { | ||
34 | struct elf_note note; | ||
35 | |||
36 | note.n_namesz = strlen(name) + 1; | ||
37 | note.n_descsz = data_len; | ||
38 | note.n_type = type; | ||
39 | memcpy(buf, ¬e, sizeof(note)); | ||
40 | buf += (sizeof(note) +3)/4; | ||
41 | memcpy(buf, name, note.n_namesz); | ||
42 | buf += (note.n_namesz + 3)/4; | ||
43 | memcpy(buf, data, note.n_descsz); | ||
44 | buf += (note.n_descsz + 3)/4; | ||
45 | |||
46 | return buf; | ||
47 | } | ||
48 | |||
49 | static void final_note(u32 *buf) | ||
50 | { | ||
51 | struct elf_note note; | ||
52 | |||
53 | note.n_namesz = 0; | ||
54 | note.n_descsz = 0; | ||
55 | note.n_type = 0; | ||
56 | memcpy(buf, ¬e, sizeof(note)); | ||
57 | } | ||
58 | |||
59 | static void crash_save_this_cpu(struct pt_regs *regs, int cpu) | ||
60 | { | ||
61 | struct elf_prstatus prstatus; | ||
62 | u32 *buf; | ||
63 | |||
64 | if ((cpu < 0) || (cpu >= NR_CPUS)) | ||
65 | return; | ||
66 | |||
67 | /* Using ELF notes here is opportunistic. | ||
68 | * I need a well defined structure format | ||
69 | * for the data I pass, and I need tags | ||
70 | * on the data to indicate what information I have | ||
71 | * squirrelled away. ELF notes happen to provide | ||
72 | * all of that, no need to invent something new. | ||
73 | */ | ||
74 | |||
75 | buf = (u32*)per_cpu_ptr(crash_notes, cpu); | ||
76 | |||
77 | if (!buf) | ||
78 | return; | ||
79 | |||
80 | memset(&prstatus, 0, sizeof(prstatus)); | ||
81 | prstatus.pr_pid = current->pid; | ||
82 | elf_core_copy_regs(&prstatus.pr_reg, regs); | ||
83 | buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus, | ||
84 | sizeof(prstatus)); | ||
85 | final_note(buf); | ||
86 | } | ||
87 | |||
88 | static void crash_save_self(struct pt_regs *regs) | ||
89 | { | ||
90 | int cpu; | ||
91 | |||
92 | cpu = smp_processor_id(); | ||
93 | crash_save_this_cpu(regs, cpu); | ||
94 | } | ||
95 | |||
96 | #ifdef CONFIG_SMP | 31 | #ifdef CONFIG_SMP |
97 | static atomic_t waiting_for_crash_ipi; | 32 | static atomic_t waiting_for_crash_ipi; |
98 | 33 | ||
@@ -117,7 +52,7 @@ static int crash_nmi_callback(struct notifier_block *self, | |||
117 | return NOTIFY_STOP; | 52 | return NOTIFY_STOP; |
118 | local_irq_disable(); | 53 | local_irq_disable(); |
119 | 54 | ||
120 | crash_save_this_cpu(regs, cpu); | 55 | crash_save_cpu(regs, cpu); |
121 | disable_local_APIC(); | 56 | disable_local_APIC(); |
122 | atomic_dec(&waiting_for_crash_ipi); | 57 | atomic_dec(&waiting_for_crash_ipi); |
123 | /* Assume hlt works */ | 58 | /* Assume hlt works */ |
@@ -196,5 +131,5 @@ void machine_crash_shutdown(struct pt_regs *regs) | |||
196 | 131 | ||
197 | disable_IO_APIC(); | 132 | disable_IO_APIC(); |
198 | 133 | ||
199 | crash_save_self(regs); | 134 | crash_save_cpu(regs, smp_processor_id()); |
200 | } | 135 | } |
diff --git a/include/linux/kexec.h b/include/linux/kexec.h index a4ede62b339d..e3abcec6c51c 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h | |||
@@ -105,6 +105,7 @@ extern struct page *kimage_alloc_control_pages(struct kimage *image, | |||
105 | unsigned int order); | 105 | unsigned int order); |
106 | extern void crash_kexec(struct pt_regs *); | 106 | extern void crash_kexec(struct pt_regs *); |
107 | int kexec_should_crash(struct task_struct *); | 107 | int kexec_should_crash(struct task_struct *); |
108 | void crash_save_cpu(struct pt_regs *regs, int cpu); | ||
108 | extern struct kimage *kexec_image; | 109 | extern struct kimage *kexec_image; |
109 | extern struct kimage *kexec_crash_image; | 110 | extern struct kimage *kexec_crash_image; |
110 | 111 | ||
diff --git a/kernel/kexec.c b/kernel/kexec.c index d43692cf2321..afbbbe981be2 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c | |||
@@ -20,6 +20,8 @@ | |||
20 | #include <linux/syscalls.h> | 20 | #include <linux/syscalls.h> |
21 | #include <linux/ioport.h> | 21 | #include <linux/ioport.h> |
22 | #include <linux/hardirq.h> | 22 | #include <linux/hardirq.h> |
23 | #include <linux/elf.h> | ||
24 | #include <linux/elfcore.h> | ||
23 | 25 | ||
24 | #include <asm/page.h> | 26 | #include <asm/page.h> |
25 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
@@ -1066,6 +1068,60 @@ void crash_kexec(struct pt_regs *regs) | |||
1066 | } | 1068 | } |
1067 | } | 1069 | } |
1068 | 1070 | ||
1071 | static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data, | ||
1072 | size_t data_len) | ||
1073 | { | ||
1074 | struct elf_note note; | ||
1075 | |||
1076 | note.n_namesz = strlen(name) + 1; | ||
1077 | note.n_descsz = data_len; | ||
1078 | note.n_type = type; | ||
1079 | memcpy(buf, ¬e, sizeof(note)); | ||
1080 | buf += (sizeof(note) + 3)/4; | ||
1081 | memcpy(buf, name, note.n_namesz); | ||
1082 | buf += (note.n_namesz + 3)/4; | ||
1083 | memcpy(buf, data, note.n_descsz); | ||
1084 | buf += (note.n_descsz + 3)/4; | ||
1085 | |||
1086 | return buf; | ||
1087 | } | ||
1088 | |||
1089 | static void final_note(u32 *buf) | ||
1090 | { | ||
1091 | struct elf_note note; | ||
1092 | |||
1093 | note.n_namesz = 0; | ||
1094 | note.n_descsz = 0; | ||
1095 | note.n_type = 0; | ||
1096 | memcpy(buf, ¬e, sizeof(note)); | ||
1097 | } | ||
1098 | |||
1099 | void crash_save_cpu(struct pt_regs *regs, int cpu) | ||
1100 | { | ||
1101 | struct elf_prstatus prstatus; | ||
1102 | u32 *buf; | ||
1103 | |||
1104 | if ((cpu < 0) || (cpu >= NR_CPUS)) | ||
1105 | return; | ||
1106 | |||
1107 | /* Using ELF notes here is opportunistic. | ||
1108 | * I need a well defined structure format | ||
1109 | * for the data I pass, and I need tags | ||
1110 | * on the data to indicate what information I have | ||
1111 | * squirrelled away. ELF notes happen to provide | ||
1112 | * all of that, so there is no need to invent something new. | ||
1113 | */ | ||
1114 | buf = (u32*)per_cpu_ptr(crash_notes, cpu); | ||
1115 | if (!buf) | ||
1116 | return; | ||
1117 | memset(&prstatus, 0, sizeof(prstatus)); | ||
1118 | prstatus.pr_pid = current->pid; | ||
1119 | elf_core_copy_regs(&prstatus.pr_reg, regs); | ||
1120 | buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus, | ||
1121 | sizeof(prstatus)); | ||
1122 | final_note(buf); | ||
1123 | } | ||
1124 | |||
1069 | static int __init crash_notes_memory_init(void) | 1125 | static int __init crash_notes_memory_init(void) |
1070 | { | 1126 | { |
1071 | /* Allocate memory for saving cpu registers. */ | 1127 | /* Allocate memory for saving cpu registers. */ |