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. */ |
