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#define ___hvb MEM_SV_INTRPT + HV_GLUE_START_CPA 24 25#define ___hv_dispatch(f) (___hvb + (HV_DISPATCH_ENTRY_SIZE * f)) 26 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) 31 32#undef RELOCATE_NEW_KERNEL_VERBOSE 33 34STD_ENTRY(relocate_new_kernel) 35 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 */ 39 40 shri r1, r1, PAGE_SHIFT 41 addi r1, r1, 1 42 shli sp, r1, PAGE_SHIFT 43 addi sp, sp, -8 44 /* we now have a stack (whether we need one or not) */ 45 46 moveli r40, lo16(___hv_console_putc) 47 auli r40, r40, ha16(___hv_console_putc) 48 49#ifdef RELOCATE_NEW_KERNEL_VERBOSE 50 moveli r0, 'r' 51 jalr r40 52 53 moveli r0, '_' 54 jalr r40 55 56 moveli r0, 'n' 57 jalr r40 58 59 moveli r0, '_' 60 jalr r40 61 62 moveli r0, 'k' 63 jalr r40 64 65 moveli r0, '\n' 66 jalr r40 67#endif 68 69 /* 70 * Throughout this code r30 is pointer to the element of page 71 * list we are working on. 72 * 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 77 * of r30. 78 * 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. 83 */ 84 85 sw sp, r30 86 move r30, sp 87 addi sp, sp, -8 88 89#if CHIP_HAS_CBOX_HOME_MAP() 90 /* 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. 98 */ 99 { 100 move r0, zero /* cache_pa */ 101 move r1, zero 102 } 103 { 104 auli r2, zero, ha16(HV_FLUSH_EVICT_L2) /* cache_control */ 105 movei r3, -1 /* cache_cpumask; -1 means all client tiles */ 106 } 107 { 108 move r4, zero /* tlb_va */ 109 move r5, zero /* tlb_length */ 110 } 111 { 112 move r6, zero /* tlb_pgsize */ 113 move r7, zero /* tlb_cpumask */ 114 } 115 { 116 move r8, zero /* asids */ 117 moveli r20, lo16(___hv_flush_remote) 118 } 119 { 120 move r9, zero /* asidcount */ 121 auli r20, r20, ha16(___hv_flush_remote) 122 } 123 124 jalr r20 125#endif 126 127 /* r33 is destination pointer, default to zero */ 128 129 moveli r33, 0 130 131.Lloop: lw r10, r30 132 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 */ 135 136 seqi r0, r9, 0x1 /* IND_DESTINATION */ 137 bzt r0, .Ltry2 138 139 move r33, r10 140 141#ifdef RELOCATE_NEW_KERNEL_VERBOSE 142 moveli r0, 'd' 143 jalr r40 144#endif 145 146 addi r30, r30, 4 147 j .Lloop 148 149.Ltry2: 150 seqi r0, r9, 0x2 /* IND_INDIRECTION */ 151 bzt r0, .Ltry4 152 153 move r30, r10 154 155#ifdef RELOCATE_NEW_KERNEL_VERBOSE 156 moveli r0, 'i' 157 jalr r40 158#endif 159 160 j .Lloop 161 162.Ltry4: 163 seqi r0, r9, 0x4 /* IND_DONE */ 164 bzt r0, .Ltry8 165 166 mf 167 168#ifdef RELOCATE_NEW_KERNEL_VERBOSE 169 moveli r0, 'D' 170 jalr r40 171 moveli r0, '\n' 172 jalr r40 173#endif 174 175 move r0, r32 176 moveli r1, 0 /* arg to hv_reexec is 64 bits */ 177 178 moveli r41, lo16(___hv_reexec) 179 auli r41, r41, ha16(___hv_reexec) 180 181 jalr r41 182 183 /* we should not get here */ 184 185 moveli r0, '?' 186 jalr r40 187 moveli r0, '\n' 188 jalr r40 189 190 j .Lhalt 191 192.Ltry8: seqi r0, r9, 0x8 /* IND_SOURCE */ 193 bz r0, .Lerr /* unknown type */ 194 195 /* copy page at r10 to page at r33 */ 196 197 move r11, r33 198 199 moveli r0, lo16(PAGE_SIZE) 200 auli r0, r0, ha16(PAGE_SIZE) 201 add r33, r33, r0 202 203 /* copy word at r10 to word at r11 until r11 equals r33 */ 204 205 /* We know page size must be multiple of 16, so we can unroll 206 * 16 times safely without any edge case checking. 207 * 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.) 212 */ 213 2141: 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 } 246 { sw r11, r0 } 247 { flush r11 ; addi r11, r11, 4 } 248 249 seq r0, r33, r11 250 bzt r0, 1b 251 252#ifdef RELOCATE_NEW_KERNEL_VERBOSE 253 moveli r0, 's' 254 jalr r40 255#endif 256 257 addi r30, r30, 4 258 j .Lloop 259 260 261.Lerr: moveli r0, 'e' 262 jalr r40 263 moveli r0, 'r' 264 jalr r40 265 moveli r0, 'r' 266 jalr r40 267 moveli r0, '\n' 268 jalr r40 269.Lhalt: 270 moveli r41, lo16(___hv_halt) 271 auli r41, r41, ha16(___hv_halt) 272 273 jalr r41 274 STD_ENDPROC(relocate_new_kernel) 275 276 .section .rodata,"a" 277 278 .globl relocate_new_kernel_size 279relocate_new_kernel_size: 280 .long .Lend_relocate_new_kernel - relocate_new_kernel 281