|
|
1.1 root 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:
61: ENTRY(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:
76: ENTRY(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:
100: ENTRY(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:
120: ENTRY(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:
141: ENTRY(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:
162: ENTRY(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:
193: ENTRY(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:
208: ENTRY(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:
223: ENTRY(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:
240: ENTRY(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:
257: ENTRY(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:
284: ENTRY(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:
291: GetValid: 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:
301: GotValid: 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:
349: LoadSRs: 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:
427: ENTRY(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
449: EXT(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)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.