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