Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc
[deliverable/linux.git] / arch / tile / kernel / relocate_kernel_64.S
1 /*
2 * Copyright 2011 Tilera Corporation. All Rights Reserved.
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
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
31 shrui r1, r1, PAGE_SHIFT
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
37 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
38 moveli r40, hw2_last(hv_console_putc)
39 shl16insli r40, r40, hw1(hv_console_putc)
40 shl16insli r40, r40, hw0(hv_console_putc)
41
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
66 * incrementing r30 by eight. The exception is if the element
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
77 st sp, r30
78 move r30, sp
79 addi sp, sp, -16
80
81 /*
82 * On TILE-GX, we need to flush all tiles' caches, since we may
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 */
92 moveli r1, hw2_last(HV_FLUSH_EVICT_L2)
93 }
94 {
95 shl16insli r1, r1, hw1(HV_FLUSH_EVICT_L2)
96 movei r2, -1 /* cache_cpumask; -1 means all client tiles */
97 }
98 {
99 shl16insli r1, r1, hw0(HV_FLUSH_EVICT_L2) /* cache_control */
100 move r3, zero /* tlb_va */
101 }
102 {
103 move r4, zero /* tlb_length */
104 move r5, zero /* tlb_pgsize */
105 }
106 {
107 move r6, zero /* tlb_cpumask */
108 move r7, zero /* asids */
109 }
110 {
111 moveli r20, hw2_last(hv_flush_remote)
112 move r8, zero /* asidcount */
113 }
114 shl16insli r20, r20, hw1(hv_flush_remote)
115 shl16insli r20, r20, hw0(hv_flush_remote)
116
117 jalr r20
118
119 /* r33 is destination pointer, default to zero */
120
121 moveli r33, 0
122
123 .Lloop: ld r10, r30
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
128 cmpeqi r0, r9, 0x1 /* IND_DESTINATION */
129 beqzt r0, .Ltry2
130
131 move r33, r10
132
133 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
134 moveli r0, 'd'
135 jalr r40
136 #endif
137
138 addi r30, r30, 8
139 j .Lloop
140
141 .Ltry2:
142 cmpeqi r0, r9, 0x2 /* IND_INDIRECTION */
143 beqzt r0, .Ltry4
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:
155 cmpeqi r0, r9, 0x4 /* IND_DONE */
156 beqzt r0, .Ltry8
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
168
169 moveli r41, hw2_last(hv_reexec)
170 shl16insli r41, r41, hw1(hv_reexec)
171 shl16insli r41, r41, hw0(hv_reexec)
172
173 jalr r41
174
175 /* we should not get here */
176
177 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
178 moveli r0, '?'
179 jalr r40
180 moveli r0, '\n'
181 jalr r40
182 #endif
183
184 j .Lhalt
185
186 .Ltry8: cmpeqi r0, r9, 0x8 /* IND_SOURCE */
187 beqz r0, .Lerr /* unknown type */
188
189 /* copy page at r10 to page at r33 */
190
191 move r11, r33
192
193 moveli r0, hw2_last(PAGE_SIZE)
194 shl16insli r0, r0, hw1(PAGE_SIZE)
195 shl16insli r0, r0, hw0(PAGE_SIZE)
196 add r33, r33, r0
197
198 /* copy word at r10 to word at r11 until r11 equals r33 */
199
200 /* We know page size must be multiple of 8, so we can unroll
201 * 8 times safely without any edge case checking.
202 *
203 * Issue a flush of the destination every 8 words to avoid
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:
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
230
231 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
232 moveli r0, 's'
233 jalr r40
234 #endif
235
236 addi r30, r30, 8
237 j .Lloop
238
239
240 .Lerr:
241 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
242 moveli r0, 'e'
243 jalr r40
244 moveli r0, 'r'
245 jalr r40
246 moveli r0, 'r'
247 jalr r40
248 moveli r0, '\n'
249 jalr r40
250 #endif
251 .Lhalt:
252 moveli r41, hw2_last(hv_halt)
253 shl16insli r41, r41, hw1(hv_halt)
254 shl16insli r41, r41, hw0(hv_halt)
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
This page took 0.038097 seconds and 5 git commands to generate.