m68k: Add kexec support
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
This commit is contained in:
parent
6cf30b3547
commit
7d5f5fa276
|
@ -87,6 +87,23 @@ config MMU_SUN3
|
||||||
bool
|
bool
|
||||||
depends on MMU && !MMU_MOTOROLA && !MMU_COLDFIRE
|
depends on MMU && !MMU_MOTOROLA && !MMU_COLDFIRE
|
||||||
|
|
||||||
|
config KEXEC
|
||||||
|
bool "kexec system call"
|
||||||
|
depends on M68KCLASSIC
|
||||||
|
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 independent of the system firmware. And like a reboot
|
||||||
|
you can start any kernel with it, not just Linux.
|
||||||
|
|
||||||
|
The name comes from the similarity 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. As of this writing the exact hardware
|
||||||
|
interface is strongly in flux, so no good recommendation can be
|
||||||
|
made.
|
||||||
|
|
||||||
menu "Platform setup"
|
menu "Platform setup"
|
||||||
|
|
||||||
source arch/m68k/Kconfig.cpu
|
source arch/m68k/Kconfig.cpu
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef _ASM_M68K_KEXEC_H
|
||||||
|
#define _ASM_M68K_KEXEC_H
|
||||||
|
|
||||||
|
#ifdef CONFIG_KEXEC
|
||||||
|
|
||||||
|
/* Maximum physical address we can use pages from */
|
||||||
|
#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
|
||||||
|
/* Maximum address we can reach in physical address mode */
|
||||||
|
#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
|
||||||
|
/* Maximum address we can use for the control code buffer */
|
||||||
|
#define KEXEC_CONTROL_MEMORY_LIMIT (-1UL)
|
||||||
|
|
||||||
|
#define KEXEC_CONTROL_PAGE_SIZE 4096
|
||||||
|
|
||||||
|
#define KEXEC_ARCH KEXEC_ARCH_68K
|
||||||
|
|
||||||
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
|
static inline void crash_setup_regs(struct pt_regs *newregs,
|
||||||
|
struct pt_regs *oldregs)
|
||||||
|
{
|
||||||
|
/* Dummy implementation for now */
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __ASSEMBLY__ */
|
||||||
|
|
||||||
|
#endif /* CONFIG_KEXEC */
|
||||||
|
|
||||||
|
#endif /* _ASM_M68K_KEXEC_H */
|
|
@ -22,3 +22,5 @@ obj-$(CONFIG_PCI) += pcibios.o
|
||||||
|
|
||||||
obj-$(CONFIG_HAS_DMA) += dma.o
|
obj-$(CONFIG_HAS_DMA) += dma.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
|
||||||
|
|
||||||
|
|
|
@ -98,6 +98,9 @@ int main(void)
|
||||||
DEFINE(CIABBASE, &ciab);
|
DEFINE(CIABBASE, &ciab);
|
||||||
DEFINE(C_PRA, offsetof(struct CIA, pra));
|
DEFINE(C_PRA, offsetof(struct CIA, pra));
|
||||||
DEFINE(ZTWOBASE, zTwoBase);
|
DEFINE(ZTWOBASE, zTwoBase);
|
||||||
|
|
||||||
|
/* enum m68k_fixup_type */
|
||||||
|
DEFINE(M68K_FIXUP_MEMOFFSET, m68k_fixup_memoffset);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* machine_kexec.c - handle transition of Linux booting another kernel
|
||||||
|
*/
|
||||||
|
#include <linux/compiler.h>
|
||||||
|
#include <linux/kexec.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
|
||||||
|
#include <asm/cacheflush.h>
|
||||||
|
#include <asm/page.h>
|
||||||
|
#include <asm/setup.h>
|
||||||
|
|
||||||
|
extern const unsigned char relocate_new_kernel[];
|
||||||
|
extern const size_t relocate_new_kernel_size;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (*relocate_kernel_t)(unsigned long ptr,
|
||||||
|
unsigned long start,
|
||||||
|
unsigned long cpu_mmu_flags) __noreturn;
|
||||||
|
|
||||||
|
void machine_kexec(struct kimage *image)
|
||||||
|
{
|
||||||
|
void *reboot_code_buffer;
|
||||||
|
unsigned long cpu_mmu_flags;
|
||||||
|
|
||||||
|
reboot_code_buffer = page_address(image->control_code_page);
|
||||||
|
|
||||||
|
memcpy(reboot_code_buffer, relocate_new_kernel,
|
||||||
|
relocate_new_kernel_size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we do not want to be bothered.
|
||||||
|
*/
|
||||||
|
local_irq_disable();
|
||||||
|
|
||||||
|
pr_info("Will call new kernel at 0x%08lx. Bye...\n", image->start);
|
||||||
|
__flush_cache_all();
|
||||||
|
cpu_mmu_flags = m68k_cputype | m68k_mmutype << 8;
|
||||||
|
((relocate_kernel_t) reboot_code_buffer)(image->head & PAGE_MASK,
|
||||||
|
image->start,
|
||||||
|
cpu_mmu_flags);
|
||||||
|
}
|
|
@ -0,0 +1,159 @@
|
||||||
|
#include <linux/linkage.h>
|
||||||
|
|
||||||
|
#include <asm/asm-offsets.h>
|
||||||
|
#include <asm/page.h>
|
||||||
|
#include <asm/setup.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define MMU_BASE 8 /* MMU flags base in cpu_mmu_flags */
|
||||||
|
|
||||||
|
.text
|
||||||
|
|
||||||
|
ENTRY(relocate_new_kernel)
|
||||||
|
movel %sp@(4),%a0 /* a0 = ptr */
|
||||||
|
movel %sp@(8),%a1 /* a1 = start */
|
||||||
|
movel %sp@(12),%d1 /* d1 = cpu_mmu_flags */
|
||||||
|
movew #PAGE_MASK,%d2 /* d2 = PAGE_MASK */
|
||||||
|
|
||||||
|
/* Disable MMU */
|
||||||
|
|
||||||
|
btst #MMU_BASE + MMUB_68851,%d1
|
||||||
|
jeq 3f
|
||||||
|
|
||||||
|
1: /* 68851 or 68030 */
|
||||||
|
|
||||||
|
lea %pc@(.Lcopy),%a4
|
||||||
|
2: addl #0x00000000,%a4 /* virt_to_phys() */
|
||||||
|
|
||||||
|
.section ".m68k_fixup","aw"
|
||||||
|
.long M68K_FIXUP_MEMOFFSET, 2b+2
|
||||||
|
.previous
|
||||||
|
|
||||||
|
.chip 68030
|
||||||
|
pmove %tc,%d0 /* Disable MMU */
|
||||||
|
bclr #7,%d0
|
||||||
|
pmove %d0,%tc
|
||||||
|
jmp %a4@ /* Jump to physical .Lcopy */
|
||||||
|
.chip 68k
|
||||||
|
|
||||||
|
3:
|
||||||
|
btst #MMU_BASE + MMUB_68030,%d1
|
||||||
|
jne 1b
|
||||||
|
|
||||||
|
btst #MMU_BASE + MMUB_68040,%d1
|
||||||
|
jeq 6f
|
||||||
|
|
||||||
|
4: /* 68040 or 68060 */
|
||||||
|
|
||||||
|
lea %pc@(.Lcont040),%a4
|
||||||
|
5: addl #0x00000000,%a4 /* virt_to_phys() */
|
||||||
|
|
||||||
|
.section ".m68k_fixup","aw"
|
||||||
|
.long M68K_FIXUP_MEMOFFSET, 5b+2
|
||||||
|
.previous
|
||||||
|
|
||||||
|
movel %a4,%d0
|
||||||
|
andl #0xff000000,%d0
|
||||||
|
orw #0xe020,%d0 /* Map 16 MiB, enable, cacheable */
|
||||||
|
.chip 68040
|
||||||
|
movec %d0,%itt0
|
||||||
|
movec %d0,%dtt0
|
||||||
|
.chip 68k
|
||||||
|
jmp %a4@ /* Jump to physical .Lcont040 */
|
||||||
|
|
||||||
|
.Lcont040:
|
||||||
|
moveq #0,%d0
|
||||||
|
.chip 68040
|
||||||
|
movec %d0,%tc /* Disable MMU */
|
||||||
|
movec %d0,%itt0
|
||||||
|
movec %d0,%itt1
|
||||||
|
movec %d0,%dtt0
|
||||||
|
movec %d0,%dtt1
|
||||||
|
.chip 68k
|
||||||
|
jra .Lcopy
|
||||||
|
|
||||||
|
6:
|
||||||
|
btst #MMU_BASE + MMUB_68060,%d1
|
||||||
|
jne 4b
|
||||||
|
|
||||||
|
.Lcopy:
|
||||||
|
movel %a0@+,%d0 /* d0 = entry = *ptr */
|
||||||
|
jeq .Lflush
|
||||||
|
|
||||||
|
btst #2,%d0 /* entry & IND_DONE? */
|
||||||
|
jne .Lflush
|
||||||
|
|
||||||
|
btst #1,%d0 /* entry & IND_INDIRECTION? */
|
||||||
|
jeq 1f
|
||||||
|
andw %d2,%d0
|
||||||
|
movel %d0,%a0 /* ptr = entry & PAGE_MASK */
|
||||||
|
jra .Lcopy
|
||||||
|
|
||||||
|
1:
|
||||||
|
btst #0,%d0 /* entry & IND_DESTINATION? */
|
||||||
|
jeq 2f
|
||||||
|
andw %d2,%d0
|
||||||
|
movel %d0,%a2 /* a2 = dst = entry & PAGE_MASK */
|
||||||
|
jra .Lcopy
|
||||||
|
|
||||||
|
2:
|
||||||
|
btst #3,%d0 /* entry & IND_SOURCE? */
|
||||||
|
jeq .Lcopy
|
||||||
|
|
||||||
|
andw %d2,%d0
|
||||||
|
movel %d0,%a3 /* a3 = src = entry & PAGE_MASK */
|
||||||
|
movew #PAGE_SIZE/32 - 1,%d0 /* d0 = PAGE_SIZE/32 - 1 */
|
||||||
|
3:
|
||||||
|
movel %a3@+,%a2@+ /* *dst++ = *src++ */
|
||||||
|
movel %a3@+,%a2@+ /* *dst++ = *src++ */
|
||||||
|
movel %a3@+,%a2@+ /* *dst++ = *src++ */
|
||||||
|
movel %a3@+,%a2@+ /* *dst++ = *src++ */
|
||||||
|
movel %a3@+,%a2@+ /* *dst++ = *src++ */
|
||||||
|
movel %a3@+,%a2@+ /* *dst++ = *src++ */
|
||||||
|
movel %a3@+,%a2@+ /* *dst++ = *src++ */
|
||||||
|
movel %a3@+,%a2@+ /* *dst++ = *src++ */
|
||||||
|
dbf %d0, 3b
|
||||||
|
jra .Lcopy
|
||||||
|
|
||||||
|
.Lflush:
|
||||||
|
/* Flush all caches */
|
||||||
|
|
||||||
|
btst #CPUB_68020,%d1
|
||||||
|
jeq 2f
|
||||||
|
|
||||||
|
1: /* 68020 or 68030 */
|
||||||
|
.chip 68030
|
||||||
|
movec %cacr,%d0
|
||||||
|
orw #0x808,%d0
|
||||||
|
movec %d0,%cacr
|
||||||
|
.chip 68k
|
||||||
|
jra .Lreincarnate
|
||||||
|
|
||||||
|
2:
|
||||||
|
btst #CPUB_68030,%d1
|
||||||
|
jne 1b
|
||||||
|
|
||||||
|
btst #CPUB_68040,%d1
|
||||||
|
jeq 4f
|
||||||
|
|
||||||
|
3: /* 68040 or 68060 */
|
||||||
|
.chip 68040
|
||||||
|
nop
|
||||||
|
cpusha %bc
|
||||||
|
nop
|
||||||
|
cinva %bc
|
||||||
|
nop
|
||||||
|
.chip 68k
|
||||||
|
jra .Lreincarnate
|
||||||
|
|
||||||
|
4:
|
||||||
|
btst #CPUB_68060,%d1
|
||||||
|
jne 3b
|
||||||
|
|
||||||
|
.Lreincarnate:
|
||||||
|
jmp %a1@
|
||||||
|
|
||||||
|
relocate_new_kernel_end:
|
||||||
|
|
||||||
|
ENTRY(relocate_new_kernel_size)
|
||||||
|
.long relocate_new_kernel_end - relocate_new_kernel
|
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
#define KEXEC_ARCH_DEFAULT ( 0 << 16)
|
#define KEXEC_ARCH_DEFAULT ( 0 << 16)
|
||||||
#define KEXEC_ARCH_386 ( 3 << 16)
|
#define KEXEC_ARCH_386 ( 3 << 16)
|
||||||
|
#define KEXEC_ARCH_68K ( 4 << 16)
|
||||||
#define KEXEC_ARCH_X86_64 (62 << 16)
|
#define KEXEC_ARCH_X86_64 (62 << 16)
|
||||||
#define KEXEC_ARCH_PPC (20 << 16)
|
#define KEXEC_ARCH_PPC (20 << 16)
|
||||||
#define KEXEC_ARCH_PPC64 (21 << 16)
|
#define KEXEC_ARCH_PPC64 (21 << 16)
|
||||||
|
|
Loading…
Reference in New Issue