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