2 * arch/ia64/kernel/crash.c
4 * Architecture specific (ia64) functions for kexec based crash dumps.
6 * Created by: Khalid Aziz <khalid.aziz@hp.com>
7 * Copyright (C) 2005 Hewlett-Packard Development Company, L.P.
8 * Copyright (C) 2005 Intel Corp Zou Nan hai <nanhai.zou@intel.com>
11 #include <linux/smp.h>
12 #include <linux/delay.h>
13 #include <linux/crash_dump.h>
14 #include <linux/bootmem.h>
15 #include <linux/kexec.h>
16 #include <linux/elfcore.h>
17 #include <linux/sysctl.h>
18 #include <linux/init.h>
20 #include <asm/kdebug.h>
22 #include <asm/uaccess.h>
24 int kdump_status[NR_CPUS];
25 atomic_t kdump_cpu_freezed;
26 atomic_t kdump_in_progress;
27 int kdump_on_init = 1;
29 copy_oldmem_page(unsigned long pfn, char *buf,
30 size_t csize, unsigned long offset, int userbuf)
36 vaddr = __va(pfn<<PAGE_SHIFT);
38 if (copy_to_user(buf, (vaddr + offset), csize)) {
42 memcpy(buf, (vaddr + offset), csize);
46 static inline Elf64_Word
47 *append_elf_note(Elf64_Word *buf, char *name, unsigned type, void *data,
50 struct elf_note *note = (struct elf_note *)buf;
51 note->n_namesz = strlen(name) + 1;
52 note->n_descsz = data_len;
54 buf += (sizeof(*note) + 3)/4;
55 memcpy(buf, name, note->n_namesz);
56 buf += (note->n_namesz + 3)/4;
57 memcpy(buf, data, data_len);
58 buf += (data_len + 3)/4;
65 memset(buf, 0, sizeof(struct elf_note));
68 extern void ia64_dump_cpu_regs(void *);
70 static DEFINE_PER_CPU(struct elf_prstatus, elf_prstatus);
76 unsigned long cfm, sof, sol;
78 int cpu = smp_processor_id();
79 struct elf_prstatus *prstatus = &per_cpu(elf_prstatus, cpu);
81 elf_greg_t *dst = (elf_greg_t *)&(prstatus->pr_reg);
82 memset(prstatus, 0, sizeof(*prstatus));
83 prstatus->pr_pid = current->pid;
85 ia64_dump_cpu_regs(dst);
87 sol = (cfm >> 7) & 0x7f;
89 dst[46] = (unsigned long)ia64_rse_skip_regs((unsigned long *)dst[46],
92 buf = (u64 *) per_cpu_ptr(crash_notes, cpu);
95 buf = append_elf_note(buf, "CORE", NT_PRSTATUS, prstatus,
101 kdump_wait_cpu_freeze(void)
103 int cpu_num = num_online_cpus() - 1;
105 while(timeout-- > 0) {
106 if (atomic_read(&kdump_cpu_freezed) == cpu_num)
114 machine_crash_shutdown(struct pt_regs *pt)
116 /* This function is only called after the system
117 * has paniced or is otherwise in a critical state.
118 * The minimum amount of code to allow a kexec'd kernel
119 * to run successfully needs to happen here.
121 * In practice this means shooting down the other cpus in
124 kexec_disable_iosapic();
126 kdump_smp_send_stop();
127 if (kdump_wait_cpu_freeze() && kdump_on_init) {
128 //not all cpu response to IPI, send INIT to freeze them
129 kdump_smp_send_init();
135 machine_kdump_on_init(void)
138 kexec_disable_iosapic();
139 machine_kexec(ia64_kimage);
143 kdump_cpu_freeze(struct unw_frame_info *info, void *arg)
147 cpuid = smp_processor_id();
148 crash_save_this_cpu();
149 current->thread.ksp = (__u64)info->sw - 16;
150 atomic_inc(&kdump_cpu_freezed);
151 kdump_status[cpuid] = 1;
157 ia64_jump_to_sal(&sal_boot_rendez_state[cpuid]);
161 kdump_init_notifier(struct notifier_block *self, unsigned long val, void *data)
163 struct ia64_mca_notify_die *nd;
164 struct die_args *args = data;
169 if (val != DIE_INIT_MONARCH_ENTER &&
170 val != DIE_INIT_SLAVE_ENTER &&
171 val != DIE_MCA_RENDZVOUS_LEAVE &&
172 val != DIE_MCA_MONARCH_LEAVE)
175 nd = (struct ia64_mca_notify_die *)args->err;
176 /* Reason code 1 means machine check rendezous*/
177 if ((val == DIE_INIT_MONARCH_ENTER || DIE_INIT_SLAVE_ENTER) &&
182 case DIE_INIT_MONARCH_ENTER:
183 machine_kdump_on_init();
185 case DIE_INIT_SLAVE_ENTER:
186 unw_init_running(kdump_cpu_freeze, NULL);
188 case DIE_MCA_RENDZVOUS_LEAVE:
189 if (atomic_read(&kdump_in_progress))
190 unw_init_running(kdump_cpu_freeze, NULL);
192 case DIE_MCA_MONARCH_LEAVE:
193 /* die_register->signr indicate if MCA is recoverable */
195 machine_kdump_on_init();
202 static ctl_table kdump_on_init_table[] = {
204 .ctl_name = CTL_UNNUMBERED,
205 .procname = "kdump_on_init",
206 .data = &kdump_on_init,
207 .maxlen = sizeof(int),
209 .proc_handler = &proc_dointvec,
214 static ctl_table sys_table[] = {
216 .ctl_name = CTL_KERN,
217 .procname = "kernel",
219 .child = kdump_on_init_table,
226 machine_crash_setup(void)
228 char *from = strstr(saved_command_line, "elfcorehdr=");
229 static struct notifier_block kdump_init_notifier_nb = {
230 .notifier_call = kdump_init_notifier,
234 elfcorehdr_addr = memparse(from+11, &from);
235 saved_max_pfn = (unsigned long)-1;
236 if((ret = register_die_notifier(&kdump_init_notifier_nb)) != 0)
239 register_sysctl_table(sys_table, 0);
244 __initcall(machine_crash_setup);