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