| 1 | This patch updates kernel part of kexec for MIPS platform to support |
| 2 | kdump, 64-bit, SMP and simplify code adaptation to new boards. It does |
| 3 | the following: |
| 4 | |
| 5 | - hooks for machine-specific actions are introduced |
| 6 | (_machine_kexec_prepare, |
| 7 | _machine_kexec_shutdown, _machine_crash_shutdown); |
| 8 | - kexec reboot on SMP machine is implemented; |
| 9 | - add boot parameters passing to new kernel (array kexec_args[] is |
| 10 | copied to |
| 11 | registers a0-a3 on reboot ); |
| 12 | - crash dump functionality is added (boot kernel with non-default physical |
| 13 | start, parse "crashkernel=..." command line parameter, copy_oldmem_page() |
| 14 | is implemeted to read memory dump after reboot-on-crashi, |
| 15 | crash_setup_regs() |
| 16 | is updated to correctly store registers on crash); |
| 17 | |
| 18 | kexec/kdump funtionality was tested on several Cavium Octeon boards |
| 19 | (mips64 SMP). The way we do it was the following: |
| 20 | - _machine_kexec_prepare was find kexec segment with command line and |
| 21 | save it's pointed into internal bootloader structure. |
| 22 | - _machine_kexec_shutdown was used to stop boards IO and make all non-boot |
| 23 | CPUs spin in function relocated_kexec_smp_wait() |
| 24 | - _machine_crash_shutdown just calls default_machine_crash_shutdown() |
| 25 | We tested 1) 'common' kexec reboot (by 'kexec -e'), 2) kexec-on-panic |
| 26 | ('kexec -p ...') and 3) access to/proc/vmcore (with gdb). |
| 27 | |
| 28 | Signed-off-by: Maxim Syrchin <[11]msyrchin at ru.mvista.com> |
| 29 | --- |
| 30 | arch/mips/Kconfig | 23 +++++++++ |
| 31 | arch/mips/Makefile | 4 ++ |
| 32 | arch/mips/kernel/Makefile | 3 +- |
| 33 | arch/mips/kernel/crash.c | 91 ++++++++++++++++++++++++++++++++++ |
| 34 | arch/mips/kernel/crash_dump.c | 96 ++++++++++++++++++++++++++++++++++++ |
| 35 | arch/mips/kernel/machine_kexec.c | 52 ++++++++++++++++++- |
| 36 | arch/mips/kernel/relocate_kernel.S | 93 ++++++++++++++++++++++++++++++++++- |
| 37 | arch/mips/kernel/setup.c | 10 +++- |
| 38 | arch/mips/include/asm/kexec.h | 21 ++++++++- |
| 39 | 9 files changed, 386 insertions(+), 7 deletions(-) |
| 40 | create mode 100644 arch/mips/kernel/crash.c |
| 41 | create mode 100644 arch/mips/kernel/crash_dump.c |
| 42 | |
| 43 | --- |
| 44 | arch/mips/Kconfig | 23 23 + 0 - 0 ! |
| 45 | arch/mips/Makefile | 4 4 + 0 - 0 ! |
| 46 | arch/mips/kernel/Makefile | 3 2 + 1 - 0 ! |
| 47 | arch/mips/kernel/crash.c | 90 90 + 0 - 0 ! |
| 48 | arch/mips/kernel/crash_dump.c | 96 96 + 0 - 0 ! |
| 49 | arch/mips/kernel/machine_kexec.c | 66 60 + 6 - 0 ! |
| 50 | arch/mips/kernel/relocate_kernel.S | 96 95 + 1 - 0 ! |
| 51 | arch/mips/kernel/setup.c | 10 9 + 1 - 0 ! |
| 52 | arch/mips/include/asm/kexec.h | 21 20 + 1 - 0 ! |
| 53 | 9 files changed, 399 insertions(+), 10 deletions(-) |
| 54 | |
| 55 | --- a/arch/mips/Kconfig |
| 56 | +++ b/arch/mips/Kconfig |
| 57 | @@ -1966,6 +1966,29 @@ config KEXEC |
| 58 | support. As of this writing the exact hardware interface is |
| 59 | strongly in flux, so no good recommendation can be made. |
| 60 | |
| 61 | +config CRASH_DUMP |
| 62 | + bool "kernel crash dumps (EXPERIMENTAL)" |
| 63 | + depends on EXPERIMENTAL |
| 64 | + help |
| 65 | + Generate crash dump after being started by kexec. |
| 66 | + This should be normally only set in special crash dump kernels |
| 67 | + which are loaded in the main kernel with kexec-tools into |
| 68 | + a specially reserved region and then later executed after |
| 69 | + a crash by kdump/kexec. The crash dump kernel must be compiled |
| 70 | + to a memory address not used by the main kernel or BIOS using |
| 71 | + PHYSICAL_START. |
| 72 | + |
| 73 | +config PHYSICAL_START |
| 74 | + hex "Physical address where the kernel is loaded" |
| 75 | + default "0xffffffff84000000" |
| 76 | + depends on CRASH_DUMP |
| 77 | + help |
| 78 | + This gives the CKSEG0 or KSEG0 address where the kernel is loaded. |
| 79 | + If you plan to use kernel for capturing the crash dump change |
| 80 | + this value to start of the reserved region (the "X" value as |
| 81 | + specified in the "crashkernel=[12]YM at XM" command line boot parameter |
| 82 | + passed to the panic-ed kernel). |
| 83 | + |
| 84 | config SECCOMP |
| 85 | bool "Enable seccomp to safely compute untrusted bytecode" |
| 86 | depends on PROC_FS |
| 87 | --- a/arch/mips/Makefile |
| 88 | +++ b/arch/mips/Makefile |
| 89 | @@ -603,6 +603,10 @@ else |
| 90 | load-$(CONFIG_CPU_CAVIUM_OCTEON) += 0xffffffff81100000 |
| 91 | endif |
| 92 | |
| 93 | +ifdef CONFIG_PHYSICAL_START |
| 94 | +load-y = $(CONFIG_PHYSICAL_START) |
| 95 | +endif |
| 96 | + |
| 97 | cflags-y += -I$(srctree)/arch/mips/include/asm/mach-generic |
| 98 | drivers-$(CONFIG_PCI) += arch/mips/pci/ |
| 99 | |
| 100 | --- a/arch/mips/kernel/Makefile |
| 101 | +++ b/arch/mips/kernel/Makefile |
| 102 | @@ -83,7 +83,8 @@ obj-$(CONFIG_I8253) += i8253.o |
| 103 | |
| 104 | obj-$(CONFIG_GPIO_TXX9) += gpio_txx9.o |
| 105 | |
| 106 | -obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o |
| 107 | +obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o |
| 108 | +obj-$(CONFIG_CRASH_DUMP) += crash_dump.o |
| 109 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
| 110 | obj-$(CONFIG_MIPS_MACHINE) += mips_machine.o |
| 111 | |
| 112 | --- /dev/null |
| 113 | +++ b/arch/mips/kernel/crash.c |
| 114 | @@ -0,0 +1,90 @@ |
| 115 | +/* |
| 116 | + * Architecture specific (MIPS) functions for kexec based crash dumps. |
| 117 | + * |
| 118 | + * Copyright (C) 2005, IBM Corp. |
| 119 | + * Copyright (C) 2008, MontaVista Software Inc. |
| 120 | + * |
| 121 | + * This source code is licensed under the GNU General Public License, |
| 122 | + * Version 2. See the file COPYING for more details. |
| 123 | + * |
| 124 | + */ |
| 125 | + |
| 126 | +#undef DEBUG |
| 127 | + |
| 128 | +#include <linux/kernel.h> |
| 129 | +#include <linux/smp.h> |
| 130 | +#include <linux/reboot.h> |
| 131 | +#include <linux/kexec.h> |
| 132 | +#include <linux/bootmem.h> |
| 133 | +#include <linux/crash_dump.h> |
| 134 | +#include <linux/delay.h> |
| 135 | +#include <linux/init.h> |
| 136 | +#include <linux/irq.h> |
| 137 | +#include <linux/types.h> |
| 138 | +#include <linux/sched.h> |
| 139 | + |
| 140 | + |
| 141 | + |
| 142 | +/* This keeps a track of which one is crashing cpu. */ |
| 143 | +int crashing_cpu = -1; |
| 144 | +static cpumask_t cpus_in_crash = CPU_MASK_NONE; |
| 145 | + |
| 146 | +#ifdef CONFIG_SMP |
| 147 | + |
| 148 | +void crash_shutdown_secondary(void *ignore) |
| 149 | +{ |
| 150 | + struct pt_regs* regs; |
| 151 | + int cpu = smp_processor_id(); |
| 152 | + |
| 153 | + regs = task_pt_regs(current); |
| 154 | + if (!cpu_online(cpu)) |
| 155 | + return; |
| 156 | + |
| 157 | + local_irq_disable(); |
| 158 | + if (!cpu_isset(cpu, cpus_in_crash)) |
| 159 | + crash_save_cpu(regs, cpu); |
| 160 | + cpu_set(cpu, cpus_in_crash); |
| 161 | + |
| 162 | + while(!atomic_read(&kexec_ready_to_reboot)) { |
| 163 | + cpu_relax(); |
| 164 | + } |
| 165 | + relocated_kexec_smp_wait(NULL); |
| 166 | + /* NOTREACHED */ |
| 167 | +} |
| 168 | + |
| 169 | +static void crash_kexec_prepare_cpus(void) |
| 170 | +{ |
| 171 | + unsigned int msecs; |
| 172 | + |
| 173 | + unsigned int ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */ |
| 174 | + |
| 175 | + smp_call_function (crash_shutdown_secondary, NULL, 0); |
| 176 | + smp_wmb(); |
| 177 | + |
| 178 | + /* |
| 179 | + * FIXME: Until we will have the way to stop other CPUSs reliabally, |
| 180 | + * the crash CPU will send an IPI and wait for other CPUs to |
| 181 | + * respond. |
| 182 | + * Delay of at least 10 seconds. |
| 183 | + */ |
| 184 | + printk(KERN_EMERG "Sending IPI to other cpus...\n"); |
| 185 | + msecs = 10000; |
| 186 | + while ((cpus_weight(cpus_in_crash) < ncpus) && (--msecs > 0)) { |
| 187 | + cpu_relax(); |
| 188 | + mdelay(1); |
| 189 | + } |
| 190 | + |
| 191 | +} |
| 192 | + |
| 193 | +#else |
| 194 | +static void crash_kexec_prepare_cpus(void) {} |
| 195 | +#endif |
| 196 | + |
| 197 | +void default_machine_crash_shutdown(struct pt_regs *regs) |
| 198 | +{ |
| 199 | + local_irq_disable(); |
| 200 | + crashing_cpu = smp_processor_id(); |
| 201 | + crash_save_cpu(regs, crashing_cpu); |
| 202 | + crash_kexec_prepare_cpus(); |
| 203 | + cpu_set(crashing_cpu, cpus_in_crash); |
| 204 | +} |
| 205 | --- /dev/null |
| 206 | +++ b/arch/mips/kernel/crash_dump.c |
| 207 | @@ -0,0 +1,96 @@ |
| 208 | +/* |
| 209 | + * Routines for doing kexec-based kdump. |
| 210 | + * |
| 211 | + * Copyright (C) 2005, IBM Corp. |
| 212 | + * Copyright (C) 2008, MontaVista Software Inc. |
| 213 | + * |
| 214 | + * This source code is licensed under the GNU General Public License, |
| 215 | + * Version 2. See the file COPYING for more details. |
| 216 | + */ |
| 217 | + |
| 218 | +#include <linux/highmem.h> |
| 219 | +#include <linux/bootmem.h> |
| 220 | +#include <linux/crash_dump.h> |
| 221 | +#include <asm/uaccess.h> |
| 222 | + |
| 223 | +#ifdef CONFIG_PROC_VMCORE |
| 224 | +static int __init parse_elfcorehdr(char *p) |
| 225 | +{ |
| 226 | + if (p) |
| 227 | + elfcorehdr_addr = memparse(p, &p); |
| 228 | + return 1; |
| 229 | +} |
| 230 | +__setup("elfcorehdr=", parse_elfcorehdr); |
| 231 | +#endif |
| 232 | + |
| 233 | +static int __init parse_savemaxmem(char *p) |
| 234 | +{ |
| 235 | + if (p) |
| 236 | + saved_max_pfn = (memparse(p, &p) >> PAGE_SHIFT) - 1; |
| 237 | + |
| 238 | + return 1; |
| 239 | +} |
| 240 | +__setup("savemaxmem=", parse_savemaxmem); |
| 241 | + |
| 242 | + |
| 243 | +static void *kdump_buf_page; |
| 244 | + |
| 245 | +/** |
| 246 | + * copy_oldmem_page - copy one page from "oldmem" |
| 247 | + * @pfn: page frame number to be copied |
| 248 | + * @buf: target memory address for the copy; this can be in kernel address |
| 249 | + * space or user address space (see @userbuf) |
| 250 | + * @csize: number of bytes to copy |
| 251 | + * @offset: offset in bytes into the page (based on pfn) to begin the copy |
| 252 | + * @userbuf: if set, @buf is in user address space, use copy_to_user(), |
| 253 | + * otherwise @buf is in kernel address space, use memcpy(). |
| 254 | + * |
| 255 | + * Copy a page from "oldmem". For this page, there is no pte mapped |
| 256 | + * in the current kernel. |
| 257 | + * |
| 258 | + * Calling copy_to_user() in atomic context is not desirable. Hence first |
| 259 | + * copying the data to a pre-allocated kernel page and then copying to user |
| 260 | + * space in non-atomic context. |
| 261 | + */ |
| 262 | +ssize_t copy_oldmem_page(unsigned long pfn, char *buf, |
| 263 | + size_t csize, unsigned long offset, int userbuf) |
| 264 | +{ |
| 265 | + void *vaddr; |
| 266 | + |
| 267 | + if (!csize) |
| 268 | + return 0; |
| 269 | + |
| 270 | + vaddr = kmap_atomic_pfn(pfn, KM_PTE0); |
| 271 | + |
| 272 | + if (!userbuf) { |
| 273 | + memcpy(buf, (vaddr + offset), csize); |
| 274 | + kunmap_atomic(vaddr, KM_PTE0); |
| 275 | + } else { |
| 276 | + if (!kdump_buf_page) { |
| 277 | + printk(KERN_WARNING "Kdump: Kdump buffer page not" |
| 278 | + " allocated\n"); |
| 279 | + return -EFAULT; |
| 280 | + } |
| 281 | + copy_page(kdump_buf_page, vaddr); |
| 282 | + kunmap_atomic(vaddr, KM_PTE0); |
| 283 | + if (copy_to_user(buf, (kdump_buf_page + offset), csize)) |
| 284 | + return -EFAULT; |
| 285 | + } |
| 286 | + |
| 287 | + return csize; |
| 288 | +} |
| 289 | + |
| 290 | +static int __init kdump_buf_page_init(void) |
| 291 | +{ |
| 292 | + int ret = 0; |
| 293 | + |
| 294 | + kdump_buf_page = kmalloc(PAGE_SIZE, GFP_KERNEL); |
| 295 | + if (!kdump_buf_page) { |
| 296 | + printk(KERN_WARNING "Kdump: Failed to allocate kdump buffer" |
| 297 | + " page\n"); |
| 298 | + ret = -ENOMEM; |
| 299 | + } |
| 300 | + |
| 301 | + return ret; |
| 302 | +} |
| 303 | +arch_initcall(kdump_buf_page_init); |
| 304 | --- a/arch/mips/kernel/machine_kexec.c |
| 305 | +++ b/arch/mips/kernel/machine_kexec.c |
| 306 | @@ -19,9 +19,25 @@ extern const size_t relocate_new_kernel_ |
| 307 | extern unsigned long kexec_start_address; |
| 308 | extern unsigned long kexec_indirection_page; |
| 309 | |
| 310 | +extern unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3; |
| 311 | + |
| 312 | +int (*_machine_kexec_prepare)(struct kimage *) = NULL; |
| 313 | +void (*_machine_kexec_shutdown)(void) = NULL; |
| 314 | +void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL; |
| 315 | +#ifdef CONFIG_SMP |
| 316 | +void (*relocated_kexec_smp_wait) (void *); |
| 317 | +atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0); |
| 318 | +#endif |
| 319 | + |
| 320 | int |
| 321 | machine_kexec_prepare(struct kimage *kimage) |
| 322 | { |
| 323 | + kexec_args[0] = fw_arg0; |
| 324 | + kexec_args[1] = fw_arg1; |
| 325 | + kexec_args[2] = fw_arg2; |
| 326 | + kexec_args[3] = fw_arg3; |
| 327 | + if (_machine_kexec_prepare) |
| 328 | + return _machine_kexec_prepare(kimage); |
| 329 | return 0; |
| 330 | } |
| 331 | |
| 332 | @@ -33,13 +49,18 @@ machine_kexec_cleanup(struct kimage *kim |
| 333 | void |
| 334 | machine_shutdown(void) |
| 335 | { |
| 336 | + if (_machine_kexec_shutdown) |
| 337 | + _machine_kexec_shutdown(); |
| 338 | } |
| 339 | |
| 340 | void |
| 341 | machine_crash_shutdown(struct pt_regs *regs) |
| 342 | { |
| 343 | + if (_machine_crash_shutdown) |
| 344 | + _machine_crash_shutdown(regs); |
| 345 | + else |
| 346 | + default_machine_crash_shutdown(regs); |
| 347 | } |
| 348 | - |
| 349 | typedef void (*noretfun_t)(void) __attribute__((noreturn)); |
| 350 | |
| 351 | void |
| 352 | @@ -52,7 +73,9 @@ machine_kexec(struct kimage *image) |
| 353 | reboot_code_buffer = |
| 354 | (unsigned long)page_address(image->control_code_page); |
| 355 | |
| 356 | - kexec_start_address = image->start; |
| 357 | + kexec_start_address = |
| 358 | + (unsigned long) phys_to_virt(image->start); |
| 359 | + |
| 360 | kexec_indirection_page = |
| 361 | (unsigned long) phys_to_virt(image->head & PAGE_MASK); |
| 362 | |
| 363 | @@ -63,7 +86,7 @@ machine_kexec(struct kimage *image) |
| 364 | * The generic kexec code builds a page list with physical |
| 365 | * addresses. they are directly accessible through KSEG0 (or |
| 366 | * CKSEG0 or XPHYS if on 64bit system), hence the |
| 367 | - * pys_to_virt() call. |
| 368 | + * phys_to_virt() call. |
| 369 | */ |
| 370 | for (ptr = &image->head; (entry = *ptr) && !(entry &IND_DONE); |
| 371 | ptr = (entry & IND_INDIRECTION) ? |
| 372 | @@ -78,8 +101,39 @@ machine_kexec(struct kimage *image) |
| 373 | */ |
| 374 | local_irq_disable(); |
| 375 | |
| 376 | - printk("Will call new kernel at %08lx\n", image->start); |
| 377 | - printk("Bye ...\n"); |
| 378 | + printk(KERN_EMERG "Will call new kernel at %08lx\n", image->start); |
| 379 | + printk(KERN_EMERG "Bye ...\n"); |
| 380 | __flush_cache_all(); |
| 381 | - ((noretfun_t) reboot_code_buffer)(); |
| 382 | +#ifdef CONFIG_SMP |
| 383 | + /* All secondary cpus now may jump to kexec_wait cycle */ |
| 384 | + relocated_kexec_smp_wait = (void *)(reboot_code_buffer + |
| 385 | + (kexec_smp_wait - relocate_new_kernel)); |
| 386 | + smp_wmb(); |
| 387 | + atomic_set(&kexec_ready_to_reboot,1); |
| 388 | +#endif |
| 389 | + |
| 390 | + ((noretfun_t) reboot_code_buffer)(); |
| 391 | + printk(KERN_EMERG "Bye ...\n"); |
| 392 | +} |
| 393 | + |
| 394 | +/* crashkernel=[13]size at addr specifies the location to reserve for |
| 395 | + * a crash kernel. By reserving this memory we guarantee |
| 396 | + * that linux never sets it up as a DMA target. |
| 397 | + * Useful for holding code to do something appropriate |
| 398 | + * after a kernel panic. |
| 399 | + */ |
| 400 | +static int __init parse_crashkernel_cmdline(char *arg) |
| 401 | +{ |
| 402 | + unsigned long size, base; |
| 403 | + size = memparse(arg, &arg); |
| 404 | + if (*arg == '@') { |
| 405 | + base = memparse(arg+1, &arg); |
| 406 | + /* FIXME: Do I want a sanity check |
| 407 | + * to validate the memory range? |
| 408 | + */ |
| 409 | + crashk_res.start = base; |
| 410 | + crashk_res.end = base + size - 1; |
| 411 | + } |
| 412 | + return 0; |
| 413 | } |
| 414 | +early_param("crashkernel", parse_crashkernel_cmdline); |
| 415 | --- a/arch/mips/kernel/relocate_kernel.S |
| 416 | +++ b/arch/mips/kernel/relocate_kernel.S |
| 417 | @@ -14,7 +14,13 @@ |
| 418 | #include <asm/stackframe.h> |
| 419 | #include <asm/addrspace.h> |
| 420 | |
| 421 | + |
| 422 | LEAF(relocate_new_kernel) |
| 423 | + PTR_L a0, arg0 |
| 424 | + PTR_L a1, arg1 |
| 425 | + PTR_L a2, arg2 |
| 426 | + PTR_L a3, arg3 |
| 427 | + |
| 428 | PTR_L s0, kexec_indirection_page |
| 429 | PTR_L s1, kexec_start_address |
| 430 | |
| 431 | @@ -26,7 +32,6 @@ process_entry: |
| 432 | and s3, s2, 0x1 |
| 433 | beq s3, zero, 1f |
| 434 | and s4, s2, ~0x1 /* store destination addr in s4 */ |
| 435 | - move a0, s4 |
| 436 | b process_entry |
| 437 | |
| 438 | 1: |
| 439 | @@ -40,6 +45,7 @@ process_entry: |
| 440 | /* done page */ |
| 441 | and s3, s2, 0x4 |
| 442 | beq s3, zero, 1f |
| 443 | + nop |
| 444 | b done |
| 445 | 1: |
| 446 | /* source page */ |
| 447 | @@ -56,14 +62,102 @@ copy_word: |
| 448 | PTR_ADD s2, s2, SZREG |
| 449 | LONG_SUB s6, s6, 1 |
| 450 | beq s6, zero, process_entry |
| 451 | + nop |
| 452 | b copy_word |
| 453 | + nop |
| 454 | b process_entry |
| 455 | |
| 456 | done: |
| 457 | +#ifdef CONFIG_SMP |
| 458 | + /* kexec_flag reset is signal to other CPUs what kernel |
| 459 | + was moved to it's location. Note - we need relocated address |
| 460 | + of kexec_flag. */ |
| 461 | + |
| 462 | + bal 1f |
| 463 | + 1: move t1,ra; |
| 464 | + PTR_LA t2,1b |
| 465 | + PTR_LA t0,kexec_flag |
| 466 | + PTR_SUB t0,t0,t2; |
| 467 | + PTR_ADD t0,t1,t0; |
| 468 | + LONG_S zero,(t0) |
| 469 | +#endif |
| 470 | + |
| 471 | + /* Some platforms need I-cache to be flushed before |
| 472 | + * jumping to new kernel. |
| 473 | + */ |
| 474 | + |
| 475 | /* jump to kexec_start_address */ |
| 476 | j s1 |
| 477 | END(relocate_new_kernel) |
| 478 | |
| 479 | +#ifdef CONFIG_SMP |
| 480 | +/* |
| 481 | + * Other CPUs should wait until code is relocated and |
| 482 | + * then start at entry point. |
| 483 | + */ |
| 484 | +LEAF(kexec_smp_wait) |
| 485 | + PTR_L a0, s_arg0 |
| 486 | + PTR_L a1, s_arg1 |
| 487 | + PTR_L a2, s_arg2 |
| 488 | + PTR_L a3, s_arg3 |
| 489 | + PTR_L s1, kexec_start_address |
| 490 | + |
| 491 | + /* Non-relocated address works for args and kexec_start_address ( old |
| 492 | + * kernel is not overwritten). But we need relocated address of |
| 493 | + * kexec_flag. |
| 494 | + */ |
| 495 | + |
| 496 | + bal 1f |
| 497 | +1: move t1,ra; |
| 498 | + PTR_LA t2,1b |
| 499 | + PTR_LA t0,kexec_flag |
| 500 | + PTR_SUB t0,t0,t2; |
| 501 | + PTR_ADD t0,t1,t0; |
| 502 | + |
| 503 | +1: LONG_L s0, (t0) |
| 504 | + bne s0, zero,1b |
| 505 | + |
| 506 | + j s1 |
| 507 | + END(kexec_smp_wait) |
| 508 | +#endif |
| 509 | + |
| 510 | + |
| 511 | +#ifdef __mips64 |
| 512 | + /* all PTR's must be aligned to 8 byte in 64-bit mode */ |
| 513 | + .align 3 |
| 514 | +#endif |
| 515 | + |
| 516 | +/* All parameters to new kernel are passed in registers a0-a3. |
| 517 | + * kexec_args[0..3] are uses to prepare register values. |
| 518 | + */ |
| 519 | + |
| 520 | +kexec_args: |
| 521 | + EXPORT(kexec_args) |
| 522 | +arg0: PTR 0x0 |
| 523 | +arg1: PTR 0x0 |
| 524 | +arg2: PTR 0x0 |
| 525 | +arg3: PTR 0x0 |
| 526 | + .size kexec_args,PTRSIZE*4 |
| 527 | + |
| 528 | +#ifdef CONFIG_SMP |
| 529 | +/* |
| 530 | + * Secondary CPUs may have different kernel parameters in |
| 531 | + * their registers a0-a3. secondary_kexec_args[0..3] are used |
| 532 | + * to prepare register values. |
| 533 | + */ |
| 534 | +secondary_kexec_args: |
| 535 | + EXPORT(secondary_kexec_args) |
| 536 | +s_arg0: PTR 0x0 |
| 537 | +s_arg1: PTR 0x0 |
| 538 | +s_arg2: PTR 0x0 |
| 539 | +s_arg3: PTR 0x0 |
| 540 | + .size secondary_kexec_args,PTRSIZE*4 |
| 541 | +kexec_flag: |
| 542 | + LONG 0x1 |
| 543 | + |
| 544 | +#endif |
| 545 | + |
| 546 | + |
| 547 | kexec_start_address: |
| 548 | EXPORT(kexec_start_address) |
| 549 | PTR 0x0 |
| 550 | --- a/arch/mips/kernel/setup.c |
| 551 | +++ b/arch/mips/kernel/setup.c |
| 552 | @@ -21,7 +21,7 @@ |
| 553 | #include <linux/console.h> |
| 554 | #include <linux/pfn.h> |
| 555 | #include <linux/debugfs.h> |
| 556 | - |
| 557 | +#include <linux/kexec.h> |
| 558 | #include <asm/addrspace.h> |
| 559 | #include <asm/bootinfo.h> |
| 560 | #include <asm/bugs.h> |
| 561 | @@ -489,6 +489,11 @@ static void __init arch_mem_init(char ** |
| 562 | } |
| 563 | |
| 564 | bootmem_init(); |
| 565 | +#ifdef CONFIG_CRASH_DUMP |
| 566 | + if (crashk_res.start != crashk_res.end) |
| 567 | + reserve_bootmem(crashk_res.start, |
| 568 | + crashk_res.end - crashk_res.start + 1); |
| 569 | +#endif |
| 570 | sparse_init(); |
| 571 | paging_init(); |
| 572 | } |
| 573 | @@ -543,6 +548,9 @@ static void __init resource_init(void) |
| 574 | */ |
| 575 | request_resource(res, &code_resource); |
| 576 | request_resource(res, &data_resource); |
| 577 | +#ifdef CONFIG_KEXEC |
| 578 | + request_resource(res, &crashk_res); |
| 579 | +#endif |
| 580 | } |
| 581 | } |
| 582 | |
| 583 | --- a/arch/mips/include/asm/kexec.h |
| 584 | +++ b/arch/mips/include/asm/kexec.h |
| 585 | @@ -9,6 +9,8 @@ |
| 586 | #ifndef _MIPS_KEXEC |
| 587 | # define _MIPS_KEXEC |
| 588 | |
| 589 | +#include <asm/stacktrace.h> |
| 590 | + |
| 591 | /* Maximum physical address we can use pages from */ |
| 592 | #define KEXEC_SOURCE_MEMORY_LIMIT (0x20000000) |
| 593 | /* Maximum address we can reach in physical address mode */ |
| 594 | @@ -24,7 +26,24 @@ |
| 595 | static inline void crash_setup_regs(struct pt_regs *newregs, |
| 596 | struct pt_regs *oldregs) |
| 597 | { |
| 598 | - /* Dummy implementation for now */ |
| 599 | + if (oldregs) |
| 600 | + memcpy(newregs, oldregs, sizeof(*newregs)); |
| 601 | + else |
| 602 | + prepare_frametrace(newregs); |
| 603 | } |
| 604 | |
| 605 | +#ifdef CONFIG_KEXEC |
| 606 | +struct kimage; |
| 607 | +extern unsigned long kexec_args[4]; |
| 608 | +extern int (*_machine_kexec_prepare)(struct kimage *); |
| 609 | +extern void (*_machine_kexec_shutdown)(void); |
| 610 | +extern void (*_machine_crash_shutdown)(struct pt_regs *regs); |
| 611 | +extern void default_machine_crash_shutdown(struct pt_regs *regs); |
| 612 | +#ifdef CONFIG_SMP |
| 613 | +extern const unsigned char kexec_smp_wait[]; |
| 614 | +extern unsigned long secondary_kexec_args[4]; |
| 615 | +extern void (*relocated_kexec_smp_wait) (void *); |
| 616 | +extern atomic_t kexec_ready_to_reboot; |
| 617 | +#endif |
| 618 | +#endif |
| 619 | #endif /* !_MIPS_KEXEC */ |
| 620 | |