[MIPS] Add support for kexec
A tiny userland application loading the kernel and invoking kexec_load for mips is available here: http://chac.le-poulpe.net/~nico/kexec/kexec-2006-10-18.tar.gz Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
parent
c237923009
commit
583bb86fbb
|
@ -766,6 +766,23 @@ config TOSHIBA_RBTX4938
|
||||||
|
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
|
config KEXEC
|
||||||
|
bool "Kexec system call (EXPERIMENTAL)"
|
||||||
|
depends on EXPERIMENTAL
|
||||||
|
help
|
||||||
|
kexec is a system call that implements the ability to shutdown your
|
||||||
|
current kernel, and to start another kernel. It is like a reboot
|
||||||
|
but it is indepedent of the system firmware. And like a reboot
|
||||||
|
you can start any kernel with it, not just Linux.
|
||||||
|
|
||||||
|
The name comes from the similiarity to the exec system call.
|
||||||
|
|
||||||
|
It is an ongoing process to be certain the hardware in a machine
|
||||||
|
is properly shutdown, so do not be surprised if this code does not
|
||||||
|
initially work for you. It may help to enable device hotplugging
|
||||||
|
support. As of this writing the exact hardware interface is
|
||||||
|
strongly in flux, so no good recommendation can be made.
|
||||||
|
|
||||||
source "arch/mips/ddb5xxx/Kconfig"
|
source "arch/mips/ddb5xxx/Kconfig"
|
||||||
source "arch/mips/gt64120/ev64120/Kconfig"
|
source "arch/mips/gt64120/ev64120/Kconfig"
|
||||||
source "arch/mips/jazz/Kconfig"
|
source "arch/mips/jazz/Kconfig"
|
||||||
|
|
|
@ -67,6 +67,8 @@ obj-$(CONFIG_64BIT) += cpu-bugs64.o
|
||||||
|
|
||||||
obj-$(CONFIG_I8253) += i8253.o
|
obj-$(CONFIG_I8253) += i8253.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
|
||||||
|
|
||||||
CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi)
|
CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi)
|
||||||
|
|
||||||
EXTRA_AFLAGS := $(CFLAGS)
|
EXTRA_AFLAGS := $(CFLAGS)
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* machine_kexec.c for kexec
|
||||||
|
* Created by <nschichan@corp.free.fr> on Thu Oct 12 15:15:06 2006
|
||||||
|
*
|
||||||
|
* This source code is licensed under the GNU General Public License,
|
||||||
|
* Version 2. See the file COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kexec.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
|
||||||
|
#include <asm/cacheflush.h>
|
||||||
|
#include <asm/page.h>
|
||||||
|
|
||||||
|
const extern unsigned char relocate_new_kernel[];
|
||||||
|
const extern unsigned int relocate_new_kernel_size;
|
||||||
|
|
||||||
|
extern unsigned long kexec_start_address;
|
||||||
|
extern unsigned long kexec_indirection_page;
|
||||||
|
|
||||||
|
int
|
||||||
|
machine_kexec_prepare(struct kimage *kimage)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
machine_kexec_cleanup(struct kimage *kimage)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
machine_shutdown(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
machine_crash_shutdown(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
machine_kexec(struct kimage *image)
|
||||||
|
{
|
||||||
|
unsigned long reboot_code_buffer;
|
||||||
|
unsigned long entry;
|
||||||
|
unsigned long *ptr;
|
||||||
|
|
||||||
|
reboot_code_buffer =
|
||||||
|
(unsigned long)page_address(image->control_code_page);
|
||||||
|
|
||||||
|
kexec_start_address = image->start;
|
||||||
|
kexec_indirection_page = phys_to_virt(image->head & PAGE_MASK);
|
||||||
|
|
||||||
|
memcpy((void*)reboot_code_buffer, relocate_new_kernel,
|
||||||
|
relocate_new_kernel_size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The generic kexec code builds a page list with physical
|
||||||
|
* addresses. they are directly accessible through KSEG0 (or
|
||||||
|
* CKSEG0 or XPHYS if on 64bit system), hence the
|
||||||
|
* pys_to_virt() call.
|
||||||
|
*/
|
||||||
|
for (ptr = &image->head; (entry = *ptr) && !(entry &IND_DONE);
|
||||||
|
ptr = (entry & IND_INDIRECTION) ?
|
||||||
|
phys_to_virt(entry & PAGE_MASK) : ptr + 1) {
|
||||||
|
if (*ptr & IND_SOURCE || *ptr & IND_INDIRECTION ||
|
||||||
|
*ptr & IND_DESTINATION)
|
||||||
|
*ptr = phys_to_virt(*ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we do not want to be bothered.
|
||||||
|
*/
|
||||||
|
local_irq_disable();
|
||||||
|
|
||||||
|
flush_icache_range(reboot_code_buffer,
|
||||||
|
reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE);
|
||||||
|
|
||||||
|
printk("Will call new kernel at %08x\n", image->start);
|
||||||
|
printk("Bye ...\n");
|
||||||
|
flush_cache_all();
|
||||||
|
((void (*)(void))reboot_code_buffer)();
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* relocate_kernel.S for kexec
|
||||||
|
* Created by <nschichan@corp.free.fr> on Thu Oct 12 17:49:57 2006
|
||||||
|
*
|
||||||
|
* This source code is licensed under the GNU General Public License,
|
||||||
|
* Version 2. See the file COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <asm/asm.h>
|
||||||
|
#include <asm/asmmacro.h>
|
||||||
|
#include <asm/regdef.h>
|
||||||
|
#include <asm/page.h>
|
||||||
|
#include <asm/mipsregs.h>
|
||||||
|
#include <asm/stackframe.h>
|
||||||
|
#include <asm/addrspace.h>
|
||||||
|
|
||||||
|
.globl relocate_new_kernel
|
||||||
|
relocate_new_kernel:
|
||||||
|
|
||||||
|
PTR_L s0, kexec_indirection_page
|
||||||
|
PTR_L s1, kexec_start_address
|
||||||
|
|
||||||
|
process_entry:
|
||||||
|
PTR_L s2, (s0)
|
||||||
|
PTR_ADD s0, s0, SZREG
|
||||||
|
|
||||||
|
/* destination page */
|
||||||
|
and s3, s2, 0x1
|
||||||
|
beq s3, zero, 1f
|
||||||
|
and s4, s2, ~0x1 /* store destination addr in s4 */
|
||||||
|
move a0, s4
|
||||||
|
b process_entry
|
||||||
|
|
||||||
|
1:
|
||||||
|
/* indirection page, update s0 */
|
||||||
|
and s3, s2, 0x2
|
||||||
|
beq s3, zero, 1f
|
||||||
|
and s0, s2, ~0x2
|
||||||
|
b process_entry
|
||||||
|
|
||||||
|
1:
|
||||||
|
/* done page */
|
||||||
|
and s3, s2, 0x4
|
||||||
|
beq s3, zero, 1f
|
||||||
|
b done
|
||||||
|
1:
|
||||||
|
/* source page */
|
||||||
|
and s3, s2, 0x8
|
||||||
|
beq s3, zero, process_entry
|
||||||
|
and s2, s2, ~0x8
|
||||||
|
li s6, (1 << PAGE_SHIFT) / SZREG
|
||||||
|
|
||||||
|
copy_word:
|
||||||
|
/* copy page word by word */
|
||||||
|
REG_L s5, (s2)
|
||||||
|
REG_S s5, (s4)
|
||||||
|
INT_ADD s4, s4, SZREG
|
||||||
|
INT_ADD s2, s2, SZREG
|
||||||
|
INT_SUB s6, s6, 1
|
||||||
|
beq s6, zero, process_entry
|
||||||
|
b copy_word
|
||||||
|
b process_entry
|
||||||
|
|
||||||
|
done:
|
||||||
|
/* jump to kexec_start_address */
|
||||||
|
j s1
|
||||||
|
|
||||||
|
.globl kexec_start_address
|
||||||
|
kexec_start_address:
|
||||||
|
.long 0x0
|
||||||
|
|
||||||
|
.globl kexec_indirection_page
|
||||||
|
kexec_indirection_page:
|
||||||
|
.long 0x0
|
||||||
|
|
||||||
|
relocate_new_kernel_end:
|
||||||
|
|
||||||
|
.globl relocate_new_kernel_size
|
||||||
|
relocate_new_kernel_size:
|
||||||
|
.long relocate_new_kernel_end - relocate_new_kernel
|
|
@ -653,7 +653,7 @@ einval: li v0, -EINVAL
|
||||||
sys sys_move_pages 6
|
sys sys_move_pages 6
|
||||||
sys sys_set_robust_list 2
|
sys sys_set_robust_list 2
|
||||||
sys sys_get_robust_list 3 /* 4310 */
|
sys sys_get_robust_list 3 /* 4310 */
|
||||||
sys sys_ni_syscall 0
|
sys sys_kexec_load 4
|
||||||
sys sys_getcpu 3
|
sys sys_getcpu 3
|
||||||
sys sys_epoll_pwait 6
|
sys sys_epoll_pwait 6
|
||||||
.endm
|
.endm
|
||||||
|
|
|
@ -468,6 +468,6 @@ sys_call_table:
|
||||||
PTR sys_move_pages
|
PTR sys_move_pages
|
||||||
PTR sys_set_robust_list
|
PTR sys_set_robust_list
|
||||||
PTR sys_get_robust_list
|
PTR sys_get_robust_list
|
||||||
PTR sys_ni_syscall /* 5270 */
|
PTR sys_kexec_load /* 5270 */
|
||||||
PTR sys_getcpu
|
PTR sys_getcpu
|
||||||
PTR sys_epoll_pwait
|
PTR sys_epoll_pwait
|
||||||
|
|
|
@ -394,6 +394,6 @@ EXPORT(sysn32_call_table)
|
||||||
PTR sys_move_pages
|
PTR sys_move_pages
|
||||||
PTR compat_sys_set_robust_list
|
PTR compat_sys_set_robust_list
|
||||||
PTR compat_sys_get_robust_list
|
PTR compat_sys_get_robust_list
|
||||||
PTR sys_ni_syscall
|
PTR compat_sys_kexec_load
|
||||||
PTR sys_getcpu
|
PTR sys_getcpu
|
||||||
PTR sys_epoll_pwait
|
PTR sys_epoll_pwait
|
||||||
|
|
|
@ -516,7 +516,7 @@ sys_call_table:
|
||||||
PTR compat_sys_move_pages
|
PTR compat_sys_move_pages
|
||||||
PTR compat_sys_set_robust_list
|
PTR compat_sys_set_robust_list
|
||||||
PTR compat_sys_get_robust_list /* 4310 */
|
PTR compat_sys_get_robust_list /* 4310 */
|
||||||
PTR sys_ni_syscall
|
PTR compat_sys_kexec_load
|
||||||
PTR sys_getcpu
|
PTR sys_getcpu
|
||||||
PTR sys_epoll_pwait
|
PTR sys_epoll_pwait
|
||||||
.size sys_call_table,.-sys_call_table
|
.size sys_call_table,.-sys_call_table
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* kexec.h for kexec
|
||||||
|
* Created by <nschichan@corp.free.fr> on Thu Oct 12 14:59:34 2006
|
||||||
|
*
|
||||||
|
* This source code is licensed under the GNU General Public License,
|
||||||
|
* Version 2. See the file COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MIPS_KEXEC
|
||||||
|
# define _MIPS_KEXEC
|
||||||
|
|
||||||
|
/* Maximum physical address we can use pages from */
|
||||||
|
#define KEXEC_SOURCE_MEMORY_LIMIT (0x20000000)
|
||||||
|
/* Maximum address we can reach in physical address mode */
|
||||||
|
#define KEXEC_DESTINATION_MEMORY_LIMIT (0x20000000)
|
||||||
|
/* Maximum address we can use for the control code buffer */
|
||||||
|
#define KEXEC_CONTROL_MEMORY_LIMIT (0x20000000)
|
||||||
|
|
||||||
|
#define KEXEC_CONTROL_CODE_SIZE 4096
|
||||||
|
|
||||||
|
/* The native architecture */
|
||||||
|
#define KEXEC_ARCH KEXEC_ARCH_MIPS
|
||||||
|
|
||||||
|
#define MAX_NOTE_BYTES 1024
|
||||||
|
|
||||||
|
static inline void crash_setup_regs(struct pt_regs *newregs,
|
||||||
|
struct pt_regs *oldregs)
|
||||||
|
{
|
||||||
|
/* Dummy implementation for now */
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !_MIPS_KEXEC */
|
|
@ -122,6 +122,8 @@ extern struct kimage *kexec_crash_image;
|
||||||
#define KEXEC_ARCH_IA_64 (50 << 16)
|
#define KEXEC_ARCH_IA_64 (50 << 16)
|
||||||
#define KEXEC_ARCH_S390 (22 << 16)
|
#define KEXEC_ARCH_S390 (22 << 16)
|
||||||
#define KEXEC_ARCH_SH (42 << 16)
|
#define KEXEC_ARCH_SH (42 << 16)
|
||||||
|
#define KEXEC_ARCH_MIPS_LE (10 << 16)
|
||||||
|
#define KEXEC_ARCH_MIPS ( 8 << 16)
|
||||||
|
|
||||||
#define KEXEC_FLAGS (KEXEC_ON_CRASH) /* List of defined/legal kexec flags */
|
#define KEXEC_FLAGS (KEXEC_ON_CRASH) /* List of defined/legal kexec flags */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue