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
44 ofwstk:
45 .space OFWSTKSZ
46 rtas_regsave:
47 .space 32 /* 4 * sizeof(register_t) */
48 GLOBAL(ofmsr)
49 .llong 0, 0, 0, 0, 0 /* msr/sprg0-3 used in Open Firmware */
50 GLOBAL(rtasmsr)
51 .llong 0
52 GLOBAL(openfirmware_entry)
53 .llong 0 /* Open Firmware entry point */
54 GLOBAL(rtas_entry)
55 .llong 0 /* RTAS entry point */
56
57 TOC_ENTRY(ofmsr)
58 TOC_ENTRY(ofwstk)
59 TOC_ENTRY(rtasmsr)
60 TOC_ENTRY(openfirmware_entry)
61 TOC_ENTRY(rtas_entry)
62 TOC_ENTRY(rtas_regsave)
63
64 /*
65 * Open Firmware Real-mode Entry Point. This is a huge pain.
66 */
67
68 ASENTRY_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
157 1:
158 mflr %r5
159 addi %r5, %r5, (2f-1b)
160 mtlr %r5
161 li %r5, 0
162 rfid
163 2:
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
181 1: 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
187 2:
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
219 ASEND(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
228 ASENTRY_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
310 1:
311 mflr %r5
312 addi %r5, %r5, (2f-1b)
313 mtlr %r5
314 li %r5, 0
315 rfid
316 2:
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
346 1: 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
352 2:
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
384 ASEND(rtascall)
Cache object: 60eb40c292e243088f43c56d19c39b7c
|