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