Commit 7d5f5fa2 authored by Geert Uytterhoeven's avatar Geert Uytterhoeven
Browse files

m68k: Add kexec support

parent 6cf30b35
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -87,6 +87,23 @@ config MMU_SUN3
	bool
	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"

source arch/m68k/Kconfig.cpu
+29 −0
Original line number Diff line number Diff line
#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 */
+2 −0
Original line number Diff line number Diff line
@@ -22,3 +22,5 @@ obj-$(CONFIG_PCI) += pcibios.o

obj-$(CONFIG_HAS_DMA)	+= dma.o

obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
+3 −0
Original line number Diff line number Diff line
@@ -98,6 +98,9 @@ int main(void)
	DEFINE(CIABBASE, &ciab);
	DEFINE(C_PRA, offsetof(struct CIA, pra));
	DEFINE(ZTWOBASE, zTwoBase);

	/* enum m68k_fixup_type */
	DEFINE(M68K_FIXUP_MEMOFFSET, m68k_fixup_memoffset);
#endif

	return 0;
+58 −0
Original line number Diff line number Diff line
/*
 * 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);
}
Loading