1/* 2 * Copyright 2010 Tilera Corporation. All Rights Reserved. 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 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 31 shri r1, r1, PAGE_SHIFT 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 37 moveli r40, lo16(hv_console_putc) 38 auli r40, r40, ha16(hv_console_putc) 39 40#ifdef RELOCATE_NEW_KERNEL_VERBOSE 41 moveli r0, 'r' 42 jalr r40 43 44 moveli r0, '_' 45 jalr r40 46 47 moveli r0, 'n' 48 jalr r40 49 50 moveli r0, '_' 51 jalr r40 52 53 moveli r0, 'k' 54 jalr r40 55 56 moveli r0, '\n' 57 jalr r40 58#endif 59 60 /* 61 * Throughout this code r30 is pointer to the element of page 62 * list we are working on. 63 * 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 68 * of r30. 69 * 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. 74 */ 75 76 sw sp, r30 77 move r30, sp 78 addi sp, sp, -8 79 80 /* 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. 88 */ 89 { 90 move r0, zero /* cache_pa */ 91 move r1, zero 92 } 93 { 94 auli r2, zero, ha16(HV_FLUSH_EVICT_L2) /* cache_control */ 95 movei r3, -1 /* cache_cpumask; -1 means all client tiles */ 96 } 97 { 98 move r4, zero /* tlb_va */ 99 move r5, zero /* tlb_length */ 100 } 101 { 102 move r6, zero /* tlb_pgsize */ 103 move r7, zero /* tlb_cpumask */ 104 } 105 { 106 move r8, zero /* asids */ 107 moveli r20, lo16(hv_flush_remote) 108 } 109 { 110 move r9, zero /* asidcount */ 111 auli r20, r20, ha16(hv_flush_remote) 112 } 113 114 jalr r20 115 116 /* r33 is destination pointer, default to zero */ 117 118 moveli r33, 0 119 120.Lloop: lw r10, r30 121 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 */ 124 125 seqi r0, r9, 0x1 /* IND_DESTINATION */ 126 bzt r0, .Ltry2 127 128 move r33, r10 129 130#ifdef RELOCATE_NEW_KERNEL_VERBOSE 131 moveli r0, 'd' 132 jalr r40 133#endif 134 135 addi r30, r30, 4 136 j .Lloop 137 138.Ltry2: 139 seqi r0, r9, 0x2 /* IND_INDIRECTION */ 140 bzt r0, .Ltry4 141 142 move r30, r10 143 144#ifdef RELOCATE_NEW_KERNEL_VERBOSE 145 moveli r0, 'i' 146 jalr r40 147#endif 148 149 j .Lloop 150 151.Ltry4: 152 seqi r0, r9, 0x4 /* IND_DONE */ 153 bzt r0, .Ltry8 154 155 mf 156 157#ifdef RELOCATE_NEW_KERNEL_VERBOSE 158 moveli r0, 'D' 159 jalr r40 160 moveli r0, '\n' 161 jalr r40 162#endif 163 164 move r0, r32 165 moveli r1, 0 /* arg to hv_reexec is 64 bits */ 166 167 moveli r41, lo16(hv_reexec) 168 auli r41, r41, ha16(hv_reexec) 169 170 jalr r41 171 172 /* we should not get here */ 173 174 moveli r0, '?' 175 jalr r40 176 moveli r0, '\n' 177 jalr r40 178 179 j .Lhalt 180 181.Ltry8: seqi r0, r9, 0x8 /* IND_SOURCE */ 182 bz r0, .Lerr /* unknown type */ 183 184 /* copy page at r10 to page at r33 */ 185 186 move r11, r33 187 188 moveli r0, lo16(PAGE_SIZE) 189 auli r0, r0, ha16(PAGE_SIZE) 190 add r33, r33, r0 191 192 /* copy word at r10 to word at r11 until r11 equals r33 */ 193 194 /* We know page size must be multiple of 16, so we can unroll 195 * 16 times safely without any edge case checking. 196 * 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.) 201 */ 202 2031: 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 } 235 { sw r11, r0 } 236 { flush r11 ; addi r11, r11, 4 } 237 238 seq r0, r33, r11 239 bzt r0, 1b 240 241#ifdef RELOCATE_NEW_KERNEL_VERBOSE 242 moveli r0, 's' 243 jalr r40 244#endif 245 246 addi r30, r30, 4 247 j .Lloop 248 249 250.Lerr: moveli r0, 'e' 251 jalr r40 252 moveli r0, 'r' 253 jalr r40 254 moveli r0, 'r' 255 jalr r40 256 moveli r0, '\n' 257 jalr r40 258.Lhalt: 259 moveli r41, lo16(hv_halt) 260 auli r41, r41, ha16(hv_halt) 261 262 jalr r41 263 STD_ENDPROC(relocate_new_kernel) 264 265 .section .rodata,"a" 266 267 .globl relocate_new_kernel_size 268relocate_new_kernel_size: 269 .long .Lend_relocate_new_kernel - relocate_new_kernel 270