2 * Copyright 2010 Tilera Corporation. All Rights Reserved.
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.
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
14 * copy new kernel into place and then call hv_reexec
18 #include <linux/linkage.h>
19 #include <arch/chip.h>
21 #include <hv/hypervisor.h>
23 #undef RELOCATE_NEW_KERNEL_VERBOSE
25 STD_ENTRY(relocate_new_kernel)
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 */
31 shri r1, r1, PAGE_SHIFT
33 shli sp, r1, PAGE_SHIFT
35 /* we now have a stack (whether we need one or not) */
37 moveli r40, lo16(hv_console_putc)
38 auli r40, r40, ha16(hv_console_putc)
40 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
61 * Throughout this code r30 is pointer to the element of page
62 * list we are working on.
64 * Normally we get to the next element of the page list by
65 * incrementing r30 by four. The exception is if the element
66 * on the page list is an IND_INDIRECTION in which case we use
67 * the element with the low bits masked off as the new value
70 * To get this started, we need the value passed to us (which
71 * will always be an IND_INDIRECTION) in memory somewhere with
72 * r30 pointing at it. To do that, we push the value passed
73 * to us on the stack and make r30 point to it.
81 * On TILEPro, we need to flush all tiles' caches, since we may
82 * have been doing hash-for-home caching there. Note that we
83 * must do this _after_ we're completely done modifying any memory
84 * other than our output buffer (which we know is locally cached).
85 * We want the caches to be fully clean when we do the reexec,
86 * because the hypervisor is going to do this flush again at that
87 * point, and we don't want that second flush to overwrite any memory.
90 move r0, zero /* cache_pa */
94 auli r2, zero, ha16(HV_FLUSH_EVICT_L2) /* cache_control */
95 movei r3, -1 /* cache_cpumask; -1 means all client tiles */
98 move r4, zero /* tlb_va */
99 move r5, zero /* tlb_length */
102 move r6, zero /* tlb_pgsize */
103 move r7, zero /* tlb_cpumask */
106 move r8, zero /* asids */
107 moveli r20, lo16(hv_flush_remote)
110 move r9, zero /* asidcount */
111 auli r20, r20, ha16(hv_flush_remote)
116 /* r33 is destination pointer, default to zero */
122 andi r9, r10, 0xf /* low 4 bits tell us what type it is */
123 xor r10, r10, r9 /* r10 is now value with low 4 bits stripped */
125 seqi r0, r9, 0x1 /* IND_DESTINATION */
130 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
139 seqi r0, r9, 0x2 /* IND_INDIRECTION */
144 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
152 seqi r0, r9, 0x4 /* IND_DONE */
157 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
165 moveli r1, 0 /* arg to hv_reexec is 64 bits */
167 moveli r41, lo16(hv_reexec)
168 auli r41, r41, ha16(hv_reexec)
172 /* we should not get here */
181 .Ltry8: seqi r0, r9, 0x8 /* IND_SOURCE */
182 bz r0, .Lerr /* unknown type */
184 /* copy page at r10 to page at r33 */
188 moveli r0, lo16(PAGE_SIZE)
189 auli r0, r0, ha16(PAGE_SIZE)
192 /* copy word at r10 to word at r11 until r11 equals r33 */
194 /* We know page size must be multiple of 16, so we can unroll
195 * 16 times safely without any edge case checking.
197 * Issue a flush of the destination every 16 words to avoid
198 * incoherence when starting the new kernel. (Now this is
199 * just good paranoia because the hv_reexec call will also
200 * take care of this.)
204 { lw r0, r10; addi r10, r10, 4 }
205 { sw r11, r0; addi r11, r11, 4 }
206 { lw r0, r10; addi r10, r10, 4 }
207 { sw r11, r0; addi r11, r11, 4 }
208 { lw r0, r10; addi r10, r10, 4 }
209 { sw r11, r0; addi r11, r11, 4 }
210 { lw r0, r10; addi r10, r10, 4 }
211 { sw r11, r0; addi r11, r11, 4 }
212 { lw r0, r10; addi r10, r10, 4 }
213 { sw r11, r0; addi r11, r11, 4 }
214 { lw r0, r10; addi r10, r10, 4 }
215 { sw r11, r0; addi r11, r11, 4 }
216 { lw r0, r10; addi r10, r10, 4 }
217 { sw r11, r0; addi r11, r11, 4 }
218 { lw r0, r10; addi r10, r10, 4 }
219 { sw r11, r0; addi r11, r11, 4 }
220 { lw r0, r10; addi r10, r10, 4 }
221 { sw r11, r0; addi r11, r11, 4 }
222 { lw r0, r10; addi r10, r10, 4 }
223 { sw r11, r0; addi r11, r11, 4 }
224 { lw r0, r10; addi r10, r10, 4 }
225 { sw r11, r0; addi r11, r11, 4 }
226 { lw r0, r10; addi r10, r10, 4 }
227 { sw r11, r0; addi r11, r11, 4 }
228 { lw r0, r10; addi r10, r10, 4 }
229 { sw r11, r0; addi r11, r11, 4 }
230 { lw r0, r10; addi r10, r10, 4 }
231 { sw r11, r0; addi r11, r11, 4 }
232 { lw r0, r10; addi r10, r10, 4 }
233 { sw r11, r0; addi r11, r11, 4 }
234 { lw r0, r10; addi r10, r10, 4 }
236 { flush r11 ; addi r11, r11, 4 }
241 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
250 .Lerr: moveli r0, 'e'
259 moveli r41, lo16(hv_halt)
260 auli r41, r41, ha16(hv_halt)
263 STD_ENDPROC(relocate_new_kernel)
267 .globl relocate_new_kernel_size
268 relocate_new_kernel_size:
269 .long .Lend_relocate_new_kernel - relocate_new_kernel