crash.c revision 8385a6a3acfbb4b68150c25cfe9084b6c4f501cf
1/* 2 * Architecture specific (PPC64) functions for kexec based crash dumps. 3 * 4 * Copyright (C) 2005, IBM Corp. 5 * 6 * Created by: Haren Myneni 7 * 8 * This source code is licensed under the GNU General Public License, 9 * Version 2. See the file COPYING for more details. 10 * 11 */ 12 13#undef DEBUG 14 15#include <linux/kernel.h> 16#include <linux/smp.h> 17#include <linux/reboot.h> 18#include <linux/kexec.h> 19#include <linux/bootmem.h> 20#include <linux/crash_dump.h> 21#include <linux/delay.h> 22#include <linux/elf.h> 23#include <linux/elfcore.h> 24#include <linux/init.h> 25#include <linux/types.h> 26 27#include <asm/processor.h> 28#include <asm/machdep.h> 29#include <asm/kdump.h> 30#include <asm/lmb.h> 31#include <asm/firmware.h> 32#include <asm/smp.h> 33 34#ifdef DEBUG 35#include <asm/udbg.h> 36#define DBG(fmt...) udbg_printf(fmt) 37#else 38#define DBG(fmt...) 39#endif 40 41/* This keeps a track of which one is crashing cpu. */ 42int crashing_cpu = -1; 43 44static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data, 45 size_t data_len) 46{ 47 struct elf_note note; 48 49 note.n_namesz = strlen(name) + 1; 50 note.n_descsz = data_len; 51 note.n_type = type; 52 memcpy(buf, ¬e, sizeof(note)); 53 buf += (sizeof(note) +3)/4; 54 memcpy(buf, name, note.n_namesz); 55 buf += (note.n_namesz + 3)/4; 56 memcpy(buf, data, note.n_descsz); 57 buf += (note.n_descsz + 3)/4; 58 59 return buf; 60} 61 62static void final_note(u32 *buf) 63{ 64 struct elf_note note; 65 66 note.n_namesz = 0; 67 note.n_descsz = 0; 68 note.n_type = 0; 69 memcpy(buf, ¬e, sizeof(note)); 70} 71 72static void crash_save_this_cpu(struct pt_regs *regs, int cpu) 73{ 74 struct elf_prstatus prstatus; 75 u32 *buf; 76 77 if ((cpu < 0) || (cpu >= NR_CPUS)) 78 return; 79 80 /* Using ELF notes here is opportunistic. 81 * I need a well defined structure format 82 * for the data I pass, and I need tags 83 * on the data to indicate what information I have 84 * squirrelled away. ELF notes happen to provide 85 * all of that that no need to invent something new. 86 */ 87 buf = (u32*)per_cpu_ptr(crash_notes, cpu); 88 if (!buf) 89 return; 90 91 memset(&prstatus, 0, sizeof(prstatus)); 92 prstatus.pr_pid = current->pid; 93 elf_core_copy_regs(&prstatus.pr_reg, regs); 94 buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus, 95 sizeof(prstatus)); 96 final_note(buf); 97} 98 99#ifdef CONFIG_SMP 100static atomic_t waiting_for_crash_ipi; 101 102void crash_ipi_callback(struct pt_regs *regs) 103{ 104 int cpu = smp_processor_id(); 105 106 if (cpu == crashing_cpu) 107 return; 108 109 if (!cpu_online(cpu)) 110 return; 111 112 if (ppc_md.kexec_cpu_down) 113 ppc_md.kexec_cpu_down(1, 1); 114 115 local_irq_disable(); 116 117 crash_save_this_cpu(regs, cpu); 118 atomic_dec(&waiting_for_crash_ipi); 119 kexec_smp_wait(); 120 /* NOTREACHED */ 121} 122 123static void crash_kexec_prepare_cpus(void) 124{ 125 unsigned int msecs; 126 127 atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); 128 129 crash_send_ipi(crash_ipi_callback); 130 smp_wmb(); 131 132 /* 133 * FIXME: Until we will have the way to stop other CPUSs reliabally, 134 * the crash CPU will send an IPI and wait for other CPUs to 135 * respond. If not, proceed the kexec boot even though we failed to 136 * capture other CPU states. 137 */ 138 msecs = 1000000; 139 while ((atomic_read(&waiting_for_crash_ipi) > 0) && (--msecs > 0)) { 140 barrier(); 141 mdelay(1); 142 } 143 144 /* Would it be better to replace the trap vector here? */ 145 146 /* 147 * FIXME: In case if we do not get all CPUs, one possibility: ask the 148 * user to do soft reset such that we get all. 149 * IPI handler is already set by the panic cpu initially. Therefore, 150 * all cpus could invoke this handler from die() and the panic CPU 151 * will call machine_kexec() directly from this handler to do 152 * kexec boot. 153 */ 154 if (atomic_read(&waiting_for_crash_ipi)) 155 printk(KERN_ALERT "done waiting: %d cpus not responding\n", 156 atomic_read(&waiting_for_crash_ipi)); 157 /* Leave the IPI callback set */ 158} 159#else 160static void crash_kexec_prepare_cpus(void) 161{ 162 /* 163 * move the secondarys to us so that we can copy 164 * the new kernel 0-0x100 safely 165 * 166 * do this if kexec in setup.c ? 167 */ 168 smp_release_cpus(); 169} 170 171#endif 172 173void default_machine_crash_shutdown(struct pt_regs *regs) 174{ 175 /* 176 * This function is only called after the system 177 * has paniced or is otherwise in a critical state. 178 * The minimum amount of code to allow a kexec'd kernel 179 * to run successfully needs to happen here. 180 * 181 * In practice this means stopping other cpus in 182 * an SMP system. 183 * The kernel is broken so disable interrupts. 184 */ 185 local_irq_disable(); 186 187 if (ppc_md.kexec_cpu_down) 188 ppc_md.kexec_cpu_down(1, 0); 189 190 /* 191 * Make a note of crashing cpu. Will be used in machine_kexec 192 * such that another IPI will not be sent. 193 */ 194 crashing_cpu = smp_processor_id(); 195 crash_kexec_prepare_cpus(); 196 crash_save_this_cpu(regs, crashing_cpu); 197} 198