2 * Copyright 2011 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 shrui r1, r1, PAGE_SHIFT
33 shli sp, r1, PAGE_SHIFT
35 /* we now have a stack (whether we need one or not) */
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)
62 * Throughout this code r30 is pointer to the element of page
63 * list we are working on.
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
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.
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.
91 move r0, zero /* cache_pa */
92 moveli r1, hw2_last(HV_FLUSH_EVICT_L2)
95 shl16insli r1, r1, hw1(HV_FLUSH_EVICT_L2)
96 movei r2, -1 /* cache_cpumask; -1 means all client tiles */
99 shl16insli r1, r1, hw0(HV_FLUSH_EVICT_L2) /* cache_control */
100 move r3, zero /* tlb_va */
103 move r4, zero /* tlb_length */
104 move r5, zero /* tlb_pgsize */
107 move r6, zero /* tlb_cpumask */
108 move r7, zero /* asids */
111 moveli r20, hw2_last(hv_flush_remote)
112 move r8, zero /* asidcount */
114 shl16insli r20, r20, hw1(hv_flush_remote)
115 shl16insli r20, r20, hw0(hv_flush_remote)
119 /* r33 is destination pointer, default to zero */
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 */
128 cmpeqi r0, r9, 0x1 /* IND_DESTINATION */
133 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
142 cmpeqi r0, r9, 0x2 /* IND_INDIRECTION */
147 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
155 cmpeqi r0, r9, 0x4 /* IND_DONE */
160 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
169 moveli r41, hw2_last(hv_reexec)
170 shl16insli r41, r41, hw1(hv_reexec)
171 shl16insli r41, r41, hw0(hv_reexec)
175 /* we should not get here */
177 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
186 .Ltry8: cmpeqi r0, r9, 0x8 /* IND_SOURCE */
187 beqz r0, .Lerr /* unknown type */
189 /* copy page at r10 to page at r33 */
193 moveli r0, hw2_last(PAGE_SIZE)
194 shl16insli r0, r0, hw1(PAGE_SIZE)
195 shl16insli r0, r0, hw0(PAGE_SIZE)
198 /* copy word at r10 to word at r11 until r11 equals r33 */
200 /* We know page size must be multiple of 8, so we can unroll
201 * 8 times safely without any edge case checking.
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.)
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 }
226 { flush r11 ; addi r11, r11, 8 }
231 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
241 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
252 moveli r41, hw2_last(hv_halt)
253 shl16insli r41, r41, hw1(hv_halt)
254 shl16insli r41, r41, hw0(hv_halt)
257 STD_ENDPROC(relocate_new_kernel)
261 .globl relocate_new_kernel_size
262 relocate_new_kernel_size:
263 .long .Lend_relocate_new_kernel - relocate_new_kernel