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 24 /* 3 * 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 %r0 68 std %r0,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-32 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 li %r5,0 133 stw %r5,4(%r1) 134 stw %r5,0(%r1) 135 136 /* Finally, branch to OF */ 137 mtctr %r4 138 bctrl 139 140 /* Reload stack pointer and MSR from the OFW stack */ 141 ld %r6,24(%r1) 142 ld %r2,16(%r1) 143 ld %r1,8(%r1) 144 145 /* Now set the real MSR */ 146 mtmsrd %r6 147 isync 148 149 /* Sign-extend the return value from OF */ 150 extsw %r3,%r3 151 152 /* Restore all the non-volatile registers */ 153 ld %r5,48(%r1) 154 mtcr %r5 155 ld %r13,56(%r1) 156 ld %r14,64(%r1) 157 ld %r15,72(%r1) 158 ld %r16,80(%r1) 159 ld %r17,88(%r1) 160 ld %r18,96(%r1) 161 ld %r19,104(%r1) 162 ld %r20,112(%r1) 163 ld %r21,120(%r1) 164 ld %r22,128(%r1) 165 ld %r23,136(%r1) 166 ld %r24,144(%r1) 167 ld %r25,152(%r1) 168 ld %r26,160(%r1) 169 ld %r27,168(%r1) 170 ld %r28,176(%r1) 171 ld %r29,184(%r1) 172 ld %r30,192(%r1) 173 ld %r31,200(%r1) 174 175 /* Restore the stack and link register */ 176 ld %r1,0(%r1) 177 ld %r0,16(%r1) 178 mtlr %r0 179 blr 180 181/* 182 * RTAS 32-bit Entry Point. Similar to the OF one, but simpler (no separate 183 * stack) 184 * 185 * C prototype: int rtascall(void *callbuffer, void *rtas_privdat); 186 */ 187 188ASENTRY_NOPROF(rtascall) 189 mflr %r0 190 std %r0,16(%r1) 191 stdu %r1,-208(%r1) 192 193 /* 194 * We need to save the following, because RTAS's register save/ 195 * restore code assumes that the contents of registers are 196 * at most 32 bits wide: lr, cr, r2, r13-r31, the old MSR. These 197 * get placed in that order in the stack. 198 */ 199 200 mfcr %r5 201 std %r5,48(%r1) 202 std %r13,56(%r1) 203 std %r14,64(%r1) 204 std %r15,72(%r1) 205 std %r16,80(%r1) 206 std %r17,88(%r1) 207 std %r18,96(%r1) 208 std %r19,104(%r1) 209 std %r20,112(%r1) 210 std %r21,120(%r1) 211 std %r22,128(%r1) 212 std %r23,136(%r1) 213 std %r24,144(%r1) 214 std %r25,152(%r1) 215 std %r26,160(%r1) 216 std %r27,168(%r1) 217 std %r28,176(%r1) 218 std %r29,184(%r1) 219 std %r30,192(%r1) 220 std %r31,200(%r1) 221 222 /* Record the old MSR */ 223 mfmsr %r6 224 225 /* Read RTAS entry and reg save area pointers */ 226 ld %r5,TOC_REF(rtas_entry)(%r2) 227 ld %r5,0(%r5) 228 ld %r8,TOC_REF(rtas_regsave)(%r2) 229 230 /* 231 * Set the MSR to the RTAS value. This has the side effect of disabling 232 * exceptions, which is important for the next few steps. 233 */ 234 235 ld %r7,TOC_REF(rtasmsr)(%r2) 236 ld %r7,0(%r7) 237 mtmsrd %r7 238 isync 239 240 /* 241 * Set up RTAS register save area, so that we can get back all of 242 * our 64-bit pointers. Save our stack pointer, the TOC, and the MSR. 243 * Put this in r1, since RTAS is obliged to save it. Kernel globals 244 * are below 4 GB, so this is safe. 245 */ 246 mr %r7,%r1 247 mr %r1,%r8 248 std %r7,0(%r1) /* Save 64-bit stack pointer */ 249 std %r2,8(%r1) /* Save TOC */ 250 std %r6,16(%r1) /* Save MSR */ 251 252 /* Finally, branch to RTAS */ 253 mtctr %r5 254 bctrl 255 256 /* 257 * Reload stack pointer and MSR from the reg save area in r1. We are 258 * running in 32-bit mode at this point, so it doesn't matter if r1 259 * has become sign-extended. 260 */ 261 ld %r6,16(%r1) 262 ld %r2,8(%r1) 263 ld %r1,0(%r1) 264 265 /* Now set the real MSR */ 266 mtmsrd %r6 267 isync 268 269 /* Sign-extend the return value from RTAS */ 270 extsw %r3,%r3 271 272 /* Restore all the non-volatile registers */ 273 ld %r5,48(%r1) 274 mtcr %r5 275 ld %r13,56(%r1) 276 ld %r14,64(%r1) 277 ld %r15,72(%r1) 278 ld %r16,80(%r1) 279 ld %r17,88(%r1) 280 ld %r18,96(%r1) 281 ld %r19,104(%r1) 282 ld %r20,112(%r1) 283 ld %r21,120(%r1) 284 ld %r22,128(%r1) 285 ld %r23,136(%r1) 286 ld %r24,144(%r1) 287 ld %r25,152(%r1) 288 ld %r26,160(%r1) 289 ld %r27,168(%r1) 290 ld %r28,176(%r1) 291 ld %r29,184(%r1) 292 ld %r30,192(%r1) 293 ld %r31,200(%r1) 294 295 /* Restore the stack and link register */ 296 ld %r1,0(%r1) 297 ld %r0,16(%r1) 298 mtlr %r0 299 blr 300 301