Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc
[deliverable/linux.git] / arch / tile / kernel / relocate_kernel_64.S
CommitLineData
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
25STD_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
2091:
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
262relocate_new_kernel_size:
263 .long .Lend_relocate_new_kernel - relocate_new_kernel
This page took 0.688499 seconds and 5 git commands to generate.