From 0b6eb7f1c00acc5f9427ddcd08636b7817f52e3b Mon Sep 17 00:00:00 2001 From: Mans Rullgard Date: Mon, 3 May 2010 03:18:41 +0100 Subject: [PATCH] kexec as module for PCH C-200 Hack warning: this contains hardcoded memory addresses. It will not work on any other system. --- arch/mips/Kconfig | 2 +- arch/mips/kernel/Makefile | 4 ++- arch/mips/kernel/machine_kexec.c | 11 ++++++++++ include/linux/kexec.h | 11 ++++++--- kernel/kexec.c | 41 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 63 insertions(+), 6 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index fb7a5bd..d4ed1eb 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1789,7 +1789,7 @@ config MIPS_INSANE_LARGE recommended for normal users. config KEXEC - bool "Kexec system call (EXPERIMENTAL)" + tristate "Kexec system call (EXPERIMENTAL)" depends on EXPERIMENTAL help kexec is a system call that implements the ability to shutdown your diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 4924626..25aa246 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -64,7 +64,9 @@ obj-$(CONFIG_64BIT) += cpu-bugs64.o obj-$(CONFIG_I8253) += i8253.o -obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o +obj-$(CONFIG_KEXEC) += mips_kexec.o +mips_kexec-objs += machine_kexec.o relocate_kernel.o + obj-$(CONFIG_EARLY_PRINTK) += early_printk.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) diff --git a/arch/mips/kernel/machine_kexec.c b/arch/mips/kernel/machine_kexec.c index 8f42fa8..0b8fc5b 100644 --- a/arch/mips/kernel/machine_kexec.c +++ b/arch/mips/kernel/machine_kexec.c @@ -6,6 +6,7 @@ * Version 2. See the file COPYING for more details. */ +#include #include #include #include @@ -13,6 +14,11 @@ #include #include +/* HACK */ +#include +#define flush_cache_all() blast_dcache32() +#define flush_icache_range(a, b) blast_icache32() + extern const unsigned char relocate_new_kernel[]; extern const unsigned int relocate_new_kernel_size; @@ -24,21 +30,25 @@ machine_kexec_prepare(struct kimage *kimage) { return 0; } +EXPORT_SYMBOL(machine_kexec_prepare); void machine_kexec_cleanup(struct kimage *kimage) { } +EXPORT_SYMBOL(machine_kexec_cleanup); void machine_shutdown(void) { } +EXPORT_SYMBOL(machine_shutdown); void machine_crash_shutdown(struct pt_regs *regs) { } +EXPORT_SYMBOL(machine_crash_shutdown); void machine_kexec(struct kimage *image) @@ -83,3 +93,4 @@ machine_kexec(struct kimage *image) flush_cache_all(); ((void (*)(void))reboot_code_buffer)(); } +EXPORT_SYMBOL(machine_kexec); diff --git a/include/linux/kexec.h b/include/linux/kexec.h index 8c2c7fc..e2aa28e 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -1,7 +1,7 @@ #ifndef LINUX_KEXEC_H #define LINUX_KEXEC_H -#ifdef CONFIG_KEXEC +#if defined CONFIG_KEXEC || defined CONFIG_KEXEC_MODULE #include #include #include @@ -118,8 +118,6 @@ extern asmlinkage long compat_sys_kexec_load(unsigned long entry, #endif extern struct page *kimage_alloc_control_pages(struct kimage *image, unsigned int order); -extern void crash_kexec(struct pt_regs *); -int kexec_should_crash(struct task_struct *); void crash_save_cpu(struct pt_regs *regs, int cpu); extern struct kimage *kexec_image; extern struct kimage *kexec_crash_image; @@ -155,7 +153,12 @@ typedef u32 note_buf_t[KEXEC_NOTE_BYTES/4]; extern note_buf_t *crash_notes; -#else /* !CONFIG_KEXEC */ +#endif /* CONFIG_KEXEC || CONFIG_KEXEC_MODULE */ + +#ifdef CONFIG_KEXEC +extern void crash_kexec(struct pt_regs *); +int kexec_should_crash(struct task_struct *); +#else struct pt_regs; struct task_struct; static inline void crash_kexec(struct pt_regs *regs) { } diff --git a/kernel/kexec.c b/kernel/kexec.c index 25db14b..6d2e322 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -28,6 +28,7 @@ #include #include #include +#include /* Per cpu memory for storing cpu states in case of system crash. */ note_buf_t* crash_notes; @@ -40,12 +41,14 @@ struct resource crashk_res = { .flags = IORESOURCE_BUSY | IORESOURCE_MEM }; +#ifdef CONFIG_KEXEC int kexec_should_crash(struct task_struct *p) { if (in_interrupt() || !p->pid || is_init(p) || panic_on_oops) return 1; return 0; } +#endif /* * When kexec transitions to the new kernel there is a one-to-one @@ -1001,6 +1004,8 @@ out: BUG_ON(!locked); kimage_free(image); + printk("kexec_load(%lx) = %d\n", entry, result); + return result; } @@ -1043,6 +1048,7 @@ asmlinkage long compat_sys_kexec_load(unsigned long entry, } #endif +#ifdef CONFIG_KEXEC void crash_kexec(struct pt_regs *regs) { int locked; @@ -1135,3 +1141,38 @@ static int __init crash_notes_memory_init(void) return 0; } module_init(crash_notes_memory_init) +#endif + +#ifdef CONFIG_KEXEC_MODULE +/** + * kernel_kexec - reboot the system + * + * Move into place and start executing a preloaded standalone + * executable. If nothing was preloaded return an error. + */ +asmlinkage long sys_do_kexec(int magic1, int magic2, unsigned int cmd, + void __user *arg) +{ + struct kimage *image; + void (*device_shutdown)(void) = (void*)0x8423fe50; + image = xchg(&kexec_image, NULL); + if (!image) + return -1; + device_shutdown(); + printk(KERN_EMERG "Starting new kernel\n"); + machine_shutdown(); + machine_kexec(image); + return 0; +} + +static int __init kexec_init(void) +{ + unsigned long (*sys_call_table)[2] = (void*)0x84012e30; + sys_call_table[__NR_kexec_load - __NR_Linux][0] = + (unsigned long)sys_kexec_load; + sys_call_table[__NR_reboot - __NR_Linux][0] = + (unsigned long)sys_do_kexec; + return 0; +} +module_init(kexec_init) +#endif -- 1.7.0.4