]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ppc/POWERMAC/mp/MP_2p.s
e4951d28a9247354093d479dfa0b9c42f66200ca
[apple/xnu.git] / osfmk / ppc / POWERMAC / mp / MP_2p.s
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
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
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * @OSF_COPYRIGHT_INTERNAL_USE_ONLY@
27 */
28
29 /*
30 MP_2p.s
31
32 MP low-level signaling, configuration, et all. This is for a and Apple/Daystar 2p board
33
34 Lovingly crafted by Bill Angell using traditional methods
35
36 */
37
38 #include <ppc/asm.h>
39 #include <ppc/proc_reg.h>
40 #include <ppc/POWERMAC/mp/MPPlugIn.h>
41 #include <assym.s>
42 #include <mach/machine/vm_param.h>
43
44
45
46 .set MPPlugInVersion,0 /* Current version code */
47
48 /* */
49 /* Interfaces to hardware */
50 /* */
51
52 .set PCI1ARdisp, 0x00800000 /* Displacement from Bandit to PCI1 address configuiration register */
53 .set GrandCdisp, 0x01000000 /* Displacement from Bandit to Grand Central */
54 .set EventsReg, 0x20 /* Interruption events register (latched) */
55 .set LevelsReg, 0x2C /* Interruption levels register (unlatched) */
56 .set MaskReg, 0x24 /* Interruption mask register */
57 .set ClearReg, 0x28 /* Interruption clear register */
58 .set TicksPerMic, 11 /* We'll use 11 ticks per µS - 120MHz is really 10, 180MHz is 11.24 */
59 .set EtherNRdisp, 0x01019000 /* Displacement into bandit of EtherNet ROM */
60
61 #ifdef __ELF__
62 .section ".data"
63 #else
64 .data
65 #endif
66
67 .align 5 /* Get us out to the end */
68
69 .globl MPPIwork
70 #ifdef __ELF__
71 .type MPPIwork,@function
72 #endif
73
74 MPPIwork:
75 MPPIstatus: .byte 0 /* Global MP board status */
76 .set MPPIinit, 0x80 /* Global initialization complete */
77 .set MPPI2Pv2, 0x40 /* Second rev of 2P board (no watchdog and different state machine) */
78 .byte 0 /* Reserved */
79 MPPIinst: .byte 0 /* Mask of CPUs installed */
80 MPPIonline: .byte 0 /* Mask of CPUs online (i.e., initialized) */
81 MPPIlogCPU: .long 0 /* Used to configure CPU addresses */
82 MPPITBsync: .long 0 /* Used to sync time bases */
83 .long 0
84 MPPIHammer: .long 0 /* Address of HammerHead */
85 MPPIGrandC: .long 0 /* Address of GrandCentral */
86 MPPIPCI1Adr: .long 0 /* Address of PCI1's config reg addr */
87 MPPIEther: .long 0 /* Address of EtherNet ROM */
88
89 .align 5
90 MPPISncFght: .fill 4,4,0 /* Space for 9 passes of a TB sync fight + 1 guard pass */
91 .fill 4,4,0
92 .fill 4,4,0
93 .fill 4,4,0
94 .fill 4,4,0
95 .fill 4,4,0
96 .fill 4,4,0
97 .fill 4,4,0
98 .fill 4,4,0
99 .fill 4,4,0
100 .align 7 /* Point to the start of the CPU status */
101
102 .globl EXT(MPPICPUs)
103 #ifdef __ELF__
104 .type EXT(MPPICPUs),@function
105 #endif
106 EXT(MPPICPUs): /* Start of Processor specific areas */
107 /* There are 8 of these indexed by processor number */
108
109
110 MPPICPU0: .fill 8,4,0 /* First processor */
111 MPPICPU1: .fill 8,4,0 /* Second processor */
112 MPPICPU2: .fill 8,4,0 /* Third processor */
113 MPPICPU3: .fill 8,4,0 /* Fourth processor */
114 .set MPPIMaxCPU, (.-EXT(MPPICPUs)-32)/32 /* Get the maximum CPU address */
115
116
117 .text
118
119 /******************************************************************************************************** */
120 /******************************************************************************************************** */
121 /* */
122 /* Here starteth ye stuff */
123 /* */
124 /******************************************************************************************************** */
125 /******************************************************************************************************** */
126
127 /******************************************************************************************************** */
128 /* */
129 /* Validate that the hardware matches with our code. At this point, we cannot check */
130 /* for anything other than the possibility of this working. There's no version code */
131 /* or nothin'. So, if we have a second processor and are a 604 or 604e, we'll say */
132 /* we're capable. Also we'll check version codes for our code. */
133 /* */
134 /* When we get here, DDAT and IDAT are both on, 'rupts are disabled. */
135 /* */
136 /* We're called like this: */
137 /* OSStatus MP_probe(MPPlugInSpecPtr spec, UInt32 HammerheadAddr); */
138 /* */
139 /******************************************************************************************************** */
140
141 ENTRY(MPprobe, TAG_NO_FRAME_USED)
142
143
144 MPPIbase: mfpvr r7 /* Get the processor version */
145 rlwinm r7,r7,16,16,31 /* Isolate the processor type */
146
147 lbz r5,ArbConfig(r4) /* See if there is another processor */
148
149 andi. r5,r5,TwoCPU /* Are we a real live two processor? */
150 beq OneWay /* Nope, we be gone... */
151
152 cmplwi cr0,r7,4 /* Are we a 604? */
153 beq SeemsOK /* Yeah, we're cool... */
154 cmplwi cr0,r7,9 /* Are we a 604E? */
155 beq SeemsOK /* Yeah, go finish up... */
156
157 OneWay: li r3,0 /* Say we can't find the proper CPU */
158 blr /* Leave... */
159
160 SeemsOK: mr r10,r3 /* Save the parameter list */
161
162 lwz r4,MPSversionID(r10) /* Get the version ID */
163 cmplwi cr0,r4,kMPPlugInVersionID /* Correct version? */
164 beq IsOK /* Yeah, we think we're ok... */
165
166 li r3,0 /* Set bad version' */
167 blr /* Leave... */
168
169 IsOK: mflr r11 /* Save the LR */
170 lis r9,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
171 bl SetBase1 /* Jump to the next instruction */
172 SetBase1: mflr r12 /* Get the base register */
173 ori r9,r9,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
174 addi r12,r12,LOW_ADDR(MPPIbase-SetBase1) /* Adjust to the start of all our code */
175
176 stw r12,MPSbaseAddr(r10) /* Save off the common base for all functions */
177
178 la r5,LOW_ADDR(MPPIFunctions-MPPIbase)(r12) /* Point to the base of all functions */
179 stw r5,MPSareaAddr(r10) /* Pass back the code address */
180
181 la r5,LOW_ADDR(MPPIFuncOffs-MPPIbase)(r12) /* Point to the function offset table */
182 stw r5,MPSoffsetTableAddr(r10) /* Pass back the pointer to the offset table */
183
184 li r5,LOW_ADDR(MPPISize-MPPIFunctions) /* Get our size without data area */
185 stw r5,MPSareaSize(r10) /* Save it */
186
187 stw r9,MPSdataArea(r10) /* Save it */
188
189 la r5,LOW_ADDR(EXT(MPPICPUs)-MPPIwork)(r9) /* Point to the CPU area base */
190 stw r5,MPSCPUArea(r10) /* Save it */
191
192 mtlr r11 /* Restore that return address */
193 li r3,1 /* Set no error */
194 blr /* Leave, we're all done... */
195
196 /******************************************************************************************************** */
197 /******************************************************************************************************** */
198 /* */
199 /* Here starteth ye code that starteth up ye second prothether. */
200 /* Yea, though ye prothether executeth asynchronously, it appears unto men */
201 /* in ye shape of a synchronous process. By ye instruction of He who gave it */
202 /* form and being, it stopeth to worship and praise its Lord, to joyously */
203 /* receive His blessings and teachings, to guide its way along the path to */
204 /* righteous execution. */
205 /* */
206 /******************************************************************************************************** */
207 /******************************************************************************************************** */
208
209
210 /******************************************************************************************************** */
211 /* */
212 /* Initialize the MP hardware. This will bring the other processor online. */
213 /* */
214 /* First we will tick the board to its 5th state the "TBEN off" state. */
215 /* */
216 /* Just for giggles, here's the states: */
217 /* */
218 /* 1) 1st ROM - This state exists after motherboard reset */
219 /* 2) Open Firmware - Transitions here when the SecInt line is first asserted */
220 /* Open Firmware attempts to execute some code on the secondary */
221 /* processor to obtain the PVR register. It's got some problems */
222 /* and hangs the secondary disabled. */
223 /* 3) Reset (my name) - Entered when the SecInt line is deasserted. A timer starts and */
224 /* 468µS later the reset line is pulled. I may have this wrong here, */
225 /* it may be that the reset line is held for 468µS. Either way, */
226 /* this state is invisible to us. */
227 /* 4) 2nd ROM - This state exists when the secondary processor begins executing */
228 /* after the reset. */
229 /* 5) TBEN off - We transition here when SecInt is asserted in the 2nd ROM state. */
230 /* In this state, the TBEN pin is set to disable the timebase from */
231 /* running on all processors, thus freezing time. (Performace analysis */
232 /* note: here would be the best time to run stats, all tests would */
233 /* run in 0 time giving us infinite speed.) Also the "primary arbitration" */
234 /* mode is set. This mode causes the CPU board to arbitrate both processors */
235 /* using a single bus master. This gets us around the L2 cache dumbness. */
236 /* We should also note that because of this, there is now no way to */
237 /* tell if we are on the secondary processor, the WhoAmI register will */
238 /* always indicate the primary processor. We need to have sewn */
239 /* name tags into our underwear before now. */
240 /* Finally, this state is the only way we can tell if we are executing */
241 /* on the older version of the 2-way board. When it is in this state */
242 /* "primary arbitration" has not been enabled yet. The WhoAmI register */
243 /* will indicate if we are on the secondary processor on not. We should */
244 /* check this because we need to do signals differently. */
245 /* 6) TBEN on - The next assertion of SecInt brings us to our final destination. For */
246 /* those of you who will be deplaning, please remember that timebases */
247 /* are running and primary arbitration is enabled. Always remember: */
248 /* buckle up for safety and if you're tired pull over for a rest. */
249 /* */
250 /******************************************************************************************************** */
251
252 ENTRY(MPinstall, TAG_NO_FRAME_USED)
253
254 /* int MP_install(unsigned int *physAddr, unsigned int band1, unsigned int hammerh, unsigned int grandc,
255 * unsigned int pci1ar, unsigned int enetr);
256 */
257
258 lis r11,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
259 mflr r0 /* Save the LR */
260 ori r11,r11,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
261
262 stw r5,MPPIHammer-MPPIwork(r11) /* Save the HammerHead address for later */
263 stw r6,MPPIGrandC-MPPIwork(r11) /* Save address of Grand Central */
264 stw r7,MPPIPCI1Adr-MPPIwork(r11) /* Save the PCI1 address register address */
265 stw r8,MPPIEther-MPPIwork(r11) /* Save Ethernet ROM address */
266
267 li r4,LOW_ADDR(0xC080) /* Set CPU 0&1 installed, CPU 0 online */
268 lis r10,(MPPICOnline+MPPICReady)>>16 /* Set CPU 0 online and ready */
269
270 mfspr r6,pir /* Get the PIR contents */
271
272 sth r4,MPPIinst-MPPIwork(r11) /* Set 'em for later */
273 rlwinm r6,r6,0,0,27 /* Clear to use processor 0 */
274 stw r10,EXT(MPPICPUs)-MPPIwork(r11) /* Preset CPU 0 online and ready */
275
276 mtspr pir,r6 /* Set our PIR */
277
278 /* */
279 /* Ok, ok, enough of this. Let's really start 'em up. */
280 /* */
281
282 lis r9,HIGH_ADDR(CPUInit) /* Top of init code */
283 li r6,1 /* Get the other guy's CPU address */
284 ori r9,r9,LOW_ADDR(CPUInit) /* Get physical address of init code */
285
286 mfmsr r8 /* Get the MSR */
287
288 stw r6,MPPIlogCPU-MPPIwork(r11) /* Set the logical CPU address to assign */
289
290 rlwinm r6,r8,0,17,15 /* Turn off interruptions */
291 sync /* Make sure the work area is updated */
292 mtmsr r6 /* Flip the EE bit off */
293 isync /* Chill a bit */
294
295 stw r9,0(r7) /* Pass the initialization code address to our friend */
296 sync /* Fence off the pig */
297
298 li r6,0 /* Clear this out */
299 stb r6,IntReg(r5) /* Kick the other processor */
300 eieio /* Pig in the sty */
301
302 /* At this point we should be in the "TBEN off" state. The second processor should be starting */
303 /* to come up. */
304
305 /* Note that we are assuming that the secondary processor will reset the interrupt request. */
306 /* If we are on one of the old boards, we will die in about 256µS if it is not reset, 'cause */
307 /* of that silly watchchihuahua timer. We can't use the TB or decrimenter here to set a */
308 /* timeout because when we are in "TBEN off" state these guys don't run. */
309
310 lis r4,HIGH_ADDR(SpinTimeOut) /* Get about 1 second at 200MHz */
311 /* At 120 MHz this is 1.66 seconds, at 400MHz it is .5 */
312 /* All these are more than enough time for this handshake */
313 ori r4,r4,LOW_ADDR(SpinTimeOut) /* Get the bottom part */
314
315 WaitReady: lwz r9,0(r7) /* Get this back */
316 mr. r9,r9 /* The other processor will set to 0 */
317 /* when it is ready for the work area address */
318 beq CodeUp /* The code is up on the other side */
319 subi r4,r4,1 /* Count the try */
320 mr. r4,r4 /* Did we timeout? */
321 bne+ WaitReady /* Nope... */
322
323 li r3,kMPPInitTO1 /* Set that we timed out with initial code bringup */
324 mtmsr r8 /* Restore the interrupt state */
325 mtlr r0 /* Restore the return addess */
326 blr /* Return a failure... */
327
328 CodeUp: isync /* Make sure we don't prefetch past here */
329
330 /* Timebase is stopped here, no need for the funky "get time base right" loop */
331
332 mftbu r4 /* Get upper timebase half */
333 mftb r9 /* Get bottom */
334 stw r4,MPPITBsync-MPPIwork(r11) /* Save the top */
335 stw r9,MPPITBsync+4-MPPIwork(r11) /* Save the second half */
336 sync /* Be very sure it's there */
337
338 stw r11,0(r7) /* Set the PCI1 adr reg non-zero - this releases the spin */
339 /* loop and allows the timebase to be set. */
340 eieio
341
342 lis r9,HIGH_ADDR(SpinTimeOut) /* Get the spin time */
343 ori r9,r9,LOW_ADDR(SpinTimeOut) /* Get the bottom part */
344
345 WaitTBset: lwz r4,0(r7) /* Get this back */
346 mr. r4,r4 /* When zero, the other guy's TB is set up */
347 beq- TBSetUp /* She's'a all done... */
348 subi r9,r9,1 /* Count the try */
349 mr. r9,r9 /* Did we timeout? */
350 bne+ WaitTBset /* Nope... */
351
352 li r3,kMPPInitTO3 /* Set that we timed out setting clock */
353 mtmsr r8 /* Restore the interrupt state */
354 isync
355 mtlr r0 /* Restore the return addess */
356 blr /* Return a failure... */
357
358 TBSetUp: stb r6,IntReg(r5) /* Kick the other processor again */
359 /* This will tick us to the next state */
360 eieio
361
362 SpinDelay: addi r6,r6,1 /* Bump spin count (we finally are trashing R6) */
363 cmplwi cr0,r6,4096 /* Spun enough? */
364 ble+ SpinDelay /* Nope... */
365
366 li r6,SecInt /* Set the interrupt bit */
367 stb r6,IntReg(r5) /* Deassert the external signal */
368 /* */
369 /* Ok, the other processor should be online in a spin waiting for a start signal from */
370 /* us. It should be in the reset state with no external interruptions pending. There may */
371 /* be a decrimenter pop waiting in the wings though. */
372 /* */
373
374 lwz r7,MPPIGrandC-MPPIwork(r11) /* Point to GrandCentral */
375 lwz r4,MaskReg(r7) /* Get the grand central mask register (note that this */
376 /* is a little-endian area, but I'm too lazy to access it that way */
377 /* so I'll document what it really should be, but, probably, it would */
378 /* have been much, much easier just to code up the lwbrx and be done */
379 /* with it rather than producing this monograph describing my alternate */
380 /* access method that I really don't explain anyway. */
381 ori r4,r4,0x0040 /* Flip on bit 30 (hah, figure that one out). This enables the */
382 /* Ext10 interrupt which is connected to the MACE ethernet chip's */
383 /* chip-select pin. */
384 stw r4,MaskReg(r7) /* Stick it on back */
385 eieio
386
387 mtlr r0 /* Get back the original LR */
388 sync /* Make sure all storage ops are done */
389 mtmsr r8 /* Restore the MSR */
390 isync
391 li r3,kSIGPnoErr /* Set that we worked jest fine and dandy */
392 blr /* Bye now... */
393
394 .align 5
395 /******************************************************************************************************** */
396 /******************************************************************************************************** */
397 /* */
398 /* This is where the individual SIGP function calls reside. */
399 /* Also, it is where we cram the second processor's initialization code wo'w we */
400 /* can use physical addressing. */
401 /* */
402 /******************************************************************************************************** */
403 /******************************************************************************************************** */
404
405 MPPIFunctions: /* Start of all externally called functions and interrupt handling code */
406
407
408 /******************************************************************************************************** */
409 /* */
410 /* Count the number of processors. This hardwires to 2 (or 1 if no secondary) */
411 /* */
412 /******************************************************************************************************** */
413
414 CountProcessors:
415 lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
416 mfmsr r9 /* Get the MSR */
417 ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
418
419 ori r10,r9,0x0010 /* Turn on DDAT */
420
421 lwz r8,MPPIHammer-MPPIwork(r12) /* Point to the HammerHead controller */
422
423 mtmsr r10 /* Turn on DDAT */
424 isync /* Kill speculation */
425
426 li r3,2 /* Assume we have them all */
427 lbz r5,ArbConfig(r8) /* Check if we've seen a second processor */
428 andi. r5,r5,TwoCPU /* Are we a real live two processor? */
429 mtmsr r9 /* Put back the DDAT */
430 isync
431
432 bnelr+ /* Yeah... */
433 li r3,1 /* Nope, set a count of 1 */
434 blr /* Leave, we're inadequate... */
435
436 /******************************************************************************************************** */
437 /* */
438 /* Start up the selected processor (R3=processor; R4=physical start address; R5=pass-thru parm) */
439 /* */
440 /******************************************************************************************************** */
441
442 StartProcessor:
443
444 mr r7,r5 /* Copy pass-thru parameter */
445 mfspr r10,pir /* Get our processor number */
446 rlwinm r9,r3,5,23,26 /* Get index into CPU array */
447 cmplw cr0,r3,r10 /* Trying to start ourselves? */
448 lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
449 cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */
450 li r3,kMPPHairyPalms /* Set trying to do it to ourselves */
451 beqlr- /* Self abuse... */
452 li r3,kSIGPTargetAddrErr /* CPU number is too big */
453 bgtlr- cr1 /* Sure are... (Get our address also) */
454 ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
455 la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */
456 mflr r11 /* Save the return address */
457 add r9,r9,r12 /* Point right at the entry */
458
459 SPretry: lwarx r5,0,r9 /* Pick up the status flags (MPPICStat) and reserve it */
460 li r3,kSIGPInterfaceBusyErr /* Fill dead space and get busy return code */
461 rlwinm. r0,r5,0,0,0 /* Are we marked as busy? */
462 lis r6,MPPICOnline>>16 /* Get the online flag */
463 bne- ErrorReturn /* Yeah, go leave, don't bother me now... */
464 and. r0,r5,r6 /* Are we online */
465 li r3,kMPPOffline /* Set offline */
466 beq- ErrorReturn /* Ain't online, ain't ready, buzz off... */
467 li r3,kMPPBadState /* Set bad state */
468 oris r5,r5,(MPPICBusy>>16)&0x0000FFFF /* Turn on the busy bit */
469
470 stwcx. r5,0,r9 /* Try to set busy */
471 bne- SPretry
472
473 ori r6,r10,MPPICfStrt<<8 /* Put the Start function in front of the processor ID */
474 rlwimi r5,r6,0,16,31 /* Put these behind the status flags */
475 stw r4,MPPICParm0(r9) /* Set the starting physical address parameter */
476 stw r7,MPPICParm2(r9) /* Set pass-thru parameter */
477
478 sync /* Make sure it's all out there */
479 b KickAndGo /* We're done now... */
480
481 /******************************************************************************************************** */
482 /* */
483 /* Reset the selected processor (R3=processor). You can't reset yourself or the primary. */
484 /* We're gonna try, try real hard... This is not for the faint-of-heart. */
485 /* If there's ever any way to yank a reset line, we'll do it here. */
486 /* */
487 /******************************************************************************************************** */
488
489 ResetProcessor:
490 mfspr r10,pir /* Get our processor number */
491 rlwinm r9,r3,5,23,26 /* Get index into CPU array */
492 rlwinm r10,r10,0,28,31 /* Clean up the PIR */
493 cmplw cr0,r3,r10 /* Trying to start ourselves? */
494 cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */
495 li r3,kMPPHairyPalms /* Set trying to do it to ourselves */
496 beqlr- /* Self abuse... */
497 mr. r9,r9 /* Trying to reset the primary?!? Dude, that's insubordination!!!! */
498 lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
499 li r3,kMPPInvalCPU /* Say that that's a major offense */
500 beqlr- /* Bye now... */
501 li r3,kSIGPTargetAddrErr /* CPU number is too big */
502 bgtlr- cr1 /* Sure are... (Get our address also) */
503 ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
504
505 la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */
506 mflr r11 /* Save the return address */
507 add r9,r9,r12 /* Point right at the entry */
508
509 li r4,16 /* Try for 16 times to get the busy lock */
510
511 RSlockS: mftb r6 /* Time stamp start */
512
513 RSlock: lwarx r5,0,r9 /* Pick up the status flags (MPPICStat) and reserve it */
514 rlwinm. r0,r5,0,2,2 /* Are we online */
515 li r3,kMPPOffline /* Set offline */
516 cmplwi cr1,r5,0 /* Check for busy */
517 beq- ErrorReturn /* Ain't online, ain't ready, buzz off... */
518 bge+ cr1,RSnotBusy /* Not busy, make it so... */
519
520 mftb r7 /* Stamp the time */
521 sub r7,r7,r6 /* Get elapsed time */
522 rlwinm. r7,r7,16,16,31 /* Divide ticks by microseconds (this is pretty darn "kinda-in-the-ballpark") */
523 cmplwi cr0,r7,TicksPerMic /* See if we hit 65536µS yet */
524 blt+ RSlock /* Not yet... */
525
526 RSatmtCnt: subi r4,r4,1 /* Count the retries */
527 mr. r4,r4 /* Are we done yet? */
528 bgt+ RSlockS /* Start the lock attempt again... */
529
530 li r3,kMPPCantLock /* Say we can't get the lock */
531 b ErrorReturn /* Bye, dude... */
532
533 RSnotBusy: rlwinm r5,r5,0,0,15 /* Clear out the function and requestor */
534 oris r5,r5,(MPPICBusy>>16)&0x0000FFFF /* Set busy */
535 or r5,r10,r5 /* Add in our processor */
536 ori r5,r5,MPPICfReset<<8 /* Set the reset function */
537 stwcx. r5,0,r9 /* Cram it back */
538 bne- RSatmtCnt /* We lost the reservation... */
539 b KickAndGo /* Try to send it across... */
540
541
542 /******************************************************************************************************** */
543 /* */
544 /* Here we will try to resume execution of a stopped processor (R3=processor). */
545 /* */
546 /******************************************************************************************************** */
547
548 ResumeProcessor:
549 mfspr r10,pir /* Get our processor number */
550 rlwinm r9,r3,5,23,26 /* Get index into CPU array */
551 cmplw cr0,r3,r10 /* Trying to resume ourselves? */
552 cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */
553 li r3,kMPPHairyPalms /* Set trying to do it to ourselves */
554 beqlr- /* Self abuse... */
555 li r3,kSIGPTargetAddrErr /* CPU number is too big */
556 bgtlr- cr1 /* Sure are... (Get our address also) */
557 lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
558 la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */
559 ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
560 mflr r11 /* Save the link register */
561 add r9,r9,r12 /* Point right at the entry */
562
563 RPretry: lwarx r5,0,r9 /* Pick up the status flags (MPPICStat) and reserve it */
564 li r3,kSIGPInterfaceBusyErr /* Fill dead space and get busy return code */
565 rlwinm. r0,r5,0,0,0 /* Are we marked as busy? */
566 lis r6,MPPICOnline>>16 /* Get the online flag */
567 bne- ErrorReturn /* Yeah, go leave, don't bother me now... */
568 and. r0,r5,r6 /* Are we online */
569 li r3,kMPPOffline /* Set offline */
570 lis r6,MPPICReady>>16 /* Get the ready bit */
571 beq- ErrorReturn /* Ain't online, ain't ready, buzz off... */
572 and. r0,r5,r6 /* Are we ready? */
573 li r3,kMPPNotReady /* Set not ready */
574 lis r6,MPPICStop>>16 /* Get the stopped bit */
575 beq- ErrorReturn /* Ain't ready, buzz off... */
576 and. r0,r5,r6 /* Are we stopped? */
577 li r3,kMPPNotStopped /* Set not stopped */
578 oris r5,r5,(MPPICBusy>>16)&0x0000FFFF /* Turn on the busy bit */
579 beq- ErrorReturn /* Nope, not stopped, so how do we resume? */
580
581 stwcx. r5,0,r9 /* Try to set busy */
582 bne- RPretry
583
584 ori r6,r10,MPPICfResm<<8 /* Put the resume function in front of the processor ID */
585 rlwimi r5,r6,0,16,31 /* Put these behind the status flags */
586 b KickAndGo /* We're done now... */
587
588
589
590 /******************************************************************************************************** */
591 /* */
592 /* Here we will try to stop execution of a running processor (R3=processor). */
593 /* */
594 /******************************************************************************************************** */
595
596 StopProcessor:
597 mfspr r10,pir /* Get our processor number */
598 rlwinm r9,r3,5,23,26 /* Get index into CPU array */
599 cmplw cr0,r3,r10 /* Are we doing ourselves? */
600 cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */
601 li r3,kMPPHairyPalms /* Set trying to do it to ourselves */
602 beqlr- /* Self abuse... */
603 li r3,kSIGPTargetAddrErr /* CPU number is too big */
604 bgtlr- cr1 /* Sure are... (Get our address also) */
605 lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
606 la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */
607 ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
608 mflr r11 /* Save the link register */
609 add r9,r9,r12 /* Point right at the entry */
610
611 PPretry: lwarx r5,0,r9 /* Pick up the status flags (MPPICStat) and reserve it */
612 li r3,kSIGPInterfaceBusyErr /* Fill dead space and get busy return code */
613 rlwinm. r0,r5,0,0,0 /* Are we marked as busy? */
614 lis r6,MPPICOnline>>16 /* Get the online flag */
615 bne- ErrorReturn /* Yeah, go leave, don't bother me now... */
616 and. r0,r5,r6 /* Are we online */
617 li r3,kMPPOffline /* Set offline */
618 lis r6,MPPICReady>>16 /* Get the ready bit */
619 beq- ErrorReturn /* Ain't online, ain't ready, buzz off... */
620 and. r0,r5,r6 /* Are we ready? */
621 li r3,kMPPNotReady /* Set not ready */
622 lis r6,MPPICStop>>16 /* Get the stopped bit */
623 beq- ErrorReturn /* Ain't ready, buzz off... */
624 and. r0,r5,r6 /* Are we stopped? */
625 li r3,kMPPNotRunning /* Set not running */
626 oris r5,r5,(MPPICBusy>>16)&0x0000FFFF /* Turn on the busy bit */
627 bne- ErrorReturn /* Nope, already stopped, so how do we stop? */
628
629 stwcx. r5,0,r9 /* Try to set busy */
630 ori r10,r10,MPPICfStop<<8 /* Put the stop function in front of the processor ID */
631 bne- PPretry
632
633 rlwimi r5,r10,0,16,31 /* Put these behind the status flags */
634 b KickAndGo /* We're done now... */
635
636
637 /******************************************************************************************************** */
638 /* */
639 /* Here we will try to signal a running processor (R3=processor). */
640 /* Note that this should have good performace. Well, actually, seeing as how slow we really are, it */
641 /* probably is moot anyhow. */
642 /* Another note: this function (and all most others as well) will return a timeout when the */
643 /* second processor tries to do itself on the old version of the board. This happens because */
644 /* In order to keep the watchchihuahua from popping (just imagine the scene: that little runt-dog just so */
645 /* excited that its veins and eyes bulge and then explode) signaling to the secondary */
646 /* is done syncronously and disabled. If the secondary signals the secondary, it will never enable so */
647 /* it will never see the 'rupt, so it will never clear it, so it will time out, so there... */
648 /* */
649 /******************************************************************************************************** */
650
651 SignalProcessor:
652 mfspr r10,pir /* Get our processor number */
653 rlwinm r9,r3,5,23,26 /* Get index into CPU array */
654 lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
655 cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */
656 li r3,kSIGPTargetAddrErr /* CPU number is too big */
657 bgtlr- cr1 /* Sure are... (Get our address also) */
658 la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */
659 ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
660 mflr r11 /* Save the link register */
661 add r9,r9,r12 /* Point right at the entry */
662
663 SiPretry: lwarx r5,0,r9 /* Pick up the status flags (MPPICStat) and reserve it */
664 li r3,kSIGPInterfaceBusyErr /* Fill dead space and get busy return code */
665 rlwinm. r0,r5,0,0,0 /* Are we marked as busy? */
666 lis r6,MPPICOnline>>16 /* Get the online flag */
667 bne- ErrorReturn /* Yeah, go leave, don't bother me now... */
668 and. r0,r5,r6 /* Are we online */
669 li r3,kMPPOffline /* Set offline */
670 lis r6,MPPICReady>>16 /* Get the ready bit */
671 beq- ErrorReturn /* Ain't online, ain't ready, buzz off... */
672 and. r0,r5,r6 /* Are we ready? */
673 li r3,kMPPNotReady /* Set not ready */
674 oris r5,r5,(MPPICBusy>>16)&0x0000FFFF /* Turn on the busy bit */
675 beq- ErrorReturn /* Ain't ready, buzz off... */
676
677 stwcx. r5,0,r9 /* Try to set busy */
678 ori r10,r10,MPPICfSigp<<8 /* Put the SIGP function in front of the processor ID */
679 bne- SiPretry
680
681 stw r4,MPPICParm0(r9) /* Pass along the SIGP parameter */
682
683 rlwimi r5,r10,0,16,31 /* Put these behind the status flags */
684 b KickAndGo /* We're done now... */
685
686
687 /******************************************************************************************************** */
688 /* */
689 /* Here we will store the state of a processor (R3=processor; R4=status area). */
690 /* Self abuse will store the state as is, is not asynchronous, and grows hair on your palms. */
691 /* */
692 /******************************************************************************************************** */
693
694 StoreProcessorStatus:
695 mfspr r10,pir /* Get our processor number */
696 rlwinm r9,r3,5,23,26 /* Get index into CPU array */
697 cmplw cr0,r3,r10 /* Saving our own state??? Abusing oneself??? */
698 cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */
699 li r3,kSIGPTargetAddrErr /* CPU number is too big */
700 mflr r11 /* Save the link register */
701 beq Flagellant /* Oh baby, oh baby... */
702 bgtlr- cr1 /* Sure are... (Get our address also) */
703 lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
704 la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */
705 ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
706 add r9,r9,r12 /* Point right at the entry */
707
708 SSretry: lwarx r5,0,r9 /* Pick up the status flags (MPPICStat) and reserve it */
709 li r3,kSIGPInterfaceBusyErr /* Fill dead space and get busy return code */
710 rlwinm. r0,r5,0,0,0 /* Are we marked as busy? */
711 lis r6,MPPICOnline>>16 /* Get the online flag */
712 bne- ErrorReturn /* Yeah, go leave, don't bother me now... */
713 and. r0,r5,r6 /* Are we online */
714 li r3,kMPPOffline /* Set offline */
715 beq- ErrorReturn /* Ain't online, buzz off... */
716 oris r5,r5,(MPPICBusy>>16)&0x0000FFFF /* Turn on the busy bit */
717
718 stwcx. r5,0,r9 /* Try to set busy */
719 ori r10,r10,MPPICfStat<<8 /* Put the store status function in front of the processor ID */
720 bne- SSretry /* Lost reservation, return busy... */
721
722 li r0,0 /* Get false */
723 stb r0,CSAregsAreValid(r4) /* Set that the registers ain't valid */
724 stw r4,MPPICParm0(r9) /* Set the status area physical address parameter */
725
726 rlwimi r5,r10,0,16,31 /* Put these behind the status flags */
727 b KickAndGo /* We're done now... */
728
729 /* Spill one's seed upon the soil */
730
731 Flagellant: bl StoreStatus /* Go store off all the registers 'n' stuff */
732 mtlr r11 /* Restore the return address */
733 li r3,kSIGPnoErr /* Return no error */
734 blr /* Leave... */
735
736
737 /******************************************************************************************************** */
738 /* */
739 /* Here we will attempt to syncronize clocks (R3=processor). */
740 /* Self abuse will just return with an all-ok code. */
741 /* */
742 /******************************************************************************************************** */
743
744 SynchClock:
745 mfspr r10,pir /* Get our processor number */
746 rlwinm r9,r3,5,23,26 /* Get index into CPU array */
747 cmplw cr0,r3,r10 /* Cleaning our own clock?? */
748 cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */
749 lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
750 li r3,kSIGPnoErr /* Assume self-cleaning clock */
751 beqlr /* Oh baby, oh baby... */
752 li r3,kSIGPTargetAddrErr /* CPU number is too big */
753 bgtlr- cr1 /* Sure are... (Get our address also) */
754 ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
755 la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */
756 mflr r11 /* Save the link register */
757 add r9,r9,r12 /* Point right at the entry */
758
759 SyCretry: lwarx r5,0,r9 /* Pick up the status flags (MPPICStat) and reserve it */
760 li r3,kSIGPInterfaceBusyErr /* Fill dead space and get busy return code */
761 rlwinm. r0,r5,0,0,0 /* Are we marked as busy? */
762 lis r6,MPPICOnline>>16 /* Get the online flag */
763 bne- ErrorReturn /* Yeah, go leave, don't bother me now... */
764 and. r0,r5,r6 /* Are we online */
765 li r3,kMPPOffline /* Set offline */
766 beq- ErrorReturn /* Ain't online, ain't ready, buzz off... */
767 oris r5,r5,(MPPICBusy>>16)&0x0000FFFF /* Turn on the busy bit */
768 li r0,0 /* Clear this */
769
770 stwcx. r5,0,r9 /* Try to set busy */
771 ori r10,r10,MPPICfTBsy<<8 /* Put the timebase sync function in front of the processor ID */
772 bne- SyCretry /* Lost reservation, return busy... */
773
774 stw r0,MPPITBsync+4-MPPIwork(r12) /* Make sure the parm area is 0 */
775 mr r0,r11 /* Save the LR */
776 bl SyCbase /* Get a base register */
777 SyCbase: rlwimi r5,r10,0,16,31 /* Put these behind the status flags */
778 mflr r11 /* Get the base */
779 la r11,(4*4)(r11) /* DON'T MESS WITH THESE INSTRUCTIONS Make up the return point */
780 b KickAndGo /* Go signal the other side */
781
782 SyCKrtrn: mr r11,r0 /* Restore the return */
783
784 /* */
785 /* Start sync'ing 'er up */
786 /* */
787
788 mftb r4 /* Take a timeout stamp (don't need top half, we have at least 13 hours) */
789
790 SyCInP0: lwz r5,0(r9) /* Get the CPU status word */
791 rlwinm r5,r5,24,24,31 /* Isolate the command byte */
792 cmplwi cr0,r5,MPPICfTBsy1 /* Have we reached time base sync phase 1 yet? */
793 beq SyCInP1 /* Yeah, we're in phase 1... */
794 mftb r5 /* Get the bottom half of the timer again */
795 sub r5,r5,r4 /* How long we been messin' around? */
796 cmplwi cr0,r5,1000*TicksPerMic /* Don't try more'n' a 1000µS */
797 blt+ SyCInP0 /* We haven't, so wait some more... */
798 li r3,kMPPTimeOut /* Signal timeout */
799 b ErrorReturn /* By dude... */
800
801 /* */
802 /* Here we make sure there is enough time to sync the clocks before the lower part of the TB ticks */
803 /* up into the high part. This eliminates the need for any funky */
804 /* "get-the-top-then-get-the-bottom-then-get-the-top-again-to-see-if-it-changed" stuff. That would */
805 /* only make the sync harder to do. */
806 /* */
807 /* Also, because we use the lower TB value for the signal, we also need to make sure we do not have */
808 /* a value of 0, we would be ever-so-sorry if it was. */
809 /* */
810
811 SyCInP1: li r4,lo16(0xC000) /* Get the minimum time left on clock before tick ('bout 1 1/4 ms) */
812 li r8,0 /* Get a 0 constant */
813
814 SyCdelay: mftb r5 /* Get the time left */
815 cmplw cr0,r5,r4 /* See if there is sufficient time before carry into high clock */
816 bgt- SyCdelay /* Nope, hang until it is... */
817 mr. r5,r5 /* Did we just tick, however? */
818 beq- SyCdelay /* Yeah, wait until it is at least 1... */
819
820 mftbu r4 /* Get the upper */
821 stw r4,MPPITBsync-MPPIwork(r12) /* Make sure the top half is set */
822 sync /* Wait until it is done */
823
824 mftb r5 /* Get the lower timebase now */
825 stw r5,MPPITBsync+4-MPPIwork(r12) /* Shove it out for the other processor */
826
827 la r6,MPPISncFght-MPPIwork(r12) /* Point to the courtroom area */
828 li r5,0 /* Point to the first line */
829
830 SyCclear: dcbz r5,r6 /* Clear the court */
831 addi r5,r5,32 /* Point to the next line */
832 cmplwi cr0,r5,10*2*32 /* Enough for 9 iterations, 2 chunks at a time */
833 blt+ SyCclear /* Clear the whole smear... */
834 sync /* Make sure everyone's out */
835
836 mftb r5 /* Get the lower timebase now */
837
838 SyCWait: lwz r7,MPPITBsync+4-MPPIwork(r12) /* Get it back */
839 mftb r6 /* Get the bottom half again */
840 mr. r7,r7 /* Have they set their clock yet? */
841 sub r0,r6,r5 /* See if we're hung up */
842 beq- SyCdonesync /* Clock is set */
843 cmplwi cr0,r0,1000*TicksPerMic /* Timeout if we spend more than 1000µS doing this */
844 blt+ SyCWait /* No timeout, wait some more... */
845 li r3,kMPPTimeOut /* Set timeout */
846 b ErrorReturn /* Leave... */
847
848 /* */
849 /* Ok, so now we have set a preliminary TB value on the second processor. It's close, but only */
850 /* within handgranade range. */
851 /* */
852 /* What we will do now is to let the processors (starting with the other guy) argue about the time for */
853 /* a while (10 passes-we use the middle 8). We'll look at the results and try to adjust the other processor's */
854 /* time such that the timing windows are overlapping evenly. This should put the TBs close enough together */
855 /* (0-2 ticks) that the difference is undetectable. */
856 /* */
857
858
859
860 SyCdonesync:
861 li r4,0 /* Clear this */
862 la r5,MPPISncFght-MPPIwork(r12) /* Point to the squared circle */
863
864 SyCWtArg:
865 dcbf 0,r5 /* Make sure of it */
866 sync /* Doubly shure */
867 lwz r6,0(r5) /* Listen for the defence argument */
868
869 mr. r6,r6 /* See if they are done */
870 beq+ SyCWtArg /* Nope, still going... */
871
872 mftb r7 /* They're done, time for rebuttal */
873 stw r7,32(r5) /* Make rebuttle */
874
875 addi r4,r4,1 /* Count rounds */
876
877 cmplwi cr0,r4,10 /* See if we've gone 8 rounds plus an extra one */
878 addi r5,r5,64 /* Point to the next round areas */
879
880 blt+ SyCWtArg /* Not yet, come out of your corners fighting... */
881
882 mftb r5 /* Stamp the wait */
883
884 SyCWadj: lwz r7,MPPITBsync+4-MPPIwork(r12) /* Get adjustment flag */
885 mftb r6 /* Get timebase again */
886
887 mr. r7,r7 /* Have they set their timebase with adjusted time yet? */
888 sub r6,r6,r5 /* Get elapsed time */
889 bne+ SyCdone /* They say it, sync done... */
890 cmplwi cr0,r6,1000*TicksPerMic /* Timeout if we spend more than 1000µS doing this */
891 blt+ SyCWadj /* Still time, wait until adjustment is done... */
892
893 li r3,kMPPTimeOut /* Set timeout */
894 b ErrorReturn /* Pass it back... */
895
896 SyCdone: li r3,kSIGPnoErr /* No errors */
897 mtlr r11 /* Restore LR */
898 blr /* Leave... */
899
900
901 /******************************************************************************************************** */
902 /* */
903 /* Here we will get the physical address of the interrupt handler. */
904 /* */
905 /******************************************************************************************************** */
906
907 GetExtHandlerAddress:
908 mflr r11 /* Save our return */
909 bl GEXbase /* Make a base address */
910 GEXbase: mflr r3 /* Get address into our base */
911 addi r3,r3,LOW_ADDR(GotSignal-GEXbase) /* Get the logical address of the 'rupt handler */
912
913 mtlr r11 /* Restore LR */
914 blr
915
916
917 /******************************************************************************************************** */
918 /* */
919 /* Here we will get a snapshot of the processor's current signaling state (R3=processor). */
920 /* */
921 /******************************************************************************************************** */
922
923 ProcessorState:
924 lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
925 rlwinm r9,r3,5,23,26 /* Get index into CPU array */
926 cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */
927 li r3,kSIGPTargetAddrErr /* CPU number is too big */
928 bgtlr- cr1 /* Sure are... (Get our address also) */
929 la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */
930 ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
931 add r9,r9,r12 /* Point right at the entry */
932 lwz r4,MPPICStat(r9) /* Get the status word */
933 li r3,kSIGPnoErr /* Set no errors */
934 rlwinm. r4,r4,0,0,0 /* Test for busy status */
935 beqlr /* Return kSIGPnoErr if not busy */
936 li r3,kSIGPInterfaceBusyErr /* Otherwise, return busy */
937 blr /* Return it */
938
939 /******************************************************************************************************** */
940 /* */
941 /* Here we will try to handle any pending messages (just as if an interruption occurred). */
942 /* The purpose of this function is to assure the message passing system runs even */
943 /* though external interrupts are disabled. Lacking a separate physical signalling */
944 /* class, we have to share the external interrupt signal. Unfortunately, there are */
945 /* times when disabled loops occur (in spin locks, in the debugger, etc.), and when they */
946 /* happen, a low level message sent to a processor will not get processed, hence this */
947 /* function exists to be called from those disabled loops. Since the calls are often */
948 /* from disabled code, all that can be done is to process any pending *message*. Any */
949 /* pending notification interruption (referred to throughtout this code as a SIGP */
950 /* interruption) must remain pending. */
951 /* */
952 /******************************************************************************************************** */
953
954 RunSIGPRun:
955 lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
956 mfspr r3,pir /* Get our CPU address */
957 rlwinm r9,r3,5,23,26 /* Get index into CPU array */
958 ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
959 la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */
960 mflr r11 /* Save the link register */
961 add r9,r9,r12 /* Point right at our entry */
962 lwz r3,MPPICPriv(r9) /* Get our privates */
963 cmplw cr1,r11,r11 /* Make sure IdleWait doesn't try to clear 'rupt request */
964 oris r3,r3,MPPICXRun>>16 /* Diddle with them and show we entered here */
965 stw r3,MPPICPriv(r9) /* Put away our privates */
966 b IdleWait /* Go pretend there was an interrupt... */
967
968 /******************************************************************************************************** */
969 /* */
970 /* Error return. We only need this when we leave with a reservation. We really SHOULD clear it... */
971 /* */
972 /******************************************************************************************************** */
973
974 ErrorReturn:
975 mtlr r11 /* Restore LR */
976 blr
977
978 /******************************************************************************************************** */
979 /* */
980 /* Kick the target processor. Note that we won't set the passing bit until we are ready to exit. */
981 /* The reason for this is that we have the silly, old watchchihuahua board to deal with. Because */
982 /* we can't just set the interrupt and leave, we gotta wait for it to be seen on the other side. */
983 /* This means that there could be a timeout and if so, we need to back off the function request else */
984 /* we'd see busy when they tried to redrive it. We'll have to deal with a tad of spin on the secondary side. */
985 /* note that this just applies to a primary to secondary function on the old board. */
986 /* */
987 /******************************************************************************************************** */
988
989 KickAndGo:
990 la r8,MPPICPU0-MPPIwork(r12) /* Get the primary work area address */
991 mtlr r11 /* Restore the link register */
992 cmplw cr0,r8,r9 /* Which is target? primary or secondary? */
993 mfmsr r11 /* Save off the MSR */
994 oris r5,r5,MPPICPass>>16 /* Set the passing bit on */
995 stw r5,MPPICStat(r9) /* Store the pass and let the other processor go on */
996
997 beq KickPrimary /* The target is the primary... */
998
999 ori r3,r11,0x0010 /* Turn on DDAT bit */
1000 lbz r4,MPPIstatus-MPPIwork(r12) /* Load up the global status byte */
1001 lwz r8,MPPIHammer-MPPIwork(r12) /* Point to the Hammerhead area */
1002
1003 mtmsr r3 /* Turn on DDAT */
1004 isync
1005
1006 andi. r4,r4,MPPI2Pv2 /* Are we on the new or old board? */
1007 li r3,0 /* Set the bit for an interrupt request */
1008 beq KickOld /* Ok, it's the old board... */
1009
1010 sync /* Make sure this is out there */
1011 stb r3,IntReg(r8) /* Set the interruption signal */
1012 eieio
1013
1014 mtmsr r11 /* Set DDAT back to what it was */
1015 isync
1016 li r3,kSIGPnoErr /* Set no errors */
1017 blr /* Leave... */
1018
1019 KickOld: li r4,8 /* Set the number of tries */
1020
1021 KickAgain: mftb r6 /* Stamp the bottom half of time base */
1022 stb r3,IntReg(r8) /* Stick the interrupt */
1023 eieio /* Fence me in */
1024
1025 CheckKick: lbz r10,IntReg(r8) /* Get the interrupt request back again */
1026 mr. r10,r10 /* Yes? Got it? */
1027 bne FinalDelay /* Yeah, do the final delay and then go away... */
1028
1029 mftb r7 /* Get the time again */
1030 sub r7,r7,r6 /* Get time-so-far */
1031 cmplwi cr0,r7,75*TicksPerMic /* Hold it for 75µS (average disable is supposed to be 100µS or so) */
1032 blt+ CheckKick /* Keep waiting the whole time... */
1033
1034 li r10,SecInt /* Set the deassert bit */
1035 mftb r6 /* Stamp start of deassert time */
1036 stb r10,IntReg(r8) /* Deassert the interrupt request */
1037 eieio
1038
1039 DeassertWT: mftb r7 /* Stamp out the time */
1040 sub r7,r7,r6 /* Get elapsed */
1041 cmplwi cr0,r7,16*TicksPerMic /* Hold off 16µS (minimum is 12µS) */
1042 blt+ DeassertWT /* Keep spinning... */
1043
1044 subi r4,r4,1 /* See if we have another retry we can do */
1045 mr. r4,r4 /* Are we there yet? */
1046 blt+ KickAgain /* Retry one more time... */
1047
1048 rlwinm r5,r5,0,2,31 /* Clear busy and passing bits */
1049 rlwinm r5,r5,0,24,15 /* Clear the function request to idle */
1050
1051 mtmsr r11 /* Restore DDAT stuff */
1052 isync
1053
1054 stw r5,MPPICStat(r9) /* Rescind the request */
1055 li r3,kMPPTimeOut /* Set timeout */
1056 blr /* Leave... */
1057
1058 FinalDelay: mftb r6 /* Stamp the start of the final delay */
1059
1060 FinalDelayW:
1061 mftb r7 /* Stamp out the time */
1062 sub r7,r7,r6 /* Get elapsed */
1063 cmplwi cr0,r7,16*TicksPerMic /* Hold off 16µS (minimum is 12µS) */
1064 blt+ FinalDelayW /* Keep spinning... */
1065
1066 mtmsr r11 /* Restore DDAT stuff */
1067 isync
1068 li r3,kSIGPnoErr /* Set no errors */
1069 blr /* Leave... */
1070
1071 KickPrimary:
1072 ori r3,r11,0x0010 /* Turn on the DDAT bit */
1073 lwz r8,MPPIEther-MPPIwork(r12) /* Get the address of the ethernet ROM */
1074
1075 mtmsr r3 /* Turn on DDAT */
1076 isync
1077
1078 li r4,4 /* Get flip count */
1079
1080 sync /* Make sure the status word is out there */
1081
1082 FlipOff: lbz r3,0(r8) /* Reference ethernet ROM to get chip select twiddled */
1083 eieio /* Make sure of this (Hmm, this is chip select, not memory-mapped */
1084 /* storage. Do we even need the eieio?) */
1085
1086 addic. r4,r4,-1 /* Have we flipped them off enough? */
1087 bgt+ FlipOff /* Not yet, they deserve more... */
1088
1089 mtmsr r11 /* Restore DDAT stuff */
1090 isync
1091 li r3,kSIGPnoErr /* Set no errors */
1092 blr /* Return... */
1093
1094 /******************************************************************************************************** */
1095 /* */
1096 /* This is the code for the secondary processor */
1097 /* */
1098 /******************************************************************************************************** */
1099
1100 /* Note that none of this code needs locks because there's kind of a synchronization */
1101 /* shuffle going on. */
1102
1103 /* */
1104 /* First, we need to do a bit of initialization of the processor. */
1105 /* */
1106
1107
1108 CPUInit:
1109 li r27,0x3040 /* Set floating point and machine checks on, IP to 0xFFF0xxxx */
1110 mtmsr r27 /* Load 'em on in */
1111 isync
1112
1113 lis r28,-32768 /* Turn on machine checks */
1114 /* should be 0x8000 */
1115 ori r28,r28,0xCC84 /* Enable caches, clear them, */
1116 /* disable serial execution and turn BHT on */
1117 sync
1118 mtspr HID0,r28 /* Start the cache clear */
1119 sync
1120
1121 /* */
1122 /* Clear out the TLB. They be garbage after hard reset. */
1123 /* */
1124
1125 li r0,512 /* Get number of TLB entries (FIX THIS) */
1126 li r3,0 /* Start at 0 */
1127 mtctr r0 /* Set the CTR */
1128
1129 purgeTLB: tlbie r3 /* Purge this entry */
1130 addi r3,r3,4096 /* Next page */
1131 bdnz purgeTLB /* Do 'em all... */
1132
1133 sync /* Make sure all TLB purges are done */
1134 tlbsync /* Make sure on other processors also */
1135 sync /* Make sure the TLBSYNC is done */
1136
1137 /* */
1138 /* Clear out the BATs. They are garbage after hard reset. */
1139 /* */
1140
1141 li r3,0 /* Clear a register */
1142
1143 mtspr DBAT0L,r3 /* Clear BAT */
1144 mtspr DBAT0U,r3 /* Clear BAT */
1145 mtspr DBAT1L,r3 /* Clear BAT */
1146 mtspr DBAT1U,r3 /* Clear BAT */
1147 mtspr DBAT2L,r3 /* Clear BAT */
1148 mtspr DBAT2U,r3 /* Clear BAT */
1149 mtspr DBAT3L,r3 /* Clear BAT */
1150 mtspr DBAT3U,r3 /* Clear BAT */
1151
1152 mtspr IBAT0L,r3 /* Clear BAT */
1153 mtspr IBAT0U,r3 /* Clear BAT */
1154 mtspr IBAT1L,r3 /* Clear BAT */
1155 mtspr IBAT1U,r3 /* Clear BAT */
1156 mtspr IBAT2L,r3 /* Clear BAT */
1157 mtspr IBAT2U,r3 /* Clear BAT */
1158 mtspr IBAT3L,r3 /* Clear BAT */
1159 mtspr IBAT3U,r3 /* Clear BAT */
1160
1161 /* */
1162 /* Map 0xF0000000 to 0xFFFFFFFF for I/O; make it R/W non-cacheable */
1163 /* Map 0x00000000 to 0x0FFFFFFF for mainstore; make it R/W cachable */
1164 /* */
1165
1166 lis r6,0xF000 /* Set RPN to last segment */
1167 ori r6,r6,0x1FFF /* Set up upper BAT for 256M, access both */
1168
1169 lis r7,0xF000 /* Set RPN to last segment */
1170 ori r7,r7,0x0032 /* Set up lower BAT for 256M, access both, non-cachable */
1171
1172 mtspr DBAT0L,r7 /* Setup ROM and I/O mapped areas */
1173 mtspr DBAT0U,r6 /* Now do the upper DBAT */
1174 sync
1175
1176 li r6,0x1FFF /* Set up upper BAT for 256M, access both */
1177 li r7,0x0012 /* Set up lower BAT for r/w access */
1178
1179 mtspr DBAT1L,r7 /* Set up an initial view of mainstore */
1180 mtspr DBAT1U,r6 /* Now do the upper DBAT */
1181 sync
1182
1183 /* */
1184 /* Clean up SDR and segment registers */
1185 /* */
1186
1187 li r3,0 /* Clear a register */
1188 mtspr SDR1,r3 /* Clear SDR1 */
1189
1190 li r4,0 /* Clear index for segment registers */
1191 lis r5,0x1000 /* Set the segment indexer */
1192
1193 clearSR: mtsrin r3,r4 /* Zero out the SR */
1194 add. r4,r4,r5 /* Point to the next segment */
1195 bne- clearSR /* Keep going until we wrap back to 0 */
1196
1197 lis r5,HIGH_ADDR(EXT(FloatInit)) /* Get top of floating point init value */
1198 ori r5,r5,LOW_ADDR(EXT(FloatInit)) /* Slam bottom */
1199 lfd f0,0(r5) /* Initialize FP0 */
1200 fmr f1,f0 /* Ours in not */
1201 fmr f2,f0 /* to wonder why, */
1202 fmr f3,f0 /* ours is but to */
1203 fmr f4,f0 /* do or die! */
1204 fmr f5,f0
1205 fmr f6,f0
1206 fmr f7,f0
1207 fmr f8,f0
1208 fmr f9,f0
1209 fmr f10,f0
1210 fmr f11,f0
1211 fmr f12,f0
1212 fmr f13,f0
1213 fmr f14,f0
1214 fmr f15,f0
1215 fmr f16,f0
1216 fmr f17,f0
1217 fmr f18,f0
1218 fmr f19,f0
1219 fmr f20,f0
1220 fmr f21,f0
1221 fmr f22,f0
1222 fmr f23,f0
1223 fmr f24,f0
1224 fmr f25,f0
1225 fmr f26,f0
1226 fmr f27,f0
1227 fmr f28,f0
1228 fmr f29,f0
1229 fmr f30,f0
1230 fmr f31,f0
1231
1232 /* */
1233 /* Whew, that was like, work, man! What a cleaning job, I should be neater */
1234 /* when I reset. */
1235 /* */
1236 /* Finally we can get some data DAT turned on and we can reset the interrupt */
1237 /* (which may have been done before we get here) and get into the bring up */
1238 /* handshakes. */
1239 /* */
1240 /* Note that here we need to use the actual V=R addresses for HammerHead */
1241 /* and PCI1 adr. There are no virtual mappings set up on this processor. */
1242 /* We need to switch once the firmware is initialized. Also, we don't know */
1243 /* where our control block is yet. */
1244 /* */
1245
1246 lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
1247 ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
1248
1249 mfmsr r3 /* Get the MSR */
1250 ori r3,r3,0x0010 /* Turn data DAT on */
1251 mtmsr r3 /* DAT is on (well, almost) */
1252 isync /* Now it is for sure */
1253
1254 lis r8,HammerHead>>16 /* Point to the HammerHead controller */
1255 li r7,SecInt /* Get value to reset */
1256 stb r7,IntReg(r8) /* Reset the interrupt */
1257 eieio /* Fence it off */
1258
1259 /* */
1260 /* Now we can plant and harvest some bits. */
1261 /* */
1262
1263 lwz r6,MPPIlogCPU-MPPIwork(r12) /* Get the logical CPU address to assign */
1264 mfspr r7,pir /* Get the old PIR */
1265 rlwimi r7,r6,0,27,31 /* Copy all of the reserved parts */
1266 mtspr pir,r7 /* Set it */
1267
1268 /* */
1269 /* This little piece of code here determines if we are on the first or second version */
1270 /* of the two processor board. The old one shouldn't ever be shipped (well, maybe by */
1271 /* DayStar) but there are some around here. */
1272 /* */
1273 /* The newer version of the 2P board has a different state machine than the older one. */
1274 /* When we are in the board state we're in now, primary arbitration is turned on while */
1275 /* it is not until the next state in the old board. By checking the our bus address */
1276 /* (WhoAmI) we can tell. */
1277 /* */
1278
1279 lbz r7,WhoAmI(r8) /* Get the current bus master ID */
1280 andi. r7,r7,PriCPU /* Do we think we're the primary? */
1281 beq On2Pv1 /* No, that means we're on the old 2P board */
1282
1283 lbz r7,MPPIstatus-MPPIwork(r12) /* Get the status byte */
1284 ori r7,r7,MPPI2Pv2 /* Show we're on the new board */
1285 stb r7,MPPIstatus-MPPIwork(r12) /* Set the board version */
1286
1287 On2Pv1: rlwinm r9,r6,5,23,26 /* Get index into the CPU specific area */
1288
1289 la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Index to processor */
1290 add r9,r9,r12 /* Get a base for our CPU specific area */
1291
1292 oris r6,r6,((MPPICBusy+MPPICOnline+MPPICStop)>>16)&0x0000FFFF /* Set CPU busy, online, stopped, */
1293 /* and busy set by himself */
1294 stw r6,MPPICStat(r9) /* Save the whole status word */
1295
1296 li r4,0x80 /* Get beginnings of a CPU address mask */
1297 lhz r11,MPPIinst-MPPIwork(r12) /* Get the installed and online status flags */
1298 srw r4,r4,r6 /* Make a mask */
1299 rlwimi r4,r4,8,16,23 /* Double up the mask for both flags */
1300 or r11,r11,r4 /* Set that we are installed and online */
1301 sync /* Make sure the main processor sees the rest of the stuff */
1302
1303 sth r11,MPPIinst-MPPIwork(r12) /* We're almost done, just need to set the TB */
1304
1305 lis r5,PCI1AdrReg>>16 /* Point to the PCI1 address register */
1306 li r4,0 /* Clear this out */
1307 stw r4,0(r5) /* Set PCI register to 0 to show we're ready for TB sync */
1308 eieio /* Fence it off */
1309
1310 Wait4TB: lwz r7,0(r5) /* Get the PCI1 reg to see if time to set time */
1311 mr. r7,r7 /* Is it ready yet? */
1312 beq Wait4TB /* Nope, wait for it... */
1313 isync /* No peeking... */
1314
1315 lwz r3,MPPITBsync-MPPIwork(r12) /* Get the high word of TB */
1316 lwz r4,MPPITBsync+4-MPPIwork(r12) /* Get the low word */
1317
1318 /* Note that we need no TB magic here 'cause they ain't running */
1319
1320 mttbu r3 /* Set the high part */
1321 mttbl r4 /* Set the low part */
1322
1323 rlwinm r6,r6,0,2,31 /* Clear the busy bit and passed */
1324 stw r6,MPPICStat(r9) /* Store the status word */
1325
1326 sync /* Make sure all is right with the world */
1327
1328 li r3,0 /* Set the init done signal */
1329 stw r3,0(r5) /* Feed the dog and let him out */
1330 sync /* Make sure this is pushed on out */
1331
1332 li r27,0x3040 /* Make MSR the way we likes it */
1333 mtmsr r27 /* Load 'em on in */
1334 isync
1335
1336 /* */
1337 /* Jump on to the idle wait loop. We're online and ready, but we're */
1338 /* still in the reset state. We need to wait until we see a start signal. */
1339 /* */
1340 /* Note that the idle loop expects R9 to be our CPU-specific work area; */
1341 /* R12 is the base of the code and global work area */
1342 /* */
1343
1344 cmplw cr1,r11,r12 /* Make sure IdleWait knows to clear 'rupt request */
1345 b IdleWait
1346
1347
1348 /******************************************************************************************************** */
1349 /******************************************************************************************************** */
1350 /* */
1351 /* Here is the interruption handler. */
1352 /* */
1353 /* What we'll do here is to get our registers into a standard state and figure out which */
1354 /* which processor we are on. The processors have pretty much the same code. The primary */
1355 /* will reset the the secondary to primary interruption bit and the secondary will reset the SecInt */
1356 /* flags. */
1357 /* */
1358 /* The primary to secondary interrupt is an exception interruption contolled by a bit in the */
1359 /* Hammerhead IntReg. The only bit in here is SecInt which is active low. Writing a 0 into the */
1360 /* bit (bit 0) yanks on the external pin on the secondary. Note that it is the only external */
1361 /* connected on the secondary. SecInt must be set to 1 to clear the interruption. On the old */
1362 /* 2P board, asserting the external interrupt causes a watchdog timer to start which expires unless */
1363 /* the interrupt request is withdrawn. On a 180Mhz system the time to expire is about 256µS, */
1364 /* not very long. So, what we need to do is to time the assertion and if it has not been reset */
1365 /* reset, do it ourself. Unfortunatelty we need to keep it deasserted for at least 12µS or the */
1366 /* watchdog will not stop. This leads to another problem: even if the secondary processor sees */
1367 /* the interrupt and deasserts the request itself, we cannot reassert before the 12µS limit, */
1368 /* else havoc will be wrought. We just gotta make sure. */
1369 /* */
1370 /* So, the secondary to primary interrupt is megafunky. The mother board is wired with the */
1371 /* MACE ethernet chip's chip-select pin wired to Grand Centeral's external interrrupt #10 pin. */
1372 /* This causes a transient interrupt whenever MACE is diddled. GC latches the interrupt into the */
1373 /* events register where we can see it and clear it. */
1374 /* */
1375 /******************************************************************************************************** */
1376 /******************************************************************************************************** */
1377
1378 GotSignal: mfspr r9,pir /* Get our processor ID */
1379 lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
1380 rlwinm r9,r9,5,23,26 /* Clean this up */
1381 ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
1382 la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */
1383 mflr r11 /* Save our return */
1384 add r9,r9,r12 /* Point right at the entry */
1385
1386 /* We'll come in here if we're stopped and found the 'rupt via polling */
1387 /* or we were kicked off by the PollSIGP call. We need */
1388 /* to wipe out the interrupt request no matter how we got here. */
1389
1390 SimRupt: mfmsr r4 /* Get the MSR */
1391
1392 la r8,MPPICPU0-MPPIwork(r12) /* Get address of main processor's work area */
1393 ori r5,r4,0x0010 /* Turn on the DDAT bit */
1394 cmplw cr0,r8,r9 /* Are we on the main? */
1395 cmplw cr1,r4,r4 /* Set CR1 to indicate we've cleared any 'rupts */
1396 bne SecondarySig /* Go if we are not on main processor... */
1397
1398 /* */
1399 /* Handle the secondary to primary signal */
1400 /* */
1401
1402 PrimarySig:
1403
1404 lwz r8,MPPIGrandC-MPPIwork(r12) /* Get the address of the Grand Central area base */
1405 mtmsr r5 /* Turn on DDAT */
1406 isync /* Now don't be usin' dem speculative executions */
1407 li r7,EventsReg /* Get address of the interrupt events register */
1408 lwbrx r6,r7,r8 /* Grab the interruption events */
1409
1410 lis r5,0x4000 /* Get the mask for the Ext10 pin */
1411 and. r0,r6,r5 /* See if our bit is on */
1412 li r7,ClearReg /* Point to the interruption clear register */
1413
1414 beq+ SkpClr /* Skip the clear 'cause it's supposed to be soooo slow... */
1415
1416 stwbrx r5,r7,r8 /* Reset the interrupt latch */
1417 eieio /* Fence off the last 'rupt */
1418
1419 SkpClr: mtmsr r4 /* Set MSR to entry state */
1420 isync /* Make sure we ain't gunked up no future storage references */
1421
1422 bne+ IdleWait /* Go join up and decode the function... */
1423
1424 mtlr r11 /* Restore return address */
1425 andc. r0,r6,r5 /* Any other bits on? */
1426 li r3,kMPVainInterrupt /* Assume we got nothing */
1427 beqlr /* We got nothing, tell 'em to eat 'rupt... */
1428 li r3,kMPIOInterruptPending /* Tell them to process an I/O 'rupt */
1429 blr /* Ignore the interrupt... */
1430
1431 /* */
1432 /* Handle the primary to secondary signal */
1433 /* */
1434
1435 SecondarySig:
1436 lwz r3,MPPICStat(r9) /* Pick up our status word */
1437 lis r8,HammerHead>>16 /* Get the address of the hammerhead (used during INIT on non-main processor) */
1438 rlwinm. r3,r3,0,3,3 /* Check if we are already "in-the-know" (all started up) */
1439 beq- UseAltAddr /* Nope, use hardcoded Hammerhead address */
1440 lwz r8,MPPIHammer-MPPIwork(r12) /* Get the kernel's HammerHead area */
1441
1442 UseAltAddr: mtmsr r5 /* Turn on DDAT */
1443 isync /* Now don't be usin' dem speculative executions */
1444 li r0,SecInt /* Get the Secondary interrupt bit */
1445 stb r0,IntReg(r8) /* Reset the interrupt request */
1446 mtmsr r4 /* Set MSR to entry state */
1447 eieio /* Fence me in */
1448 isync /* Make sure we ain't gunked up no future storage references */
1449
1450 b IdleWait /* Go decode this request... */
1451
1452 /******************************************************************************************************** */
1453 /******************************************************************************************************** */
1454 /* */
1455 /* This is the idle wait. */
1456 /* */
1457 /* We're stuck in here so long as we are stopped or reset. */
1458 /* All functions except for "start" pass back through here. Start is weird because */
1459 /* it is an initial thing, i.e., we can't have gotten here via any kind of exception, */
1460 /* so there is no state to restore. The "started" code is expected to require no know */
1461 /* state and will take care of all initialization/fixup required. */
1462 /* */
1463 /******************************************************************************************************** */
1464 /******************************************************************************************************** */
1465
1466 BadRuptState: /* We don't do anything special yet for a bad state, just eat request */
1467 KillBusy: rlwinm r3, r3, 0, 2, 31 /* Remove the message pending flags. */
1468 rlwinm r3, r3, 0, 24, 16 /* Set the function to idle. */
1469 stw r3,MPPICStat(r9) /* Update/unlock the status word. */
1470
1471 ReenterWait: cmplwi cr1,r9,0 /* Turn off the 'rupt cleared flag */
1472
1473 IdleWait: lis r4,MPPICBusy>>16 /* Get busy status */
1474
1475 SpinIdle:
1476 lwz r3,MPPICStat(r9) /* Pick up our status word */
1477
1478 and. r5,r3,r4 /* Isolate the busy bit */
1479 lis r6,MPPICPass>>16 /* Get the passed busy flag */
1480 bne TooBusy /* Work, work, work, that's all we do is work... */
1481
1482 rlwinm. r5,r3,0,4,4 /* See if we are stopped */
1483 lwz r8,MPPICPriv(r9) /* Pick up our private flags */
1484 bne- SpinIdle /* Yeah, keep spinning... */
1485
1486
1487 /* */
1488 /* Restore the state and get outta here. Now, we shouldn't be in a reset state and not be stopped, */
1489 /* so we can go ahead and safely return up a level because it exists. If we are reset, no state exists */
1490 /* and we should always be stopped. */
1491 /* */
1492
1493 rlwinm r4, r8, 1, 0, 0 /* Get the explicit run bit, shifted left one. */
1494 rlwinm. r5, r8, 0, 0, 0 /* See if there is a SIGP signal pending */
1495 and r4, r8, r4 /* Turn off the SIGP pending bit if this was not an explicit run */
1496 /* Also the explicit run bit is cleared */
1497 mtlr r11 /* Restore the return point */
1498 li r3,kMPVainInterrupt /* Tell the interrupt handler to ignore the interrupt */
1499 stw r4,MPPICPriv(r9) /* Set that flag back for later */
1500 beqlr /* Time to leave if we ate the 'rupt... */
1501
1502 li r3,kMPSignalPending /* Set that there is a SIGP interruption pending */
1503
1504 blr /* Go away, let our caller handle this thing... QED!!!!!!!!! */
1505
1506 /* */
1507 /* QQQQQ EEEEEEEEEE DDDDDDDDD */
1508 /* QQQQQQQQQ EEEEEEEEEE DDDDDDDDDDD */
1509 /* QQQQ QQQQ EEEE DDD DDD */
1510 /* QQQQ QQQQ EEEEEEEEEE DDD DDD */
1511 /* QQQQ Q QQQQ EEEEEEEEEE DDD DDD */
1512 /* QQQQ QQQQQ EEEE DDD DDD */
1513 /* QQQQQQQQQQQ EEEEEEEEEE DDDDDDDDDDD */
1514 /* QQQQQ QQQ EEEEEEEEEE DDDDDDDDD */
1515 /* */
1516 /* (I finished here) */
1517 /* */
1518
1519
1520 /* */
1521 /* This is where we decode the function and do what's right. */
1522 /* First we need to check if it's really time to do something. */
1523 /* */
1524
1525 TooBusy: and. r5,r3,r6 /* See if the passed flag is on */
1526 beq SpinIdle /* No, not yet, try the whole smear again... */
1527
1528 beq+ cr1,KeepRupt /* Don't clear 'rupt if we already did (or entered via RunSIGRun) */
1529
1530 lwz r5,MPPICPriv(r9) /* Get the private flags */
1531 rlwinm. r5, r5, 0, 1, 1 /* Did we enter via RunSIGPRun? */
1532 beq SimRupt /* Nope, 's'ok, go clear physical 'rupt... */
1533
1534 KeepRupt:
1535 bl GetOurBase /* Get our address */
1536 GetOurBase: rlwinm r4,r3,26,22,29 /* Get the opcode index * 4 */
1537 mflr r12 /* Get the base address */
1538 la r7,LOW_ADDR(IFuncTable-GetOurBase)(r12) /* Point to the function table */
1539
1540 cmplwi cr0,r4,7*4 /* See if they sent us some bogus junk */
1541 /* Change 7 if we add more functions */
1542 add r7,r7,r4 /* Point right at the entry */
1543 bgt- KillBusy /* Bad request code, reset busy and eat it... */
1544
1545 mtlr r7 /* Set up the LR */
1546
1547 blr /* Go execute the function... */
1548
1549 IFuncTable:
1550 b KillBusy /* This handles the signal in vain... */
1551 b IStart /* This handles the start function */
1552 b IResume /* This handles the resume function */
1553 b IStop /* This handles the stop function */
1554 b ISIGP /* This handles the SIGP function */
1555 b IStatus /* This handles the store status function */
1556 b ITBsync /* This handles the synchronize timer base function */
1557 b IReset /* This handles the reset function */
1558
1559 /******************************************************************************************************** */
1560 /******************************************************************************************************** */
1561 /* */
1562 /* Here are the functions handled at interrupt time */
1563 /* */
1564 /******************************************************************************************************** */
1565 /******************************************************************************************************** */
1566
1567 /******************************************************************************************************** */
1568 /* */
1569 /* The Start function. This guy requires that the processor be in the reset and online state. */
1570 /* */
1571 /******************************************************************************************************** */
1572
1573 IStart: lis r4,MPPICOnline>>16 /* Get bits required to be on */
1574 isync /* Make sure we haven't gone past here */
1575 and r6,r3,r4 /* See if they are on */
1576 cmplw cr1,r6,r4 /* Are they all on? */
1577 lwz r4,MPPICParm0(r9) /* Get the physical address of the code to go to */
1578 bne- cr1,BadRuptState /* Some required state bits are off */
1579 rlwinm r3,r3,0,2,31 /* Kill the busy bits */
1580 rlwinm r3,r3,0,24,15 /* Set the function to idle */
1581 oris r3,r3,MPPICReady>>16 /* Set ready state */
1582 rlwinm r3,r3,0,5,3 /* Clear out the stop bit */
1583 mtlr r4 /* Set the LR */
1584 stw r3,MPPICStat(r9) /* Clear out the status flags */
1585 lwz r3,MPPICParm2(r9) /* Get pass-thru parameter */
1586 blrl /* Start up the code... */
1587 /* */
1588 /* The rules for coming back here via BLR are just opposite the normal way: you can trash R0-R3 and */
1589 /* R13-R31, all the CRs; don't touch SPRG1 or SPRG3, the MSR, the SRs or BATs 0 and 1. */
1590 /* Follow these simple rules and you allowed back; don't follow them and die. */
1591 /* We only come back here if there is some kind of startup failure so's we can try again later */
1592 /* */
1593
1594 lwz r3,MPPICStat(r9) /* Get back the status word */
1595 cmplw cr1,r4,r4 /* Show that we have already taken care of the 'rupt */
1596 rlwinm r3,r3,0,4,2 /* Reset the ready bit */
1597 b KillBusy /* Back into the fold... */
1598
1599 /******************************************************************************************************** */
1600 /* */
1601 /* The Resume function. This guy requires that the processor be online and ready. */
1602 /* */
1603 /******************************************************************************************************** */
1604
1605 IResume: lis r4,(MPPICOnline+MPPICReady)>>16 /* Get states required to be set */
1606 and r6,r3,r4 /* See if they are on */
1607 cmplw cr0,r6,r4 /* Are they all on? */
1608 bne- BadRuptState /* Some required off state bits are on */
1609 rlwinm r3,r3,0,5,3 /* Clear out the stop bit */
1610 b KillBusy /* Get going... */
1611
1612 /******************************************************************************************************** */
1613 /* */
1614 /* The Stop function. All we care about here is that the guy is online. */
1615 /* */
1616 /******************************************************************************************************** */
1617
1618 IStop: lis r4,MPPICOnline>>16 /* All we care about is if we are online or not */
1619 and. r6,r3,r4 /* See if we are online */
1620 beq- BadRuptState /* Some required off state bits are on */
1621 oris r3,r3,MPPICStop>>16 /* Set the stop bit */
1622 b KillBusy /* Get stopped... */
1623
1624
1625 /******************************************************************************************************** */
1626 /* */
1627 /* The SIGP function. All we care about here is that the guy is online. */
1628 /* */
1629 /******************************************************************************************************** */
1630
1631 ISIGP: lis r4,(MPPICOnline+MPPICReady)>>16 /* Get states required to be set */
1632 and r6,r3,r4 /* See if they are on */
1633 lwz r7,MPPICPriv(r9) /* Get the private flags */
1634 cmplw cr0,r6,r4 /* Are they all on? */
1635 oris r6,r7,(MPPICSigp>>16)&0x0000FFFF /* Set the SIGP pending bit */
1636 bne- BadRuptState /* Some required off state bits are on */
1637 lwz r4,MPPICParm0(r9) /* Get the SIGP parameter */
1638 stw r6,MPPICPriv(r9) /* Stick the pending bit back */
1639 stw r4,MPPICParm0BU(r9) /* Back up parm 0 so it is safe once we unlock */
1640 b KillBusy /* Get stopped... */
1641
1642 /******************************************************************************************************** */
1643 /* */
1644 /* The store status function. This guy requires that the processor be in the stopped state. */
1645 /* */
1646 /******************************************************************************************************** */
1647
1648 IStatus: lis r4,MPPICOnline>>16 /* All we care about is if we are online or not */
1649 and. r6,r3,r4 /* See if we are online */
1650 isync /* Make sure we havn't gone past here */
1651 beq- BadRuptState /* Some required off state bits are on */
1652 lwz r4,MPPICParm0(r9) /* Get the status area physical address */
1653 rlwinm. r6,r3,0,3,3 /* Test processor ready */
1654
1655 beq INotReady /* Not ready, don't assume valid exception save area */
1656 bl StoreStatus /* Go store off all the registers 'n' stuff */
1657 b KillBusy /* All done... */
1658
1659 INotReady:
1660 lis r7,0xDEAD /* Get 0xDEAD + 1 */
1661 ori r7,r7,0xF1D0 /* Get 0xDEADF1D0 */
1662 stw r7,CSAgpr+(0*4)(r4) /* Store invalid R0 */
1663 stw r7,CSAgpr+(1*4)(r4) /* Store invalid R1 */
1664 stw r7,CSAgpr+(2*4)(r4) /* Store invalid R2 */
1665 stw r7,CSAgpr+(3*4)(r4) /* Store invalid R3 */
1666 stw r7,CSAgpr+(4*4)(r4) /* Store invalid R4 */
1667 stw r7,CSAgpr+(5*4)(r4) /* Store invalid R5 */
1668 stw r7,CSAgpr+(6*4)(r4) /* Store invalid R6 */
1669 stw r7,CSAgpr+(7*4)(r4) /* Store invalid R7 */
1670 stw r7,CSAgpr+(8*4)(r4) /* Store invalid R8 */
1671 stw r7,CSAgpr+(9*4)(r4) /* Store invalid R9 */
1672 stw r7,CSAgpr+(10*4)(r4) /* Store invalid R10 */
1673 stw r7,CSAgpr+(11*4)(r4) /* Store invalid R11 */
1674 stw r7,CSAgpr+(12*4)(r4) /* Store invalid R12 */
1675 stw r13,CSAgpr+(13*4)(r4) /* Save general registers */
1676 stw r14,CSAgpr+(14*4)(r4) /* Save general registers */
1677 stw r15,CSAgpr+(15*4)(r4) /* Save general registers */
1678 stw r16,CSAgpr+(16*4)(r4) /* Save general registers */
1679 stw r17,CSAgpr+(17*4)(r4) /* Save general registers */
1680 stw r18,CSAgpr+(18*4)(r4) /* Save general registers */
1681 stw r19,CSAgpr+(19*4)(r4) /* Save general registers */
1682 stw r20,CSAgpr+(20*4)(r4) /* Save general registers */
1683 stw r21,CSAgpr+(21*4)(r4) /* Save general registers */
1684 stw r22,CSAgpr+(22*4)(r4) /* Save general registers */
1685 stw r23,CSAgpr+(23*4)(r4) /* Save general registers */
1686 stw r24,CSAgpr+(24*4)(r4) /* Save general registers */
1687 stw r25,CSAgpr+(25*4)(r4) /* Save general registers */
1688 stw r26,CSAgpr+(26*4)(r4) /* Save general registers */
1689 stw r27,CSAgpr+(27*4)(r4) /* Save general registers */
1690 stw r28,CSAgpr+(28*4)(r4) /* Save general registers */
1691 stw r29,CSAgpr+(29*4)(r4) /* Save general registers */
1692 stw r30,CSAgpr+(30*4)(r4) /* Save general registers */
1693 stw r31,CSAgpr+(31*4)(r4) /* Save general registers */
1694 bl StoreLiveStatus
1695 b KillBusy
1696
1697 /* */
1698 /* Save the whole status. Lot's of busy work. */
1699 /* Anything marked unclean is of the devil and should be shunned. Actually, it depends upon */
1700 /* knowledge of firmware control areas and is no good for a plug in. But, we've sacrificed the */
1701 /* white ram and are standing within a circle made of his skin, so we can dance with the devil */
1702 /* safely. */
1703 /* */
1704
1705 StoreStatus:
1706 mfspr r10,sprg0 /* Get the pointer to the exception save area (unclean) */
1707
1708 lwz r5,saver0(r13) /* Get R0 (unclean) */
1709 lwz r6,saver1(r13) /* Get R1 (unclean) */
1710 lwz r7,saver2(r13) /* Get R2 (unclean) */
1711 stw r5,CSAgpr+(0*4)(r4) /* Save R0 */
1712 stw r6,CSAgpr+(1*4)(r4) /* Save R1 */
1713 stw r7,CSAgpr+(2*4)(r4) /* Save R2 */
1714 lwz r5,saver3(r13) /* Get R3 (unclean) */
1715 lwz r6,saver4(r13) /* Get R4 (unclean) */
1716 lwz r7,saver5(r13) /* Get R5 (unclean) */
1717 stw r5,CSAgpr+(3*4)(r4) /* Save R3 */
1718 stw r6,CSAgpr+(4*4)(r4) /* Save R4 */
1719 stw r7,CSAgpr+(5*4)(r4) /* Save R5 */
1720 lwz r5,saver6(r13) /* Get R6 (unclean) */
1721 lwz r6,saver7(r13) /* Get R7 (unclean) */
1722 lwz r7,saver8(r13) /* Get R8 (unclean) */
1723 stw r5,CSAgpr+(6*4)(r4) /* Save R6 */
1724 stw r6,CSAgpr+(7*4)(r4) /* Save R7 */
1725 stw r7,CSAgpr+(8*4)(r4) /* Save R8 */
1726 lwz r5,saver9(r13) /* Get R9 (unclean) */
1727 lwz r6,saver10(r13) /* Get R10 (unclean) */
1728 lwz r7,saver11(r13) /* Get R11 (unclean) */
1729 stw r5,CSAgpr+(9*4)(r4) /* Save R9 */
1730 stw r6,CSAgpr+(10*4)(r4) /* Save R10 */
1731 lwz r5,saver12(r13) /* Get R12 (unclean) */
1732 stw r7,CSAgpr+(11*4)(r4) /* Save R11 */
1733 stw r5,CSAgpr+(12*4)(r4) /* Save R12 */
1734
1735 lwz r5,saver13(r13) /* Get R13 (unclean) */
1736 lwz r6,saver14(r13) /* Get R14 (unclean) */
1737 lwz r7,saver15(r13) /* Get R15 (unclean) */
1738 stw r5,CSAgpr+(13*4)(r4) /* Save R13 */
1739 stw r6,CSAgpr+(14*4)(r4) /* Save R14 */
1740 stw r7,CSAgpr+(15*4)(r4) /* Save R15 */
1741 lwz r5,saver16(r13) /* Get R16 (unclean) */
1742 lwz r6,saver17(r13) /* Get R17 (unclean) */
1743 lwz r7,saver18(r13) /* Get R18 (unclean) */
1744 stw r5,CSAgpr+(16*4)(r4) /* Save R16 */
1745 stw r6,CSAgpr+(17*4)(r4) /* Save R17 */
1746 stw r7,CSAgpr+(18*4)(r4) /* Save R18 */
1747 lwz r5,saver19(r13) /* Get R19 (unclean) */
1748 lwz r6,saver20(r13) /* Get R20 (unclean) */
1749 lwz r7,saver21(r13) /* Get R21 (unclean) */
1750 stw r5,CSAgpr+(19*4)(r4) /* Save R19 */
1751 stw r6,CSAgpr+(20*4)(r4) /* Save R20 */
1752 stw r7,CSAgpr+(21*4)(r4) /* Save R21 */
1753 lwz r5,saver22(r13) /* Get R22 (unclean) */
1754 lwz r6,saver23(r13) /* Get R23 (unclean) */
1755 lwz r7,saver24(r13) /* Get R24 (unclean) */
1756 stw r5,CSAgpr+(22*4)(r4) /* Save R22 */
1757 stw r6,CSAgpr+(23*4)(r4) /* Save R23*/
1758 stw r7,CSAgpr+(24*4)(r4) /* Save R24 */
1759 lwz r5,saver25(r13) /* Get R25 (unclean) */
1760 lwz r6,saver26(r13) /* Get R26 (unclean) */
1761 lwz r7,saver27(r13) /* Get R27 (unclean) */
1762 stw r5,CSAgpr+(25*4)(r4) /* Save R25 */
1763 stw r6,CSAgpr+(26*4)(r4) /* Save R26 */
1764 stw r7,CSAgpr+(27*4)(r4) /* Save R27 */
1765
1766 lwz r5,saver28(r13) /* Get R28 (unclean) */
1767 lwz r6,saver29(r13) /* Get R29 (unclean) */
1768 lwz r7,saver30(r13) /* Get R30 (unclean) */
1769 stw r5,CSAgpr+(28*4)(r4) /* Save R28 */
1770 lwz r5,saver31(r13) /* Get R31(unclean) */
1771 stw r6,CSAgpr+(29*4)(r4) /* Save R29 */
1772 stw r7,CSAgpr+(30*4)(r4) /* Save R30 */
1773 stw r5,CSAgpr+(31*4)(r4) /* Save R31 */
1774
1775 StoreLiveStatus:
1776 mfmsr r5 /* Get the current MSR */
1777 ori r6,r5,0x2000 /* Turn on floating point instructions */
1778 mtmsr r6 /* Turn them on */
1779 isync /* Make sure they're on */
1780
1781 stfd f0,CSAfpr+(0*8)(r4) /* Save floating point registers */
1782 stfd f1,CSAfpr+(1*8)(r4) /* Save floating point registers */
1783 stfd f2,CSAfpr+(2*8)(r4) /* Save floating point registers */
1784 stfd f3,CSAfpr+(3*8)(r4) /* Save floating point registers */
1785 stfd f4,CSAfpr+(4*8)(r4) /* Save floating point registers */
1786 stfd f5,CSAfpr+(5*8)(r4) /* Save floating point registers */
1787 stfd f6,CSAfpr+(6*8)(r4) /* Save floating point registers */
1788 stfd f7,CSAfpr+(7*8)(r4) /* Save floating point registers */
1789 stfd f8,CSAfpr+(8*8)(r4) /* Save floating point registers */
1790 stfd f9,CSAfpr+(9*8)(r4) /* Save floating point registers */
1791 stfd f10,CSAfpr+(10*8)(r4) /* Save floating point registers */
1792 stfd f11,CSAfpr+(11*8)(r4) /* Save floating point registers */
1793 stfd f12,CSAfpr+(12*8)(r4) /* Save floating point registers */
1794 stfd f13,CSAfpr+(13*8)(r4) /* Save floating point registers */
1795 stfd f14,CSAfpr+(14*8)(r4) /* Save floating point registers */
1796 stfd f15,CSAfpr+(15*8)(r4) /* Save floating point registers */
1797 stfd f16,CSAfpr+(16*8)(r4) /* Save floating point registers */
1798 stfd f17,CSAfpr+(17*8)(r4) /* Save floating point registers */
1799 stfd f18,CSAfpr+(18*8)(r4) /* Save floating point registers */
1800 stfd f19,CSAfpr+(19*8)(r4) /* Save floating point registers */
1801 stfd f20,CSAfpr+(20*8)(r4) /* Save floating point registers */
1802 stfd f21,CSAfpr+(21*8)(r4) /* Save floating point registers */
1803 stfd f22,CSAfpr+(22*8)(r4) /* Save floating point registers */
1804 stfd f23,CSAfpr+(23*8)(r4) /* Save floating point registers */
1805 stfd f24,CSAfpr+(24*8)(r4) /* Save floating point registers */
1806 stfd f25,CSAfpr+(25*8)(r4) /* Save floating point registers */
1807 stfd f26,CSAfpr+(26*8)(r4) /* Save floating point registers */
1808 stfd f27,CSAfpr+(27*8)(r4) /* Save floating point registers */
1809 stfd f28,CSAfpr+(28*8)(r4) /* Save floating point registers */
1810 stfd f29,CSAfpr+(29*8)(r4) /* Save floating point registers */
1811 stfd f30,CSAfpr+(30*8)(r4) /* Save floating point registers */
1812 stfd f31,CSAfpr+(31*8)(r4) /* Save floating point registers */
1813
1814 mffs f1 /* Get the FPSCR */
1815 stfd f1,CSAfpscr-4(r4) /* Save the whole thing (we'll overlay the first half with CR later) */
1816
1817 lfd f1,CSAfpr+(1*4)(r4) /* Restore F1 */
1818
1819 mtmsr r5 /* Put the floating point back to what it was before */
1820 isync /* Wait for it */
1821
1822 lwz r6,savecr(r13) /* Get the old CR (unclean) */
1823 stw r6,CSAcr(r4) /* Save the CR */
1824
1825 mfxer r6 /* Get the XER */
1826 stw r6,CSAxer(r4) /* Save the XER */
1827
1828 lwz r6,savelr(r13) /* Get the old LR (unclean) */
1829 stw r6,CSAlr(r4) /* Save the LR */
1830
1831 mfctr r6 /* Get the CTR */
1832 stw r6,CSActr(r4) /* Save the CTR */
1833
1834 STtbase: mftbu r5 /* Get the upper timebase */
1835 mftb r6 /* Get the lower */
1836 mftbu r7 /* Get the top again */
1837 cmplw cr0,r5,r7 /* Did it tick? */
1838 bne- STtbase /* Yeah, do it again... */
1839
1840 mfdec r7 /* Get the decrimenter (make it at about the same time as the TB) */
1841 stw r7,CSAdec(r4) /* Save the decrimenter */
1842
1843
1844 stw r5,CSAtbu(r4) /* Stash the top part */
1845 stw r6,CSAtbl(r4) /* Stash the lower part */
1846
1847 lwz r5,savesrr1(r13) /* SRR1 at exception is as close as we get to the MSR (unclean) */
1848 lwz r6,savesrr0(r13) /* Get SRR0 also */
1849 stw r5,CSAmsr(r4) /* Save the MSR */
1850 stw r6,CSApc(r4) /* Save the PC */
1851 stw r5,CSAsrr1(r4) /* Set SRR1 also */
1852 stw r6,CSAsrr0(r4) /* Save SRR0 */
1853
1854 mfpvr r5 /* Get the PVR */
1855 stw r5,CSApvr(r4) /* Save the PVR */
1856
1857 mfspr r5,pir /* Get the PIR */
1858 stw r5,CSApir(r4) /* Save the PIR */
1859
1860 mfspr r5,ibat0u /* Get the upper IBAT0 */
1861 mfspr r6,ibat0l /* Get the lower IBAT0 */
1862 stw r5,CSAibat+(0*8+0)(r4) /* Save the upper IBAT0 */
1863 stw r6,CSAibat+(0*8+4)(r4) /* Save the upper IBAT0 */
1864
1865 mfspr r5,ibat1u /* Get the upper IBAT1 */
1866 mfspr r6,ibat1l /* Get the lower IBAT1 */
1867 stw r5,CSAibat+(1*8+0)(r4) /* Save the upper IBAT1 */
1868 stw r6,CSAibat+(1*8+4)(r4) /* Save the upper IBAT1 */
1869
1870 mfspr r5,ibat2u /* Get the upper IBAT2 */
1871 mfspr r6,ibat2l /* Get the lower IBAT2 */
1872 stw r5,CSAibat+(2*8+0)(r4) /* Save the upper IBAT2 */
1873 stw r6,CSAibat+(2*8+4)(r4) /* Save the upper IBAT2 */
1874
1875 mfspr r5,ibat3u /* Get the upper IBAT3 */
1876 mfspr r6,ibat3l /* Get the lower IBAT3 */
1877 stw r5,CSAibat+(3*8+0)(r4) /* Save the upper IBAT3 */
1878 stw r6,CSAibat+(3*8+4)(r4) /* Save the upper IBAT3 */
1879
1880 mfspr r5,dbat0u /* Get the upper DBAT0 */
1881 mfspr r6,dbat0l /* Get the lower DBAT0 */
1882 stw r5,CSAdbat+(0*8+0)(r4) /* Save the upper DBAT0 */
1883 stw r6,CSAdbat+(0*8+4)(r4) /* Save the upper DBAT0 */
1884
1885 mfspr r5,dbat1u /* Get the upper DBAT1 */
1886 mfspr r6,dbat1l /* Get the lower DBAT1 */
1887 stw r5,CSAdbat+(1*8+0)(r4) /* Save the upper DBAT1 */
1888 stw r6,CSAdbat+(1*8+4)(r4) /* Save the upper DBAT1 */
1889
1890 mfspr r5,dbat2u /* Get the upper DBAT2 */
1891 mfspr r6,dbat2l /* Get the lower DBAT2 */
1892 stw r5,CSAdbat+(2*8+0)(r4) /* Save the upper DBAT2 */
1893 stw r6,CSAdbat+(2*8+4)(r4) /* Save the upper DBAT2 */
1894
1895 mfspr r5,dbat3u /* Get the upper DBAT3 */
1896 mfspr r6,dbat3l /* Get the lower DBAT3 */
1897 stw r5,CSAdbat+(3*8+0)(r4) /* Save the upper DBAT3 */
1898 stw r6,CSAdbat+(3*8+4)(r4) /* Save the upper DBAT3 */
1899
1900 mfsdr1 r5 /* Get the SDR1 */
1901 stw r5,CSAsdr1(r4) /* Save the SDR1 */
1902
1903 mfsr r5,sr0 /* Get SR 0 */
1904 mfsr r6,sr1 /* Get SR 1 */
1905 mfsr r7,sr2 /* Get SR 2 */
1906 stw r5,CSAsr+(0*4)(r4) /* Save SR 0 */
1907 stw r6,CSAsr+(1*4)(r4) /* Save SR 1 */
1908 mfsr r5,sr3 /* Get SR 3 */
1909 mfsr r6,sr4 /* Get SR 4 */
1910 stw r7,CSAsr+(2*4)(r4) /* Save SR 2 */
1911 mfsr r7,sr5 /* Get SR 5 */
1912 stw r5,CSAsr+(3*4)(r4) /* Save SR 3 */
1913 stw r6,CSAsr+(4*4)(r4) /* Save SR 4 */
1914 mfsr r5,sr6 /* Get SR 6 */
1915 mfsr r6,sr7 /* Get SR 7 */
1916 stw r7,CSAsr+(5*4)(r4) /* Save SR 5 */
1917 mfsr r7,sr8 /* Get SR 8 */
1918 stw r5,CSAsr+(6*4)(r4) /* Save SR 6 */
1919 stw r6,CSAsr+(7*4)(r4) /* Save SR 7 */
1920 mfsr r5,sr9 /* Get SR 9 */
1921 mfsr r6,sr10 /* Get SR 11 */
1922 stw r7,CSAsr+(8*4)(r4) /* Save SR 8 */
1923 mfsr r7,sr11 /* Get SR 11 */
1924 stw r5,CSAsr+(9*4)(r4) /* Save SR 9 */
1925 stw r6,CSAsr+(10*4)(r4) /* Save SR 10 */
1926 mfsr r5,sr12 /* Get SR 12 */
1927 mfsr r6,sr13 /* Get SR 13 */
1928 stw r7,CSAsr+(11*4)(r4) /* Save SR 11 */
1929 mfsr r7,sr14 /* Get SR 14 */
1930 stw r5,CSAsr+(12*4)(r4) /* Save SR 12 */
1931 stw r6,CSAsr+(13*4)(r4) /* Save SR 13 */
1932 mfsr r5,sr15 /* Get SR 15 */
1933 stw r7,CSAsr+(14*4)(r4) /* Save SR 14 */
1934 stw r5,CSAsr+(15*4)(r4) /* Save SR 15 */
1935
1936 mfdar r6 /* Get the DAR */
1937 stw r6,CSAdar(r4) /* Save it */
1938
1939 mfdsisr r5 /* Get the DSISR */
1940 stw r5,CSAdsisr(r4) /* Save it */
1941
1942 stw r10,CSAsprg+(1*4)(r4) /* Save SPRG1 */
1943 mfspr r7,sprg0 /* Get SPRG0 */
1944 mfspr r6,sprg2 /* Get SPRG2 */
1945 stw r7,CSAsprg+(0*4)(r4) /* Save SPRG0 */
1946 mfspr r5,sprg3 /* Get SPRG3 */
1947 stw r6,CSAsprg+(2*4)(r4) /* Save SPRG2 */
1948 stw r5,CSAsprg+(3*4)(r4) /* Save SPRG4 */
1949
1950 mfspr r6,1013 /* Get the DABR */
1951 mfspr r7,1010 /* Get the IABR */
1952 stw r6,CSAdabr(r4) /* Save the DABR */
1953 stw r7,CSAiabr(r4) /* Save the IABR */
1954
1955 mfspr r5,282 /* Get the EAR */
1956 stw r5,CSAear(r4) /* Save the EAR */
1957
1958 lis r7,0xDEAD /* Get 0xDEAD */
1959 ori r7,r7,0xF1D0 /* Get 0xDEADF1D0 */
1960
1961 mfpvr r5 /* Get the processor type */
1962 rlwinm r5,r5,16,16,31 /* Isolate the processor */
1963 cmplwi cr1,r5,4 /* Set CR1_EQ if this is a plain 604, something else if it's a 604E */
1964
1965 mfspr r6,hid0 /* Get HID0 */
1966 mr r5,r7 /* Assume 604 */
1967 beq cr1,NoHID1 /* It is... */
1968 mfspr r5,hid1 /* Get the HID1 */
1969
1970 NoHID1: stw r6,CSAhid+(0*4)(r4) /* Save HID0 */
1971 stw r5,CSAhid+(1*4)(r4) /* Save HID1 */
1972 stw r7,CSAhid+(2*4)(r4) /* Save HID2 */
1973 stw r7,CSAhid+(3*4)(r4) /* Save HID3 */
1974 stw r7,CSAhid+(4*4)(r4) /* Save HID4 */
1975 stw r7,CSAhid+(5*4)(r4) /* Save HID5 */
1976 stw r7,CSAhid+(6*4)(r4) /* Save HID6 */
1977 stw r7,CSAhid+(7*4)(r4) /* Save HID7 */
1978 stw r7,CSAhid+(8*4)(r4) /* Save HID8 */
1979 stw r7,CSAhid+(9*4)(r4) /* Save HID9 */
1980 stw r7,CSAhid+(10*4)(r4) /* Save HID10 */
1981 stw r7,CSAhid+(11*4)(r4) /* Save HID11 */
1982 stw r7,CSAhid+(12*4)(r4) /* Save HID12 */
1983 stw r7,CSAhid+(13*4)(r4) /* Save HID13 */
1984 stw r7,CSAhid+(14*4)(r4) /* Save HID14 */
1985 stw r7,CSAhid+(15*4)(r4) /* Save HID15 */
1986
1987 mfspr r6,952 /* Get MMCR0 */
1988 mr r5,r7 /* Assume 604 */
1989 beq NoMMCR1 /* It is... */
1990 mfspr r5,956 /* Get the MMCR1 */
1991
1992 NoMMCR1: stw r6,CSAmmcr+(0*4)(r4) /* Save MMCR0 */
1993 stw r5,CSAmmcr+(1*4)(r4) /* Save MMCR1 */
1994
1995 mfspr r6,953 /* Get PMC1 */
1996 mfspr r5,954 /* Get PMC2 */
1997 stw r6,CSApmc+(0*4)(r4) /* Save PMC1 */
1998 stw r5,CSApmc+(1*4)(r4) /* Save PMC2 */
1999
2000 mr r6,r7 /* Assume 604 */
2001 mr r5,r7 /* Assume 604 */
2002 beq NoPMC3 /* Yeah... */
2003 mfspr r6,957 /* Get the PMC3 for a 604E */
2004 mfspr r5,958 /* Get the PMC4 for a 604E */
2005
2006 NoPMC3: stw r6,CSApmc+(2*4)(r4) /* Save PMC3 */
2007 stw r5,CSApmc+(3*4)(r4) /* Save PMC4 */
2008
2009 mfspr r6,955 /* Get SIA */
2010 mfspr r5,959 /* Get SDA */
2011 stw r6,CSAsia(r4) /* Save the SIA */
2012 stw r5,CSAsda(r4) /* Save the SDA */
2013
2014 stw r7,CSAmq(r4) /* There is no MQ on either the 604 or 604E */
2015
2016
2017 lwz r6,MPPICStat(r9) /* Get the status of this processor */
2018 lis r10,MPPICReady>>16 /* Get the flag for reset or not */
2019 li r5,kSIGPResetState /* Assume we're operating */
2020 and. r0,r6,r10 /* See if the ready bit is set */
2021 lis r10,MPPICStop>>16 /* Get the flag for stopped or not */
2022 beq SetStateInf /* Go set that we are reset... */
2023 and. r0,r6,r10 /* Are we stopped? */
2024 li r5,kSIGPStoppedState /* Assume we area */
2025 bne SetStateInf /* We are, go set it... */
2026 li r5,kSIGPOperatingState /* Not stopped, so we're going */
2027
2028 SetStateInf: stb r5,CSAstate(r4) /* Set the state byte */
2029
2030 li r0,1 /* Set the truth */
2031 sync /* Make sure it's stored */
2032
2033 stb r0,CSAregsAreValid(r4) /* Set that the status is valid */
2034
2035 blr /* We're done here... */
2036
2037
2038 /******************************************************************************************************** */
2039 /* */
2040 /* The synchronize time base function. No state requirements for this one. */
2041 /* */
2042 /******************************************************************************************************** */
2043
2044 ITBsync: /* This handles the synchronize time base function */
2045 lis r12,HIGH_ADDR(MPPIwork) /* Get the top of work area */
2046 li r0,MPPICfTBsy1 /* Get the flag for TB sync state 1 */
2047 li r7,0 /* Get a 0 */
2048 ori r12,r12,LOW_ADDR(MPPIwork) /* Get low part of work area */
2049 mttbl r7 /* Clear the bottom of the TB so's there's noupper ticks */
2050 mttbu r7 /* Clear the top part, just 'cause I wanna */
2051
2052 sync /* Make sure all is saved */
2053 stb r0,MPPICStat+2(r9) /* Tell the main dude to tell us the time */
2054 isync /* Make sure we don't go nowhere's */
2055
2056 /* */
2057 /* Remember that the sync'ing processor insures that the TB won't tick the high part for at least */
2058 /* 16k ticks. That should be way longer than we need for the whole process here */
2059 /* */
2060
2061 WaitTBLower: lwz r5,MPPITBsync+4-MPPIwork(r12) /* Get the lower part of the TB */
2062 mttbl r5 /* Put it in just in case it's set now */
2063 mr. r5,r5 /* Was it actually? */
2064 beq+ WaitTBLower /* Nope, go check again... */
2065 lwz r4,MPPITBsync-MPPIwork(r12) /* Get the high order part */
2066 mttbu r4 /* Set the top half also */
2067
2068 stw r7,MPPITBsync+4-MPPIwork(r12) /* Tell 'em we've got it */
2069
2070 sync
2071
2072 li r4,0 /* Clear this */
2073 la r5,MPPISncFght-32-MPPIwork(r12) /* Point to the squared circle (our corner) */
2074
2075 b TB1stPnch /* Go take the first punch... */
2076
2077 TBSargue:
2078 dcbf 0,r5 /* *** Fix cache coherency (data integrity) HW bug *** */
2079 sync /* *** Fix cache coherency (data integrity) HW bug *** */
2080 lwz r6,0(r5) /* Listen for the procecution's argument */
2081 mr. r6,r6 /* See if they are done */
2082 beq+ TBSargue /* Nope, still going... */
2083
2084 TB1stPnch: mftb r7 /* They're done, time for rebuttal */
2085 stw r7,32(r5) /* Make rebuttle */
2086
2087 addi r4,r4,1 /* Count rounds */
2088
2089 cmplwi cr0,r4,10 /* See if we've gone 9 more rounds */
2090 addi r5,r5,64 /* Point to the next round areas */
2091
2092 blt+ TBSargue /* Not yet, come out of your corners fighting... */
2093
2094 /* */
2095 /* We'll set the latest-up-to-datest from the other processor now */
2096 /* */
2097 TBSetTB:
2098 dcbf 0,r5 /* *** Fix cache coherency (data integrity) HW bug *** */
2099 sync /* *** Fix cache coherency (data integrity) HW bug *** */
2100 lwz r6,0(r5) /* Listen for the procecution's argument */
2101 mttbl r6 /* Set it just in case it's ok */
2102 mr. r6,r6 /* See if they are done */
2103 beq+ TBSetTB /* Nope, still going... */
2104
2105 /* */
2106 /* Get average duration for each processor. We skip the first pass on the asumption */
2107 /* that the caches were not warmed up and it would take longer. In proctice this */
2108 /* is what was seen. */
2109 /* */
2110
2111 mr r0,r11 /* Move return address to a safe register */
2112
2113 li r4,0 /* Clear a counter */
2114 li r3,0 /* Clear accumulator for duration */
2115 li r10,0 /* Clear start time accumulator top half */
2116 li r11,0 /* Clear start time accumulator bottom half */
2117 li r1,0 /* Clear start time accumulator top half */
2118 li r2,0 /* Clear start time accumulator bottom half */
2119 li r10,0 /* Clear accumulator for durations */
2120 la r5,MPPISncFght+64-MPPIwork(r12) /* Get second round start time address */
2121
2122 TBSaccumU: lwz r6,0(r5) /* Get start time */
2123 lwz r11,32(r5) /* Get the other processor's start time */
2124 lwz r7,64(r5) /* Get end time */
2125 lwz r8,96(r5) /* Other proc's end time */
2126 sub r7,r7,r6 /* Get duration */
2127 sub r8,r8,r11 /* Get other side's duration */
2128 addi r4,r4,1 /* Count arguments */
2129 add r3,r3,r7 /* Accumulate durations */
2130 add r2,r2,r7 /* Accumulate other side's durations */
2131 cmplwi cr0,r4,8 /* Have we gotten them all yet? */
2132 addi r5,r5,64 /* Step to the next argument */
2133 blt+ TBSaccumU /* We're not done yet... */
2134
2135 add r7,r2,r3 /* Sum the two differences */
2136 addi r7,r7,0x10 /* Round up */
2137 rlwinm r7,r7,27,5,31 /* Get the average difference divided in half */
2138
2139 mftb r8 /* Get the time now */
2140 add r8,r8,r7 /* Slide the window */
2141 mttbl r8 /* Set the time */
2142
2143 stw r12,MPPITBsync+4-MPPIwork(r12) /* Show that we are done */
2144
2145 lwz r3,MPPICStat(r9) /* Get back our status */
2146 mr r11,r0 /* Restore the return register */
2147 b KillBusy /* We're all done now, done for it, c'est la vie... */
2148
2149
2150 /******************************************************************************************************** */
2151 /* */
2152 /* The reset function. No state requirements for this one. */
2153 /* This suicides the processor. Our caller is never returned to (good english). The only way out of */
2154 /* this is a start function subsequently. So, we give a flying f**k about the registers 'n' sutff. */
2155 /* */
2156 /******************************************************************************************************** */
2157
2158 IReset: lis r28,0x8000 /* Turn on machine checks */
2159
2160 ori r28,r28,0xCC84 /* Enable caches, clear them, */
2161 /* disable serial execution and turn BHT on */
2162 sync
2163 mtspr HID0,r28 /* Start the cache clear */
2164 sync
2165
2166 /* */
2167 /* Clear out the TLB. They be garbage after hard reset. */
2168 /* */
2169
2170 li r0,512 /* Get number of TLB entries (FIX THIS) */
2171 li r3,0 /* Start at 0 */
2172 mtctr r0 /* Set the CTR */
2173
2174 IRpurgeTLB: tlbie r3 /* Purge this entry */
2175 addi r3,r3,4096 /* Next page */
2176 bdnz IRpurgeTLB /* Do 'em all... */
2177
2178 sync /* Make sure all TLB purges are done */
2179 tlbsync /* Make sure on other processors also */
2180 sync /* Make sure the TLBSYNC is done */
2181
2182 /* */
2183 /* Clear out the BATs. */
2184 /* */
2185
2186 li r3,0 /* Clear a register */
2187
2188 mtspr DBAT0L,r3 /* Clear BAT */
2189 mtspr DBAT0U,r3 /* Clear BAT */
2190 mtspr DBAT1L,r3 /* Clear BAT */
2191 mtspr DBAT1U,r3 /* Clear BAT */
2192 mtspr DBAT2L,r3 /* Clear BAT */
2193 mtspr DBAT2U,r3 /* Clear BAT */
2194 mtspr DBAT3L,r3 /* Clear BAT */
2195 mtspr DBAT3U,r3 /* Clear BAT */
2196
2197 mtspr IBAT0L,r3 /* Clear BAT */
2198 mtspr IBAT0U,r3 /* Clear BAT */
2199 mtspr IBAT1L,r3 /* Clear BAT */
2200 mtspr IBAT1U,r3 /* Clear BAT */
2201 mtspr IBAT2L,r3 /* Clear BAT */
2202 mtspr IBAT2U,r3 /* Clear BAT */
2203 mtspr IBAT3L,r3 /* Clear BAT */
2204 mtspr IBAT3U,r3 /* Clear BAT */
2205
2206 /* */
2207 /* Map 0xF0000000 to 0xFFFFFFFF for I/O; make it R/W non-cacheable */
2208 /* Map 0x00000000 to 0x0FFFFFFF for mainstore; make it R/W cachable */
2209 /* */
2210
2211 lis r6,0xF000 /* Set RPN to last segment */
2212 ori r6,r6,0x1FFF /* Set up upper BAT for 256M, access both */
2213
2214 lis r7,0xF000 /* Set RPN to last segment */
2215 ori r7,r7,0x0032 /* Set up lower BAT for 256M, access both, non-cachable */
2216
2217 mtspr DBAT0L,r7 /* Setup ROM and I/O mapped areas */
2218 mtspr DBAT0U,r6 /* Now do the upper DBAT */
2219 sync
2220
2221 li r6,0x1FFF /* Set up upper BAT for 256M, access both */
2222 li r7,0x0012 /* Set up lower BAT for r/w access */
2223
2224 mtspr DBAT1L,r7 /* Set up an initial view of mainstore */
2225 mtspr DBAT1U,r6 /* Now do the upper DBAT */
2226 sync
2227
2228 /* */
2229 /* Clean up SDR and segment registers */
2230 /* */
2231
2232 li r3,0 /* Clear a register */
2233 mtspr SDR1,r3 /* Clear SDR1 */
2234
2235 li r4,0 /* Clear index for segment registers */
2236 lis r5,0x1000 /* Set the segment indexer */
2237
2238 IRclearSR: mtsrin r3,r4 /* Zero out the SR */
2239 add. r4,r4,r5 /* Point to the next segment */
2240 bne- IRclearSR /* Keep going until we wrap back to 0 */
2241
2242 lis r3,(MPPICOnline+MPPICStop)>>16 /* Set the reset/online state flags */
2243 b KillBusy /* Go wipe out the busy flags... */
2244
2245 /* (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) */
2246 /* */
2247 /* Here lies the Phoney Firmware used to test SIGPs. Take this out later. */
2248 /* */
2249 /* (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) */
2250
2251 mp_PhoneyFirmware:
2252
2253 li r27,0x3040 /* Set floating point and machine checks on, IP to 0xFFF0xxxx */
2254 mtmsr r27 /* Load 'em on in */
2255 isync
2256
2257 bl PhoneyBase /* Make a base register */
2258 PhoneyBase: mflr r26 /* Get it */
2259 addi r26,r26,LOW_ADDR(MPPIbase-PhoneyBase) /* Adjust it back */
2260
2261 la r20,LOW_ADDR(rupttab-MPPIbase)(r26) /* Get the address of the interrupt table */
2262 la r21,LOW_ADDR(rupttabend-MPPIbase)(r26) /* Get the end of the table */
2263
2264 relocate: lwz r22,0(r20) /* Get the displacement to routine */
2265 add r22,r22,r12 /* Relocate to the physical address */
2266 stw r22,0(r20) /* Stick it back */
2267 addi r20,r20,4 /* Point to the next one */
2268 cmplw cr0,r20,r21 /* Still in table? */
2269 ble+ cr0,relocate /* Yeah... */
2270
2271 la r20,LOW_ADDR(rupttab-MPPIbase)(r26) /* Get the interrupt table back again */
2272 mtsprg 3,r20 /* Activate the phoney Rupt table */
2273
2274 lis r24,hi16(HammerHead) /* Get the actual hammerhead address */
2275 ori r24,r24,0x0032 /* Make R/W non-cachable */
2276 lwz r23,MPPIHammer-MPPIwork(r12) /* Get the address mapped on the main processor */
2277 ori r23,r23,0x0003 /* Set both super and user valid for 128KB */
2278
2279 mtspr DBAT0L,r24 /* Setup hammerhead's real address */
2280 mtspr DBAT0U,r23 /* Map hammerhead to the same virtual address as on the main processor */
2281 sync /* Make sure it is done */
2282
2283 la r25,MPPICPU2-MPPIwork(r12) /* Point to a phoney register save area */
2284 mtsprg 1,r25 /* Phoney up initialized processor state */
2285
2286 lis r24,0xFEED /* Get 0xFEED */
2287 ori r24,r24,0xF1D0 /* Get 0xFEEDF1D0 */
2288
2289 stw r24,CSAgpr+(0*4)(r25) /* Store invalid R0 */
2290 stw r24,CSAgpr+(1*4)(r25) /* Store invalid R1 */
2291 stw r24,CSAgpr+(2*4)(r25) /* Store invalid R2 */
2292 stw r24,CSAgpr+(3*4)(r25) /* Store invalid R3 */
2293 stw r24,CSAgpr+(4*4)(r25) /* Store invalid r4 */
2294 stw r24,CSAgpr+(5*4)(r25) /* Store invalid R5 */
2295 stw r24,CSAgpr+(6*4)(r25) /* Store invalid R6 */
2296 stw r24,CSAgpr+(7*4)(r25) /* Store invalid r7 */
2297 stw r24,CSAgpr+(8*4)(r25) /* Store invalid R8 */
2298 stw r24,CSAgpr+(9*4)(r25) /* Store invalid R9 */
2299 stw r24,CSAgpr+(10*4)(r25) /* Store invalid R10 */
2300 stw r24,CSAgpr+(11*4)(r25) /* Store invalid R11 */
2301 stw r24,CSAgpr+(12*4)(r25) /* Store invalid R12 */
2302
2303 waititout: lwz r25,0x30(br0) /* Get wait count */
2304 mfmsr r24 /* Get the MSR */
2305 addi r25,r25,1 /* Bounce it up */
2306 ori r24,r24,0x8000 /* Turn on external interruptions */
2307 stw r25,0x30(br0) /* Save back the count */
2308 mtmsr r24 /* Set it */
2309 isync /* Stop until we're here */
2310 b waititout /* Loop forever... */
2311
2312 /* */
2313 /* Phoney interrupt handlers */
2314 /* */
2315
2316 pexternal: mflr r29 /* Get the LR value */
2317 lwz r29,0(r29) /* Get the rupt code */
2318 stw r29,0x0B0(br0) /* Save the code */
2319 bl GotSignal /* Call the signal handler */
2320 oris r3,r3,0x8000 /* Turn on high bit so we see a code 0 */
2321 stw r3,0xA8(br0) /* Save return code in debug area */
2322
2323 ignorerupt: mflr r29 /* Get the LR value */
2324 lwz r29,0(r29) /* Get the rupt code */
2325 stw r29,0x0B0(br0) /* Save the code */
2326 rfi /* Bail to from whence we commest... */
2327 .long 0
2328 .long 0
2329 .long 0
2330 .long 0
2331 .long 0
2332 .long 0
2333 .long 0
2334
2335 rupttab: .long ignorerupt
2336 .long ignorerupt
2337 .long ignorerupt
2338 .long ignorerupt
2339 .long ignorerupt
2340 .long pexternal /* Phoney external handler */
2341 .long ignorerupt
2342 .long ignorerupt
2343 .long ignorerupt
2344 .long ignorerupt
2345 .long ignorerupt
2346 .long ignorerupt
2347 .long ignorerupt
2348 .long ignorerupt
2349 .long ignorerupt
2350 .long ignorerupt
2351 .long ignorerupt
2352 .long ignorerupt
2353 .long ignorerupt
2354 .long ignorerupt
2355 .long ignorerupt
2356 .long ignorerupt
2357 .long ignorerupt
2358 .long ignorerupt
2359 .long ignorerupt
2360 .long ignorerupt
2361 .long ignorerupt
2362 .long ignorerupt
2363 .long ignorerupt
2364 .long ignorerupt
2365 .long ignorerupt
2366 .long ignorerupt
2367 .long ignorerupt
2368 .long ignorerupt
2369 .long ignorerupt
2370 .long ignorerupt
2371 .long ignorerupt
2372 .long ignorerupt
2373 .long ignorerupt
2374 .long ignorerupt
2375 .long ignorerupt
2376 .long ignorerupt
2377 .long ignorerupt
2378 .long ignorerupt
2379 .long ignorerupt
2380 .long ignorerupt
2381 .long ignorerupt
2382 rupttabend: .long ignorerupt
2383
2384 /* (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) */
2385 /* */
2386 /* Here lies the end of the Phoney Firmware used to test SIGPs. Take this out later. */
2387 /* */
2388 /* (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) */
2389
2390
2391 /* */
2392 /* Table of function offsets */
2393 /* */
2394
2395 MPPIFuncOffs:
2396
2397 .long CountProcessors-MPPIFunctions /* Offset to routine */
2398 .long StartProcessor-MPPIFunctions /* Offset to routine */
2399 .long ResumeProcessor-MPPIFunctions /* Offset to routine */
2400 .long StopProcessor-MPPIFunctions /* Offset to routine */
2401 .long ResetProcessor-MPPIFunctions /* Offset to routine */
2402 .long SignalProcessor-MPPIFunctions /* Offset to routine */
2403 .long StoreProcessorStatus-MPPIFunctions /* Offset to routine */
2404 .long SynchClock-MPPIFunctions /* Offset to routine */
2405 .long GetExtHandlerAddress-MPPIFunctions /* Offset to routine */
2406 .long GotSignal-MPPIFunctions /* Offset to routine */
2407 .long ProcessorState-MPPIFunctions /* Offset to routine */
2408 .long RunSIGPRun-MPPIFunctions /* Offset to routine */
2409 .long mp_PhoneyFirmware-MPPIFunctions /* (TEST/DEBUG) */
2410
2411 MPPISize:
2412