]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ppc/MPinterfaces.s
xnu-344.21.74.tar.gz
[apple/xnu.git] / osfmk / ppc / MPinterfaces.s
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
d7e50217 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
d7e50217
A
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
d7e50217
A
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/*
26 * @OSF_FREE_COPYRIGHT@
27 */
28/*
29 * @APPLE_FREE_COPYRIGHT@
30 */
31
32/*
33 MPinterfaces.s
34
35 General interface to the MP hardware handlers anonymous
36
37 Lovingly crafted by Bill Angell using traditional methods and only natural or recycled materials.
38 No animal products are used other than rendered otter bile.
39
40*/
41
42#include <cpus.h>
43#include <ppc/asm.h>
44#include <ppc/proc_reg.h>
45#include <ppc/POWERMAC/mp/MPPlugIn.h>
46#include <mach/machine/vm_param.h>
47#include <assym.s>
48
49/*
50 * This first section is the glue for the high level C code.
51 * Anything that needs any kind of system services (e.g., VM) has to be done here. The firmware
52 * code that implements the SC runs in real mode.
53 */
54
55
56
57/* #define MPI_DEBUGGING 0 */
58#define MPI_DEBUGGING 0
59
60/*
61 * The routine that implements cpu_number.
62 */
63
64ENTRY(cpu_number, TAG_NO_FRAME_USED)
65
66 mfmsr r9 /* Save the old MSR */
67 rlwinm r8,r9,0,17,15 /* Clear interruptions */
68 mtmsr r8 /* Interrupts off */
69 mfsprg r7,0 /* Get per-proc block */
70 lhz r3,PP_CPU_NUMBER(r7) /* Get CPU number */
71 mtmsr r9 /* Restore interruptions to entry */
72 blr /* Return... */
73
74
75/*
76 * The routine glues to the count CPU firmware call
77 */
78
79ENTRY(MPgetProcCount, TAG_NO_FRAME_USED)
80
81 mr r12,r0 /* Keep R0 pristene */
82 lis r0,HIGH_ADDR(MPgetProcCountCall) /* Top half of MPgetProcCount firmware call number */
83 ori r0,r0,LOW_ADDR(MPgetProcCountCall) /* Bottom half */
84 sc /* Go see how many processors we have */
85
86#if MPI_DEBUGGING
87 lis r0,HIGH_ADDR(CutTrace) /* Top half of trace entry maker call */
88 ori r0,r0,LOW_ADDR(CutTrace) /* Bottom half of trace entry maker call */
89 sc /* Cut a backend trace entry */
90#endif
91
92 mr r0,r12 /* Restore R0 */
93
94 blr /* Return, pass back R3... */
95
96/*
97 * The routine glues to the start CPU firmware call - actually it's really a boot
98 * The first parameter is the CPU number to start
99 * The second parameter is the real address of the code used to boot the processor
100 * The third parameter is the real addess of the CSA for the subject processor
101 */
102
103ENTRY(MPstart, TAG_NO_FRAME_USED)
104
105 mr r12,r0 /* Keep R0 pristene */
106 lis r0,HIGH_ADDR(MPstartCall) /* Top half of MPstartCall firmware call number */
107 ori r0,r0,LOW_ADDR(MPstartCall) /* Bottom half */
108 sc /* Go see how many processors we have */
109
110#if MPI_DEBUGGING
111 lis r0,HIGH_ADDR(CutTrace) /* Top half of trace entry maker call */
112 ori r0,r0,LOW_ADDR(CutTrace) /* Bottom half of trace entry maker call */
113 sc /* Cut a backend trace entry */
114#endif
115
116 mr r0,r12 /* Restore R0 */
117 blr /* Return... */
118
119/*
120 * This routine glues to the get external interrupt handler physical address
121 */
122
123ENTRY(MPexternalHook, TAG_NO_FRAME_USED)
124
125 mr r12,r0 /* Keep R0 pristene */
126 lis r0,HIGH_ADDR(MPexternalHookCall) /* Top half of MPexternalHookCall firmware call number */
127 ori r0,r0,LOW_ADDR(MPexternalHookCall) /* Bottom half */
128 sc /* Go see how many processors we have */
129
130#if MPI_DEBUGGING
131 lis r0,HIGH_ADDR(CutTrace) /* Top half of trace entry maker call */
132 ori r0,r0,LOW_ADDR(CutTrace) /* Bottom half of trace entry maker call */
133 sc /* Cut a backend trace entry */
134#endif
135
136 mr r0,r12 /* Restore R0 */
137 blr /* Return... */
138
139
140/*
141 * This routine glues to the signal processor routine
142 */
143
144ENTRY(MPsignal, TAG_NO_FRAME_USED)
145
146 mr r12,r0 /* Keep R0 pristene */
147 lis r0,HIGH_ADDR(MPsignalCall) /* Top half of MPsignalCall firmware call number */
148 ori r0,r0,LOW_ADDR(MPsignalCall) /* Bottom half */
149 sc /* Go kick the other guy */
150
151#if MPI_DEBUGGING
152 lis r0,HIGH_ADDR(CutTrace) /* Top half of trace entry maker call */
153 ori r0,r0,LOW_ADDR(CutTrace) /* Bottom half of trace entry maker call */
154 sc /* Cut a backend trace entry */
155#endif
156
157 mr r0,r12 /* Restore R0 */
158 blr /* Return... */
159
160
161/*
162 * This routine glues to the stop processor routine
163 */
164
165ENTRY(MPstop, TAG_NO_FRAME_USED)
166
167 mr r12,r0 /* Keep R0 pristene */
168 lis r0,HIGH_ADDR(MPstopCall) /* Top half of MPsignalCall firmware call number */
169 ori r0,r0,LOW_ADDR(MPstopCall) /* Bottom half */
170 sc /* Stop the other guy cold */
171
172#if MPI_DEBUGGING
173 lis r0,HIGH_ADDR(CutTrace) /* Top half of trace entry maker call */
174 ori r0,r0,LOW_ADDR(CutTrace) /* Bottom half of trace entry maker call */
175 sc /* Cut a backend trace entry */
176#endif
177
178 mr r0,r12 /* Restore R0 */
179 blr /* Return... */
180
181
182/* *************************************************************************************************************
183 *
184 * This second section is the glue for the low level stuff directly into the MP plugin.
185 * At this point every register in existence should be saved. Well, they're saved,
186 * but R13 points to the savearea, and R20 to the trace entry. Please be careful
187 * with these. You won't like what happens if they're different when you exit.
188 *
189 ***************************************************************************************************************/
190
191
192/*
193 * See how many physical processors we have
194 */
195
196ENTRY(MPgetProcCountLL, TAG_NO_FRAME_USED)
197
198 lis r11,HIGH_ADDR(EXT(MPEntries)) /* Get the address of the MP entry block (in the V=R area) */
199 ori r11,r11,LOW_ADDR(EXT(MPEntries)) /* Get the bottom of the MP spec area */
200 lwz r10,kCountProcessors*4(r11) /* Get the routine entry point */
201 mflr r14 /* Save the return in an unused register */
202 mtlr r10 /* Set it */
203 blrl /* Call the routine */
204 mtlr r14 /* Restore firmware caller address */
205 blr /* Leave... */
206
207/*
208 * Start up a processor
209 */
210
211ENTRY(MPstartLL, TAG_NO_FRAME_USED)
212
213 lis r11,HIGH_ADDR(EXT(MPEntries)) /* Get the address of the MP entry block (in the V=R area) */
214 ori r11,r11,LOW_ADDR(EXT(MPEntries)) /* Get the bottom of the MP spec area */
215 lwz r10,kStartProcessor*4(r11) /* Get the routine entry point */
216 mflr r14 /* Save the return in an unused register */
217 mtlr r10 /* Set it */
218 blrl /* Call the routine */
219 mtlr r14 /* Restore firmware caller address */
220 blr /* Leave... */
221
222/*
223 * Get physical address of SIGP external handler
224 */
225
226ENTRY(MPexternalHookLL, TAG_NO_FRAME_USED)
227
228 lis r11,HIGH_ADDR(EXT(MPEntries)) /* Get the address of the MP entry block (in the V=R area) */
229 ori r11,r11,LOW_ADDR(EXT(MPEntries)) /* Get the bottom of the MP spec area */
230 lwz r10,kExternalHook*4(r11) /* Get the routine entry point */
231 mflr r14 /* Save the return in an unused register */
232 mtlr r10 /* Set it */
233 blrl /* Call the routine */
234 mtlr r14 /* Restore firmware caller address */
235 blr /* Leave... */
236
237
238
239/*
240 * Send a signal to another processor
241 */
242
243ENTRY(MPsignalLL, TAG_NO_FRAME_USED)
244
245 lis r11,HIGH_ADDR(EXT(MPEntries)) /* Get the address of the MP entry block (in the V=R area) */
246 ori r11,r11,LOW_ADDR(EXT(MPEntries)) /* Get the bottom of the MP spec area */
247 lwz r10,kSignalProcessor*4(r11) /* Get the routine entry point */
248 mflr r14 /* Save the return in an unused register */
249 mtlr r10 /* Set it */
250 blrl /* Call the routine */
251 mtlr r14 /* Restore firmware caller address */
252 blr /* Leave... */
253
254
255
256/*
257 * Stop another processor
258 */
259
260ENTRY(MPstopLL, TAG_NO_FRAME_USED)
261
262 lis r11,HIGH_ADDR(EXT(MPEntries)) /* Get the address of the MP entry block (in the V=R area) */
263 ori r11,r11,LOW_ADDR(EXT(MPEntries)) /* Get the bottom of the MP spec area */
264 lwz r10,kStopProcessor*4(r11) /* Get the routine entry point */
265 mflr r14 /* Save the return in an unused register */
266 mtlr r10 /* Set it */
267 blrl /* Call the routine */
268 mtlr r14 /* Restore firmware caller address */
269 blr /* Leave... */
270
271
272/*
273 * Third section: Miscellaneous MP related routines
274 */
275
276
277
278/*
279 * All non-primary CPUs start here.
280 * We are dispatched by the SMP driver. Addressing is real (no DR or IR),
281 * interruptions disabled, etc. R3 points to the CPUStatusArea (CSA) which contains
282 * most of the state for the processor. This is set up by the primary. Note that we
283 * do not use everything in the CSA. Caches should be clear and coherent with
284 * no paradoxies (well, maybe one doxie, a pair would be pushing it).
285 */
286
287ENTRY(start_secondary,TAG_NO_FRAME_USED)
288
289 mr r31,r3 /* Get the pointer to the CSA */
290
291 lis r21,HIGH_ADDR(SpinTimeOut) /* Get the top part of the spin timeout */
292 ori r21,r21,LOW_ADDR(SpinTimeOut) /* Slam in the bottom part */
293
294GetValid: lbz r10,CSAregsAreValid(r31) /* Get the CSA validity value */
295
296
297 mr. r10,r10 /* Is the area valid yet? */
298 bne GotValid /* Yeah... */
299 addic. r21,r21,-1 /* Count the try */
300 isync /* Make sure we don't prefetch the valid flag */
301 bge+ GetValid /* Still more tries left... */
302 blr /* Return and cancel startup request... */
303
304GotValid: li r21,0 /* Set the valid flag off (the won't be after the RFI) */
305 lwz r10,CSAdec(r31) /* Get the decrimenter */
306 stb r21,CSAregsAreValid(r31) /* Clear that validity flag */
307
308 lwz r11,CSAdbat+(0*8)+0(r31) /* Get the first DBAT */
309 lwz r12,CSAdbat+(0*8)+4(r31) /* Get the first DBAT */
310 lwz r13,CSAdbat+(1*8)+0(r31) /* Get the second DBAT */
311 mtdec r10 /* Set the decrimenter */
312 lwz r14,CSAdbat+(1*8)+4(r31) /* Get the second DBAT */
313 mtdbatu 0,r11 /* Set top part of DBAT 0 */
314 lwz r15,CSAdbat+(2*8)+0(r31) /* Get the third DBAT */
315 mtdbatl 0,r12 /* Set lower part of DBAT 0 */
316 lwz r16,CSAdbat+(2*8)+4(r31) /* Get the third DBAT */
317 mtdbatu 1,r13 /* Set top part of DBAT 1 */
318 lwz r17,CSAdbat+(3*8)+0(r31) /* Get the fourth DBAT */
319 mtdbatl 1,r14 /* Set lower part of DBAT 1 */
320 lwz r18,CSAdbat+(3*8)+4(r31) /* Get the fourth DBAT */
321 mtdbatu 2,r15 /* Set top part of DBAT 2 */
322 lwz r11,CSAibat+(0*8)+0(r31) /* Get the first IBAT */
323 mtdbatl 2,r16 /* Set lower part of DBAT 2 */
324 lwz r12,CSAibat+(0*8)+4(r31) /* Get the first IBAT */
325 mtdbatu 3,r17 /* Set top part of DBAT 3 */
326 lwz r13,CSAibat+(1*8)+0(r31) /* Get the second IBAT */
327 mtdbatl 3,r18 /* Set lower part of DBAT 3 */
328 lwz r14,CSAibat+(1*8)+4(r31) /* Get the second IBAT */
329 mtibatu 0,r11 /* Set top part of IBAT 0 */
330 lwz r15,CSAibat+(2*8)+0(r31) /* Get the third IBAT */
331 mtibatl 0,r12 /* Set lower part of IBAT 0 */
332 lwz r16,CSAibat+(2*8)+4(r31) /* Get the third IBAT */
333 mtibatu 1,r13 /* Set top part of IBAT 1 */
334 lwz r17,CSAibat+(3*8)+0(r31) /* Get the fourth IBAT */
335 mtibatl 1,r14 /* Set lower part of IBAT 1 */
336 lwz r18,CSAibat+(3*8)+4(r31) /* Get the fourth IBAT */
337 mtibatu 2,r15 /* Set top part of IBAT 2 */
338 lwz r11,CSAsdr1(r31) /* Get the SDR1 value */
339 mtibatl 2,r16 /* Set lower part of IBAT 2 */
340 lwz r12,CSAsprg(r31) /* Get SPRG0 (the per_proc_info address) */
341 mtibatu 3,r17 /* Set top part of IBAT 3 */
342 lwz r13,CSAmsr(r31) /* Get the MSR */
343 mtibatl 3,r18 /* Set lower part of IBAT 3 */
344 lwz r14,CSApc(r31) /* Get the PC */
345 sync /* Sync up */
346 mtsdr1 r11 /* Set the SDR1 value */
347 sync /* Sync up */
348
349 la r10,CSAsr-4(r31) /* Point to SR 0 - 4 */
350 li r9,0 /* Start at SR 0 */
351
352LoadSRs: lwz r8,4(r10) /* Get the next SR in line */
353 addi r10,r10,4
354 mtsrin r8,r9 /* Load up the SR */
355 addis r9,r9,0x1000 /* Bump to the next SR */
356 mr. r9,r9 /* See if we wrapped back to 0 */
357 bne+ LoadSRs /* Not yet... */
358
359 lwz r0,CSAgpr+(0*4)(r31) /* Get a GPR */
360 lwz r9,CSAsprg+(1*4)(r31) /* Get SPRG1 (the initial active savearea) */
361 mtsrr1 r13 /* Set the MSR to dispatch */
362 lwz r1,CSAgpr+(1*4)(r31) /* Get a GPR */
363 mtsprg 0,r12 /* Set the SPRG0 (per_proc_into) value */
364 lwz r2,CSAgpr+(2*4)(r31) /* Get a GPR */
365 mtsrr0 r14 /* Set the PC to dispatch */
366 lwz r3,CSAgpr+(3*4)(r31) /* Get a GPR */
367 mtsprg 1,r9 /* Set the SPRG1 (the initial active savearea) value */
368 lwz r4,CSAgpr+(4*4)(r31) /* Get a GPR */
369 lwz r5,CSAgpr+(5*4)(r31) /* Get a GPR */
370 lwz r6,CSAgpr+(6*4)(r31) /* Get a GPR */
371 lwz r7,CSAgpr+(7*4)(r31) /* Get a GPR */
372 lwz r8,CSAgpr+(8*4)(r31) /* Get a GPR */
373 lwz r9,CSAgpr+(9*4)(r31) /* Get a GPR */
374 lwz r10,CSAgpr+(10*4)(r31) /* Get a GPR */
375 lwz r11,CSAgpr+(11*4)(r31) /* Get a GPR */
376 lwz r12,CSAgpr+(12*4)(r31) /* Get a GPR */
377 lwz r13,CSAgpr+(13*4)(r31) /* Get a GPR */
378 lwz r14,CSAgpr+(14*4)(r31) /* Get a GPR */
379 lwz r15,CSAgpr+(15*4)(r31) /* Get a GPR */
380 lwz r16,CSAgpr+(16*4)(r31) /* Get a GPR */
381 lwz r17,CSAgpr+(17*4)(r31) /* Get a GPR */
382 lwz r18,CSAgpr+(18*4)(r31) /* Get a GPR */
383 lwz r19,CSAgpr+(19*4)(r31) /* Get a GPR */
384 lwz r20,CSAgpr+(20*4)(r31) /* Get a GPR */
385 lwz r21,CSAgpr+(21*4)(r31) /* Get a GPR */
386 lwz r22,CSAgpr+(22*4)(r31) /* Get a GPR */
387 lwz r23,CSAgpr+(23*4)(r31) /* Get a GPR */
388 lwz r24,CSAgpr+(24*4)(r31) /* Get a GPR */
389 lwz r25,CSAgpr+(25*4)(r31) /* Get a GPR */
390 lwz r26,CSAgpr+(26*4)(r31) /* Get a GPR */
391 lwz r27,CSAgpr+(27*4)(r31) /* Get a GPR */
392 lwz r28,CSAgpr+(28*4)(r31) /* Get a GPR */
393 lwz r29,CSAgpr+(29*4)(r31) /* Get a GPR */
394 lwz r30,CSAgpr+(30*4)(r31) /* Get a GPR */
395 lwz r31,CSAgpr+(31*4)(r31) /* Get a GPR */
396
397 sync /* Make sure we're sunk */
398
399 rfi /* Get the whole shebang going... */
400
401 .long 0
402 .long 0
403 .long 0
404 .long 0
405 .long 0
406 .long 0
407 .long 0
408 .long 0
409
410
411
412
413/*
414 * This routine handles requests to firmware from another processor. It is actually the second level
415 * of a three level signaling protocol. The first level is handled in the physical MP driver. It is the
416 * basic physical control for the processor, e.g., physical stop, reset, start. The second level (this
417 * one) handles cross-processor firmware requests, e.g., complete TLB purges. The last are AST requests
418 * which are handled directly by mach.
419 *
420 * If this code handles the request (based upon MPPICParm0BU which is valid until the next SIGP happens -
421 * actually, don't count on it once you enable) it will RFI back to the
422 * interrupted code. If not, it will return and let the higher level interrupt handler be called.
423 *
424 * We need to worry about registers we use here, check in lowmem_vectors to see what is boten and verboten.
425 *
426 * Note that there are no functions implemented yet.
427 */
428
429
430ENTRY(MPsignalFW, TAG_NO_FRAME_USED)
431
432
433 mfspr r7,pir /* Get the processor address */
434 lis r6,HIGH_ADDR(EXT(MPPICPUs)) /* Get high part of CPU control block array */
435 rlwinm r7,r7,5,23,26 /* Get index into CPU array */
436 ori r6,r6,HIGH_ADDR(EXT(MPPICPUs)) /* Get low part of CPU control block array */
437 add r7,r7,r6 /* Point to the control block for this processor */
438 lwz r6,MPPICParm0BU(r7) /* Just pick this up for now */
439 blr /* Leave... */
440
441
442/*
443 * Make space for the maximum supported CPUs in the data section
444 */
445
446#ifdef __ELF__
447 .section ".data"
448#else
449 .data
450#endif
451 .align 5
452EXT(CSA):
453 .set ., .+(CSAsize*NCPUS)
454#ifndef __MACHO__
455 .type EXT(CSA), @object
456 .size EXT(CSA), CSAsize*NCPUS
457#endif
458 .globl EXT(CSA)