History

m68k: Add kexec support

Geert Uytterhoeven committed 13 years ago

Commit 7d5f5fa1 parent 6cf30b37 files · +269 −0Browse files

Unified · Split

7 files
  1. arch/m68k/Kconfig +17 −0
  2. arch/m68k/include/asm/kexec.h +29 −0
  3. arch/m68k/kernel/Makefile +2 −0
  4. arch/m68k/kernel/asm-offsets.c +3 −0
  5. arch/m68k/kernel/machine_kexec.c +58 −0
  6. arch/m68k/kernel/relocate_kernel.S +159 −0
  7. include/uapi/linux/kexec.h +1 −0
arch/m68k/Kconfig+17−0
@@ -87,6 +87,23 @@ config MMU_SUN3 · 86 unmodified lines
8787 bool
8888 depends on MMU && !MMU_MOTOROLA && !MMU_COLDFIRE
8989
90+config KEXEC
91+ bool "kexec system call"
92+ depends on M68KCLASSIC
93+ help
94+ kexec is a system call that implements the ability to shutdown your
95+ current kernel, and to start another kernel. It is like a reboot
96+ but it is independent of the system firmware. And like a reboot
97+ you can start any kernel with it, not just Linux.
98+
99+ The name comes from the similarity to the exec system call.
100+
101+ It is an ongoing process to be certain the hardware in a machine
102+ is properly shutdown, so do not be surprised if this code does not
103+ initially work for you. As of this writing the exact hardware
104+ interface is strongly in flux, so no good recommendation can be
105+ made.
106+
90107 menu "Platform setup"
91108
92109 source arch/m68k/Kconfig.cpu
arch/m68k/include/asm/kexec.h+29−0
@@ -0,0 +1,29 @@
1+#ifndef _ASM_M68K_KEXEC_H
2+#define _ASM_M68K_KEXEC_H
3+
4+#ifdef CONFIG_KEXEC
5+
6+/* Maximum physical address we can use pages from */
7+#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
8+/* Maximum address we can reach in physical address mode */
9+#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
10+/* Maximum address we can use for the control code buffer */
11+#define KEXEC_CONTROL_MEMORY_LIMIT (-1UL)
12+
13+#define KEXEC_CONTROL_PAGE_SIZE 4096
14+
15+#define KEXEC_ARCH KEXEC_ARCH_68K
16+
17+#ifndef __ASSEMBLY__
18+
19+static inline void crash_setup_regs(struct pt_regs *newregs,
20+ struct pt_regs *oldregs)
21+{
22+ /* Dummy implementation for now */
23+}
24+
25+#endif /* __ASSEMBLY__ */
26+
27+#endif /* CONFIG_KEXEC */
28+
29+#endif /* _ASM_M68K_KEXEC_H */
arch/m68k/kernel/Makefile+2−0
@@ -22,3 +22,5 @@ obj-$(CONFIG_PCI) += pcibios.o · 21 unmodified lines
2222
2323 obj-$(CONFIG_HAS_DMA) += dma.o
2424
25+obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
26+
arch/m68k/kernel/asm-offsets.c+3−0
@@ -98,6 +98,9 @@ int main(void) · 97 unmodified lines
9898 DEFINE(CIABBASE, &ciab);
9999 DEFINE(C_PRA, offsetof(struct CIA, pra));
100100 DEFINE(ZTWOBASE, zTwoBase);
101+
102+ /* enum m68k_fixup_type */
103+ DEFINE(M68K_FIXUP_MEMOFFSET, m68k_fixup_memoffset);
101104 #endif
102105
103106 return 0;
arch/m68k/kernel/machine_kexec.c+58−0
@@ -0,0 +1,58 @@
1+/*
2+ * machine_kexec.c - handle transition of Linux booting another kernel
3+ */
4+#include <linux/compiler.h>
5+#include <linux/kexec.h>
6+#include <linux/mm.h>
7+#include <linux/delay.h>
8+
9+#include <asm/cacheflush.h>
10+#include <asm/page.h>
11+#include <asm/setup.h>
12+
13+extern const unsigned char relocate_new_kernel[];
14+extern const size_t relocate_new_kernel_size;
15+
16+int machine_kexec_prepare(struct kimage *kimage)
17+{
18+ return 0;
19+}
20+
21+void machine_kexec_cleanup(struct kimage *kimage)
22+{
23+}
24+
25+void machine_shutdown(void)
26+{
27+}
28+
29+void machine_crash_shutdown(struct pt_regs *regs)
30+{
31+}
32+
33+typedef void (*relocate_kernel_t)(unsigned long ptr,
34+ unsigned long start,
35+ unsigned long cpu_mmu_flags) __noreturn;
36+
37+void machine_kexec(struct kimage *image)
38+{
39+ void *reboot_code_buffer;
40+ unsigned long cpu_mmu_flags;
41+
42+ reboot_code_buffer = page_address(image->control_code_page);
43+
44+ memcpy(reboot_code_buffer, relocate_new_kernel,
45+ relocate_new_kernel_size);
46+
47+ /*
48+ * we do not want to be bothered.
49+ */
50+ local_irq_disable();
51+
52+ pr_info("Will call new kernel at 0x%08lx. Bye...\n", image->start);
53+ __flush_cache_all();
54+ cpu_mmu_flags = m68k_cputype | m68k_mmutype << 8;
55+ ((relocate_kernel_t) reboot_code_buffer)(image->head & PAGE_MASK,
56+ image->start,
57+ cpu_mmu_flags);
58+}
arch/m68k/kernel/relocate_kernel.S+159−0
@@ -0,0 +1,159 @@
1+#include <linux/linkage.h>
2+
3+#include <asm/asm-offsets.h>
4+#include <asm/page.h>
5+#include <asm/setup.h>
6+
7+
8+#define MMU_BASE 8 /* MMU flags base in cpu_mmu_flags */
9+
10+.text
11+
12+ENTRY(relocate_new_kernel)
13+ movel %sp@(4),%a0 /* a0 = ptr */
14+ movel %sp@(8),%a1 /* a1 = start */
15+ movel %sp@(12),%d1 /* d1 = cpu_mmu_flags */
16+ movew #PAGE_MASK,%d2 /* d2 = PAGE_MASK */
17+
18+ /* Disable MMU */
19+
20+ btst #MMU_BASE + MMUB_68851,%d1
21+ jeq 3f
22+
23+1: /* 68851 or 68030 */
24+
25+ lea %pc@(.Lcopy),%a4
26+2: addl #0x00000000,%a4 /* virt_to_phys() */
27+
28+ .section ".m68k_fixup","aw"
29+ .long M68K_FIXUP_MEMOFFSET, 2b+2
30+ .previous
31+
32+ .chip 68030
33+ pmove %tc,%d0 /* Disable MMU */
34+ bclr #7,%d0
35+ pmove %d0,%tc
36+ jmp %a4@ /* Jump to physical .Lcopy */
37+ .chip 68k
38+
39+3:
40+ btst #MMU_BASE + MMUB_68030,%d1
41+ jne 1b
42+
43+ btst #MMU_BASE + MMUB_68040,%d1
44+ jeq 6f
45+
46+4: /* 68040 or 68060 */
47+
48+ lea %pc@(.Lcont040),%a4
49+5: addl #0x00000000,%a4 /* virt_to_phys() */
50+
51+ .section ".m68k_fixup","aw"
52+ .long M68K_FIXUP_MEMOFFSET, 5b+2
53+ .previous
54+
55+ movel %a4,%d0
56+ andl #0xff000000,%d0
57+ orw #0xe020,%d0 /* Map 16 MiB, enable, cacheable */
58+ .chip 68040
59+ movec %d0,%itt0
60+ movec %d0,%dtt0
61+ .chip 68k
62+ jmp %a4@ /* Jump to physical .Lcont040 */
63+
64+.Lcont040:
65+ moveq #0,%d0
66+ .chip 68040
67+ movec %d0,%tc /* Disable MMU */
68+ movec %d0,%itt0
69+ movec %d0,%itt1
70+ movec %d0,%dtt0
71+ movec %d0,%dtt1
72+ .chip 68k
73+ jra .Lcopy
74+
75+6:
76+ btst #MMU_BASE + MMUB_68060,%d1
77+ jne 4b
78+
79+.Lcopy:
80+ movel %a0@+,%d0 /* d0 = entry = *ptr */
81+ jeq .Lflush
82+
83+ btst #2,%d0 /* entry & IND_DONE? */
84+ jne .Lflush
85+
86+ btst #1,%d0 /* entry & IND_INDIRECTION? */
87+ jeq 1f
88+ andw %d2,%d0
89+ movel %d0,%a0 /* ptr = entry & PAGE_MASK */
90+ jra .Lcopy
91+
92+1:
93+ btst #0,%d0 /* entry & IND_DESTINATION? */
94+ jeq 2f
95+ andw %d2,%d0
96+ movel %d0,%a2 /* a2 = dst = entry & PAGE_MASK */
97+ jra .Lcopy
98+
99+2:
100+ btst #3,%d0 /* entry & IND_SOURCE? */
101+ jeq .Lcopy
102+
103+ andw %d2,%d0
104+ movel %d0,%a3 /* a3 = src = entry & PAGE_MASK */
105+ movew #PAGE_SIZE/32 - 1,%d0 /* d0 = PAGE_SIZE/32 - 1 */
106+3:
107+ movel %a3@+,%a2@+ /* *dst++ = *src++ */
108+ movel %a3@+,%a2@+ /* *dst++ = *src++ */
109+ movel %a3@+,%a2@+ /* *dst++ = *src++ */
110+ movel %a3@+,%a2@+ /* *dst++ = *src++ */
111+ movel %a3@+,%a2@+ /* *dst++ = *src++ */
112+ movel %a3@+,%a2@+ /* *dst++ = *src++ */
113+ movel %a3@+,%a2@+ /* *dst++ = *src++ */
114+ movel %a3@+,%a2@+ /* *dst++ = *src++ */
115+ dbf %d0, 3b
116+ jra .Lcopy
117+
118+.Lflush:
119+ /* Flush all caches */
120+
121+ btst #CPUB_68020,%d1
122+ jeq 2f
123+
124+1: /* 68020 or 68030 */
125+ .chip 68030
126+ movec %cacr,%d0
127+ orw #0x808,%d0
128+ movec %d0,%cacr
129+ .chip 68k
130+ jra .Lreincarnate
131+
132+2:
133+ btst #CPUB_68030,%d1
134+ jne 1b
135+
136+ btst #CPUB_68040,%d1
137+ jeq 4f
138+
139+3: /* 68040 or 68060 */
140+ .chip 68040
141+ nop
142+ cpusha %bc
143+ nop
144+ cinva %bc
145+ nop
146+ .chip 68k
147+ jra .Lreincarnate
148+
149+4:
150+ btst #CPUB_68060,%d1
151+ jne 3b
152+
153+.Lreincarnate:
154+ jmp %a1@
155+
156+relocate_new_kernel_end:
157+
158+ENTRY(relocate_new_kernel_size)
159+ .long relocate_new_kernel_end - relocate_new_kernel
include/uapi/linux/kexec.h+1−0
@@ -18,6 +18,7 @@ · 17 unmodified lines
1818 */
1919 #define KEXEC_ARCH_DEFAULT ( 0 << 16)
2020 #define KEXEC_ARCH_386 ( 3 << 16)
21+#define KEXEC_ARCH_68K ( 4 << 16)
2122 #define KEXEC_ARCH_X86_64 (62 << 16)
2223 #define KEXEC_ARCH_PPC (20 << 16)
2324 #define KEXEC_ARCH_PPC64 (21 << 16)