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