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