Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[IA64] IA64 Kexec/kdump

Changes and updates.

1. Remove fake rendz path and related code according to discuss with Khalid Aziz.
2. fc.i offset fix in relocate_kernel.S.
3. iospic shutdown code eoi and mask race fix from Fujitsu.
4. Warm boot hook in machine_kexec to SN SAL code from Jack Steiner.
5. Send slave to SAL slave loop patch from Jay Lan.
6. Kdump on non-recoverable MCA event patch from Jay Lan
7. Use CTL_UNNUMBERED in kdump_on_init sysctl.

Signed-off-by: Zou Nan hai <nanhai.zou@intel.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>

authored by

Zou Nan hai and committed by
Tony Luck
a7956113 620034c8

+969 -6
+23
arch/ia64/Kconfig
··· 434 434 435 435 source "drivers/sn/Kconfig" 436 436 437 + config KEXEC 438 + bool "kexec system call (EXPERIMENTAL)" 439 + depends on EXPERIMENTAL && !IA64_HP_SIM && (!SMP || HOTPLUG_CPU) 440 + help 441 + kexec is a system call that implements the ability to shutdown your 442 + current kernel, and to start another kernel. It is like a reboot 443 + but it is indepedent of the system firmware. And like a reboot 444 + you can start any kernel with it, not just Linux. 445 + 446 + The name comes from the similiarity to the exec system call. 447 + 448 + It is an ongoing process to be certain the hardware in a machine 449 + is properly shutdown, so do not be surprised if this code does not 450 + initially work for you. It may help to enable device hotplugging 451 + support. As of this writing the exact hardware interface is 452 + strongly in flux, so no good recommendation can be made. 453 + 454 + config CRASH_DUMP 455 + bool "kernel crash dumps (EXPERIMENTAL)" 456 + depends on EXPERIMENTAL && IA64_MCA_RECOVERY && !IA64_HP_SIM && (!SMP || HOTPLUG_CPU) 457 + help 458 + Generate crash dump after being started by kexec. 459 + 437 460 source "drivers/firmware/Kconfig" 438 461 439 462 source "fs/Kconfig.binfmt"
+1
arch/ia64/kernel/Makefile
··· 28 28 obj-$(CONFIG_CPU_FREQ) += cpufreq/ 29 29 obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o 30 30 obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o 31 + obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o 31 32 obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o 32 33 obj-$(CONFIG_AUDIT) += audit.o 33 34 obj-$(CONFIG_PCI_MSI) += msi_ia64.o
+245
arch/ia64/kernel/crash.c
··· 1 + /* 2 + * arch/ia64/kernel/crash.c 3 + * 4 + * Architecture specific (ia64) functions for kexec based crash dumps. 5 + * 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> 9 + * 10 + */ 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> 19 + 20 + #include <asm/kdebug.h> 21 + #include <asm/mca.h> 22 + #include <asm/uaccess.h> 23 + 24 + int kdump_status[NR_CPUS]; 25 + atomic_t kdump_cpu_freezed; 26 + atomic_t kdump_in_progress; 27 + int kdump_on_init = 1; 28 + ssize_t 29 + copy_oldmem_page(unsigned long pfn, char *buf, 30 + size_t csize, unsigned long offset, int userbuf) 31 + { 32 + void *vaddr; 33 + 34 + if (!csize) 35 + return 0; 36 + vaddr = __va(pfn<<PAGE_SHIFT); 37 + if (userbuf) { 38 + if (copy_to_user(buf, (vaddr + offset), csize)) { 39 + return -EFAULT; 40 + } 41 + } else 42 + memcpy(buf, (vaddr + offset), csize); 43 + return csize; 44 + } 45 + 46 + static inline Elf64_Word 47 + *append_elf_note(Elf64_Word *buf, char *name, unsigned type, void *data, 48 + size_t data_len) 49 + { 50 + struct elf_note *note = (struct elf_note *)buf; 51 + note->n_namesz = strlen(name) + 1; 52 + note->n_descsz = data_len; 53 + note->n_type = type; 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; 59 + return buf; 60 + } 61 + 62 + static void 63 + final_note(void *buf) 64 + { 65 + memset(buf, 0, sizeof(struct elf_note)); 66 + } 67 + 68 + extern void ia64_dump_cpu_regs(void *); 69 + 70 + static DEFINE_PER_CPU(struct elf_prstatus, elf_prstatus); 71 + 72 + void 73 + crash_save_this_cpu() 74 + { 75 + void *buf; 76 + unsigned long cfm, sof, sol; 77 + 78 + int cpu = smp_processor_id(); 79 + struct elf_prstatus *prstatus = &per_cpu(elf_prstatus, cpu); 80 + 81 + elf_greg_t *dst = (elf_greg_t *)&(prstatus->pr_reg); 82 + memset(prstatus, 0, sizeof(*prstatus)); 83 + prstatus->pr_pid = current->pid; 84 + 85 + ia64_dump_cpu_regs(dst); 86 + cfm = dst[43]; 87 + sol = (cfm >> 7) & 0x7f; 88 + sof = cfm & 0x7f; 89 + dst[46] = (unsigned long)ia64_rse_skip_regs((unsigned long *)dst[46], 90 + sof - sol); 91 + 92 + buf = (u64 *) per_cpu_ptr(crash_notes, cpu); 93 + if (!buf) 94 + return; 95 + buf = append_elf_note(buf, "CORE", NT_PRSTATUS, prstatus, 96 + sizeof(*prstatus)); 97 + final_note(buf); 98 + } 99 + 100 + static int 101 + kdump_wait_cpu_freeze(void) 102 + { 103 + int cpu_num = num_online_cpus() - 1; 104 + int timeout = 1000; 105 + while(timeout-- > 0) { 106 + if (atomic_read(&kdump_cpu_freezed) == cpu_num) 107 + return 0; 108 + udelay(1000); 109 + } 110 + return 1; 111 + } 112 + 113 + void 114 + machine_crash_shutdown(struct pt_regs *pt) 115 + { 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. 120 + * 121 + * In practice this means shooting down the other cpus in 122 + * an SMP system. 123 + */ 124 + kexec_disable_iosapic(); 125 + #ifdef CONFIG_SMP 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(); 130 + } 131 + #endif 132 + } 133 + 134 + static void 135 + machine_kdump_on_init(void) 136 + { 137 + local_irq_disable(); 138 + kexec_disable_iosapic(); 139 + machine_kexec(ia64_kimage); 140 + } 141 + 142 + void 143 + kdump_cpu_freeze(struct unw_frame_info *info, void *arg) 144 + { 145 + int cpuid; 146 + local_irq_disable(); 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; 152 + mb(); 153 + if (cpuid == 0) { 154 + for (;;) 155 + cpu_relax(); 156 + } else 157 + ia64_jump_to_sal(&sal_boot_rendez_state[cpuid]); 158 + } 159 + 160 + static int 161 + kdump_init_notifier(struct notifier_block *self, unsigned long val, void *data) 162 + { 163 + struct ia64_mca_notify_die *nd; 164 + struct die_args *args = data; 165 + 166 + if (!kdump_on_init) 167 + return NOTIFY_DONE; 168 + 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) 173 + return NOTIFY_DONE; 174 + 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) && 178 + nd->sos->rv_rc == 1) 179 + return NOTIFY_DONE; 180 + 181 + switch (val) { 182 + case DIE_INIT_MONARCH_ENTER: 183 + machine_kdump_on_init(); 184 + break; 185 + case DIE_INIT_SLAVE_ENTER: 186 + unw_init_running(kdump_cpu_freeze, NULL); 187 + break; 188 + case DIE_MCA_RENDZVOUS_LEAVE: 189 + if (atomic_read(&kdump_in_progress)) 190 + unw_init_running(kdump_cpu_freeze, NULL); 191 + break; 192 + case DIE_MCA_MONARCH_LEAVE: 193 + /* die_register->signr indicate if MCA is recoverable */ 194 + if (!args->signr) 195 + machine_kdump_on_init(); 196 + break; 197 + } 198 + return NOTIFY_DONE; 199 + } 200 + 201 + #ifdef CONFIG_SYSCTL 202 + static ctl_table kdump_on_init_table[] = { 203 + { 204 + .ctl_name = CTL_UNNUMBERED, 205 + .procname = "kdump_on_init", 206 + .data = &kdump_on_init, 207 + .maxlen = sizeof(int), 208 + .mode = 0644, 209 + .proc_handler = &proc_dointvec, 210 + }, 211 + { .ctl_name = 0 } 212 + }; 213 + 214 + static ctl_table sys_table[] = { 215 + { 216 + .ctl_name = CTL_KERN, 217 + .procname = "kernel", 218 + .mode = 0555, 219 + .child = kdump_on_init_table, 220 + }, 221 + { .ctl_name = 0 } 222 + }; 223 + #endif 224 + 225 + static int 226 + machine_crash_setup(void) 227 + { 228 + char *from = strstr(saved_command_line, "elfcorehdr="); 229 + static struct notifier_block kdump_init_notifier_nb = { 230 + .notifier_call = kdump_init_notifier, 231 + }; 232 + int ret; 233 + if (from) 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) 237 + return ret; 238 + #ifdef CONFIG_SYSCTL 239 + register_sysctl_table(sys_table, 0); 240 + #endif 241 + return 0; 242 + } 243 + 244 + __initcall(machine_crash_setup); 245 +
+62 -3
arch/ia64/kernel/efi.c
··· 26 26 #include <linux/types.h> 27 27 #include <linux/time.h> 28 28 #include <linux/efi.h> 29 + #include <linux/kexec.h> 29 30 30 31 #include <asm/io.h> 31 32 #include <asm/kregs.h> ··· 42 41 struct efi efi; 43 42 EXPORT_SYMBOL(efi); 44 43 static efi_runtime_services_t *runtime; 45 - static unsigned long mem_limit = ~0UL, max_addr = ~0UL; 44 + static unsigned long mem_limit = ~0UL, max_addr = ~0UL, min_addr = 0UL; 46 45 47 46 #define efi_call_virt(f, args...) (*(f))(args) 48 47 ··· 422 421 mem_limit = memparse(cp + 4, &cp); 423 422 } else if (memcmp(cp, "max_addr=", 9) == 0) { 424 423 max_addr = GRANULEROUNDDOWN(memparse(cp + 9, &cp)); 424 + } else if (memcmp(cp, "min_addr=", 9) == 0) { 425 + min_addr = GRANULEROUNDDOWN(memparse(cp + 9, &cp)); 425 426 } else { 426 427 while (*cp != ' ' && *cp) 427 428 ++cp; ··· 431 428 ++cp; 432 429 } 433 430 } 431 + if (min_addr != 0UL) 432 + printk(KERN_INFO "Ignoring memory below %luMB\n", min_addr >> 20); 434 433 if (max_addr != ~0UL) 435 434 printk(KERN_INFO "Ignoring memory above %luMB\n", max_addr >> 20); 436 435 ··· 899 894 as = max(contig_low, md->phys_addr); 900 895 ae = min(contig_high, efi_md_end(md)); 901 896 902 - /* keep within max_addr= command line arg */ 897 + /* keep within max_addr= and min_addr= command line arg */ 898 + as = max(as, min_addr); 903 899 ae = min(ae, max_addr); 904 900 if (ae <= as) 905 901 continue; ··· 1010 1004 } else 1011 1005 ae = efi_md_end(md); 1012 1006 1013 - /* keep within max_addr= command line arg */ 1007 + /* keep within max_addr= and min_addr= command line arg */ 1008 + as = max(as, min_addr); 1014 1009 ae = min(ae, max_addr); 1015 1010 if (ae <= as) 1016 1011 continue; ··· 1123 1116 */ 1124 1117 insert_resource(res, code_resource); 1125 1118 insert_resource(res, data_resource); 1119 + #ifdef CONFIG_KEXEC 1120 + insert_resource(res, &efi_memmap_res); 1121 + insert_resource(res, &boot_param_res); 1122 + if (crashk_res.end > crashk_res.start) 1123 + insert_resource(res, &crashk_res); 1124 + #endif 1126 1125 } 1127 1126 } 1128 1127 } 1128 + 1129 + #ifdef CONFIG_KEXEC 1130 + /* find a block of memory aligned to 64M exclude reserved regions 1131 + rsvd_regions are sorted 1132 + */ 1133 + unsigned long 1134 + kdump_find_rsvd_region (unsigned long size, 1135 + struct rsvd_region *r, int n) 1136 + { 1137 + int i; 1138 + u64 start, end; 1139 + u64 alignment = 1UL << _PAGE_SIZE_64M; 1140 + void *efi_map_start, *efi_map_end, *p; 1141 + efi_memory_desc_t *md; 1142 + u64 efi_desc_size; 1143 + 1144 + efi_map_start = __va(ia64_boot_param->efi_memmap); 1145 + efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; 1146 + efi_desc_size = ia64_boot_param->efi_memdesc_size; 1147 + 1148 + for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { 1149 + md = p; 1150 + if (!efi_wb(md)) 1151 + continue; 1152 + start = ALIGN(md->phys_addr, alignment); 1153 + end = efi_md_end(md); 1154 + for (i = 0; i < n; i++) { 1155 + if (__pa(r[i].start) >= start && __pa(r[i].end) < end) { 1156 + if (__pa(r[i].start) > start + size) 1157 + return start; 1158 + start = ALIGN(__pa(r[i].end), alignment); 1159 + if (i < n-1 && __pa(r[i+1].start) < start + size) 1160 + continue; 1161 + else 1162 + break; 1163 + } 1164 + } 1165 + if (end > start + size) 1166 + return start; 1167 + } 1168 + 1169 + printk(KERN_WARNING "Cannot reserve 0x%lx byte of memory for crashdump\n", 1170 + size); 1171 + return ~0UL; 1172 + } 1173 + #endif
+1 -1
arch/ia64/kernel/entry.S
··· 1575 1575 data8 sys_mq_timedreceive // 1265 1576 1576 data8 sys_mq_notify 1577 1577 data8 sys_mq_getsetattr 1578 - data8 sys_ni_syscall // reserved for kexec_load 1578 + data8 sys_kexec_load 1579 1579 data8 sys_ni_syscall // reserved for vserver 1580 1580 data8 sys_waitid // 1270 1581 1581 data8 sys_add_key
+21
arch/ia64/kernel/iosapic.c
··· 288 288 /* do nothing... */ 289 289 } 290 290 291 + 292 + #ifdef CONFIG_KEXEC 293 + void 294 + kexec_disable_iosapic(void) 295 + { 296 + struct iosapic_intr_info *info; 297 + struct iosapic_rte_info *rte; 298 + u8 vec = 0; 299 + for (info = iosapic_intr_info; info < 300 + iosapic_intr_info + IA64_NUM_VECTORS; ++info, ++vec) { 301 + list_for_each_entry(rte, &info->rtes, 302 + rte_list) { 303 + iosapic_write(rte->addr, 304 + IOSAPIC_RTE_LOW(rte->rte_index), 305 + IOSAPIC_MASK|vec); 306 + iosapic_eoi(rte->addr, vec); 307 + } 308 + } 309 + } 310 + #endif 311 + 291 312 static void 292 313 mask_irq (unsigned int irq) 293 314 {
+133
arch/ia64/kernel/machine_kexec.c
··· 1 + /* 2 + * arch/ia64/kernel/machine_kexec.c 3 + * 4 + * Handle transition of Linux booting another kernel 5 + * Copyright (C) 2005 Hewlett-Packard Development Comapny, L.P. 6 + * Copyright (C) 2005 Khalid Aziz <khalid.aziz@hp.com> 7 + * Copyright (C) 2006 Intel Corp, Zou Nan hai <nanhai.zou@intel.com> 8 + * 9 + * This source code is licensed under the GNU General Public License, 10 + * Version 2. See the file COPYING for more details. 11 + */ 12 + 13 + #include <linux/mm.h> 14 + #include <linux/kexec.h> 15 + #include <linux/cpu.h> 16 + #include <linux/irq.h> 17 + #include <asm/mmu_context.h> 18 + #include <asm/setup.h> 19 + #include <asm/delay.h> 20 + #include <asm/meminit.h> 21 + 22 + typedef void (*relocate_new_kernel_t)(unsigned long, unsigned long, 23 + struct ia64_boot_param *, unsigned long); 24 + 25 + struct kimage *ia64_kimage; 26 + 27 + struct resource efi_memmap_res = { 28 + .name = "EFI Memory Map", 29 + .start = 0, 30 + .end = 0, 31 + .flags = IORESOURCE_BUSY | IORESOURCE_MEM 32 + }; 33 + 34 + struct resource boot_param_res = { 35 + .name = "Boot parameter", 36 + .start = 0, 37 + .end = 0, 38 + .flags = IORESOURCE_BUSY | IORESOURCE_MEM 39 + }; 40 + 41 + 42 + /* 43 + * Do what every setup is needed on image and the 44 + * reboot code buffer to allow us to avoid allocations 45 + * later. 46 + */ 47 + int machine_kexec_prepare(struct kimage *image) 48 + { 49 + void *control_code_buffer; 50 + const unsigned long *func; 51 + 52 + func = (unsigned long *)&relocate_new_kernel; 53 + /* Pre-load control code buffer to minimize work in kexec path */ 54 + control_code_buffer = page_address(image->control_code_page); 55 + memcpy((void *)control_code_buffer, (const void *)func[0], 56 + relocate_new_kernel_size); 57 + flush_icache_range((unsigned long)control_code_buffer, 58 + (unsigned long)control_code_buffer + relocate_new_kernel_size); 59 + ia64_kimage = image; 60 + 61 + return 0; 62 + } 63 + 64 + void machine_kexec_cleanup(struct kimage *image) 65 + { 66 + } 67 + 68 + void machine_shutdown(void) 69 + { 70 + int cpu; 71 + 72 + for_each_online_cpu(cpu) { 73 + if (cpu != smp_processor_id()) 74 + cpu_down(cpu); 75 + } 76 + kexec_disable_iosapic(); 77 + } 78 + 79 + /* 80 + * Do not allocate memory (or fail in any way) in machine_kexec(). 81 + * We are past the point of no return, committed to rebooting now. 82 + */ 83 + extern void *efi_get_pal_addr(void); 84 + static void ia64_machine_kexec(struct unw_frame_info *info, void *arg) 85 + { 86 + struct kimage *image = arg; 87 + relocate_new_kernel_t rnk; 88 + void *pal_addr = efi_get_pal_addr(); 89 + unsigned long code_addr = (unsigned long)page_address(image->control_code_page); 90 + unsigned long vector; 91 + int ii; 92 + 93 + if (image->type == KEXEC_TYPE_CRASH) { 94 + crash_save_this_cpu(); 95 + current->thread.ksp = (__u64)info->sw - 16; 96 + } 97 + 98 + /* Interrupts aren't acceptable while we reboot */ 99 + local_irq_disable(); 100 + 101 + /* Mask CMC and Performance Monitor interrupts */ 102 + ia64_setreg(_IA64_REG_CR_PMV, 1 << 16); 103 + ia64_setreg(_IA64_REG_CR_CMCV, 1 << 16); 104 + 105 + /* Mask ITV and Local Redirect Registers */ 106 + ia64_set_itv(1 << 16); 107 + ia64_set_lrr0(1 << 16); 108 + ia64_set_lrr1(1 << 16); 109 + 110 + /* terminate possible nested in-service interrupts */ 111 + for (ii = 0; ii < 16; ii++) 112 + ia64_eoi(); 113 + 114 + /* unmask TPR and clear any pending interrupts */ 115 + ia64_setreg(_IA64_REG_CR_TPR, 0); 116 + ia64_srlz_d(); 117 + vector = ia64_get_ivr(); 118 + while (vector != IA64_SPURIOUS_INT_VECTOR) { 119 + ia64_eoi(); 120 + vector = ia64_get_ivr(); 121 + } 122 + platform_kernel_launch_event(); 123 + rnk = (relocate_new_kernel_t)&code_addr; 124 + (*rnk)(image->head, image->start, ia64_boot_param, 125 + GRANULEROUNDDOWN((unsigned long) pal_addr)); 126 + BUG(); 127 + } 128 + 129 + void machine_kexec(struct kimage *image) 130 + { 131 + unw_init_running(ia64_machine_kexec, image); 132 + for(;;); 133 + }
+5
arch/ia64/kernel/mca.c
··· 82 82 #include <asm/system.h> 83 83 #include <asm/sal.h> 84 84 #include <asm/mca.h> 85 + #include <asm/kexec.h> 85 86 86 87 #include <asm/irq.h> 87 88 #include <asm/hw_irq.h> ··· 1239 1238 } else { 1240 1239 /* Dump buffered message to console */ 1241 1240 ia64_mlogbuf_finish(1); 1241 + #ifdef CONFIG_CRASH_DUMP 1242 + atomic_set(&kdump_in_progress, 1); 1243 + monarch_cpu = -1; 1244 + #endif 1242 1245 } 1243 1246 if (notify_die(DIE_MCA_MONARCH_LEAVE, "MCA", regs, (long)&nd, 0, recover) 1244 1247 == NOTIFY_STOP)
+334
arch/ia64/kernel/relocate_kernel.S
··· 1 + /* 2 + * arch/ia64/kernel/relocate_kernel.S 3 + * 4 + * Relocate kexec'able kernel and start it 5 + * 6 + * Copyright (C) 2005 Hewlett-Packard Development Company, L.P. 7 + * Copyright (C) 2005 Khalid Aziz <khalid.aziz@hp.com> 8 + * Copyright (C) 2005 Intel Corp, Zou Nan hai <nanhai.zou@intel.com> 9 + * 10 + * This source code is licensed under the GNU General Public License, 11 + * Version 2. See the file COPYING for more details. 12 + */ 13 + #include <asm/asmmacro.h> 14 + #include <asm/kregs.h> 15 + #include <asm/page.h> 16 + #include <asm/pgtable.h> 17 + #include <asm/mca_asm.h> 18 + 19 + /* Must be relocatable PIC code callable as a C function 20 + */ 21 + GLOBAL_ENTRY(relocate_new_kernel) 22 + .prologue 23 + alloc r31=ar.pfs,4,0,0,0 24 + .body 25 + .reloc_entry: 26 + { 27 + rsm psr.i| psr.ic 28 + mov r2=ip 29 + } 30 + ;; 31 + { 32 + flushrs // must be first insn in group 33 + srlz.i 34 + } 35 + ;; 36 + dep r2=0,r2,61,3 //to physical address 37 + ;; 38 + //first switch to physical mode 39 + add r3=1f-.reloc_entry, r2 40 + movl r16 = IA64_PSR_AC|IA64_PSR_BN|IA64_PSR_IC 41 + mov ar.rsc=0 // put RSE in enforced lazy mode 42 + ;; 43 + add sp=(memory_stack_end - 16 - .reloc_entry),r2 44 + add r8=(register_stack - .reloc_entry),r2 45 + ;; 46 + mov r18=ar.rnat 47 + mov ar.bspstore=r8 48 + ;; 49 + mov cr.ipsr=r16 50 + mov cr.iip=r3 51 + mov cr.ifs=r0 52 + srlz.i 53 + ;; 54 + mov ar.rnat=r18 55 + rfi 56 + ;; 57 + 1: 58 + //physical mode code begin 59 + mov b6=in1 60 + dep r28=0,in2,61,3 //to physical address 61 + 62 + // purge all TC entries 63 + #define O(member) IA64_CPUINFO_##member##_OFFSET 64 + GET_THIS_PADDR(r2, cpu_info) // load phys addr of cpu_info into r2 65 + ;; 66 + addl r17=O(PTCE_STRIDE),r2 67 + addl r2=O(PTCE_BASE),r2 68 + ;; 69 + ld8 r18=[r2],(O(PTCE_COUNT)-O(PTCE_BASE));; // r18=ptce_base 70 + ld4 r19=[r2],4 // r19=ptce_count[0] 71 + ld4 r21=[r17],4 // r21=ptce_stride[0] 72 + ;; 73 + ld4 r20=[r2] // r20=ptce_count[1] 74 + ld4 r22=[r17] // r22=ptce_stride[1] 75 + mov r24=r0 76 + ;; 77 + adds r20=-1,r20 78 + ;; 79 + #undef O 80 + 2: 81 + cmp.ltu p6,p7=r24,r19 82 + (p7) br.cond.dpnt.few 4f 83 + mov ar.lc=r20 84 + 3: 85 + ptc.e r18 86 + ;; 87 + add r18=r22,r18 88 + br.cloop.sptk.few 3b 89 + ;; 90 + add r18=r21,r18 91 + add r24=1,r24 92 + ;; 93 + br.sptk.few 2b 94 + 4: 95 + srlz.i 96 + ;; 97 + //purge TR entry for kernel text and data 98 + movl r16=KERNEL_START 99 + mov r18=KERNEL_TR_PAGE_SHIFT<<2 100 + ;; 101 + ptr.i r16, r18 102 + ptr.d r16, r18 103 + ;; 104 + srlz.i 105 + ;; 106 + 107 + // purge TR entry for percpu data 108 + movl r16=PERCPU_ADDR 109 + mov r18=PERCPU_PAGE_SHIFT<<2 110 + ;; 111 + ptr.d r16,r18 112 + ;; 113 + srlz.d 114 + ;; 115 + 116 + // purge TR entry for pal code 117 + mov r16=in3 118 + mov r18=IA64_GRANULE_SHIFT<<2 119 + ;; 120 + ptr.i r16,r18 121 + ;; 122 + srlz.i 123 + ;; 124 + 125 + // purge TR entry for stack 126 + mov r16=IA64_KR(CURRENT_STACK) 127 + ;; 128 + shl r16=r16,IA64_GRANULE_SHIFT 129 + movl r19=PAGE_OFFSET 130 + ;; 131 + add r16=r19,r16 132 + mov r18=IA64_GRANULE_SHIFT<<2 133 + ;; 134 + ptr.d r16,r18 135 + ;; 136 + srlz.i 137 + ;; 138 + 139 + //copy segments 140 + movl r16=PAGE_MASK 141 + mov r30=in0 // in0 is page_list 142 + br.sptk.few .dest_page 143 + ;; 144 + .loop: 145 + ld8 r30=[in0], 8;; 146 + .dest_page: 147 + tbit.z p0, p6=r30, 0;; // 0x1 dest page 148 + (p6) and r17=r30, r16 149 + (p6) br.cond.sptk.few .loop;; 150 + 151 + tbit.z p0, p6=r30, 1;; // 0x2 indirect page 152 + (p6) and in0=r30, r16 153 + (p6) br.cond.sptk.few .loop;; 154 + 155 + tbit.z p0, p6=r30, 2;; // 0x4 end flag 156 + (p6) br.cond.sptk.few .end_loop;; 157 + 158 + tbit.z p6, p0=r30, 3;; // 0x8 source page 159 + (p6) br.cond.sptk.few .loop 160 + 161 + and r18=r30, r16 162 + 163 + // simple copy page, may optimize later 164 + movl r14=PAGE_SIZE/8 - 1;; 165 + mov ar.lc=r14;; 166 + 1: 167 + ld8 r14=[r18], 8;; 168 + st8 [r17]=r14;; 169 + fc.i r17 170 + add r17=8, r17 171 + br.ctop.sptk.few 1b 172 + br.sptk.few .loop 173 + ;; 174 + 175 + .end_loop: 176 + sync.i // for fc.i 177 + ;; 178 + srlz.i 179 + ;; 180 + srlz.d 181 + ;; 182 + br.call.sptk.many b0=b6;; 183 + 184 + .align 32 185 + memory_stack: 186 + .fill 8192, 1, 0 187 + memory_stack_end: 188 + register_stack: 189 + .fill 8192, 1, 0 190 + register_stack_end: 191 + relocate_new_kernel_end: 192 + END(relocate_new_kernel) 193 + 194 + .global relocate_new_kernel_size 195 + relocate_new_kernel_size: 196 + data8 relocate_new_kernel_end - relocate_new_kernel 197 + 198 + GLOBAL_ENTRY(ia64_dump_cpu_regs) 199 + .prologue 200 + alloc loc0=ar.pfs,1,2,0,0 201 + .body 202 + mov ar.rsc=0 // put RSE in enforced lazy mode 203 + add loc1=4*8, in0 // save r4 and r5 first 204 + ;; 205 + { 206 + flushrs // flush dirty regs to backing store 207 + srlz.i 208 + } 209 + st8 [loc1]=r4, 8 210 + ;; 211 + st8 [loc1]=r5, 8 212 + ;; 213 + add loc1=32*8, in0 214 + mov r4=ar.rnat 215 + ;; 216 + st8 [in0]=r0, 8 // r0 217 + st8 [loc1]=r4, 8 // rnat 218 + mov r5=pr 219 + ;; 220 + st8 [in0]=r1, 8 // r1 221 + st8 [loc1]=r5, 8 // pr 222 + mov r4=b0 223 + ;; 224 + st8 [in0]=r2, 8 // r2 225 + st8 [loc1]=r4, 8 // b0 226 + mov r5=b1; 227 + ;; 228 + st8 [in0]=r3, 24 // r3 229 + st8 [loc1]=r5, 8 // b1 230 + mov r4=b2 231 + ;; 232 + st8 [in0]=r6, 8 // r6 233 + st8 [loc1]=r4, 8 // b2 234 + mov r5=b3 235 + ;; 236 + st8 [in0]=r7, 8 // r7 237 + st8 [loc1]=r5, 8 // b3 238 + mov r4=b4 239 + ;; 240 + st8 [in0]=r8, 8 // r8 241 + st8 [loc1]=r4, 8 // b4 242 + mov r5=b5 243 + ;; 244 + st8 [in0]=r9, 8 // r9 245 + st8 [loc1]=r5, 8 // b5 246 + mov r4=b6 247 + ;; 248 + st8 [in0]=r10, 8 // r10 249 + st8 [loc1]=r5, 8 // b6 250 + mov r5=b7 251 + ;; 252 + st8 [in0]=r11, 8 // r11 253 + st8 [loc1]=r5, 8 // b7 254 + mov r4=b0 255 + ;; 256 + st8 [in0]=r12, 8 // r12 257 + st8 [loc1]=r4, 8 // ip 258 + mov r5=loc0 259 + ;; 260 + st8 [in0]=r13, 8 // r13 261 + extr.u r5=r5, 0, 38 // ar.pfs.pfm 262 + mov r4=r0 // user mask 263 + ;; 264 + st8 [in0]=r14, 8 // r14 265 + st8 [loc1]=r5, 8 // cfm 266 + ;; 267 + st8 [in0]=r15, 8 // r15 268 + st8 [loc1]=r4, 8 // user mask 269 + mov r5=ar.rsc 270 + ;; 271 + st8 [in0]=r16, 8 // r16 272 + st8 [loc1]=r5, 8 // ar.rsc 273 + mov r4=ar.bsp 274 + ;; 275 + st8 [in0]=r17, 8 // r17 276 + st8 [loc1]=r4, 8 // ar.bsp 277 + mov r5=ar.bspstore 278 + ;; 279 + st8 [in0]=r18, 8 // r18 280 + st8 [loc1]=r5, 8 // ar.bspstore 281 + mov r4=ar.rnat 282 + ;; 283 + st8 [in0]=r19, 8 // r19 284 + st8 [loc1]=r4, 8 // ar.rnat 285 + mov r5=ar.ccv 286 + ;; 287 + st8 [in0]=r20, 8 // r20 288 + st8 [loc1]=r5, 8 // ar.ccv 289 + mov r4=ar.unat 290 + ;; 291 + st8 [in0]=r21, 8 // r21 292 + st8 [loc1]=r4, 8 // ar.unat 293 + mov r5 = ar.fpsr 294 + ;; 295 + st8 [in0]=r22, 8 // r22 296 + st8 [loc1]=r5, 8 // ar.fpsr 297 + mov r4 = ar.unat 298 + ;; 299 + st8 [in0]=r23, 8 // r23 300 + st8 [loc1]=r4, 8 // unat 301 + mov r5 = ar.fpsr 302 + ;; 303 + st8 [in0]=r24, 8 // r24 304 + st8 [loc1]=r5, 8 // fpsr 305 + mov r4 = ar.pfs 306 + ;; 307 + st8 [in0]=r25, 8 // r25 308 + st8 [loc1]=r4, 8 // ar.pfs 309 + mov r5 = ar.lc 310 + ;; 311 + st8 [in0]=r26, 8 // r26 312 + st8 [loc1]=r5, 8 // ar.lc 313 + mov r4 = ar.ec 314 + ;; 315 + st8 [in0]=r27, 8 // r27 316 + st8 [loc1]=r4, 8 // ar.ec 317 + mov r5 = ar.csd 318 + ;; 319 + st8 [in0]=r28, 8 // r28 320 + st8 [loc1]=r5, 8 // ar.csd 321 + mov r4 = ar.ssd 322 + ;; 323 + st8 [in0]=r29, 8 // r29 324 + st8 [loc1]=r4, 8 // ar.ssd 325 + ;; 326 + st8 [in0]=r30, 8 // r30 327 + ;; 328 + st8 [in0]=r31, 8 // r31 329 + mov ar.pfs=loc0 330 + ;; 331 + br.ret.sptk.many rp 332 + END(ia64_dump_cpu_regs) 333 + 334 +
+38
arch/ia64/kernel/setup.c
··· 43 43 #include <linux/initrd.h> 44 44 #include <linux/pm.h> 45 45 #include <linux/cpufreq.h> 46 + #include <linux/kexec.h> 47 + #include <linux/crash_dump.h> 46 48 47 49 #include <asm/ia32.h> 48 50 #include <asm/machvec.h> ··· 254 252 efi_memmap_init(&rsvd_region[n].start, &rsvd_region[n].end); 255 253 n++; 256 254 255 + #ifdef CONFIG_KEXEC 256 + /* crashkernel=size@offset specifies the size to reserve for a crash 257 + * kernel.(offset is ingored for keep compatibility with other archs) 258 + * By reserving this memory we guarantee that linux never set's it 259 + * up as a DMA target.Useful for holding code to do something 260 + * appropriate after a kernel panic. 261 + */ 262 + { 263 + char *from = strstr(saved_command_line, "crashkernel="); 264 + unsigned long base, size; 265 + if (from) { 266 + size = memparse(from + 12, &from); 267 + if (size) { 268 + sort_regions(rsvd_region, n); 269 + base = kdump_find_rsvd_region(size, 270 + rsvd_region, n); 271 + if (base != ~0UL) { 272 + rsvd_region[n].start = 273 + (unsigned long)__va(base); 274 + rsvd_region[n].end = 275 + (unsigned long)__va(base + size); 276 + n++; 277 + crashk_res.start = base; 278 + crashk_res.end = base + size - 1; 279 + } 280 + } 281 + } 282 + efi_memmap_res.start = ia64_boot_param->efi_memmap; 283 + efi_memmap_res.end = efi_memmap_res.start + 284 + ia64_boot_param->efi_memmap_size; 285 + boot_param_res.start = __pa(ia64_boot_param); 286 + boot_param_res.end = boot_param_res.start + 287 + sizeof(*ia64_boot_param); 288 + } 289 + #endif 257 290 /* end of memory marker */ 258 291 rsvd_region[n].start = ~0UL; 259 292 rsvd_region[n].end = ~0UL; ··· 299 262 300 263 sort_regions(rsvd_region, num_rsvd_regions); 301 264 } 265 + 302 266 303 267 /** 304 268 * find_initrd - get initrd parameters from the boot parameter structure
+27 -1
arch/ia64/kernel/smp.c
··· 30 30 #include <linux/delay.h> 31 31 #include <linux/efi.h> 32 32 #include <linux/bitops.h> 33 + #include <linux/kexec.h> 33 34 34 35 #include <asm/atomic.h> 35 36 #include <asm/current.h> ··· 67 66 68 67 #define IPI_CALL_FUNC 0 69 68 #define IPI_CPU_STOP 1 69 + #define IPI_KDUMP_CPU_STOP 3 70 70 71 71 /* This needs to be cacheline aligned because it is written to by *other* CPUs. */ 72 72 static DEFINE_PER_CPU(u64, ipi_operation) ____cacheline_aligned; ··· 157 155 case IPI_CPU_STOP: 158 156 stop_this_cpu(); 159 157 break; 160 - 158 + #ifdef CONFIG_CRASH_DUMP 159 + case IPI_KDUMP_CPU_STOP: 160 + unw_init_running(kdump_cpu_freeze, NULL); 161 + break; 162 + #endif 161 163 default: 162 164 printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which); 163 165 break; ··· 219 213 send_IPI_single(smp_processor_id(), op); 220 214 } 221 215 216 + #ifdef CONFIG_CRASH_DUMP 217 + void 218 + kdump_smp_send_stop() 219 + { 220 + send_IPI_allbutself(IPI_KDUMP_CPU_STOP); 221 + } 222 + 223 + void 224 + kdump_smp_send_init() 225 + { 226 + unsigned int cpu, self_cpu; 227 + self_cpu = smp_processor_id(); 228 + for_each_online_cpu(cpu) { 229 + if (cpu != self_cpu) { 230 + if(kdump_status[cpu] == 0) 231 + platform_send_ipi(cpu, 0, IA64_IPI_DM_INIT, 0); 232 + } 233 + } 234 + } 235 + #endif 222 236 /* 223 237 * Called with preeemption disabled. 224 238 */
+8
arch/ia64/sn/kernel/setup.c
··· 769 769 return 0; 770 770 return test_bit(id, sn_prom_features); 771 771 } 772 + 773 + void 774 + sn_kernel_launch_event(void) 775 + { 776 + /* ignore status until we understand possible failure, if any*/ 777 + if (ia64_sn_kernel_launch_event()) 778 + printk(KERN_ERR "KEXEC is not supported in this PROM, Please update the PROM.\n"); 779 + } 772 780 EXPORT_SYMBOL(sn_prom_feature_available); 773 781
+47
include/asm-ia64/kexec.h
··· 1 + #ifndef _ASM_IA64_KEXEC_H 2 + #define _ASM_IA64_KEXEC_H 3 + 4 + 5 + /* Maximum physical address we can use pages from */ 6 + #define KEXEC_SOURCE_MEMORY_LIMIT (-1UL) 7 + /* Maximum address we can reach in physical address mode */ 8 + #define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL) 9 + /* Maximum address we can use for the control code buffer */ 10 + #define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE 11 + 12 + #define KEXEC_CONTROL_CODE_SIZE (8192 + 8192 + 4096) 13 + 14 + /* The native architecture */ 15 + #define KEXEC_ARCH KEXEC_ARCH_IA_64 16 + 17 + #define MAX_NOTE_BYTES 1024 18 + 19 + #define kexec_flush_icache_page(page) do { \ 20 + unsigned long page_addr = (unsigned long)page_address(page); \ 21 + flush_icache_range(page_addr, page_addr + PAGE_SIZE); \ 22 + } while(0) 23 + 24 + extern struct kimage *ia64_kimage; 25 + DECLARE_PER_CPU(u64, ia64_mca_pal_base); 26 + const extern unsigned int relocate_new_kernel_size; 27 + extern void relocate_new_kernel(unsigned long, unsigned long, 28 + struct ia64_boot_param *, unsigned long); 29 + static inline void 30 + crash_setup_regs(struct pt_regs *newregs, struct pt_regs *oldregs) 31 + { 32 + } 33 + extern struct resource efi_memmap_res; 34 + extern struct resource boot_param_res; 35 + extern void kdump_smp_send_stop(void); 36 + extern void kdump_smp_send_init(void); 37 + extern void kexec_disable_iosapic(void); 38 + extern void crash_save_this_cpu(void); 39 + struct rsvd_region; 40 + extern unsigned long kdump_find_rsvd_region(unsigned long size, 41 + struct rsvd_region *rsvd_regions, int n); 42 + extern void kdump_cpu_freeze(struct unw_frame_info *info, void *arg); 43 + extern int kdump_status[]; 44 + extern atomic_t kdump_cpu_freezed; 45 + extern atomic_t kdump_in_progress; 46 + 47 + #endif /* _ASM_IA64_KEXEC_H */
+5
include/asm-ia64/machvec.h
··· 37 37 u8 size); 38 38 typedef void ia64_mv_migrate_t(struct task_struct * task); 39 39 typedef void ia64_mv_pci_fixup_bus_t (struct pci_bus *); 40 + typedef void ia64_mv_kernel_launch_event_t(void); 40 41 41 42 /* DMA-mapping interface: */ 42 43 typedef void ia64_mv_dma_init (void); ··· 219 218 ia64_mv_setup_msi_irq_t *setup_msi_irq; 220 219 ia64_mv_teardown_msi_irq_t *teardown_msi_irq; 221 220 ia64_mv_pci_fixup_bus_t *pci_fixup_bus; 221 + ia64_mv_kernel_launch_event_t *kernel_launch_event; 222 222 } __attribute__((__aligned__(16))); /* align attrib? see above comment */ 223 223 224 224 #define MACHVEC_INIT(name) \ ··· 319 317 #endif 320 318 #ifndef platform_tlb_migrate_finish 321 319 # define platform_tlb_migrate_finish machvec_noop_mm 320 + #endif 321 + #ifndef platform_kernel_launch_event 322 + # define platform_kernel_launch_event machvec_noop 322 323 #endif 323 324 #ifndef platform_dma_init 324 325 # define platform_dma_init swiotlb_init
+2
include/asm-ia64/machvec_sn2.h
··· 67 67 extern ia64_mv_dma_mapping_error sn_dma_mapping_error; 68 68 extern ia64_mv_dma_supported sn_dma_supported; 69 69 extern ia64_mv_migrate_t sn_migrate; 70 + extern ia64_mv_kernel_launch_event_t sn_kernel_launch_event; 70 71 extern ia64_mv_setup_msi_irq_t sn_setup_msi_irq; 71 72 extern ia64_mv_teardown_msi_irq_t sn_teardown_msi_irq; 72 73 extern ia64_mv_pci_fixup_bus_t sn_pci_fixup_bus; ··· 122 121 #define platform_dma_mapping_error sn_dma_mapping_error 123 122 #define platform_dma_supported sn_dma_supported 124 123 #define platform_migrate sn_migrate 124 + #define platform_kernel_launch_event sn_kernel_launch_event 125 125 #ifdef CONFIG_PCI_MSI 126 126 #define platform_setup_msi_irq sn_setup_msi_irq 127 127 #define platform_teardown_msi_irq sn_teardown_msi_irq
+2 -1
include/asm-ia64/meminit.h
··· 15 15 * - initrd (optional) 16 16 * - command line string 17 17 * - kernel code & data 18 + * - crash dumping code reserved region 18 19 * - Kernel memory map built from EFI memory map 19 20 * 20 21 * More could be added if necessary 21 22 */ 22 - #define IA64_MAX_RSVD_REGIONS 6 23 + #define IA64_MAX_RSVD_REGIONS 7 23 24 24 25 struct rsvd_region { 25 26 unsigned long start; /* virtual address of beginning of element */
+9
include/asm-ia64/sn/sn_sal.h
··· 88 88 #define SN_SAL_INJECT_ERROR 0x02000067 89 89 #define SN_SAL_SET_CPU_NUMBER 0x02000068 90 90 91 + #define SN_SAL_KERNEL_LAUNCH_EVENT 0x02000069 92 + 91 93 /* 92 94 * Service-specific constants 93 95 */ ··· 1155 1153 struct ia64_sal_retval rv; 1156 1154 1157 1155 SAL_CALL_NOLOCK(rv, SN_SAL_SET_CPU_NUMBER, cpu, 0, 0, 0, 0, 0, 0); 1156 + return rv.status; 1157 + } 1158 + static inline int 1159 + ia64_sn_kernel_launch_event(void) 1160 + { 1161 + struct ia64_sal_retval rv; 1162 + SAL_CALL_NOLOCK(rv, SN_SAL_KERNEL_LAUNCH_EVENT, 0, 0, 0, 0, 0, 0, 0); 1158 1163 return rv.status; 1159 1164 } 1160 1165 #endif /* _ASM_IA64_SN_SN_SAL_H */
+5
include/linux/kexec.h
··· 108 108 extern struct kimage *kexec_image; 109 109 extern struct kimage *kexec_crash_image; 110 110 111 + #ifndef kexec_flush_icache_page 112 + #define kexec_flush_icache_page(page) 113 + #endif 114 + 111 115 #define KEXEC_ON_CRASH 0x00000001 112 116 #define KEXEC_ARCH_MASK 0xffff0000 113 117 ··· 136 132 extern struct resource crashk_res; 137 133 typedef u32 note_buf_t[MAX_NOTE_BYTES/4]; 138 134 extern note_buf_t *crash_notes; 135 + 139 136 140 137 #else /* !CONFIG_KEXEC */ 141 138 struct pt_regs;
+1
kernel/kexec.c
··· 851 851 memset(ptr + uchunk, 0, mchunk - uchunk); 852 852 } 853 853 result = copy_from_user(ptr, buf, uchunk); 854 + kexec_flush_icache_page(page); 854 855 kunmap(page); 855 856 if (result) { 856 857 result = (result < 0) ? result : -EIO;