diff options
| -rw-r--r-- | arch/i386/kernel/crash.c | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash.c index 882779c07874..1bb5dd98d1d4 100644 --- a/arch/i386/kernel/crash.c +++ b/arch/i386/kernel/crash.c | |||
| @@ -30,12 +30,91 @@ typedef u32 note_buf_t[MAX_NOTE_BYTES/4]; | |||
| 30 | 30 | ||
| 31 | note_buf_t crash_notes[NR_CPUS]; | 31 | note_buf_t crash_notes[NR_CPUS]; |
| 32 | 32 | ||
| 33 | static u32 *append_elf_note(u32 *buf, | ||
| 34 | char *name, unsigned type, void *data, size_t data_len) | ||
| 35 | { | ||
| 36 | struct elf_note note; | ||
| 37 | note.n_namesz = strlen(name) + 1; | ||
| 38 | note.n_descsz = data_len; | ||
| 39 | note.n_type = type; | ||
| 40 | memcpy(buf, ¬e, sizeof(note)); | ||
| 41 | buf += (sizeof(note) +3)/4; | ||
| 42 | memcpy(buf, name, note.n_namesz); | ||
| 43 | buf += (note.n_namesz + 3)/4; | ||
| 44 | memcpy(buf, data, note.n_descsz); | ||
| 45 | buf += (note.n_descsz + 3)/4; | ||
| 46 | return buf; | ||
| 47 | } | ||
| 48 | |||
| 49 | static void final_note(u32 *buf) | ||
| 50 | { | ||
| 51 | struct elf_note note; | ||
| 52 | note.n_namesz = 0; | ||
| 53 | note.n_descsz = 0; | ||
| 54 | note.n_type = 0; | ||
| 55 | memcpy(buf, ¬e, sizeof(note)); | ||
| 56 | } | ||
| 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 | if ((cpu < 0) || (cpu >= NR_CPUS)) { | ||
| 64 | return; | ||
| 65 | } | ||
| 66 | /* Using ELF notes here is opportunistic. | ||
| 67 | * I need a well defined structure format | ||
| 68 | * for the data I pass, and I need tags | ||
| 69 | * on the data to indicate what information I have | ||
| 70 | * squirrelled away. ELF notes happen to provide | ||
| 71 | * all of that that no need to invent something new. | ||
| 72 | */ | ||
| 73 | buf = &crash_notes[cpu][0]; | ||
| 74 | memset(&prstatus, 0, sizeof(prstatus)); | ||
| 75 | prstatus.pr_pid = current->pid; | ||
| 76 | elf_core_copy_regs(&prstatus.pr_reg, regs); | ||
| 77 | buf = append_elf_note(buf, "CORE", NT_PRSTATUS, | ||
| 78 | &prstatus, sizeof(prstatus)); | ||
| 79 | |||
| 80 | final_note(buf); | ||
| 81 | } | ||
| 82 | |||
| 83 | static void crash_get_current_regs(struct pt_regs *regs) | ||
| 84 | { | ||
| 85 | __asm__ __volatile__("movl %%ebx,%0" : "=m"(regs->ebx)); | ||
| 86 | __asm__ __volatile__("movl %%ecx,%0" : "=m"(regs->ecx)); | ||
| 87 | __asm__ __volatile__("movl %%edx,%0" : "=m"(regs->edx)); | ||
| 88 | __asm__ __volatile__("movl %%esi,%0" : "=m"(regs->esi)); | ||
| 89 | __asm__ __volatile__("movl %%edi,%0" : "=m"(regs->edi)); | ||
| 90 | __asm__ __volatile__("movl %%ebp,%0" : "=m"(regs->ebp)); | ||
| 91 | __asm__ __volatile__("movl %%eax,%0" : "=m"(regs->eax)); | ||
| 92 | __asm__ __volatile__("movl %%esp,%0" : "=m"(regs->esp)); | ||
| 93 | __asm__ __volatile__("movw %%ss, %%ax;" :"=a"(regs->xss)); | ||
| 94 | __asm__ __volatile__("movw %%cs, %%ax;" :"=a"(regs->xcs)); | ||
| 95 | __asm__ __volatile__("movw %%ds, %%ax;" :"=a"(regs->xds)); | ||
| 96 | __asm__ __volatile__("movw %%es, %%ax;" :"=a"(regs->xes)); | ||
| 97 | __asm__ __volatile__("pushfl; popl %0" :"=m"(regs->eflags)); | ||
| 98 | |||
| 99 | regs->eip = (unsigned long)current_text_addr(); | ||
| 100 | } | ||
| 101 | |||
| 102 | static void crash_save_self(void) | ||
| 103 | { | ||
| 104 | struct pt_regs regs; | ||
| 105 | int cpu; | ||
| 106 | cpu = smp_processor_id(); | ||
| 107 | crash_get_current_regs(®s); | ||
| 108 | crash_save_this_cpu(®s, cpu); | ||
| 109 | } | ||
| 110 | |||
| 33 | #ifdef CONFIG_SMP | 111 | #ifdef CONFIG_SMP |
| 34 | static atomic_t waiting_for_crash_ipi; | 112 | static atomic_t waiting_for_crash_ipi; |
| 35 | 113 | ||
| 36 | static int crash_nmi_callback(struct pt_regs *regs, int cpu) | 114 | static int crash_nmi_callback(struct pt_regs *regs, int cpu) |
| 37 | { | 115 | { |
| 38 | local_irq_disable(); | 116 | local_irq_disable(); |
| 117 | crash_save_this_cpu(regs, cpu); | ||
| 39 | atomic_dec(&waiting_for_crash_ipi); | 118 | atomic_dec(&waiting_for_crash_ipi); |
| 40 | /* Assume hlt works */ | 119 | /* Assume hlt works */ |
| 41 | __asm__("hlt"); | 120 | __asm__("hlt"); |
| @@ -95,4 +174,5 @@ void machine_crash_shutdown(void) | |||
| 95 | /* The kernel is broken so disable interrupts */ | 174 | /* The kernel is broken so disable interrupts */ |
| 96 | local_irq_disable(); | 175 | local_irq_disable(); |
| 97 | nmi_shootdown_cpus(); | 176 | nmi_shootdown_cpus(); |
| 177 | crash_save_self(); | ||
| 98 | } | 178 | } |
