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#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 */ 117 118 addis %r5,%r2,TOC_REF(ofmsr)@ha 119 ld %r5,TOC_REF(ofmsr)@l(%r5) 120 ld %r5,0(%r5) 121 mtmsrd %r5 122 isync 123 124 /* 125 * Set up OF stack. This needs to be accessible in real mode and 126 * use the 32-bit ABI stack frame format. The pointer to the current 127 * kernel stack is placed at the very top of the stack along with 128 * the old MSR so we can get them back later. 129 */ 130 mr %r5,%r1 131 mr %r1,%r7 132 std %r5,8(%r1) /* Save real stack pointer */ 133 std %r2,16(%r1) /* Save old TOC */ 134 std %r6,24(%r1) /* Save old MSR */ 135 std %r8,32(%r1) /* Save high 32-bits of the kernel's PC */ 136 137 li %r5,0 138 stw %r5,4(%r1) 139 stw %r5,0(%r1) 140 141 /* Finally, branch to OF */ 142 mtctr %r4 143 bctrl 144 145 /* Reload stack pointer, MSR, and reference PC from the OFW stack */ 146 ld %r7,32(%r1) 147 ld %r6,24(%r1) 148 ld %r2,16(%r1) 149 ld %r1,8(%r1) 150 151 /* Get back to the MSR/PC we want, using the cached high bits of PC */ 152 mtsrr1 %r6 153 clrrdi %r7,%r7,32 154 bl 1f 1551: mflr %r8 156 or %r8,%r8,%r7 157 addi %r8,%r8,2f-1b 158 mtsrr0 %r8 159 rfid /* Turn on MMU, exceptions, and 64-bit mode */ 160 1612: 162 /* Sign-extend the return value from OF */ 163 extsw %r3,%r3 164 165 /* Restore all the non-volatile registers */ 166 ld %r5,48(%r1) 167 mtcr %r5 168 ld %r13,56(%r1) 169 ld %r14,64(%r1) 170 ld %r15,72(%r1) 171 ld %r16,80(%r1) 172 ld %r17,88(%r1) 173 ld %r18,96(%r1) 174 ld %r19,104(%r1) 175 ld %r20,112(%r1) 176 ld %r21,120(%r1) 177 ld %r22,128(%r1) 178 ld %r23,136(%r1) 179 ld %r24,144(%r1) 180 ld %r25,152(%r1) 181 ld %r26,160(%r1) 182 ld %r27,168(%r1) 183 ld %r28,176(%r1) 184 ld %r29,184(%r1) 185 ld %r30,192(%r1) 186 ld %r31,200(%r1) 187 188 /* Restore the stack and link register */ 189 ld %r1,0(%r1) 190 ld %r0,16(%r1) 191 mtlr %r0 192 blr 193 194/* 195 * RTAS 32-bit Entry Point. Similar to the OF one, but simpler (no separate 196 * stack) 197 * 198 * C prototype: int rtascall(void *callbuffer, void *rtas_privdat); 199 */ 200 201ASENTRY_NOPROF(rtascall) 202 mflr %r9 203 std %r9,16(%r1) 204 stdu %r1,-208(%r1) 205 206 /* 207 * We need to save the following, because RTAS's register save/ 208 * restore code assumes that the contents of registers are 209 * at most 32 bits wide: lr, cr, r2, r13-r31, the old MSR. These 210 * get placed in that order in the stack. 211 */ 212 213 mfcr %r5 214 std %r5,48(%r1) 215 std %r13,56(%r1) 216 std %r14,64(%r1) 217 std %r15,72(%r1) 218 std %r16,80(%r1) 219 std %r17,88(%r1) 220 std %r18,96(%r1) 221 std %r19,104(%r1) 222 std %r20,112(%r1) 223 std %r21,120(%r1) 224 std %r22,128(%r1) 225 std %r23,136(%r1) 226 std %r24,144(%r1) 227 std %r25,152(%r1) 228 std %r26,160(%r1) 229 std %r27,168(%r1) 230 std %r28,176(%r1) 231 std %r29,184(%r1) 232 std %r30,192(%r1) 233 std %r31,200(%r1) 234 235 /* Record the old MSR */ 236 mfmsr %r6 237 238 /* Read RTAS entry and reg save area pointers */ 239 addis %r5,%r2,TOC_REF(rtas_entry)@ha 240 ld %r5,TOC_REF(rtas_entry)@l(%r5) 241 ld %r5,0(%r5) 242 addis %r8,%r2,TOC_REF(rtas_regsave)@ha 243 ld %r8,TOC_REF(rtas_regsave)@l(%r8) 244 245 /* 246 * Set the MSR to the RTAS value. This has the side effect of disabling 247 * exceptions, which is important for the next few steps. 248 */ 249 250 addis %r7,%r2,TOC_REF(rtasmsr)@ha 251 ld %r7,TOC_REF(rtasmsr)@l(%r7) 252 ld %r7,0(%r7) 253 mtmsrd %r7 254 isync 255 256 /* 257 * Set up RTAS register save area, so that we can get back all of 258 * our 64-bit pointers. Save our stack pointer, the TOC, and the MSR. 259 * Put this in r1, since RTAS is obliged to save it. Kernel globals 260 * are below 4 GB, so this is safe. 261 */ 262 mr %r7,%r1 263 mr %r1,%r8 264 std %r7,0(%r1) /* Save 64-bit stack pointer */ 265 std %r2,8(%r1) /* Save TOC */ 266 std %r6,16(%r1) /* Save MSR */ 267 std %r9,24(%r1) /* Save reference PC for high 32 bits */ 268 269 /* Finally, branch to RTAS */ 270 mtctr %r5 271 bctrl 272 273 /* 274 * Reload stack pointer, MSR, reg PC from the reg save area in r1. We 275 * are running in 32-bit mode at this point, so it doesn't matter if r1 276 * has become sign-extended. 277 */ 278 ld %r7,24(%r1) 279 ld %r6,16(%r1) 280 ld %r2,8(%r1) 281 ld %r1,0(%r1) 282 283 /* 284 * Get back to the right PC. We need to atomically re-enable 285 * exceptions, 64-bit mode, and the MMU. One thing that has likely 286 * happened is that, if we were running in the high-memory direct 287 * map, we no longer are as a result of LR truncation in RTAS. 288 * Fix this by copying the high-order bits of the LR at function 289 * entry onto the current PC and then jumping there while flipping 290 * all the MSR bits. 291 */ 292 mtsrr1 %r6 293 clrrdi %r7,%r7,32 294 bl 1f 2951: mflr %r8 296 or %r8,%r8,%r7 297 addi %r8,%r8,2f-1b 298 mtsrr0 %r8 299 rfid /* Turn on MMU, exceptions, and 64-bit mode */ 300 3012: 302 /* Sign-extend the return value from RTAS */ 303 extsw %r3,%r3 304 305 /* Restore all the non-volatile registers */ 306 ld %r5,48(%r1) 307 mtcr %r5 308 ld %r13,56(%r1) 309 ld %r14,64(%r1) 310 ld %r15,72(%r1) 311 ld %r16,80(%r1) 312 ld %r17,88(%r1) 313 ld %r18,96(%r1) 314 ld %r19,104(%r1) 315 ld %r20,112(%r1) 316 ld %r21,120(%r1) 317 ld %r22,128(%r1) 318 ld %r23,136(%r1) 319 ld %r24,144(%r1) 320 ld %r25,152(%r1) 321 ld %r26,160(%r1) 322 ld %r27,168(%r1) 323 ld %r28,176(%r1) 324 ld %r29,184(%r1) 325 ld %r30,192(%r1) 326 ld %r31,200(%r1) 327 328 /* Restore the stack and link register */ 329 ld %r1,0(%r1) 330 ld %r0,16(%r1) 331 mtlr %r0 332 blr 333 334