| kogiidena | 9d44190 | 2006-01-16 22:14:10 -0800 | [diff] [blame] | 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 | * | 
| Magnus Damm | b7cf6dd | 2009-03-18 08:51:29 +0000 | [diff] [blame] | 7 | * 2009-03-18 Magnus Damm - Added Kexec Jump support | 
|  | 8 | * | 
| kogiidena | 9d44190 | 2006-01-16 22:14:10 -0800 | [diff] [blame] | 9 | * This source code is licensed under the GNU General Public License, | 
|  | 10 | * Version 2.  See the file COPYING for more details. | 
|  | 11 | */ | 
| kogiidena | 9d44190 | 2006-01-16 22:14:10 -0800 | [diff] [blame] | 12 | #include <linux/linkage.h> | 
| Paul Mundt | 510c72ad | 2006-11-27 12:06:26 +0900 | [diff] [blame] | 13 | #include <asm/addrspace.h> | 
|  | 14 | #include <asm/page.h> | 
| kogiidena | 9d44190 | 2006-01-16 22:14:10 -0800 | [diff] [blame] | 15 |  | 
|  | 16 | .globl relocate_new_kernel | 
|  | 17 | relocate_new_kernel: | 
|  | 18 | /* r4 = indirection_page   */ | 
|  | 19 | /* r5 = reboot_code_buffer */ | 
|  | 20 | /* r6 = start_address      */ | 
| kogiidena | 9d44190 | 2006-01-16 22:14:10 -0800 | [diff] [blame] | 21 |  | 
| Magnus Damm | b7cf6dd | 2009-03-18 08:51:29 +0000 | [diff] [blame] | 22 | mov.l	10f, r0		/* PAGE_SIZE */ | 
|  | 23 | add	r5, r0		/* setup new stack at end of control page */ | 
| kogiidena | 9d44190 | 2006-01-16 22:14:10 -0800 | [diff] [blame] | 24 |  | 
| Magnus Damm | b7cf6dd | 2009-03-18 08:51:29 +0000 | [diff] [blame] | 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 | 
| kogiidena | 9d44190 | 2006-01-16 22:14:10 -0800 | [diff] [blame] | 35 |  | 
| Magnus Damm | b7cf6dd | 2009-03-18 08:51:29 +0000 | [diff] [blame] | 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 |  | 
|  | 148 | swap_pages: | 
| kogiidena | 9d44190 | 2006-01-16 22:14:10 -0800 | [diff] [blame] | 149 | bra	1f | 
| Magnus Damm | b7cf6dd | 2009-03-18 08:51:29 +0000 | [diff] [blame] | 150 | mov	r4,r0	  /* cmd = indirection_page */ | 
| kogiidena | 9d44190 | 2006-01-16 22:14:10 -0800 | [diff] [blame] | 151 | 0: | 
|  | 152 | mov.l	@r4+,r0	  /* cmd = *ind++ */ | 
|  | 153 |  | 
| Magnus Damm | e4e063d | 2009-03-18 08:49:45 +0000 | [diff] [blame] | 154 | 1:	/* addr = cmd & 0xfffffff0 */ | 
| kogiidena | 9d44190 | 2006-01-16 22:14:10 -0800 | [diff] [blame] | 155 | mov	r0,r2 | 
| kogiidena | 9d44190 | 2006-01-16 22:14:10 -0800 | [diff] [blame] | 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 | 
| Magnus Damm | b7cf6dd | 2009-03-18 08:51:29 +0000 | [diff] [blame] | 163 | mov	r2,r5 | 
| kogiidena | 9d44190 | 2006-01-16 22:14:10 -0800 | [diff] [blame] | 164 |  | 
|  | 165 | 2:	/* else if(cmd & IND_INDIRECTION) ind = addr  */ | 
|  | 166 | tst	#2,r0 | 
|  | 167 | bt	3f | 
|  | 168 | bra	0b | 
| Magnus Damm | b7cf6dd | 2009-03-18 08:51:29 +0000 | [diff] [blame] | 169 | mov	r2,r4 | 
| kogiidena | 9d44190 | 2006-01-16 22:14:10 -0800 | [diff] [blame] | 170 |  | 
| Magnus Damm | b7cf6dd | 2009-03-18 08:51:29 +0000 | [diff] [blame] | 171 | 3:	/* else if(cmd & IND_DONE) return */ | 
| kogiidena | 9d44190 | 2006-01-16 22:14:10 -0800 | [diff] [blame] | 172 | tst	#4,r0 | 
|  | 173 | bt	4f | 
| Magnus Damm | b7cf6dd | 2009-03-18 08:51:29 +0000 | [diff] [blame] | 174 | rts | 
|  | 175 | nop | 
| kogiidena | 9d44190 | 2006-01-16 22:14:10 -0800 | [diff] [blame] | 176 |  | 
|  | 177 | 4:	/* else if(cmd & IND_SOURCE) memcpy(dst,addr,PAGE_SIZE) */ | 
|  | 178 | tst	#8,r0 | 
|  | 179 | bt	0b | 
|  | 180 |  | 
| Magnus Damm | b7cf6dd | 2009-03-18 08:51:29 +0000 | [diff] [blame] | 181 | mov.l	10f,r3	  /* PAGE_SIZE */ | 
| kogiidena | 9d44190 | 2006-01-16 22:14:10 -0800 | [diff] [blame] | 182 | shlr2	r3 | 
|  | 183 | shlr2	r3 | 
|  | 184 | 5: | 
|  | 185 | dt	r3 | 
| Magnus Damm | b7cf6dd | 2009-03-18 08:51:29 +0000 | [diff] [blame] | 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 | 
| kogiidena | 9d44190 | 2006-01-16 22:14:10 -0800 | [diff] [blame] | 215 | bf	5b | 
|  | 216 |  | 
|  | 217 | bra	0b | 
| Magnus Damm | b7cf6dd | 2009-03-18 08:51:29 +0000 | [diff] [blame] | 218 | nop | 
| kogiidena | 9d44190 | 2006-01-16 22:14:10 -0800 | [diff] [blame] | 219 |  | 
|  | 220 | .align 2 | 
|  | 221 | 10: | 
|  | 222 | .long	PAGE_SIZE | 
| Magnus Damm | b7cf6dd | 2009-03-18 08:51:29 +0000 | [diff] [blame] | 223 | 11: | 
|  | 224 | .long	0 | 
|  | 225 | 12: | 
|  | 226 | .long	0x20000000 ! RB=1 | 
| kogiidena | 9d44190 | 2006-01-16 22:14:10 -0800 | [diff] [blame] | 227 |  | 
|  | 228 | relocate_new_kernel_end: | 
|  | 229 |  | 
|  | 230 | .globl relocate_new_kernel_size | 
|  | 231 | relocate_new_kernel_size: | 
|  | 232 | .long relocate_new_kernel_end - relocate_new_kernel |