aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m68k
diff options
context:
space:
mode:
authorGeert Uytterhoeven <geert@linux-m68k.org>2013-08-20 16:51:47 -0400
committerGeert Uytterhoeven <geert@linux-m68k.org>2013-12-08 05:01:47 -0500
commit7d5f5fa276efbbe45f0ed270b3f4e4a2816398c2 (patch)
tree34e7ba2d35c238bd80bfdbacbc03f209da587942 /arch/m68k
parent6cf30b35475435f453d87838fb14ad3483955a19 (diff)
m68k: Add kexec support
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Diffstat (limited to 'arch/m68k')
-rw-r--r--arch/m68k/Kconfig17
-rw-r--r--arch/m68k/include/asm/kexec.h29
-rw-r--r--arch/m68k/kernel/Makefile2
-rw-r--r--arch/m68k/kernel/asm-offsets.c3
-rw-r--r--arch/m68k/kernel/machine_kexec.c58
-rw-r--r--arch/m68k/kernel/relocate_kernel.S159
6 files changed, 268 insertions, 0 deletions
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 75f25a8e3001..178dffa9de80 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -87,6 +87,23 @@ config MMU_SUN3
87 bool 87 bool
88 depends on MMU && !MMU_MOTOROLA && !MMU_COLDFIRE 88 depends on MMU && !MMU_MOTOROLA && !MMU_COLDFIRE
89 89
90config 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
90menu "Platform setup" 107menu "Platform setup"
91 108
92source arch/m68k/Kconfig.cpu 109source arch/m68k/Kconfig.cpu
diff --git a/arch/m68k/include/asm/kexec.h b/arch/m68k/include/asm/kexec.h
new file mode 100644
index 000000000000..3df97abac147
--- /dev/null
+++ b/arch/m68k/include/asm/kexec.h
@@ -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
19static 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 */
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile
index 655347d80780..7ee5f00a9abb 100644
--- a/arch/m68k/kernel/Makefile
+++ b/arch/m68k/kernel/Makefile
@@ -22,3 +22,5 @@ obj-$(CONFIG_PCI) += pcibios.o
22 22
23obj-$(CONFIG_HAS_DMA) += dma.o 23obj-$(CONFIG_HAS_DMA) += dma.o
24 24
25obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
26
diff --git a/arch/m68k/kernel/asm-offsets.c b/arch/m68k/kernel/asm-offsets.c
index 8b7b22846366..3a386341aa6e 100644
--- a/arch/m68k/kernel/asm-offsets.c
+++ b/arch/m68k/kernel/asm-offsets.c
@@ -98,6 +98,9 @@ int main(void)
98 DEFINE(CIABBASE, &ciab); 98 DEFINE(CIABBASE, &ciab);
99 DEFINE(C_PRA, offsetof(struct CIA, pra)); 99 DEFINE(C_PRA, offsetof(struct CIA, pra));
100 DEFINE(ZTWOBASE, zTwoBase); 100 DEFINE(ZTWOBASE, zTwoBase);
101
102 /* enum m68k_fixup_type */
103 DEFINE(M68K_FIXUP_MEMOFFSET, m68k_fixup_memoffset);
101#endif 104#endif
102 105
103 return 0; 106 return 0;
diff --git a/arch/m68k/kernel/machine_kexec.c b/arch/m68k/kernel/machine_kexec.c
new file mode 100644
index 000000000000..d4affc917d9d
--- /dev/null
+++ b/arch/m68k/kernel/machine_kexec.c
@@ -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
13extern const unsigned char relocate_new_kernel[];
14extern const size_t relocate_new_kernel_size;
15
16int machine_kexec_prepare(struct kimage *kimage)
17{
18 return 0;
19}
20
21void machine_kexec_cleanup(struct kimage *kimage)
22{
23}
24
25void machine_shutdown(void)
26{
27}
28
29void machine_crash_shutdown(struct pt_regs *regs)
30{
31}
32
33typedef void (*relocate_kernel_t)(unsigned long ptr,
34 unsigned long start,
35 unsigned long cpu_mmu_flags) __noreturn;
36
37void 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}
diff --git a/arch/m68k/kernel/relocate_kernel.S b/arch/m68k/kernel/relocate_kernel.S
new file mode 100644
index 000000000000..3e09a89067ad
--- /dev/null
+++ b/arch/m68k/kernel/relocate_kernel.S
@@ -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
12ENTRY(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
231: /* 68851 or 68030 */
24
25 lea %pc@(.Lcopy),%a4
262: 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
393:
40 btst #MMU_BASE + MMUB_68030,%d1
41 jne 1b
42
43 btst #MMU_BASE + MMUB_68040,%d1
44 jeq 6f
45
464: /* 68040 or 68060 */
47
48 lea %pc@(.Lcont040),%a4
495: 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
756:
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
921:
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
992:
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 */
1063:
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
1241: /* 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
1322:
133 btst #CPUB_68030,%d1
134 jne 1b
135
136 btst #CPUB_68040,%d1
137 jeq 4f
138
1393: /* 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
1494:
150 btst #CPUB_68060,%d1
151 jne 3b
152
153.Lreincarnate:
154 jmp %a1@
155
156relocate_new_kernel_end:
157
158ENTRY(relocate_new_kernel_size)
159 .long relocate_new_kernel_end - relocate_new_kernel