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