1/*- 2 * Copyright (C) 2009-2011 Nathan Whitehorn 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include <sys/syscall.h> 27 28#include <machine/trap.h> 29#include <machine/param.h> 30#include <machine/spr.h> 31#include <machine/asm.h> 32 33#include "opt_platform.h" 34 35#define OFWSTKSZ 4096 /* 4K Open Firmware stack */ 36 37/* 38 * Globals 39 */ 40 .data 41 .align 4 42ofwstk: 43 .space OFWSTKSZ 44rtas_regsave: 45 .space 32 /* 4 * sizeof(register_t) */ 46GLOBAL(ofmsr) 47 .llong 0, 0, 0, 0, 0 /* msr/sprg0-3 used in Open Firmware */ 48GLOBAL(rtasmsr) 49 .llong 0 50GLOBAL(openfirmware_entry) 51 .llong 0 /* Open Firmware entry point */ 52GLOBAL(rtas_entry) 53 .llong 0 /* RTAS entry point */ 54 55TOC_ENTRY(ofmsr) 56TOC_ENTRY(ofwstk) 57TOC_ENTRY(rtasmsr) 58TOC_ENTRY(openfirmware_entry) 59TOC_ENTRY(rtas_entry) 60TOC_ENTRY(rtas_regsave) 61 62/* 63 * Open Firmware Real-mode Entry Point. This is a huge pain. 64 */ 65 66ASENTRY_NOPROF(ofwcall) 67 mflr %r8 68 std %r8,16(%r1) 69 stdu %r1,-208(%r1) 70 71 /* 72 * We need to save the following, because OF's register save/ 73 * restore code assumes that the contents of registers are 74 * at most 32 bits wide: lr, cr, r2, r13-r31, the old MSR. These 75 * get placed in that order in the stack. 76 */ 77 78 mfcr %r4 79 std %r4,48(%r1) 80 std %r13,56(%r1) 81 std %r14,64(%r1) 82 std %r15,72(%r1) 83 std %r16,80(%r1) 84 std %r17,88(%r1) 85 std %r18,96(%r1) 86 std %r19,104(%r1) 87 std %r20,112(%r1) 88 std %r21,120(%r1) 89 std %r22,128(%r1) 90 std %r23,136(%r1) 91 std %r24,144(%r1) 92 std %r25,152(%r1) 93 std %r26,160(%r1) 94 std %r27,168(%r1) 95 std %r28,176(%r1) 96 std %r29,184(%r1) 97 std %r30,192(%r1) 98 std %r31,200(%r1) 99 100 /* Record the old MSR */ 101 mfmsr %r6 102 103 /* read client interface handler */ 104 addis %r4,%r2,TOC_REF(openfirmware_entry)@ha 105 ld %r4,TOC_REF(openfirmware_entry)@l(%r4) 106 ld %r4,0(%r4) 107 108 /* Get OF stack pointer */ 109 addis %r7,%r2,TOC_REF(ofwstk)@ha 110 ld %r7,TOC_REF(ofwstk)@l(%r7) 111 addi %r7,%r7,OFWSTKSZ-40 112 113 /* 114 * Set the MSR to the OF value. This has the side effect of disabling 115 * exceptions, which is important for the next few steps. 116 * This does NOT, however, cause us to switch endianness. 117 */ 118 119 addis %r5,%r2,TOC_REF(ofmsr)@ha 120 ld %r5,TOC_REF(ofmsr)@l(%r5) 121 ld %r5,0(%r5) 122#if defined(__LITTLE_ENDIAN__) && defined(QEMU) 123 /* QEMU hack: qemu does not emulate mtmsrd correctly! */ 124 ori %r5,%r5,1 /* Leave PSR_LE set */ 125#endif 126 mtmsrd %r5 127 isync 128 129 /* 130 * Set up OF stack. This needs to be accessible in real mode and 131 * use the 32-bit ABI stack frame format. The pointer to the current 132 * kernel stack is placed at the very top of the stack along with 133 * the old MSR so we can get them back later. 134 */ 135 mr %r5,%r1 136 mr %r1,%r7 137 std %r5,8(%r1) /* Save real stack pointer */ 138 std %r2,16(%r1) /* Save old TOC */ 139 std %r6,24(%r1) /* Save old MSR */ 140 std %r8,32(%r1) /* Save high 32-bits of the kernel's PC */ 141 142 li %r5,0 143 stw %r5,4(%r1) 144 stw %r5,0(%r1) 145 146#ifdef __LITTLE_ENDIAN__ 147 /* Atomic context switch w/ endian change */ 148 mtmsrd %r5, 1 /* Clear PSL_EE|PSL_RI */ 149 addis %r5,%r2,TOC_REF(ofmsr)@ha 150 ld %r5,TOC_REF(ofmsr)@l(%r5) 151 ld %r5,0(%r5) 152 mtsrr0 %r4 153 mtsrr1 %r5 154 LOAD_LR_NIA 1551: 156 mflr %r5 157 addi %r5, %r5, (2f-1b) 158 mtlr %r5 159 li %r5, 0 160 rfid 1612: 162 RETURN_TO_NATIVE_ENDIAN 163#else 164 /* Finally, branch to OF */ 165 mtctr %r4 166 bctrl 167#endif 168 169 /* Reload stack pointer, MSR, and reference PC from the OFW stack */ 170 ld %r7,32(%r1) 171 ld %r6,24(%r1) 172 ld %r2,16(%r1) 173 ld %r1,8(%r1) 174 175 /* Get back to the MSR/PC we want, using the cached high bits of PC */ 176 mtsrr1 %r6 177 clrrdi %r7,%r7,32 178 bl 1f 1791: mflr %r8 180 or %r8,%r8,%r7 181 addi %r8,%r8,2f-1b 182 mtsrr0 %r8 183 rfid /* Turn on MMU, exceptions, and 64-bit mode */ 184 1852: 186 /* Sign-extend the return value from OF */ 187 extsw %r3,%r3 188 189 /* Restore all the non-volatile registers */ 190 ld %r5,48(%r1) 191 mtcr %r5 192 ld %r13,56(%r1) 193 ld %r14,64(%r1) 194 ld %r15,72(%r1) 195 ld %r16,80(%r1) 196 ld %r17,88(%r1) 197 ld %r18,96(%r1) 198 ld %r19,104(%r1) 199 ld %r20,112(%r1) 200 ld %r21,120(%r1) 201 ld %r22,128(%r1) 202 ld %r23,136(%r1) 203 ld %r24,144(%r1) 204 ld %r25,152(%r1) 205 ld %r26,160(%r1) 206 ld %r27,168(%r1) 207 ld %r28,176(%r1) 208 ld %r29,184(%r1) 209 ld %r30,192(%r1) 210 ld %r31,200(%r1) 211 212 /* Restore the stack and link register */ 213 ld %r1,0(%r1) 214 ld %r0,16(%r1) 215 mtlr %r0 216 blr 217ASEND(ofwcall) 218 219/* 220 * RTAS 32-bit Entry Point. Similar to the OF one, but simpler (no separate 221 * stack) 222 * 223 * C prototype: int rtascall(void *callbuffer, void *rtas_privdat); 224 */ 225 226ASENTRY_NOPROF(rtascall) 227 mflr %r9 228 std %r9,16(%r1) 229 stdu %r1,-208(%r1) 230 231 /* 232 * We need to save the following, because RTAS's register save/ 233 * restore code assumes that the contents of registers are 234 * at most 32 bits wide: lr, cr, r2, r13-r31, the old MSR. These 235 * get placed in that order in the stack. 236 */ 237 238 mfcr %r5 239 std %r5,48(%r1) 240 std %r13,56(%r1) 241 std %r14,64(%r1) 242 std %r15,72(%r1) 243 std %r16,80(%r1) 244 std %r17,88(%r1) 245 std %r18,96(%r1) 246 std %r19,104(%r1) 247 std %r20,112(%r1) 248 std %r21,120(%r1) 249 std %r22,128(%r1) 250 std %r23,136(%r1) 251 std %r24,144(%r1) 252 std %r25,152(%r1) 253 std %r26,160(%r1) 254 std %r27,168(%r1) 255 std %r28,176(%r1) 256 std %r29,184(%r1) 257 std %r30,192(%r1) 258 std %r31,200(%r1) 259 260 /* Record the old MSR */ 261 mfmsr %r6 262 263 /* Read RTAS entry and reg save area pointers */ 264 addis %r5,%r2,TOC_REF(rtas_entry)@ha 265 ld %r5,TOC_REF(rtas_entry)@l(%r5) 266 ld %r5,0(%r5) 267 addis %r8,%r2,TOC_REF(rtas_regsave)@ha 268 ld %r8,TOC_REF(rtas_regsave)@l(%r8) 269 270 /* 271 * Set the MSR to the RTAS value. This has the side effect of disabling 272 * exceptions, which is important for the next few steps. 273 */ 274 275 addis %r7,%r2,TOC_REF(rtasmsr)@ha 276 ld %r7,TOC_REF(rtasmsr)@l(%r7) 277 ld %r7,0(%r7) 278#ifdef __LITTLE_ENDIAN__ 279 /* QEMU hack: qemu does not emulate mtmsrd correctly! */ 280 ori %r7,%r7,1 /* Leave PSR_LE set */ 281#endif 282 mtmsrd %r7 283 isync 284 285 /* 286 * Set up RTAS register save area, so that we can get back all of 287 * our 64-bit pointers. Save our stack pointer, the TOC, and the MSR. 288 * Put this in r1, since RTAS is obliged to save it. Kernel globals 289 * are below 4 GB, so this is safe. 290 */ 291 mr %r7,%r1 292 mr %r1,%r8 293 std %r7,0(%r1) /* Save 64-bit stack pointer */ 294 std %r2,8(%r1) /* Save TOC */ 295 std %r6,16(%r1) /* Save MSR */ 296 std %r9,24(%r1) /* Save reference PC for high 32 bits */ 297 298#ifdef __LITTLE_ENDIAN__ 299 /* Atomic context switch w/ endian change */ 300 li %r7, 0 301 mtmsrd %r7, 1 /* Clear PSL_EE|PSL_RI */ 302 addis %r7,%r2,TOC_REF(rtasmsr)@ha 303 ld %r7,TOC_REF(rtasmsr)@l(%r7) 304 ld %r7,0(%r7) 305 mtsrr0 %r5 306 mtsrr1 %r7 307 LOAD_LR_NIA 3081: 309 mflr %r5 310 addi %r5, %r5, (2f-1b) 311 mtlr %r5 312 li %r5, 0 313 rfid 3142: 315 RETURN_TO_NATIVE_ENDIAN 316#else 317 /* Finally, branch to RTAS */ 318 mtctr %r5 319 bctrl 320#endif 321 322 /* 323 * Reload stack pointer, MSR, reg PC from the reg save area in r1. We 324 * are running in 32-bit mode at this point, so it doesn't matter if r1 325 * has become sign-extended. 326 */ 327 ld %r7,24(%r1) 328 ld %r6,16(%r1) 329 ld %r2,8(%r1) 330 ld %r1,0(%r1) 331 332 /* 333 * Get back to the right PC. We need to atomically re-enable 334 * exceptions, 64-bit mode, and the MMU. One thing that has likely 335 * happened is that, if we were running in the high-memory direct 336 * map, we no longer are as a result of LR truncation in RTAS. 337 * Fix this by copying the high-order bits of the LR at function 338 * entry onto the current PC and then jumping there while flipping 339 * all the MSR bits. 340 */ 341 mtsrr1 %r6 342 clrrdi %r7,%r7,32 343 bl 1f 3441: mflr %r8 345 or %r8,%r8,%r7 346 addi %r8,%r8,2f-1b 347 mtsrr0 %r8 348 rfid /* Turn on MMU, exceptions, and 64-bit mode */ 349 3502: 351 /* Sign-extend the return value from RTAS */ 352 extsw %r3,%r3 353 354 /* Restore all the non-volatile registers */ 355 ld %r5,48(%r1) 356 mtcr %r5 357 ld %r13,56(%r1) 358 ld %r14,64(%r1) 359 ld %r15,72(%r1) 360 ld %r16,80(%r1) 361 ld %r17,88(%r1) 362 ld %r18,96(%r1) 363 ld %r19,104(%r1) 364 ld %r20,112(%r1) 365 ld %r21,120(%r1) 366 ld %r22,128(%r1) 367 ld %r23,136(%r1) 368 ld %r24,144(%r1) 369 ld %r25,152(%r1) 370 ld %r26,160(%r1) 371 ld %r27,168(%r1) 372 ld %r28,176(%r1) 373 ld %r29,184(%r1) 374 ld %r30,192(%r1) 375 ld %r31,200(%r1) 376 377 /* Restore the stack and link register */ 378 ld %r1,0(%r1) 379 ld %r0,16(%r1) 380 mtlr %r0 381 blr 382ASEND(rtascall) 383