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 #define ___hvb MEM_SV_INTRPT + HV_GLUE_START_CPA
25 #define ___hv_dispatch(f) (___hvb + (HV_DISPATCH_ENTRY_SIZE * f))
27 #define ___hv_console_putc ___hv_dispatch(HV_DISPATCH_CONSOLE_PUTC)
28 #define ___hv_halt ___hv_dispatch(HV_DISPATCH_HALT)
29 #define ___hv_reexec ___hv_dispatch(HV_DISPATCH_REEXEC)
30 #define ___hv_flush_remote ___hv_dispatch(HV_DISPATCH_FLUSH_REMOTE)
32 #undef RELOCATE_NEW_KERNEL_VERBOSE
34 STD_ENTRY(relocate_new_kernel)
36 move r30, r0 /* page list */
37 move r31, r1 /* address of page we are on */
38 move r32, r2 /* start address of new kernel */
40 shri r1, r1, PAGE_SHIFT
42 shli sp, r1, PAGE_SHIFT
44 /* we now have a stack (whether we need one or not) */
46 moveli r40, lo16(___hv_console_putc)
47 auli r40, r40, ha16(___hv_console_putc)
49 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
70 * Throughout this code r30 is pointer to the element of page
71 * list we are working on.
73 * Normally we get to the next element of the page list by
74 * incrementing r30 by four. The exception is if the element
75 * on the page list is an IND_INDIRECTION in which case we use
76 * the element with the low bits masked off as the new value
79 * To get this started, we need the value passed to us (which
80 * will always be an IND_INDIRECTION) in memory somewhere with
81 * r30 pointing at it. To do that, we push the value passed
82 * to us on the stack and make r30 point to it.
89 #if CHIP_HAS_CBOX_HOME_MAP()
91 * On TILEPro, we need to flush all tiles' caches, since we may
92 * have been doing hash-for-home caching there. Note that we
93 * must do this _after_ we're completely done modifying any memory
94 * other than our output buffer (which we know is locally cached).
95 * We want the caches to be fully clean when we do the reexec,
96 * because the hypervisor is going to do this flush again at that
97 * point, and we don't want that second flush to overwrite any memory.
100 move r0, zero /* cache_pa */
104 auli r2, zero, ha16(HV_FLUSH_EVICT_L2) /* cache_control */
105 movei r3, -1 /* cache_cpumask; -1 means all client tiles */
108 move r4, zero /* tlb_va */
109 move r5, zero /* tlb_length */
112 move r6, zero /* tlb_pgsize */
113 move r7, zero /* tlb_cpumask */
116 move r8, zero /* asids */
117 moveli r20, lo16(___hv_flush_remote)
120 move r9, zero /* asidcount */
121 auli r20, r20, ha16(___hv_flush_remote)
127 /* r33 is destination pointer, default to zero */
133 andi r9, r10, 0xf /* low 4 bits tell us what type it is */
134 xor r10, r10, r9 /* r10 is now value with low 4 bits stripped */
136 seqi r0, r9, 0x1 /* IND_DESTINATION */
141 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
150 seqi r0, r9, 0x2 /* IND_INDIRECTION */
155 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
163 seqi r0, r9, 0x4 /* IND_DONE */
168 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
176 moveli r1, 0 /* arg to hv_reexec is 64 bits */
178 moveli r41, lo16(___hv_reexec)
179 auli r41, r41, ha16(___hv_reexec)
183 /* we should not get here */
192 .Ltry8: seqi r0, r9, 0x8 /* IND_SOURCE */
193 bz r0, .Lerr /* unknown type */
195 /* copy page at r10 to page at r33 */
199 moveli r0, lo16(PAGE_SIZE)
200 auli r0, r0, ha16(PAGE_SIZE)
203 /* copy word at r10 to word at r11 until r11 equals r33 */
205 /* We know page size must be multiple of 16, so we can unroll
206 * 16 times safely without any edge case checking.
208 * Issue a flush of the destination every 16 words to avoid
209 * incoherence when starting the new kernel. (Now this is
210 * just good paranoia because the hv_reexec call will also
211 * take care of this.)
215 { lw r0, r10; addi r10, r10, 4 }
216 { sw r11, r0; addi r11, r11, 4 }
217 { lw r0, r10; addi r10, r10, 4 }
218 { sw r11, r0; addi r11, r11, 4 }
219 { lw r0, r10; addi r10, r10, 4 }
220 { sw r11, r0; addi r11, r11, 4 }
221 { lw r0, r10; addi r10, r10, 4 }
222 { sw r11, r0; addi r11, r11, 4 }
223 { lw r0, r10; addi r10, r10, 4 }
224 { sw r11, r0; addi r11, r11, 4 }
225 { lw r0, r10; addi r10, r10, 4 }
226 { sw r11, r0; addi r11, r11, 4 }
227 { lw r0, r10; addi r10, r10, 4 }
228 { sw r11, r0; addi r11, r11, 4 }
229 { lw r0, r10; addi r10, r10, 4 }
230 { sw r11, r0; addi r11, r11, 4 }
231 { lw r0, r10; addi r10, r10, 4 }
232 { sw r11, r0; addi r11, r11, 4 }
233 { lw r0, r10; addi r10, r10, 4 }
234 { sw r11, r0; addi r11, r11, 4 }
235 { lw r0, r10; addi r10, r10, 4 }
236 { sw r11, r0; addi r11, r11, 4 }
237 { lw r0, r10; addi r10, r10, 4 }
238 { sw r11, r0; addi r11, r11, 4 }
239 { lw r0, r10; addi r10, r10, 4 }
240 { sw r11, r0; addi r11, r11, 4 }
241 { lw r0, r10; addi r10, r10, 4 }
242 { sw r11, r0; addi r11, r11, 4 }
243 { lw r0, r10; addi r10, r10, 4 }
244 { sw r11, r0; addi r11, r11, 4 }
245 { lw r0, r10; addi r10, r10, 4 }
247 { flush r11 ; addi r11, r11, 4 }
252 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
261 .Lerr: moveli r0, 'e'
270 moveli r41, lo16(___hv_halt)
271 auli r41, r41, ha16(___hv_halt)
274 STD_ENDPROC(relocate_new_kernel)
278 .globl relocate_new_kernel_size
279 relocate_new_kernel_size:
280 .long .Lend_relocate_new_kernel - relocate_new_kernel