[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
|
||||
|
||||
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/gt64120/ev64120/Kconfig"
|
||||
source "arch/mips/jazz/Kconfig"
|
||||
|
|
|
@ -67,6 +67,8 @@ obj-$(CONFIG_64BIT) += cpu-bugs64.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)
|
||||
|
||||
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_set_robust_list 2
|
||||
sys sys_get_robust_list 3 /* 4310 */
|
||||
sys sys_ni_syscall 0
|
||||
sys sys_kexec_load 4
|
||||
sys sys_getcpu 3
|
||||
sys sys_epoll_pwait 6
|
||||
.endm
|
||||
|
|
|
@ -468,6 +468,6 @@ sys_call_table:
|
|||
PTR sys_move_pages
|
||||
PTR sys_set_robust_list
|
||||
PTR sys_get_robust_list
|
||||
PTR sys_ni_syscall /* 5270 */
|
||||
PTR sys_kexec_load /* 5270 */
|
||||
PTR sys_getcpu
|
||||
PTR sys_epoll_pwait
|
||||
|
|
|
@ -394,6 +394,6 @@ EXPORT(sysn32_call_table)
|
|||
PTR sys_move_pages
|
||||
PTR compat_sys_set_robust_list
|
||||
PTR compat_sys_get_robust_list
|
||||
PTR sys_ni_syscall
|
||||
PTR compat_sys_kexec_load
|
||||
PTR sys_getcpu
|
||||
PTR sys_epoll_pwait
|
||||
|
|
|
@ -516,7 +516,7 @@ sys_call_table:
|
|||
PTR compat_sys_move_pages
|
||||
PTR compat_sys_set_robust_list
|
||||
PTR compat_sys_get_robust_list /* 4310 */
|
||||
PTR sys_ni_syscall
|
||||
PTR compat_sys_kexec_load
|
||||
PTR sys_getcpu
|
||||
PTR sys_epoll_pwait
|
||||
.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_S390 (22 << 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 */
|
||||
|
||||
|
|
Loading…
Reference in New Issue