1 /* 2 * ReactOS kernel 3 * Copyright (C) 2004, 2005 ReactOS Team 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 /* 20 * COPYRIGHT: See COPYING in the top level directory 21 * PROJECT: ReactOS kernel 22 * FILE: hal/halx86/mp/apic.c 23 * PURPOSE: 24 * PROGRAMMER: 25 */ 26 27 /* INCLUDE ***********************************************************************/ 28 29 #include <hal.h> 30 #include <halfuncs.h> /* Not in PCH because only used for MP HAL */ 31 #include <rtlfuncs.h> /* Not in PCH because only used for MP HAL */ 32 #define NDEBUG 33 #include <debug.h> 34 35 /* GLOBALS ***********************************************************************/ 36 37 ULONG CPUCount; /* Total number of CPUs */ 38 ULONG BootCPU; /* Bootstrap processor */ 39 ULONG OnlineCPUs; /* Bitmask of online CPUs */ 40 CPU_INFO CPUMap[MAX_CPU]; /* Map of all CPUs in the system */ 41 42 #ifdef CONFIG_SMP 43 PULONG BIOSBase; /* Virtual address of BIOS data segment */ 44 PULONG CommonBase; /* Virtual address of common area */ 45 #endif 46 47 PULONG APICBase = (PULONG)APIC_DEFAULT_BASE; /* Virtual address of local APIC */ 48 49 ULONG APICMode; /* APIC mode at startup */ 50 51 /* For debugging */ 52 ULONG lastregr[MAX_CPU]; 53 ULONG lastvalr[MAX_CPU]; 54 ULONG lastregw[MAX_CPU]; 55 ULONG lastvalw[MAX_CPU]; 56 57 #ifdef CONFIG_SMP 58 #include <pshpack1.h> 59 typedef struct _COMMON_AREA_INFO 60 { 61 ULONG Stack; /* Location of AP stack */ 62 ULONG PageDirectory; /* Page directory for an AP */ 63 ULONG NtProcessStartup; /* Kernel entry point for an AP */ 64 ULONG PaeModeEnabled; /* PAE mode is enabled */ 65 ULONG Debug[16]; /* For debugging */ 66 } COMMON_AREA_INFO, *PCOMMON_AREA_INFO; 67 #include <poppack.h> 68 #endif 69 70 extern CHAR *APstart, *APend; 71 72 #define BIOS_AREA 0x0 73 #define COMMON_AREA 0x2000 74 75 #define HZ (100) 76 #define APIC_DIVISOR (16) 77 78 #define CMOS_READ(address) { \ 79 WRITE_PORT_UCHAR((PUCHAR)0x70, address)); \ 80 READ_PORT_UCHAR((PUCHAR)0x71)); \ 81 } 82 83 #define CMOS_WRITE(address, value) { \ 84 WRITE_PORT_UCHAR((PUCHAR)0x70, address); \ 85 WRITE_PORT_UCHAR((PUCHAR)0x71, value); \ 86 } 87 88 extern ULONG_PTR KernelBase; 89 90 /* FUNCTIONS *********************************************************************/ 91 92 extern ULONG Read8254Timer(VOID); 93 extern VOID WaitFor8254Wraparound(VOID); 94 extern VOID MpsTimerInterrupt(VOID); 95 extern VOID MpsErrorInterrupt(VOID); 96 extern VOID MpsSpuriousInterrupt(VOID); 97 extern VOID MpsIpiInterrupt(VOID); 98 99 ULONG APICGetMaxLVT(VOID) 100 { 101 ULONG tmp, ver, maxlvt; 102 103 tmp = APICRead(APIC_VER); 104 ver = GET_APIC_VERSION(tmp); 105 /* 82489DXs do not report # of LVT entries. */ 106 maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(tmp) : 2; 107 108 return maxlvt; 109 } 110 111 VOID APICClear(VOID) 112 { 113 ULONG tmp, maxlvt; 114 115 maxlvt = APICGetMaxLVT(); 116 117 /* 118 * Careful: we have to set masks only first to deassert 119 * any level-triggered sources. 120 */ 121 122 if (maxlvt >= 3) 123 { 124 tmp = ERROR_VECTOR; 125 APICWrite(APIC_LVT3, tmp | APIC_LVT3_MASKED); 126 } 127 128 tmp = APICRead(APIC_LVTT); 129 APICWrite(APIC_LVTT, tmp | APIC_LVT_MASKED); 130 131 tmp = APICRead(APIC_LINT0); 132 APICWrite(APIC_LINT0, tmp | APIC_LVT_MASKED); 133 134 tmp = APICRead(APIC_LINT1); 135 APICWrite(APIC_LINT1, tmp | APIC_LVT_MASKED); 136 137 if (maxlvt >= 4) 138 { 139 tmp = APICRead(APIC_LVTPC); 140 APICWrite(APIC_LVTPC, tmp | APIC_LVT_MASKED); 141 } 142 #if 0 143 if (maxlvt >= 5) 144 { 145 tmp = APICRead(APIC_LVTTHMR); 146 APICWrite(APIC_LVTTHMR, tmp | APIC_LVT_MASKED); 147 } 148 #endif 149 /* 150 * Clean APIC state for other OSs: 151 */ 152 APICWrite(APIC_LVTT, APIC_LVT_MASKED); 153 APICWrite(APIC_LINT0, APIC_LVT_MASKED); 154 APICWrite(APIC_LINT1, APIC_LVT_MASKED); 155 156 if (maxlvt >= 3) 157 { 158 APICWrite(APIC_LVT3, APIC_LVT3_MASKED); 159 } 160 161 if (maxlvt >= 4) 162 { 163 APICWrite(APIC_LVTPC, APIC_LVT_MASKED); 164 } 165 #if 0 166 if (maxlvt >= 5) 167 { 168 APICWrite(APIC_LVTTHMR, APIC_LVT_MASKED); 169 } 170 #endif 171 } 172 173 /* Enable symetric I/O mode ie. connect the BSP's local APIC to INT and NMI lines */ 174 VOID EnableApicMode(VOID) 175 { 176 /* 177 * Do not trust the local APIC being empty at bootup. 178 */ 179 APICClear(); 180 181 WRITE_PORT_UCHAR((PUCHAR)0x22, 0x70); 182 WRITE_PORT_UCHAR((PUCHAR)0x23, 0x01); 183 } 184 185 /* Disable symetric I/O mode ie. go to PIC mode */ 186 __inline VOID DisableSMPMode(VOID) 187 { 188 /* 189 * Put the board back into PIC mode (has an effect 190 * only on certain older boards). Note that APIC 191 * interrupts, including IPIs, won't work beyond 192 * this point! The only exception are INIT IPIs. 193 */ 194 WRITE_PORT_UCHAR((PUCHAR)0x22, 0x70); 195 WRITE_PORT_UCHAR((PUCHAR)0x23, 0x00); 196 } 197 198 VOID DumpESR(VOID) 199 { 200 ULONG tmp; 201 202 if (APICGetMaxLVT() > 3) 203 { 204 APICWrite(APIC_ESR, 0); 205 } 206 tmp = APICRead(APIC_ESR); 207 DbgPrint("ESR %08x\n", tmp); 208 } 209 210 211 VOID APICDisable(VOID) 212 { 213 ULONG tmp; 214 215 APICClear(); 216 217 /* 218 * Disable APIC (implies clearing of registers for 82489DX!). 219 */ 220 tmp = APICRead(APIC_SIVR); 221 tmp &= ~APIC_SIVR_ENABLE; 222 APICWrite(APIC_SIVR, tmp); 223 } 224 225 static VOID APICDumpBit(ULONG base) 226 { 227 ULONG v, i, j; 228 229 DbgPrint("0123456789abcdef0123456789abcdef\n"); 230 for (i = 0; i < 8; i++) 231 { 232 v = APICRead(base + i*0x10); 233 for (j = 0; j < 32; j++) 234 { 235 if (v & (1<<j)) 236 DbgPrint("1"); 237 else 238 DbgPrint("0"); 239 } 240 DbgPrint("\n"); 241 } 242 } 243 244 245 VOID APICDump(VOID) 246 /* 247 * Dump the contents of the local APIC registers 248 */ 249 { 250 ULONG v, ver, maxlvt; 251 ULONG r1, r2, w1, w2; 252 ULONG CPU = ThisCPU(); 253 254 255 r1 = lastregr[CPU]; 256 r2 = lastvalr[CPU]; 257 w1 = lastregw[CPU]; 258 w2 = lastvalw[CPU]; 259 260 DbgPrint("\nPrinting local APIC contents on CPU(%d):\n", ThisCPU()); 261 v = APICRead(APIC_ID); 262 DbgPrint("... ID : %08x (%01x) ", v, GET_APIC_ID(v)); 263 v = APICRead(APIC_VER); 264 DbgPrint("... VERSION: %08x\n", v); 265 ver = GET_APIC_VERSION(v); 266 maxlvt = APICGetMaxLVT(); 267 268 v = APICRead(APIC_TPR); 269 DbgPrint("... TPR : %08x (%02x)", v, v & ~0); 270 271 if (APIC_INTEGRATED(ver)) 272 { 273 /* !82489DX */ 274 v = APICRead(APIC_APR); 275 DbgPrint("... APR : %08x (%02x)\n", v, v & ~0); 276 v = APICRead(APIC_PPR); 277 DbgPrint("... PPR : %08x\n", v); 278 } 279 280 v = APICRead(APIC_EOI); 281 DbgPrint("... EOI : %08x ! ", v); 282 v = APICRead(APIC_LDR); 283 DbgPrint("... LDR : %08x\n", v); 284 v = APICRead(APIC_DFR); 285 DbgPrint("... DFR : %08x ! ", v); 286 v = APICRead(APIC_SIVR); 287 DbgPrint("... SIVR : %08x\n", v); 288 289 if (0) 290 { 291 DbgPrint("... ISR field:\n"); 292 APICDumpBit(APIC_ISR); 293 DbgPrint("... TMR field:\n"); 294 APICDumpBit(APIC_TMR); 295 DbgPrint("... IRR field:\n"); 296 APICDumpBit(APIC_IRR); 297 } 298 299 if (APIC_INTEGRATED(ver)) 300 { 301 /* !82489DX */ 302 if (maxlvt > 3) 303 { 304 /* Due to the Pentium erratum 3AP. */ 305 APICWrite(APIC_ESR, 0); 306 } 307 v = APICRead(APIC_ESR); 308 DbgPrint("... ESR : %08x\n", v); 309 } 310 311 v = APICRead(APIC_ICR0); 312 DbgPrint("... ICR0 : %08x ! ", v); 313 v = APICRead(APIC_ICR1); 314 DbgPrint("... ICR1 : %08x ! ", v); 315 316 v = APICRead(APIC_LVTT); 317 DbgPrint("... LVTT : %08x\n", v); 318 319 if (maxlvt > 3) 320 { 321 /* PC is LVT#4. */ 322 v = APICRead(APIC_LVTPC); 323 DbgPrint("... LVTPC : %08x ! ", v); 324 } 325 v = APICRead(APIC_LINT0); 326 DbgPrint("... LINT0 : %08x ! ", v); 327 v = APICRead(APIC_LINT1); 328 DbgPrint("... LINT1 : %08x\n", v); 329 330 if (maxlvt > 2) 331 { 332 v = APICRead(APIC_LVT3); 333 DbgPrint("... LVT3 : %08x\n", v); 334 } 335 336 v = APICRead(APIC_ICRT); 337 DbgPrint("... ICRT : %08x ! ", v); 338 v = APICRead(APIC_CCRT); 339 DbgPrint("... CCCT : %08x ! ", v); 340 v = APICRead(APIC_TDCR); 341 DbgPrint("... TDCR : %08x\n", v); 342 DbgPrint("\n"); 343 DbgPrint("Last register read (offset): 0x%08X\n", r1); 344 DbgPrint("Last register read (value): 0x%08X\n", r2); 345 DbgPrint("Last register written (offset): 0x%08X\n", w1); 346 DbgPrint("Last register written (value): 0x%08X\n", w2); 347 DbgPrint("\n"); 348 } 349 350 BOOLEAN VerifyLocalAPIC(VOID) 351 { 352 SIZE_T reg0, reg1; 353 LARGE_INTEGER MsrValue; 354 355 /* The version register is read-only in a real APIC */ 356 reg0 = APICRead(APIC_VER); 357 DPRINT1("Getting VERSION: %x\n", reg0); 358 APICWrite(APIC_VER, reg0 ^ APIC_VER_MASK); 359 reg1 = APICRead(APIC_VER); 360 DPRINT1("Getting VERSION: %x\n", reg1); 361 362 /* 363 * The two version reads above should print the same 364 * numbers. If the second one is different, then we 365 * poke at a non-APIC. 366 */ 367 368 if (reg1 != reg0) 369 { 370 return FALSE; 371 } 372 373 /* 374 * Check if the version looks reasonably. 375 */ 376 reg1 = GET_APIC_VERSION(reg0); 377 if (reg1 == 0x00 || reg1 == 0xff) 378 { 379 return FALSE; 380 } 381 reg1 = APICGetMaxLVT(); 382 if (reg1 < 0x02 || reg1 == 0xff) 383 { 384 return FALSE; 385 } 386 387 /* 388 * The ID register is read/write in a real APIC. 389 */ 390 reg0 = APICRead(APIC_ID); 391 DPRINT1("Getting ID: %x\n", reg0); 392 APICWrite(APIC_ID, reg0 ^ APIC_ID_MASK); 393 reg1 = APICRead(APIC_ID); 394 DPRINT1("Getting ID: %x\n", reg1); 395 APICWrite(APIC_ID, reg0); 396 if (reg1 != (reg0 ^ APIC_ID_MASK)) 397 { 398 return FALSE; 399 } 400 401 MsrValue.QuadPart = __readmsr(0x1B /*MSR_IA32_APICBASE*/); 402 403 if (!(MsrValue.LowPart & /*MSR_IA32_APICBASE_ENABLE*/(1<<11))) 404 { 405 DPRINT1("Local APIC disabled by BIOS -- reenabling.\n"); 406 MsrValue.LowPart &= ~/*MSR_IA32_APICBASE_BASE*/(1<<11); 407 MsrValue.LowPart |= /*MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE*/(1<<11)|0xfee00000; 408 __writemsr(0x1B /*MSR_IA32_APICBASE*/, MsrValue.HighPart); 409 } 410 411 412 413 return TRUE; 414 } 415 416 #ifdef CONFIG_SMP 417 VOID APICSendIPI(ULONG Target, ULONG Mode) 418 { 419 ULONG tmp, i, flags; 420 421 /* save flags and disable interrupts */ 422 flags = __readeflags(); 423 _disable(); 424 425 /* Wait up to 100ms for the APIC to become ready */ 426 for (i = 0; i < 10000; i++) 427 { 428 tmp = APICRead(APIC_ICR0); 429 /* Check Delivery Status */ 430 if ((tmp & APIC_ICR0_DS) == 0) 431 break; 432 KeStallExecutionProcessor(10); 433 } 434 435 if (i == 10000) 436 { 437 DPRINT1("CPU(%d) Previous IPI was not delivered after 100ms.\n", ThisCPU()); 438 } 439 440 /* Setup the APIC to deliver the IPI */ 441 DPRINT("%08x %x\n", SET_APIC_DEST_FIELD(Target), Target); 442 APICWrite(APIC_ICR1, SET_APIC_DEST_FIELD(Target)); 443 444 if (Target == APIC_TARGET_SELF) 445 { 446 Mode |= APIC_ICR0_DESTS_SELF; 447 } 448 else if (Target == APIC_TARGET_ALL) 449 { 450 Mode |= APIC_ICR0_DESTS_ALL; 451 } 452 else if (Target == APIC_TARGET_ALL_BUT_SELF) 453 { 454 Mode |= APIC_ICR0_DESTS_ALL_BUT_SELF; 455 } 456 else 457 { 458 Mode |= APIC_ICR0_DESTS_FIELD; 459 } 460 461 /* Now, fire off the IPI */ 462 APICWrite(APIC_ICR0, Mode); 463 464 /* Wait up to 100ms for the APIC to become ready */ 465 for (i = 0; i < 10000; i++) 466 { 467 tmp = APICRead(APIC_ICR0); 468 /* Check Delivery Status */ 469 if ((tmp & APIC_ICR0_DS) == 0) 470 break; 471 KeStallExecutionProcessor(10); 472 } 473 474 if (i == 10000) 475 { 476 DPRINT1("CPU(%d) Current IPI was not delivered after 100ms.\n", ThisCPU()); 477 } 478 __writeeflags(flags); 479 } 480 #endif 481 482 VOID APICSetup(VOID) 483 { 484 ULONG CPU, tmp; 485 486 CPU = ThisCPU(); 487 488 // APICDump(); 489 490 DPRINT1("CPU%d:\n", CPU); 491 DPRINT1(" Physical APIC id: %d\n", GET_APIC_ID(APICRead(APIC_ID))); 492 DPRINT1(" Logical APIC id: %d\n", GET_APIC_LOGICAL_ID(APICRead(APIC_LDR))); 493 DPRINT1("%08x %08x %08x\n", APICRead(APIC_ID), APICRead(APIC_LDR), APICRead(APIC_DFR)); 494 495 /* 496 * Intel recommends to set DFR, LDR and TPR before enabling 497 * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel 498 * document number 292116). So here it goes... 499 */ 500 501 /* 502 * Put the APIC into flat delivery mode. 503 * Must be "all ones" explicitly for 82489DX. 504 */ 505 APICWrite(APIC_DFR, 0xFFFFFFFF); 506 507 /* 508 * Set up the logical destination ID. 509 */ 510 tmp = APICRead(APIC_LDR); 511 tmp &= ~APIC_LDR_MASK; 512 /* 513 * FIXME: 514 * This works only up to 8 CPU's 515 */ 516 tmp |= (1 << (KeGetCurrentProcessorNumber() + 24)); 517 APICWrite(APIC_LDR, tmp); 518 519 520 DPRINT1("CPU%d:\n", CPU); 521 DPRINT1(" Physical APIC id: %d\n", GET_APIC_ID(APICRead(APIC_ID))); 522 DPRINT1(" Logical APIC id: %d\n", GET_APIC_LOGICAL_ID(APICRead(APIC_LDR))); 523 DPRINT1("%08x %08x %08x\n", APICRead(APIC_ID), APICRead(APIC_LDR), APICRead(APIC_DFR)); 524 DPRINT1("%d\n", CPUMap[CPU].APICId); 525 526 /* Accept only higher interrupts */ 527 APICWrite(APIC_TPR, 0xef); 528 529 /* Enable local APIC */ 530 tmp = APICRead(APIC_SIVR); 531 tmp &= ~0xff; 532 tmp |= APIC_SIVR_ENABLE; 533 534 #if 0 535 tmp &= ~APIC_SIVR_FOCUS; 536 #else 537 tmp |= APIC_SIVR_FOCUS; 538 #endif 539 540 /* Set spurious interrupt vector */ 541 tmp |= SPURIOUS_VECTOR; 542 APICWrite(APIC_SIVR, tmp); 543 544 /* 545 * Set up LVT0, LVT1: 546 * 547 * set up through-local-APIC on the BP's LINT0. This is not 548 * strictly necessery in pure symmetric-IO mode, but sometimes 549 * we delegate interrupts to the 8259A. 550 */ 551 tmp = APICRead(APIC_LINT0) & APIC_LVT_MASKED; 552 if (CPU == BootCPU && (APICMode == amPIC || !tmp)) 553 { 554 tmp = APIC_DM_EXTINT; 555 DPRINT1("enabled ExtINT on CPU#%d\n", CPU); 556 } 557 else 558 { 559 tmp = APIC_DM_EXTINT | APIC_LVT_MASKED; 560 DPRINT1("masked ExtINT on CPU#%d\n", CPU); 561 } 562 APICWrite(APIC_LINT0, tmp); 563 564 /* 565 * Only the BSP should see the LINT1 NMI signal, obviously. 566 */ 567 if (CPU == BootCPU) 568 { 569 tmp = APIC_DM_NMI; 570 } 571 else 572 { 573 tmp = APIC_DM_NMI | APIC_LVT_MASKED; 574 } 575 if (!APIC_INTEGRATED(CPUMap[CPU].APICVersion)) 576 { 577 /* 82489DX */ 578 tmp |= APIC_LVT_LEVEL_TRIGGER; 579 } 580 APICWrite(APIC_LINT1, tmp); 581 582 if (APIC_INTEGRATED(CPUMap[CPU].APICVersion)) 583 { 584 /* !82489DX */ 585 if (APICGetMaxLVT() > 3) 586 { 587 /* Due to the Pentium erratum 3AP */ 588 APICWrite(APIC_ESR, 0); 589 } 590 591 tmp = APICRead(APIC_ESR); 592 DPRINT("ESR value before enabling vector: 0x%X\n", tmp); 593 594 /* Enable sending errors */ 595 tmp = ERROR_VECTOR; 596 APICWrite(APIC_LVT3, tmp); 597 598 /* 599 * Spec says clear errors after enabling vector 600 */ 601 if (APICGetMaxLVT() > 3) 602 { 603 APICWrite(APIC_ESR, 0); 604 } 605 tmp = APICRead(APIC_ESR); 606 DPRINT("ESR value after enabling vector: 0x%X\n", tmp); 607 } 608 } 609 #ifdef CONFIG_SMP 610 VOID APICSyncArbIDs(VOID) 611 { 612 ULONG i, tmp; 613 614 /* Wait up to 100ms for the APIC to become ready */ 615 for (i = 0; i < 10000; i++) 616 { 617 tmp = APICRead(APIC_ICR0); 618 /* Check Delivery Status */ 619 if ((tmp & APIC_ICR0_DS) == 0) 620 break; 621 KeStallExecutionProcessor(10); 622 } 623 624 if (i == 10000) 625 { 626 DPRINT("CPU(%d) APIC busy for 100ms.\n", ThisCPU()); 627 } 628 629 DPRINT("Synchronizing Arb IDs.\n"); 630 APICWrite(APIC_ICR0, APIC_ICR0_DESTS_ALL | APIC_ICR0_LEVEL | APIC_DM_INIT); 631 } 632 #endif 633 634 VOID MpsErrorHandler(VOID) 635 { 636 ULONG tmp1, tmp2; 637 638 APICDump(); 639 640 tmp1 = APICRead(APIC_ESR); 641 APICWrite(APIC_ESR, 0); 642 tmp2 = APICRead(APIC_ESR); 643 DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1, tmp2); 644 645 /* 646 * Acknowledge the interrupt 647 */ 648 APICSendEOI(); 649 650 /* Here is what the APIC error bits mean: 651 * 0: Send CS error 652 * 1: Receive CS error 653 * 2: Send accept error 654 * 3: Receive accept error 655 * 4: Reserved 656 * 5: Send illegal vector 657 * 6: Received illegal vector 658 * 7: Illegal register address 659 */ 660 DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1, tmp2); 661 for (;;); 662 } 663 664 VOID MpsSpuriousHandler(VOID) 665 { 666 ULONG tmp; 667 668 DPRINT("Spurious interrupt on CPU(%d)\n", ThisCPU()); 669 670 tmp = APICRead(APIC_ISR + ((SPURIOUS_VECTOR & ~0x1f) >> 1)); 671 if (tmp & (1 << (SPURIOUS_VECTOR & 0x1f))) 672 { 673 APICSendEOI(); 674 return; 675 } 676 #if 0 677 /* No need to send EOI here */ 678 APICDump(); 679 #endif 680 } 681 682 #ifdef CONFIG_SMP 683 VOID MpsIpiHandler(VOID) 684 { 685 KIRQL oldIrql; 686 687 HalBeginSystemInterrupt(IPI_LEVEL, 688 IPI_VECTOR, 689 &oldIrql); 690 _enable(); 691 #if 0 692 DbgPrint("(%s:%d) MpsIpiHandler on CPU%d, current irql is %d\n", 693 __FILE__,__LINE__, KeGetCurrentProcessorNumber(), KeGetCurrentIrql()); 694 #endif 695 696 KiIpiServiceRoutine(NULL, NULL); 697 698 #if 0 699 DbgPrint("(%s:%d) MpsIpiHandler on CPU%d done\n", __FILE__,__LINE__, KeGetCurrentProcessorNumber()); 700 #endif 701 702 _disable(); 703 HalEndSystemInterrupt(oldIrql, 0); 704 } 705 #endif 706 707 VOID 708 MpsIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame, 709 PKTRAP_FRAME TrapFrame) 710 { 711 #ifdef _M_AMD64 712 UNIMPLEMENTED; 713 #else 714 TrapFrame->SegGs = (USHORT)IrqTrapFrame->Gs; 715 TrapFrame->SegFs = (USHORT)IrqTrapFrame->Fs; 716 TrapFrame->SegEs = (USHORT)IrqTrapFrame->Es; 717 TrapFrame->SegDs = (USHORT)IrqTrapFrame->Ds; 718 TrapFrame->Eax = IrqTrapFrame->Eax; 719 TrapFrame->Ecx = IrqTrapFrame->Ecx; 720 TrapFrame->Edx = IrqTrapFrame->Edx; 721 TrapFrame->Ebx = IrqTrapFrame->Ebx; 722 TrapFrame->HardwareEsp = IrqTrapFrame->Esp; 723 TrapFrame->Ebp = IrqTrapFrame->Ebp; 724 TrapFrame->Esi = IrqTrapFrame->Esi; 725 TrapFrame->Edi = IrqTrapFrame->Edi; 726 TrapFrame->Eip = IrqTrapFrame->Eip; 727 TrapFrame->SegCs = IrqTrapFrame->Cs; 728 TrapFrame->EFlags = IrqTrapFrame->Eflags; 729 #endif 730 } 731 732 VOID 733 MpsTimerHandler(ULONG Vector, PKIRQ_TRAPFRAME Trapframe) 734 { 735 KIRQL oldIrql; 736 KTRAP_FRAME KernelTrapFrame; 737 #if 0 738 ULONG CPU; 739 static ULONG Count[MAX_CPU] = {0,}; 740 #endif 741 HalBeginSystemInterrupt(LOCAL_TIMER_VECTOR, 742 PROFILE_LEVEL, 743 &oldIrql); 744 _enable(); 745 746 #if 0 747 CPU = ThisCPU(); 748 if ((Count[CPU] % 100) == 0) 749 { 750 DbgPrint("(%s:%d) MpsTimerHandler on CPU%d, irql = %d, epi = %x, KPCR = %x\n", __FILE__, __LINE__, CPU, oldIrql,Trapframe->Eip, KeGetPcr()); 751 } 752 Count[CPU]++; 753 #endif 754 755 /* FIXME: SMP is totally broken */ 756 MpsIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame); 757 if (KeGetCurrentProcessorNumber() == 0) 758 { 759 //KeUpdateSystemTime(&KernelTrapFrame, oldIrql); 760 } 761 else 762 { 763 //KeUpdateRunTime(&KernelTrapFrame, oldIrql); 764 } 765 766 _disable(); 767 HalEndSystemInterrupt (oldIrql, 0); 768 } 769 770 VOID APICSetupLVTT(ULONG ClockTicks) 771 { 772 ULONG tmp; 773 774 tmp = GET_APIC_VERSION(APICRead(APIC_VER)); 775 if (!APIC_INTEGRATED(tmp)) 776 { 777 tmp = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) | APIC_LVT_PERIODIC | LOCAL_TIMER_VECTOR; 778 } 779 else 780 { 781 /* Periodic timer */ 782 tmp = APIC_LVT_PERIODIC | LOCAL_TIMER_VECTOR; 783 } 784 APICWrite(APIC_LVTT, tmp); 785 786 tmp = APICRead(APIC_TDCR); 787 tmp &= ~(APIC_TDCR_1 | APIC_TIMER_BASE_DIV); 788 tmp |= APIC_TDCR_16; 789 APICWrite(APIC_TDCR, tmp); 790 APICWrite(APIC_ICRT, ClockTicks / APIC_DIVISOR); 791 } 792 793 VOID 794 APICCalibrateTimer(ULONG CPU) 795 { 796 ULARGE_INTEGER t1, t2; 797 LONG tt1, tt2; 798 BOOLEAN TSCPresent; 799 800 DPRINT("Calibrating APIC timer for CPU %d\n", CPU); 801 802 APICSetupLVTT(1000000000); 803 804 TSCPresent = KeGetCurrentPrcb()->FeatureBits & KF_RDTSC ? TRUE : FALSE; 805 806 /* 807 * The timer chip counts down to zero. Let's wait 808 * for a wraparound to start exact measurement: 809 * (the current tick might have been already half done) 810 */ 811 //WaitFor8254Wraparound(); 812 813 /* 814 * We wrapped around just now. Let's start 815 */ 816 if (TSCPresent) 817 { 818 t1.QuadPart = (LONGLONG)__rdtsc(); 819 } 820 tt1 = APICRead(APIC_CCRT); 821 822 //WaitFor8254Wraparound(); 823 824 825 tt2 = APICRead(APIC_CCRT); 826 if (TSCPresent) 827 { 828 t2.QuadPart = (LONGLONG)__rdtsc(); 829 CPUMap[CPU].CoreSpeed = (HZ * (ULONG)(t2.QuadPart - t1.QuadPart)); 830 DPRINT("CPU clock speed is %ld.%04ld MHz.\n", 831 CPUMap[CPU].CoreSpeed/1000000, 832 CPUMap[CPU].CoreSpeed%1000000); 833 KeGetCurrentPrcb()->MHz = CPUMap[CPU].CoreSpeed/1000000; 834 } 835 836 CPUMap[CPU].BusSpeed = (HZ * (long)(tt1 - tt2) * APIC_DIVISOR); 837 838 /* Setup timer for normal operation */ 839 // APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100); // 100ns 840 APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 10000); // 10ms 841 // APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100000); // 100ms 842 843 DPRINT("Host bus clock speed is %ld.%04ld MHz.\n", 844 CPUMap[CPU].BusSpeed/1000000, 845 CPUMap[CPU].BusSpeed%1000000); 846 } 847 848 VOID 849 SetInterruptGate(ULONG index, ULONG_PTR address) 850 { 851 #ifdef _M_AMD64 852 KIDTENTRY64 *idt; 853 854 idt = &KeGetPcr()->IdtBase[index]; 855 856 idt->OffsetLow = address & 0xffff; 857 idt->Selector = KGDT_64_R0_CODE; 858 idt->IstIndex = 0; 859 idt->Reserved0 = 0; 860 idt->Type = 0x0e; 861 idt->Dpl = 0; 862 idt->Present = 1; 863 idt->OffsetMiddle = (address >> 16) & 0xffff; 864 idt->OffsetHigh = address >> 32; 865 idt->Reserved1 = 0; 866 idt->Alignment = 0; 867 #else 868 KIDTENTRY *idt; 869 KIDT_ACCESS Access; 870 871 /* Set the IDT Access Bits */ 872 Access.Reserved = 0; 873 Access.Present = 1; 874 Access.Dpl = 0; /* Kernel-Mode */ 875 Access.SystemSegmentFlag = 0; 876 Access.SegmentType = I386_INTERRUPT_GATE; 877 878 idt = (KIDTENTRY*)((ULONG)KeGetPcr()->IDT + index * sizeof(KIDTENTRY)); 879 idt->Offset = (USHORT)(address & 0xffff); 880 idt->Selector = KGDT_R0_CODE; 881 idt->Access = Access.Value; 882 idt->ExtendedOffset = (USHORT)(address >> 16); 883 #endif 884 } 885 886 VOID HaliInitBSP(VOID) 887 { 888 #ifdef CONFIG_SMP 889 PUSHORT ps; 890 #endif 891 892 static BOOLEAN BSPInitialized = FALSE; 893 894 /* Only initialize the BSP once */ 895 if (BSPInitialized) 896 { 897 ASSERT(FALSE); 898 return; 899 } 900 901 BSPInitialized = TRUE; 902 903 /* Setup interrupt handlers */ 904 SetInterruptGate(LOCAL_TIMER_VECTOR, (ULONG_PTR)MpsTimerInterrupt); 905 SetInterruptGate(ERROR_VECTOR, (ULONG_PTR)MpsErrorInterrupt); 906 SetInterruptGate(SPURIOUS_VECTOR, (ULONG_PTR)MpsSpuriousInterrupt); 907 #ifdef CONFIG_SMP 908 SetInterruptGate(IPI_VECTOR, (ULONG_PTR)MpsIpiInterrupt); 909 #endif 910 DPRINT("APIC is mapped at 0x%X\n", APICBase); 911 912 if (VerifyLocalAPIC()) 913 { 914 DPRINT("APIC found\n"); 915 } 916 else 917 { 918 DPRINT("No APIC found\n"); 919 ASSERT(FALSE); 920 } 921 922 if (APICMode == amPIC) 923 { 924 EnableApicMode(); 925 } 926 927 APICSetup(); 928 929 #ifdef CONFIG_SMP 930 /* BIOS data segment */ 931 BIOSBase = (PULONG)BIOS_AREA; 932 933 /* Area for communicating with the APs */ 934 CommonBase = (PULONG)COMMON_AREA; 935 936 /* Copy bootstrap code to common area */ 937 memcpy((PVOID)((ULONG_PTR)CommonBase + PAGE_SIZE), 938 &APstart, 939 (ULONG_PTR)&APend - (ULONG_PTR)&APstart + 1); 940 941 /* Set shutdown code */ 942 CMOS_WRITE(0xF, 0xA); 943 944 /* Set warm reset vector */ 945 ps = (PUSHORT)((ULONG_PTR)BIOSBase + 0x467); 946 *ps = (COMMON_AREA + PAGE_SIZE) & 0xF; 947 948 ps = (PUSHORT)((ULONG_PTR)BIOSBase + 0x469); 949 *ps = (COMMON_AREA + PAGE_SIZE) >> 4; 950 #endif 951 952 /* Calibrate APIC timer */ 953 APICCalibrateTimer(BootCPU); 954 } 955 956 #ifdef CONFIG_SMP 957 VOID 958 HaliStartApplicationProcessor(ULONG Cpu, ULONG Stack) 959 { 960 ULONG tmp, maxlvt; 961 PCOMMON_AREA_INFO Common; 962 ULONG StartupCount; 963 ULONG i, j; 964 ULONG DeliveryStatus = 0; 965 ULONG AcceptStatus = 0; 966 967 if (Cpu >= MAX_CPU || 968 Cpu >= CPUCount || 969 OnlineCPUs & (1 << Cpu)) 970 { 971 ASSERT(FALSE); 972 } 973 DPRINT1("Attempting to boot CPU %d\n", Cpu); 974 975 /* Send INIT IPI */ 976 977 APICSendIPI(Cpu, APIC_DM_INIT|APIC_ICR0_LEVEL_ASSERT); 978 979 KeStallExecutionProcessor(200); 980 981 /* Deassert INIT */ 982 983 APICSendIPI(Cpu, APIC_DM_INIT|APIC_ICR0_LEVEL_DEASSERT); 984 985 if (APIC_INTEGRATED(CPUMap[Cpu].APICVersion)) 986 { 987 /* Clear APIC errors */ 988 APICWrite(APIC_ESR, 0); 989 tmp = (APICRead(APIC_ESR) & APIC_ESR_MASK); 990 } 991 992 Common = (PCOMMON_AREA_INFO)CommonBase; 993 994 /* Write the location of the AP stack */ 995 Common->Stack = (ULONG)Stack; 996 /* Write the page directory page */ 997 Common->PageDirectory = __readcr3(); 998 /* Write the kernel entry point */ 999 Common->NtProcessStartup = (ULONG_PTR)RtlImageNtHeader((PVOID)KernelBase)->OptionalHeader.AddressOfEntryPoint + KernelBase; 1000 /* Write the state of the mae mode */ 1001 Common->PaeModeEnabled = __readcr4() & CR4_PAE ? 1 : 0; 1002 1003 DPRINT1("%x %x %x %x\n", Common->Stack, Common->PageDirectory, Common->NtProcessStartup, Common->PaeModeEnabled); 1004 1005 DPRINT("Cpu %d got stack at 0x%X\n", Cpu, Common->Stack); 1006 #if 0 1007 for (j = 0; j < 16; j++) 1008 { 1009 Common->Debug[j] = 0; 1010 } 1011 #endif 1012 1013 maxlvt = APICGetMaxLVT(); 1014 1015 /* Is this a local APIC or an 82489DX? */ 1016 StartupCount = (APIC_INTEGRATED(CPUMap[Cpu].APICVersion)) ? 2 : 0; 1017 1018 for (i = 1; i <= StartupCount; i++) 1019 { 1020 /* It's a local APIC, so send STARTUP IPI */ 1021 DPRINT("Sending startup signal %d\n", i); 1022 /* Clear errors */ 1023 APICWrite(APIC_ESR, 0); 1024 APICRead(APIC_ESR); 1025 1026 APICSendIPI(Cpu, APIC_DM_STARTUP | ((COMMON_AREA + PAGE_SIZE) >> 12)|APIC_ICR0_LEVEL_DEASSERT); 1027 1028 /* Wait up to 10ms for IPI to be delivered */ 1029 j = 0; 1030 do 1031 { 1032 KeStallExecutionProcessor(10); 1033 1034 /* Check Delivery Status */ 1035 DeliveryStatus = APICRead(APIC_ICR0) & APIC_ICR0_DS; 1036 1037 j++; 1038 } while ((DeliveryStatus) && (j < 1000)); 1039 1040 KeStallExecutionProcessor(200); 1041 1042 /* 1043 * Due to the Pentium erratum 3AP. 1044 */ 1045 if (maxlvt > 3) 1046 { 1047 APICRead(APIC_SIVR); 1048 APICWrite(APIC_ESR, 0); 1049 } 1050 1051 AcceptStatus = APICRead(APIC_ESR) & APIC_ESR_MASK; 1052 1053 if (DeliveryStatus || AcceptStatus) 1054 { 1055 break; 1056 } 1057 } 1058 1059 if (DeliveryStatus) 1060 { 1061 DPRINT("STARTUP IPI for CPU %d was never delivered.\n", Cpu); 1062 } 1063 1064 if (AcceptStatus) 1065 { 1066 DPRINT("STARTUP IPI for CPU %d was never accepted.\n", Cpu); 1067 } 1068 1069 if (!(DeliveryStatus || AcceptStatus)) 1070 { 1071 1072 /* Wait no more than 5 seconds for processor to boot */ 1073 DPRINT("Waiting for 5 seconds for CPU %d to boot\n", Cpu); 1074 1075 /* Wait no more than 5 seconds */ 1076 for (j = 0; j < 50000; j++) 1077 { 1078 if (CPUMap[Cpu].Flags & CPU_ENABLED) 1079 { 1080 break; 1081 } 1082 KeStallExecutionProcessor(100); 1083 } 1084 } 1085 1086 if (CPUMap[Cpu].Flags & CPU_ENABLED) 1087 { 1088 DbgPrint("CPU %d is now running\n", Cpu); 1089 } 1090 else 1091 { 1092 DbgPrint("Initialization of CPU %d failed\n", Cpu); 1093 } 1094 1095 #if 0 1096 DPRINT("Debug bytes are:\n"); 1097 1098 for (j = 0; j < 4; j++) 1099 { 1100 DPRINT("0x%08X 0x%08X 0x%08X 0x%08X.\n", 1101 Common->Debug[j*4+0], 1102 Common->Debug[j*4+1], 1103 Common->Debug[j*4+2], 1104 Common->Debug[j*4+3]); 1105 } 1106 1107 #endif 1108 } 1109 1110 #endif 1111 1112 VOID 1113 FASTCALL 1114 DECLSPEC_NORETURN 1115 HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame) 1116 { 1117 /* Set up a fake INT Stack */ 1118 TrapFrame->EFlags = __readeflags(); 1119 TrapFrame->SegCs = KGDT_R0_CODE; 1120 TrapFrame->Eip = TrapFrame->Eax; 1121 1122 /* Build the trap frame */ 1123 KiEnterInterruptTrap(TrapFrame); 1124 1125 /* unimplemented */ 1126 UNIMPLEMENTED; 1127 1128 /* Exit the interrupt */ 1129 KiEoiHelper(TrapFrame); 1130 1131 } 1132 1133 /* EOF */ 1134