xref: /linux/arch/sh/kernel/relocate_kernel.S (revision 0d456bad36d42d16022be045c8a53ddbb59ee478)
1/*
2 * relocate_kernel.S - put the kernel image in place to boot
3 * 2005.9.17 kogiidena@eggplant.ddo.jp
4 *
5 * LANDISK/sh4 is supported. Maybe, SH archtecture works well.
6 *
7 * 2009-03-18 Magnus Damm - Added Kexec Jump support
8 *
9 * This source code is licensed under the GNU General Public License,
10 * Version 2.  See the file COPYING for more details.
11 */
12#include <linux/linkage.h>
13#include <asm/addrspace.h>
14#include <asm/page.h>
15
16		.globl relocate_new_kernel
17relocate_new_kernel:
18	/* r4 = indirection_page   */
19	/* r5 = reboot_code_buffer */
20	/* r6 = start_address      */
21
22	mov.l	10f, r0		/* PAGE_SIZE */
23	add	r5, r0		/* setup new stack at end of control page */
24
25	/* save r15->r8 to new stack */
26	mov.l	r15, @-r0
27	mov	r0, r15
28	mov.l	r14, @-r15
29	mov.l	r13, @-r15
30	mov.l	r12, @-r15
31	mov.l	r11, @-r15
32	mov.l	r10, @-r15
33	mov.l	r9, @-r15
34	mov.l	r8, @-r15
35
36	/* save other random registers */
37	sts.l	macl, @-r15
38	sts.l	mach, @-r15
39	stc.l	gbr, @-r15
40	stc.l	ssr, @-r15
41	stc.l	sr, @-r15
42	sts.l	pr, @-r15
43	stc.l	spc, @-r15
44
45	/* switch to bank1 and save r7->r0 */
46	mov.l	12f, r9
47	stc	sr, r8
48	or	r9, r8
49	ldc	r8, sr
50	mov.l	r7, @-r15
51	mov.l	r6, @-r15
52	mov.l	r5, @-r15
53	mov.l	r4, @-r15
54	mov.l	r3, @-r15
55	mov.l	r2, @-r15
56	mov.l	r1, @-r15
57	mov.l	r0, @-r15
58
59	/* switch to bank0 and save r7->r0 */
60	mov.l	12f, r9
61	not	r9, r9
62	stc	sr, r8
63	and	r9, r8
64	ldc	r8, sr
65	mov.l	r7, @-r15
66	mov.l	r6, @-r15
67	mov.l	r5, @-r15
68	mov.l	r4, @-r15
69	mov.l	r3, @-r15
70	mov.l	r2, @-r15
71	mov.l	r1, @-r15
72	mov.l	r0, @-r15
73
74	mov.l	r4, @-r15	/* save indirection page again */
75
76	bsr	swap_pages	/* swap pages before jumping to new kernel */
77	 nop
78
79	mova	11f, r0
80	mov.l	r15, @r0	/* save pointer to stack */
81
82	jsr	@r6		/* hand over control to new kernel */
83	 nop
84
85	mov.l	11f, r15	/* get pointer to stack */
86	mov.l	@r15+, r4	/* restore r4 to get indirection page */
87
88	bsr	swap_pages	/* swap pages back to previous state */
89	 nop
90
91	/* make sure bank0 is active and restore r0->r7 */
92	mov.l	12f, r9
93	not	r9, r9
94	stc	sr, r8
95	and	r9, r8
96	ldc	r8, sr
97	mov.l	@r15+, r0
98	mov.l	@r15+, r1
99	mov.l	@r15+, r2
100	mov.l	@r15+, r3
101	mov.l	@r15+, r4
102	mov.l	@r15+, r5
103	mov.l	@r15+, r6
104	mov.l	@r15+, r7
105
106	/* switch to bank1 and restore r0->r7 */
107	mov.l	12f, r9
108	stc	sr, r8
109	or	r9, r8
110	ldc	r8, sr
111	mov.l	@r15+, r0
112	mov.l	@r15+, r1
113	mov.l	@r15+, r2
114	mov.l	@r15+, r3
115	mov.l	@r15+, r4
116	mov.l	@r15+, r5
117	mov.l	@r15+, r6
118	mov.l	@r15+, r7
119
120	/* switch back to bank0 */
121	mov.l	12f, r9
122	not	r9, r9
123	stc	sr, r8
124	and	r9, r8
125	ldc	r8, sr
126
127	/* restore other random registers */
128	ldc.l	@r15+, spc
129	lds.l	@r15+, pr
130	ldc.l	@r15+, sr
131	ldc.l	@r15+, ssr
132	ldc.l	@r15+, gbr
133	lds.l	@r15+, mach
134	lds.l	@r15+, macl
135
136	/* restore r8->r15 */
137	mov.l	@r15+, r8
138	mov.l	@r15+, r9
139	mov.l	@r15+, r10
140	mov.l	@r15+, r11
141	mov.l	@r15+, r12
142	mov.l	@r15+, r13
143	mov.l	@r15+, r14
144	mov.l	@r15+, r15
145	rts
146	 nop
147
148swap_pages:
149	bra	1f
150	 mov	r4,r0	  /* cmd = indirection_page */
1510:
152	mov.l	@r4+,r0	  /* cmd = *ind++ */
153
1541:	/* addr = cmd & 0xfffffff0 */
155	mov	r0,r2
156	mov	#-16,r1
157	and	r1,r2
158
159	/* if(cmd & IND_DESTINATION) dst = addr  */
160	tst	#1,r0
161	bt	2f
162	bra	0b
163	 mov	r2,r5
164
1652:	/* else if(cmd & IND_INDIRECTION) ind = addr  */
166	tst	#2,r0
167	bt	3f
168	bra	0b
169	 mov	r2,r4
170
1713:	/* else if(cmd & IND_DONE) return */
172	tst	#4,r0
173	bt	4f
174	rts
175	 nop
176
1774:	/* else if(cmd & IND_SOURCE) memcpy(dst,addr,PAGE_SIZE) */
178	tst	#8,r0
179	bt	0b
180
181	mov.l	10f,r3	  /* PAGE_SIZE */
182	shlr2	r3
183	shlr2	r3
1845:
185	dt	r3
186
187	/* regular kexec just overwrites the destination page
188	 * with the contents of the source page.
189	 * for the kexec jump case we need to swap the contents
190	 * of the pages.
191	 * to keep it simple swap the contents for both cases.
192	 */
193	mov.l	@(0, r2), r8
194	mov.l	@(0, r5), r1
195	mov.l	r8, @(0, r5)
196	mov.l	r1, @(0, r2)
197
198	mov.l	@(4, r2), r8
199	mov.l	@(4, r5), r1
200	mov.l	r8, @(4, r5)
201	mov.l	r1, @(4, r2)
202
203	mov.l	@(8, r2), r8
204	mov.l	@(8, r5), r1
205	mov.l	r8, @(8, r5)
206	mov.l	r1, @(8, r2)
207
208	mov.l	@(12, r2), r8
209	mov.l	@(12, r5), r1
210	mov.l	r8, @(12, r5)
211	mov.l	r1, @(12, r2)
212
213	add	#16,r5
214	add	#16,r2
215	bf	5b
216
217	bra	0b
218	 nop
219
220	.align 2
22110:
222	.long	PAGE_SIZE
22311:
224	.long	0
22512:
226	.long	0x20000000 ! RB=1
227
228relocate_new_kernel_end:
229
230	.globl relocate_new_kernel_size
231relocate_new_kernel_size:
232	.long relocate_new_kernel_end - relocate_new_kernel
233