Commit | Line | Data |
---|---|---|
867e359b | 1 | /* |
fc0c49f5 | 2 | * Copyright 2011 Tilera Corporation. All Rights Reserved. |
867e359b CM |
3 | * |
4 | * This program is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU General Public License | |
6 | * as published by the Free Software Foundation, version 2. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, but | |
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | |
11 | * NON INFRINGEMENT. See the GNU General Public License for | |
12 | * more details. | |
13 | * | |
14 | * copy new kernel into place and then call hv_reexec | |
15 | * | |
16 | */ | |
17 | ||
18 | #include <linux/linkage.h> | |
19 | #include <arch/chip.h> | |
20 | #include <asm/page.h> | |
21 | #include <hv/hypervisor.h> | |
22 | ||
867e359b CM |
23 | #undef RELOCATE_NEW_KERNEL_VERBOSE |
24 | ||
25 | STD_ENTRY(relocate_new_kernel) | |
26 | ||
27 | move r30, r0 /* page list */ | |
28 | move r31, r1 /* address of page we are on */ | |
29 | move r32, r2 /* start address of new kernel */ | |
30 | ||
fc0c49f5 | 31 | shrui r1, r1, PAGE_SHIFT |
867e359b CM |
32 | addi r1, r1, 1 |
33 | shli sp, r1, PAGE_SHIFT | |
34 | addi sp, sp, -8 | |
35 | /* we now have a stack (whether we need one or not) */ | |
36 | ||
309272f9 | 37 | #ifdef RELOCATE_NEW_KERNEL_VERBOSE |
fc0c49f5 CM |
38 | moveli r40, hw2_last(hv_console_putc) |
39 | shl16insli r40, r40, hw1(hv_console_putc) | |
40 | shl16insli r40, r40, hw0(hv_console_putc) | |
867e359b | 41 | |
867e359b CM |
42 | moveli r0, 'r' |
43 | jalr r40 | |
44 | ||
45 | moveli r0, '_' | |
46 | jalr r40 | |
47 | ||
48 | moveli r0, 'n' | |
49 | jalr r40 | |
50 | ||
51 | moveli r0, '_' | |
52 | jalr r40 | |
53 | ||
54 | moveli r0, 'k' | |
55 | jalr r40 | |
56 | ||
57 | moveli r0, '\n' | |
58 | jalr r40 | |
59 | #endif | |
60 | ||
61 | /* | |
62 | * Throughout this code r30 is pointer to the element of page | |
63 | * list we are working on. | |
64 | * | |
65 | * Normally we get to the next element of the page list by | |
fc0c49f5 | 66 | * incrementing r30 by eight. The exception is if the element |
867e359b CM |
67 | * on the page list is an IND_INDIRECTION in which case we use |
68 | * the element with the low bits masked off as the new value | |
69 | * of r30. | |
70 | * | |
71 | * To get this started, we need the value passed to us (which | |
72 | * will always be an IND_INDIRECTION) in memory somewhere with | |
73 | * r30 pointing at it. To do that, we push the value passed | |
74 | * to us on the stack and make r30 point to it. | |
75 | */ | |
76 | ||
fc0c49f5 | 77 | st sp, r30 |
867e359b | 78 | move r30, sp |
fc0c49f5 | 79 | addi sp, sp, -16 |
867e359b | 80 | |
867e359b | 81 | /* |
fc0c49f5 | 82 | * On TILE-GX, we need to flush all tiles' caches, since we may |
867e359b CM |
83 | * have been doing hash-for-home caching there. Note that we |
84 | * must do this _after_ we're completely done modifying any memory | |
85 | * other than our output buffer (which we know is locally cached). | |
86 | * We want the caches to be fully clean when we do the reexec, | |
87 | * because the hypervisor is going to do this flush again at that | |
88 | * point, and we don't want that second flush to overwrite any memory. | |
89 | */ | |
90 | { | |
91 | move r0, zero /* cache_pa */ | |
fc0c49f5 | 92 | moveli r1, hw2_last(HV_FLUSH_EVICT_L2) |
867e359b CM |
93 | } |
94 | { | |
fc0c49f5 CM |
95 | shl16insli r1, r1, hw1(HV_FLUSH_EVICT_L2) |
96 | movei r2, -1 /* cache_cpumask; -1 means all client tiles */ | |
867e359b CM |
97 | } |
98 | { | |
fc0c49f5 CM |
99 | shl16insli r1, r1, hw0(HV_FLUSH_EVICT_L2) /* cache_control */ |
100 | move r3, zero /* tlb_va */ | |
867e359b CM |
101 | } |
102 | { | |
fc0c49f5 CM |
103 | move r4, zero /* tlb_length */ |
104 | move r5, zero /* tlb_pgsize */ | |
867e359b CM |
105 | } |
106 | { | |
fc0c49f5 CM |
107 | move r6, zero /* tlb_cpumask */ |
108 | move r7, zero /* asids */ | |
867e359b CM |
109 | } |
110 | { | |
fc0c49f5 CM |
111 | moveli r20, hw2_last(hv_flush_remote) |
112 | move r8, zero /* asidcount */ | |
867e359b | 113 | } |
fc0c49f5 CM |
114 | shl16insli r20, r20, hw1(hv_flush_remote) |
115 | shl16insli r20, r20, hw0(hv_flush_remote) | |
867e359b CM |
116 | |
117 | jalr r20 | |
867e359b CM |
118 | |
119 | /* r33 is destination pointer, default to zero */ | |
120 | ||
121 | moveli r33, 0 | |
122 | ||
fc0c49f5 | 123 | .Lloop: ld r10, r30 |
867e359b CM |
124 | |
125 | andi r9, r10, 0xf /* low 4 bits tell us what type it is */ | |
126 | xor r10, r10, r9 /* r10 is now value with low 4 bits stripped */ | |
127 | ||
fc0c49f5 CM |
128 | cmpeqi r0, r9, 0x1 /* IND_DESTINATION */ |
129 | beqzt r0, .Ltry2 | |
867e359b CM |
130 | |
131 | move r33, r10 | |
132 | ||
133 | #ifdef RELOCATE_NEW_KERNEL_VERBOSE | |
134 | moveli r0, 'd' | |
135 | jalr r40 | |
136 | #endif | |
137 | ||
fc0c49f5 | 138 | addi r30, r30, 8 |
867e359b CM |
139 | j .Lloop |
140 | ||
141 | .Ltry2: | |
fc0c49f5 CM |
142 | cmpeqi r0, r9, 0x2 /* IND_INDIRECTION */ |
143 | beqzt r0, .Ltry4 | |
867e359b CM |
144 | |
145 | move r30, r10 | |
146 | ||
147 | #ifdef RELOCATE_NEW_KERNEL_VERBOSE | |
148 | moveli r0, 'i' | |
149 | jalr r40 | |
150 | #endif | |
151 | ||
152 | j .Lloop | |
153 | ||
154 | .Ltry4: | |
fc0c49f5 CM |
155 | cmpeqi r0, r9, 0x4 /* IND_DONE */ |
156 | beqzt r0, .Ltry8 | |
867e359b CM |
157 | |
158 | mf | |
159 | ||
160 | #ifdef RELOCATE_NEW_KERNEL_VERBOSE | |
161 | moveli r0, 'D' | |
162 | jalr r40 | |
163 | moveli r0, '\n' | |
164 | jalr r40 | |
165 | #endif | |
166 | ||
167 | move r0, r32 | |
867e359b | 168 | |
fc0c49f5 CM |
169 | moveli r41, hw2_last(hv_reexec) |
170 | shl16insli r41, r41, hw1(hv_reexec) | |
171 | shl16insli r41, r41, hw0(hv_reexec) | |
867e359b CM |
172 | |
173 | jalr r41 | |
174 | ||
175 | /* we should not get here */ | |
176 | ||
309272f9 | 177 | #ifdef RELOCATE_NEW_KERNEL_VERBOSE |
867e359b CM |
178 | moveli r0, '?' |
179 | jalr r40 | |
180 | moveli r0, '\n' | |
181 | jalr r40 | |
309272f9 | 182 | #endif |
867e359b CM |
183 | |
184 | j .Lhalt | |
185 | ||
fc0c49f5 CM |
186 | .Ltry8: cmpeqi r0, r9, 0x8 /* IND_SOURCE */ |
187 | beqz r0, .Lerr /* unknown type */ | |
867e359b CM |
188 | |
189 | /* copy page at r10 to page at r33 */ | |
190 | ||
191 | move r11, r33 | |
192 | ||
fc0c49f5 CM |
193 | moveli r0, hw2_last(PAGE_SIZE) |
194 | shl16insli r0, r0, hw1(PAGE_SIZE) | |
195 | shl16insli r0, r0, hw0(PAGE_SIZE) | |
867e359b CM |
196 | add r33, r33, r0 |
197 | ||
198 | /* copy word at r10 to word at r11 until r11 equals r33 */ | |
199 | ||
fc0c49f5 CM |
200 | /* We know page size must be multiple of 8, so we can unroll |
201 | * 8 times safely without any edge case checking. | |
867e359b | 202 | * |
fc0c49f5 | 203 | * Issue a flush of the destination every 8 words to avoid |
867e359b CM |
204 | * incoherence when starting the new kernel. (Now this is |
205 | * just good paranoia because the hv_reexec call will also | |
206 | * take care of this.) | |
207 | */ | |
208 | ||
209 | 1: | |
fc0c49f5 CM |
210 | { ld r0, r10; addi r10, r10, 8 } |
211 | { st r11, r0; addi r11, r11, 8 } | |
212 | { ld r0, r10; addi r10, r10, 8 } | |
213 | { st r11, r0; addi r11, r11, 8 } | |
214 | { ld r0, r10; addi r10, r10, 8 } | |
215 | { st r11, r0; addi r11, r11, 8 } | |
216 | { ld r0, r10; addi r10, r10, 8 } | |
217 | { st r11, r0; addi r11, r11, 8 } | |
218 | { ld r0, r10; addi r10, r10, 8 } | |
219 | { st r11, r0; addi r11, r11, 8 } | |
220 | { ld r0, r10; addi r10, r10, 8 } | |
221 | { st r11, r0; addi r11, r11, 8 } | |
222 | { ld r0, r10; addi r10, r10, 8 } | |
223 | { st r11, r0; addi r11, r11, 8 } | |
224 | { ld r0, r10; addi r10, r10, 8 } | |
225 | { st r11, r0 } | |
226 | { flush r11 ; addi r11, r11, 8 } | |
227 | ||
228 | cmpeq r0, r33, r11 | |
229 | beqzt r0, 1b | |
867e359b CM |
230 | |
231 | #ifdef RELOCATE_NEW_KERNEL_VERBOSE | |
232 | moveli r0, 's' | |
233 | jalr r40 | |
234 | #endif | |
235 | ||
fc0c49f5 | 236 | addi r30, r30, 8 |
867e359b CM |
237 | j .Lloop |
238 | ||
239 | ||
309272f9 CM |
240 | .Lerr: |
241 | #ifdef RELOCATE_NEW_KERNEL_VERBOSE | |
242 | moveli r0, 'e' | |
867e359b CM |
243 | jalr r40 |
244 | moveli r0, 'r' | |
245 | jalr r40 | |
246 | moveli r0, 'r' | |
247 | jalr r40 | |
248 | moveli r0, '\n' | |
249 | jalr r40 | |
309272f9 | 250 | #endif |
867e359b | 251 | .Lhalt: |
fc0c49f5 CM |
252 | moveli r41, hw2_last(hv_halt) |
253 | shl16insli r41, r41, hw1(hv_halt) | |
254 | shl16insli r41, r41, hw0(hv_halt) | |
867e359b CM |
255 | |
256 | jalr r41 | |
257 | STD_ENDPROC(relocate_new_kernel) | |
258 | ||
259 | .section .rodata,"a" | |
260 | ||
261 | .globl relocate_new_kernel_size | |
262 | relocate_new_kernel_size: | |
263 | .long .Lend_relocate_new_kernel - relocate_new_kernel |