Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenapic.c
Go to the documentation of this file.
00001 /* 00002 * ReactOS kernel 00003 * Copyright (C) 2004, 2005 ReactOS Team 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License as published by 00007 * the Free Software Foundation; either version 2 of the License, or 00008 * (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License along 00016 * with this program; if not, write to the Free Software Foundation, Inc., 00017 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00018 */ 00019 /* $Id: apic.c 45565 2010-02-10 23:24:59Z tkreuzer $ 00020 * 00021 * COPYRIGHT: See COPYING in the top level directory 00022 * PROJECT: ReactOS kernel 00023 * FILE: hal/halx86/mp/apic.c 00024 * PURPOSE: 00025 * PROGRAMMER: 00026 */ 00027 00028 /* INCLUDE ***********************************************************************/ 00029 00030 #include <hal.h> 00031 #include <halfuncs.h> /* Not in PCH because only used for MP HAL */ 00032 #include <rtlfuncs.h> /* Not in PCH because only used for MP HAL */ 00033 #define NDEBUG 00034 #include <debug.h> 00035 00036 /* GLOBALS ***********************************************************************/ 00037 00038 ULONG CPUCount; /* Total number of CPUs */ 00039 ULONG BootCPU; /* Bootstrap processor */ 00040 ULONG OnlineCPUs; /* Bitmask of online CPUs */ 00041 CPU_INFO CPUMap[MAX_CPU]; /* Map of all CPUs in the system */ 00042 00043 #ifdef CONFIG_SMP 00044 PULONG BIOSBase; /* Virtual address of BIOS data segment */ 00045 PULONG CommonBase; /* Virtual address of common area */ 00046 #endif 00047 00048 PULONG APICBase = (PULONG)APIC_DEFAULT_BASE; /* Virtual address of local APIC */ 00049 00050 ULONG APICMode; /* APIC mode at startup */ 00051 00052 /* For debugging */ 00053 ULONG lastregr[MAX_CPU]; 00054 ULONG lastvalr[MAX_CPU]; 00055 ULONG lastregw[MAX_CPU]; 00056 ULONG lastvalw[MAX_CPU]; 00057 00058 #ifdef CONFIG_SMP 00059 #include <pshpack1.h> 00060 typedef struct _COMMON_AREA_INFO 00061 { 00062 ULONG Stack; /* Location of AP stack */ 00063 ULONG PageDirectory; /* Page directory for an AP */ 00064 ULONG NtProcessStartup; /* Kernel entry point for an AP */ 00065 ULONG PaeModeEnabled; /* PAE mode is enabled */ 00066 ULONG Debug[16]; /* For debugging */ 00067 } COMMON_AREA_INFO, *PCOMMON_AREA_INFO; 00068 #include <poppack.h> 00069 #endif 00070 00071 extern CHAR *APstart, *APend; 00072 00073 #define BIOS_AREA 0x0 00074 #define COMMON_AREA 0x2000 00075 00076 #define HZ (100) 00077 #define APIC_DIVISOR (16) 00078 00079 #define CMOS_READ(address) { \ 00080 WRITE_PORT_UCHAR((PUCHAR)0x70, address)); \ 00081 READ_PORT_UCHAR((PUCHAR)0x71)); \ 00082 } 00083 00084 #define CMOS_WRITE(address, value) { \ 00085 WRITE_PORT_UCHAR((PUCHAR)0x70, address); \ 00086 WRITE_PORT_UCHAR((PUCHAR)0x71, value); \ 00087 } 00088 00089 extern ULONG_PTR KernelBase; 00090 00091 /* FUNCTIONS *********************************************************************/ 00092 00093 extern ULONG Read8254Timer(VOID); 00094 extern VOID WaitFor8254Wraparound(VOID); 00095 extern VOID MpsTimerInterrupt(VOID); 00096 extern VOID MpsErrorInterrupt(VOID); 00097 extern VOID MpsSpuriousInterrupt(VOID); 00098 extern VOID MpsIpiInterrupt(VOID); 00099 00100 ULONG APICGetMaxLVT(VOID) 00101 { 00102 ULONG tmp, ver, maxlvt; 00103 00104 tmp = APICRead(APIC_VER); 00105 ver = GET_APIC_VERSION(tmp); 00106 /* 82489DXs do not report # of LVT entries. */ 00107 maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(tmp) : 2; 00108 00109 return maxlvt; 00110 } 00111 00112 VOID APICClear(VOID) 00113 { 00114 ULONG tmp, maxlvt; 00115 00116 maxlvt = APICGetMaxLVT(); 00117 00118 /* 00119 * Careful: we have to set masks only first to deassert 00120 * any level-triggered sources. 00121 */ 00122 00123 if (maxlvt >= 3) 00124 { 00125 tmp = ERROR_VECTOR; 00126 APICWrite(APIC_LVT3, tmp | APIC_LVT3_MASKED); 00127 } 00128 00129 tmp = APICRead(APIC_LVTT); 00130 APICWrite(APIC_LVTT, tmp | APIC_LVT_MASKED); 00131 00132 tmp = APICRead(APIC_LINT0); 00133 APICWrite(APIC_LINT0, tmp | APIC_LVT_MASKED); 00134 00135 tmp = APICRead(APIC_LINT1); 00136 APICWrite(APIC_LINT1, tmp | APIC_LVT_MASKED); 00137 00138 if (maxlvt >= 4) 00139 { 00140 tmp = APICRead(APIC_LVTPC); 00141 APICWrite(APIC_LVTPC, tmp | APIC_LVT_MASKED); 00142 } 00143 #if 0 00144 if (maxlvt >= 5) 00145 { 00146 tmp = APICRead(APIC_LVTTHMR); 00147 APICWrite(APIC_LVTTHMR, tmp | APIC_LVT_MASKED); 00148 } 00149 #endif 00150 /* 00151 * Clean APIC state for other OSs: 00152 */ 00153 APICWrite(APIC_LVTT, APIC_LVT_MASKED); 00154 APICWrite(APIC_LINT0, APIC_LVT_MASKED); 00155 APICWrite(APIC_LINT1, APIC_LVT_MASKED); 00156 00157 if (maxlvt >= 3) 00158 { 00159 APICWrite(APIC_LVT3, APIC_LVT3_MASKED); 00160 } 00161 00162 if (maxlvt >= 4) 00163 { 00164 APICWrite(APIC_LVTPC, APIC_LVT_MASKED); 00165 } 00166 #if 0 00167 if (maxlvt >= 5) 00168 { 00169 APICWrite(APIC_LVTTHMR, APIC_LVT_MASKED); 00170 } 00171 #endif 00172 } 00173 00174 /* Enable symetric I/O mode ie. connect the BSP's local APIC to INT and NMI lines */ 00175 VOID EnableApicMode(VOID) 00176 { 00177 /* 00178 * Do not trust the local APIC being empty at bootup. 00179 */ 00180 APICClear(); 00181 00182 WRITE_PORT_UCHAR((PUCHAR)0x22, 0x70); 00183 WRITE_PORT_UCHAR((PUCHAR)0x23, 0x01); 00184 } 00185 00186 /* Disable symetric I/O mode ie. go to PIC mode */ 00187 __inline VOID DisableSMPMode(VOID) 00188 { 00189 /* 00190 * Put the board back into PIC mode (has an effect 00191 * only on certain older boards). Note that APIC 00192 * interrupts, including IPIs, won't work beyond 00193 * this point! The only exception are INIT IPIs. 00194 */ 00195 WRITE_PORT_UCHAR((PUCHAR)0x22, 0x70); 00196 WRITE_PORT_UCHAR((PUCHAR)0x23, 0x00); 00197 } 00198 00199 VOID DumpESR(VOID) 00200 { 00201 ULONG tmp; 00202 00203 if (APICGetMaxLVT() > 3) 00204 { 00205 APICWrite(APIC_ESR, 0); 00206 } 00207 tmp = APICRead(APIC_ESR); 00208 DbgPrint("ESR %08x\n", tmp); 00209 } 00210 00211 00212 VOID APICDisable(VOID) 00213 { 00214 ULONG tmp; 00215 00216 APICClear(); 00217 00218 /* 00219 * Disable APIC (implies clearing of registers for 82489DX!). 00220 */ 00221 tmp = APICRead(APIC_SIVR); 00222 tmp &= ~APIC_SIVR_ENABLE; 00223 APICWrite(APIC_SIVR, tmp); 00224 } 00225 00226 static VOID APICDumpBit(ULONG base) 00227 { 00228 ULONG v, i, j; 00229 00230 DbgPrint("0123456789abcdef0123456789abcdef\n"); 00231 for (i = 0; i < 8; i++) 00232 { 00233 v = APICRead(base + i*0x10); 00234 for (j = 0; j < 32; j++) 00235 { 00236 if (v & (1<<j)) 00237 DbgPrint("1"); 00238 else 00239 DbgPrint("0"); 00240 } 00241 DbgPrint("\n"); 00242 } 00243 } 00244 00245 00246 VOID APICDump(VOID) 00247 /* 00248 * Dump the contents of the local APIC registers 00249 */ 00250 { 00251 ULONG v, ver, maxlvt; 00252 ULONG r1, r2, w1, w2; 00253 ULONG CPU = ThisCPU(); 00254 00255 00256 r1 = lastregr[CPU]; 00257 r2 = lastvalr[CPU]; 00258 w1 = lastregw[CPU]; 00259 w2 = lastvalw[CPU]; 00260 00261 DbgPrint("\nPrinting local APIC contents on CPU(%d):\n", ThisCPU()); 00262 v = APICRead(APIC_ID); 00263 DbgPrint("... ID : %08x (%01x) ", v, GET_APIC_ID(v)); 00264 v = APICRead(APIC_VER); 00265 DbgPrint("... VERSION: %08x\n", v); 00266 ver = GET_APIC_VERSION(v); 00267 maxlvt = APICGetMaxLVT(); 00268 00269 v = APICRead(APIC_TPR); 00270 DbgPrint("... TPR : %08x (%02x)", v, v & ~0); 00271 00272 if (APIC_INTEGRATED(ver)) 00273 { 00274 /* !82489DX */ 00275 v = APICRead(APIC_APR); 00276 DbgPrint("... APR : %08x (%02x)\n", v, v & ~0); 00277 v = APICRead(APIC_PPR); 00278 DbgPrint("... PPR : %08x\n", v); 00279 } 00280 00281 v = APICRead(APIC_EOI); 00282 DbgPrint("... EOI : %08x ! ", v); 00283 v = APICRead(APIC_LDR); 00284 DbgPrint("... LDR : %08x\n", v); 00285 v = APICRead(APIC_DFR); 00286 DbgPrint("... DFR : %08x ! ", v); 00287 v = APICRead(APIC_SIVR); 00288 DbgPrint("... SIVR : %08x\n", v); 00289 00290 if (0) 00291 { 00292 DbgPrint("... ISR field:\n"); 00293 APICDumpBit(APIC_ISR); 00294 DbgPrint("... TMR field:\n"); 00295 APICDumpBit(APIC_TMR); 00296 DbgPrint("... IRR field:\n"); 00297 APICDumpBit(APIC_IRR); 00298 } 00299 00300 if (APIC_INTEGRATED(ver)) 00301 { 00302 /* !82489DX */ 00303 if (maxlvt > 3) 00304 { 00305 /* Due to the Pentium erratum 3AP. */ 00306 APICWrite(APIC_ESR, 0); 00307 } 00308 v = APICRead(APIC_ESR); 00309 DbgPrint("... ESR : %08x\n", v); 00310 } 00311 00312 v = APICRead(APIC_ICR0); 00313 DbgPrint("... ICR0 : %08x ! ", v); 00314 v = APICRead(APIC_ICR1); 00315 DbgPrint("... ICR1 : %08x ! ", v); 00316 00317 v = APICRead(APIC_LVTT); 00318 DbgPrint("... LVTT : %08x\n", v); 00319 00320 if (maxlvt > 3) 00321 { 00322 /* PC is LVT#4. */ 00323 v = APICRead(APIC_LVTPC); 00324 DbgPrint("... LVTPC : %08x ! ", v); 00325 } 00326 v = APICRead(APIC_LINT0); 00327 DbgPrint("... LINT0 : %08x ! ", v); 00328 v = APICRead(APIC_LINT1); 00329 DbgPrint("... LINT1 : %08x\n", v); 00330 00331 if (maxlvt > 2) 00332 { 00333 v = APICRead(APIC_LVT3); 00334 DbgPrint("... LVT3 : %08x\n", v); 00335 } 00336 00337 v = APICRead(APIC_ICRT); 00338 DbgPrint("... ICRT : %08x ! ", v); 00339 v = APICRead(APIC_CCRT); 00340 DbgPrint("... CCCT : %08x ! ", v); 00341 v = APICRead(APIC_TDCR); 00342 DbgPrint("... TDCR : %08x\n", v); 00343 DbgPrint("\n"); 00344 DbgPrint("Last register read (offset): 0x%08X\n", r1); 00345 DbgPrint("Last register read (value): 0x%08X\n", r2); 00346 DbgPrint("Last register written (offset): 0x%08X\n", w1); 00347 DbgPrint("Last register written (value): 0x%08X\n", w2); 00348 DbgPrint("\n"); 00349 } 00350 00351 BOOLEAN VerifyLocalAPIC(VOID) 00352 { 00353 SIZE_T reg0, reg1; 00354 LARGE_INTEGER MsrValue; 00355 00356 /* The version register is read-only in a real APIC */ 00357 reg0 = APICRead(APIC_VER); 00358 DPRINT1("Getting VERSION: %x\n", reg0); 00359 APICWrite(APIC_VER, reg0 ^ APIC_VER_MASK); 00360 reg1 = APICRead(APIC_VER); 00361 DPRINT1("Getting VERSION: %x\n", reg1); 00362 00363 /* 00364 * The two version reads above should print the same 00365 * numbers. If the second one is different, then we 00366 * poke at a non-APIC. 00367 */ 00368 00369 if (reg1 != reg0) 00370 { 00371 return FALSE; 00372 } 00373 00374 /* 00375 * Check if the version looks reasonably. 00376 */ 00377 reg1 = GET_APIC_VERSION(reg0); 00378 if (reg1 == 0x00 || reg1 == 0xff) 00379 { 00380 return FALSE; 00381 } 00382 reg1 = APICGetMaxLVT(); 00383 if (reg1 < 0x02 || reg1 == 0xff) 00384 { 00385 return FALSE; 00386 } 00387 00388 /* 00389 * The ID register is read/write in a real APIC. 00390 */ 00391 reg0 = APICRead(APIC_ID); 00392 DPRINT1("Getting ID: %x\n", reg0); 00393 APICWrite(APIC_ID, reg0 ^ APIC_ID_MASK); 00394 reg1 = APICRead(APIC_ID); 00395 DPRINT1("Getting ID: %x\n", reg1); 00396 APICWrite(APIC_ID, reg0); 00397 if (reg1 != (reg0 ^ APIC_ID_MASK)) 00398 { 00399 return FALSE; 00400 } 00401 00402 MsrValue.QuadPart = __readmsr(0x1B /*MSR_IA32_APICBASE*/); 00403 00404 if (!(MsrValue.LowPart & /*MSR_IA32_APICBASE_ENABLE*/(1<<11))) 00405 { 00406 DPRINT1("Local APIC disabled by BIOS -- reenabling.\n"); 00407 MsrValue.LowPart &= ~/*MSR_IA32_APICBASE_BASE*/(1<<11); 00408 MsrValue.LowPart |= /*MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE*/(1<<11)|0xfee00000; 00409 __writemsr(0x1B /*MSR_IA32_APICBASE*/, MsrValue.HighPart); 00410 } 00411 00412 00413 00414 return TRUE; 00415 } 00416 00417 #ifdef CONFIG_SMP 00418 VOID APICSendIPI(ULONG Target, ULONG Mode) 00419 { 00420 ULONG tmp, i, flags; 00421 00422 /* save flags and disable interrupts */ 00423 flags = __readeflags(); 00424 _disable(); 00425 00426 /* Wait up to 100ms for the APIC to become ready */ 00427 for (i = 0; i < 10000; i++) 00428 { 00429 tmp = APICRead(APIC_ICR0); 00430 /* Check Delivery Status */ 00431 if ((tmp & APIC_ICR0_DS) == 0) 00432 break; 00433 KeStallExecutionProcessor(10); 00434 } 00435 00436 if (i == 10000) 00437 { 00438 DPRINT1("CPU(%d) Previous IPI was not delivered after 100ms.\n", ThisCPU()); 00439 } 00440 00441 /* Setup the APIC to deliver the IPI */ 00442 DPRINT("%08x %x\n", SET_APIC_DEST_FIELD(Target), Target); 00443 APICWrite(APIC_ICR1, SET_APIC_DEST_FIELD(Target)); 00444 00445 if (Target == APIC_TARGET_SELF) 00446 { 00447 Mode |= APIC_ICR0_DESTS_SELF; 00448 } 00449 else if (Target == APIC_TARGET_ALL) 00450 { 00451 Mode |= APIC_ICR0_DESTS_ALL; 00452 } 00453 else if (Target == APIC_TARGET_ALL_BUT_SELF) 00454 { 00455 Mode |= APIC_ICR0_DESTS_ALL_BUT_SELF; 00456 } 00457 else 00458 { 00459 Mode |= APIC_ICR0_DESTS_FIELD; 00460 } 00461 00462 /* Now, fire off the IPI */ 00463 APICWrite(APIC_ICR0, Mode); 00464 00465 /* Wait up to 100ms for the APIC to become ready */ 00466 for (i = 0; i < 10000; i++) 00467 { 00468 tmp = APICRead(APIC_ICR0); 00469 /* Check Delivery Status */ 00470 if ((tmp & APIC_ICR0_DS) == 0) 00471 break; 00472 KeStallExecutionProcessor(10); 00473 } 00474 00475 if (i == 10000) 00476 { 00477 DPRINT1("CPU(%d) Current IPI was not delivered after 100ms.\n", ThisCPU()); 00478 } 00479 __writeeflags(flags); 00480 } 00481 #endif 00482 00483 VOID APICSetup(VOID) 00484 { 00485 ULONG CPU, tmp; 00486 00487 CPU = ThisCPU(); 00488 00489 // APICDump(); 00490 00491 DPRINT1("CPU%d:\n", CPU); 00492 DPRINT1(" Physical APIC id: %d\n", GET_APIC_ID(APICRead(APIC_ID))); 00493 DPRINT1(" Logical APIC id: %d\n", GET_APIC_LOGICAL_ID(APICRead(APIC_LDR))); 00494 DPRINT1("%08x %08x %08x\n", APICRead(APIC_ID), APICRead(APIC_LDR), APICRead(APIC_DFR)); 00495 00496 /* 00497 * Intel recommends to set DFR, LDR and TPR before enabling 00498 * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel 00499 * document number 292116). So here it goes... 00500 */ 00501 00502 /* 00503 * Put the APIC into flat delivery mode. 00504 * Must be "all ones" explicitly for 82489DX. 00505 */ 00506 APICWrite(APIC_DFR, 0xFFFFFFFF); 00507 00508 /* 00509 * Set up the logical destination ID. 00510 */ 00511 tmp = APICRead(APIC_LDR); 00512 tmp &= ~APIC_LDR_MASK; 00513 /* 00514 * FIXME: 00515 * This works only up to 8 CPU's 00516 */ 00517 tmp |= (1 << (KeGetCurrentProcessorNumber() + 24)); 00518 APICWrite(APIC_LDR, tmp); 00519 00520 00521 DPRINT1("CPU%d:\n", CPU); 00522 DPRINT1(" Physical APIC id: %d\n", GET_APIC_ID(APICRead(APIC_ID))); 00523 DPRINT1(" Logical APIC id: %d\n", GET_APIC_LOGICAL_ID(APICRead(APIC_LDR))); 00524 DPRINT1("%08x %08x %08x\n", APICRead(APIC_ID), APICRead(APIC_LDR), APICRead(APIC_DFR)); 00525 DPRINT1("%d\n", CPUMap[CPU].APICId); 00526 00527 /* Accept only higher interrupts */ 00528 APICWrite(APIC_TPR, 0xef); 00529 00530 /* Enable local APIC */ 00531 tmp = APICRead(APIC_SIVR); 00532 tmp &= ~0xff; 00533 tmp |= APIC_SIVR_ENABLE; 00534 00535 #if 0 00536 tmp &= ~APIC_SIVR_FOCUS; 00537 #else 00538 tmp |= APIC_SIVR_FOCUS; 00539 #endif 00540 00541 /* Set spurious interrupt vector */ 00542 tmp |= SPURIOUS_VECTOR; 00543 APICWrite(APIC_SIVR, tmp); 00544 00545 /* 00546 * Set up LVT0, LVT1: 00547 * 00548 * set up through-local-APIC on the BP's LINT0. This is not 00549 * strictly necessery in pure symmetric-IO mode, but sometimes 00550 * we delegate interrupts to the 8259A. 00551 */ 00552 tmp = APICRead(APIC_LINT0) & APIC_LVT_MASKED; 00553 if (CPU == BootCPU && (APICMode == amPIC || !tmp)) 00554 { 00555 tmp = APIC_DM_EXTINT; 00556 DPRINT1("enabled ExtINT on CPU#%d\n", CPU); 00557 } 00558 else 00559 { 00560 tmp = APIC_DM_EXTINT | APIC_LVT_MASKED; 00561 DPRINT1("masked ExtINT on CPU#%d\n", CPU); 00562 } 00563 APICWrite(APIC_LINT0, tmp); 00564 00565 /* 00566 * Only the BSP should see the LINT1 NMI signal, obviously. 00567 */ 00568 if (CPU == BootCPU) 00569 { 00570 tmp = APIC_DM_NMI; 00571 } 00572 else 00573 { 00574 tmp = APIC_DM_NMI | APIC_LVT_MASKED; 00575 } 00576 if (!APIC_INTEGRATED(CPUMap[CPU].APICVersion)) 00577 { 00578 /* 82489DX */ 00579 tmp |= APIC_LVT_LEVEL_TRIGGER; 00580 } 00581 APICWrite(APIC_LINT1, tmp); 00582 00583 if (APIC_INTEGRATED(CPUMap[CPU].APICVersion)) 00584 { 00585 /* !82489DX */ 00586 if (APICGetMaxLVT() > 3) 00587 { 00588 /* Due to the Pentium erratum 3AP */ 00589 APICWrite(APIC_ESR, 0); 00590 } 00591 00592 tmp = APICRead(APIC_ESR); 00593 DPRINT("ESR value before enabling vector: 0x%X\n", tmp); 00594 00595 /* Enable sending errors */ 00596 tmp = ERROR_VECTOR; 00597 APICWrite(APIC_LVT3, tmp); 00598 00599 /* 00600 * Spec says clear errors after enabling vector 00601 */ 00602 if (APICGetMaxLVT() > 3) 00603 { 00604 APICWrite(APIC_ESR, 0); 00605 } 00606 tmp = APICRead(APIC_ESR); 00607 DPRINT("ESR value after enabling vector: 0x%X\n", tmp); 00608 } 00609 } 00610 #ifdef CONFIG_SMP 00611 VOID APICSyncArbIDs(VOID) 00612 { 00613 ULONG i, tmp; 00614 00615 /* Wait up to 100ms for the APIC to become ready */ 00616 for (i = 0; i < 10000; i++) 00617 { 00618 tmp = APICRead(APIC_ICR0); 00619 /* Check Delivery Status */ 00620 if ((tmp & APIC_ICR0_DS) == 0) 00621 break; 00622 KeStallExecutionProcessor(10); 00623 } 00624 00625 if (i == 10000) 00626 { 00627 DPRINT("CPU(%d) APIC busy for 100ms.\n", ThisCPU()); 00628 } 00629 00630 DPRINT("Synchronizing Arb IDs.\n"); 00631 APICWrite(APIC_ICR0, APIC_ICR0_DESTS_ALL | APIC_ICR0_LEVEL | APIC_DM_INIT); 00632 } 00633 #endif 00634 00635 VOID MpsErrorHandler(VOID) 00636 { 00637 ULONG tmp1, tmp2; 00638 00639 APICDump(); 00640 00641 tmp1 = APICRead(APIC_ESR); 00642 APICWrite(APIC_ESR, 0); 00643 tmp2 = APICRead(APIC_ESR); 00644 DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1, tmp2); 00645 00646 /* 00647 * Acknowledge the interrupt 00648 */ 00649 APICSendEOI(); 00650 00651 /* Here is what the APIC error bits mean: 00652 * 0: Send CS error 00653 * 1: Receive CS error 00654 * 2: Send accept error 00655 * 3: Receive accept error 00656 * 4: Reserved 00657 * 5: Send illegal vector 00658 * 6: Received illegal vector 00659 * 7: Illegal register address 00660 */ 00661 DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1, tmp2); 00662 for (;;); 00663 } 00664 00665 VOID MpsSpuriousHandler(VOID) 00666 { 00667 ULONG tmp; 00668 00669 DPRINT("Spurious interrupt on CPU(%d)\n", ThisCPU()); 00670 00671 tmp = APICRead(APIC_ISR + ((SPURIOUS_VECTOR & ~0x1f) >> 1)); 00672 if (tmp & (1 << (SPURIOUS_VECTOR & 0x1f))) 00673 { 00674 APICSendEOI(); 00675 return; 00676 } 00677 #if 0 00678 /* No need to send EOI here */ 00679 APICDump(); 00680 #endif 00681 } 00682 00683 #ifdef CONFIG_SMP 00684 VOID MpsIpiHandler(VOID) 00685 { 00686 KIRQL oldIrql; 00687 00688 HalBeginSystemInterrupt(IPI_LEVEL, 00689 IPI_VECTOR, 00690 &oldIrql); 00691 _enable(); 00692 #if 0 00693 DbgPrint("(%s:%d) MpsIpiHandler on CPU%d, current irql is %d\n", 00694 __FILE__,__LINE__, KeGetCurrentProcessorNumber(), KeGetCurrentIrql()); 00695 #endif 00696 00697 KiIpiServiceRoutine(NULL, NULL); 00698 00699 #if 0 00700 DbgPrint("(%s:%d) MpsIpiHandler on CPU%d done\n", __FILE__,__LINE__, KeGetCurrentProcessorNumber()); 00701 #endif 00702 00703 _disable(); 00704 HalEndSystemInterrupt(oldIrql, 0); 00705 } 00706 #endif 00707 00708 VOID 00709 MpsIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame, 00710 PKTRAP_FRAME TrapFrame) 00711 { 00712 #ifdef _M_AMD64 00713 UNIMPLEMENTED; 00714 #else 00715 TrapFrame->SegGs = (USHORT)IrqTrapFrame->Gs; 00716 TrapFrame->SegFs = (USHORT)IrqTrapFrame->Fs; 00717 TrapFrame->SegEs = (USHORT)IrqTrapFrame->Es; 00718 TrapFrame->SegDs = (USHORT)IrqTrapFrame->Ds; 00719 TrapFrame->Eax = IrqTrapFrame->Eax; 00720 TrapFrame->Ecx = IrqTrapFrame->Ecx; 00721 TrapFrame->Edx = IrqTrapFrame->Edx; 00722 TrapFrame->Ebx = IrqTrapFrame->Ebx; 00723 TrapFrame->HardwareEsp = IrqTrapFrame->Esp; 00724 TrapFrame->Ebp = IrqTrapFrame->Ebp; 00725 TrapFrame->Esi = IrqTrapFrame->Esi; 00726 TrapFrame->Edi = IrqTrapFrame->Edi; 00727 TrapFrame->Eip = IrqTrapFrame->Eip; 00728 TrapFrame->SegCs = IrqTrapFrame->Cs; 00729 TrapFrame->EFlags = IrqTrapFrame->Eflags; 00730 #endif 00731 } 00732 00733 VOID 00734 MpsTimerHandler(ULONG Vector, PKIRQ_TRAPFRAME Trapframe) 00735 { 00736 KIRQL oldIrql; 00737 KTRAP_FRAME KernelTrapFrame; 00738 #if 0 00739 ULONG CPU; 00740 static ULONG Count[MAX_CPU] = {0,}; 00741 #endif 00742 HalBeginSystemInterrupt(LOCAL_TIMER_VECTOR, 00743 PROFILE_LEVEL, 00744 &oldIrql); 00745 _enable(); 00746 00747 #if 0 00748 CPU = ThisCPU(); 00749 if ((Count[CPU] % 100) == 0) 00750 { 00751 DbgPrint("(%s:%d) MpsTimerHandler on CPU%d, irql = %d, epi = %x, KPCR = %x\n", __FILE__, __LINE__, CPU, oldIrql,Trapframe->Eip, KeGetPcr()); 00752 } 00753 Count[CPU]++; 00754 #endif 00755 00756 /* FIXME: SMP is totally broken */ 00757 MpsIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame); 00758 if (KeGetCurrentProcessorNumber() == 0) 00759 { 00760 //KeUpdateSystemTime(&KernelTrapFrame, oldIrql); 00761 } 00762 else 00763 { 00764 //KeUpdateRunTime(&KernelTrapFrame, oldIrql); 00765 } 00766 00767 _disable(); 00768 HalEndSystemInterrupt (oldIrql, 0); 00769 } 00770 00771 VOID APICSetupLVTT(ULONG ClockTicks) 00772 { 00773 ULONG tmp; 00774 00775 tmp = GET_APIC_VERSION(APICRead(APIC_VER)); 00776 if (!APIC_INTEGRATED(tmp)) 00777 { 00778 tmp = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) | APIC_LVT_PERIODIC | LOCAL_TIMER_VECTOR; 00779 } 00780 else 00781 { 00782 /* Periodic timer */ 00783 tmp = APIC_LVT_PERIODIC | LOCAL_TIMER_VECTOR; 00784 } 00785 APICWrite(APIC_LVTT, tmp); 00786 00787 tmp = APICRead(APIC_TDCR); 00788 tmp &= ~(APIC_TDCR_1 | APIC_TIMER_BASE_DIV); 00789 tmp |= APIC_TDCR_16; 00790 APICWrite(APIC_TDCR, tmp); 00791 APICWrite(APIC_ICRT, ClockTicks / APIC_DIVISOR); 00792 } 00793 00794 VOID 00795 APICCalibrateTimer(ULONG CPU) 00796 { 00797 ULARGE_INTEGER t1, t2; 00798 LONG tt1, tt2; 00799 BOOLEAN TSCPresent; 00800 00801 DPRINT("Calibrating APIC timer for CPU %d\n", CPU); 00802 00803 APICSetupLVTT(1000000000); 00804 00805 TSCPresent = KeGetCurrentPrcb()->FeatureBits & KF_RDTSC ? TRUE : FALSE; 00806 00807 /* 00808 * The timer chip counts down to zero. Let's wait 00809 * for a wraparound to start exact measurement: 00810 * (the current tick might have been already half done) 00811 */ 00812 //WaitFor8254Wraparound(); 00813 00814 /* 00815 * We wrapped around just now. Let's start 00816 */ 00817 if (TSCPresent) 00818 { 00819 t1.QuadPart = (LONGLONG)__rdtsc(); 00820 } 00821 tt1 = APICRead(APIC_CCRT); 00822 00823 //WaitFor8254Wraparound(); 00824 00825 00826 tt2 = APICRead(APIC_CCRT); 00827 if (TSCPresent) 00828 { 00829 t2.QuadPart = (LONGLONG)__rdtsc(); 00830 CPUMap[CPU].CoreSpeed = (HZ * (ULONG)(t2.QuadPart - t1.QuadPart)); 00831 DPRINT("CPU clock speed is %ld.%04ld MHz.\n", 00832 CPUMap[CPU].CoreSpeed/1000000, 00833 CPUMap[CPU].CoreSpeed%1000000); 00834 KeGetCurrentPrcb()->MHz = CPUMap[CPU].CoreSpeed/1000000; 00835 } 00836 00837 CPUMap[CPU].BusSpeed = (HZ * (long)(tt1 - tt2) * APIC_DIVISOR); 00838 00839 /* Setup timer for normal operation */ 00840 // APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100); // 100ns 00841 APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 10000); // 10ms 00842 // APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100000); // 100ms 00843 00844 DPRINT("Host bus clock speed is %ld.%04ld MHz.\n", 00845 CPUMap[CPU].BusSpeed/1000000, 00846 CPUMap[CPU].BusSpeed%1000000); 00847 } 00848 00849 VOID 00850 SetInterruptGate(ULONG index, ULONG_PTR address) 00851 { 00852 #ifdef _M_AMD64 00853 KIDTENTRY64 *idt; 00854 00855 idt = &KeGetPcr()->IdtBase[index]; 00856 00857 idt->OffsetLow = address & 0xffff; 00858 idt->Selector = KGDT_64_R0_CODE; 00859 idt->IstIndex = 0; 00860 idt->Reserved0 = 0; 00861 idt->Type = 0x0e; 00862 idt->Dpl = 0; 00863 idt->Present = 1; 00864 idt->OffsetMiddle = (address >> 16) & 0xffff; 00865 idt->OffsetHigh = address >> 32; 00866 idt->Reserved1 = 0; 00867 idt->Alignment = 0; 00868 #else 00869 KIDTENTRY *idt; 00870 KIDT_ACCESS Access; 00871 00872 /* Set the IDT Access Bits */ 00873 Access.Reserved = 0; 00874 Access.Present = 1; 00875 Access.Dpl = 0; /* Kernel-Mode */ 00876 Access.SystemSegmentFlag = 0; 00877 Access.SegmentType = I386_INTERRUPT_GATE; 00878 00879 idt = (KIDTENTRY*)((ULONG)KeGetPcr()->IDT + index * sizeof(KIDTENTRY)); 00880 idt->Offset = (USHORT)(address & 0xffff); 00881 idt->Selector = KGDT_R0_CODE; 00882 idt->Access = Access.Value; 00883 idt->ExtendedOffset = (USHORT)(address >> 16); 00884 #endif 00885 } 00886 00887 VOID HaliInitBSP(VOID) 00888 { 00889 #ifdef CONFIG_SMP 00890 PUSHORT ps; 00891 #endif 00892 00893 static BOOLEAN BSPInitialized = FALSE; 00894 00895 /* Only initialize the BSP once */ 00896 if (BSPInitialized) 00897 { 00898 ASSERT(FALSE); 00899 return; 00900 } 00901 00902 BSPInitialized = TRUE; 00903 00904 /* Setup interrupt handlers */ 00905 SetInterruptGate(LOCAL_TIMER_VECTOR, (ULONG_PTR)MpsTimerInterrupt); 00906 SetInterruptGate(ERROR_VECTOR, (ULONG_PTR)MpsErrorInterrupt); 00907 SetInterruptGate(SPURIOUS_VECTOR, (ULONG_PTR)MpsSpuriousInterrupt); 00908 #ifdef CONFIG_SMP 00909 SetInterruptGate(IPI_VECTOR, (ULONG_PTR)MpsIpiInterrupt); 00910 #endif 00911 DPRINT("APIC is mapped at 0x%X\n", APICBase); 00912 00913 if (VerifyLocalAPIC()) 00914 { 00915 DPRINT("APIC found\n"); 00916 } 00917 else 00918 { 00919 DPRINT("No APIC found\n"); 00920 ASSERT(FALSE); 00921 } 00922 00923 if (APICMode == amPIC) 00924 { 00925 EnableApicMode(); 00926 } 00927 00928 APICSetup(); 00929 00930 #ifdef CONFIG_SMP 00931 /* BIOS data segment */ 00932 BIOSBase = (PULONG)BIOS_AREA; 00933 00934 /* Area for communicating with the APs */ 00935 CommonBase = (PULONG)COMMON_AREA; 00936 00937 /* Copy bootstrap code to common area */ 00938 memcpy((PVOID)((ULONG_PTR)CommonBase + PAGE_SIZE), 00939 &APstart, 00940 (ULONG_PTR)&APend - (ULONG_PTR)&APstart + 1); 00941 00942 /* Set shutdown code */ 00943 CMOS_WRITE(0xF, 0xA); 00944 00945 /* Set warm reset vector */ 00946 ps = (PUSHORT)((ULONG_PTR)BIOSBase + 0x467); 00947 *ps = (COMMON_AREA + PAGE_SIZE) & 0xF; 00948 00949 ps = (PUSHORT)((ULONG_PTR)BIOSBase + 0x469); 00950 *ps = (COMMON_AREA + PAGE_SIZE) >> 4; 00951 #endif 00952 00953 /* Calibrate APIC timer */ 00954 APICCalibrateTimer(BootCPU); 00955 } 00956 00957 #ifdef CONFIG_SMP 00958 VOID 00959 HaliStartApplicationProcessor(ULONG Cpu, ULONG Stack) 00960 { 00961 ULONG tmp, maxlvt; 00962 PCOMMON_AREA_INFO Common; 00963 ULONG StartupCount; 00964 ULONG i, j; 00965 ULONG DeliveryStatus = 0; 00966 ULONG AcceptStatus = 0; 00967 00968 if (Cpu >= MAX_CPU || 00969 Cpu >= CPUCount || 00970 OnlineCPUs & (1 << Cpu)) 00971 { 00972 ASSERT(FALSE); 00973 } 00974 DPRINT1("Attempting to boot CPU %d\n", Cpu); 00975 00976 /* Send INIT IPI */ 00977 00978 APICSendIPI(Cpu, APIC_DM_INIT|APIC_ICR0_LEVEL_ASSERT); 00979 00980 KeStallExecutionProcessor(200); 00981 00982 /* Deassert INIT */ 00983 00984 APICSendIPI(Cpu, APIC_DM_INIT|APIC_ICR0_LEVEL_DEASSERT); 00985 00986 if (APIC_INTEGRATED(CPUMap[Cpu].APICVersion)) 00987 { 00988 /* Clear APIC errors */ 00989 APICWrite(APIC_ESR, 0); 00990 tmp = (APICRead(APIC_ESR) & APIC_ESR_MASK); 00991 } 00992 00993 Common = (PCOMMON_AREA_INFO)CommonBase; 00994 00995 /* Write the location of the AP stack */ 00996 Common->Stack = (ULONG)Stack; 00997 /* Write the page directory page */ 00998 Common->PageDirectory = __readcr3(); 00999 /* Write the kernel entry point */ 01000 Common->NtProcessStartup = (ULONG_PTR)RtlImageNtHeader((PVOID)KernelBase)->OptionalHeader.AddressOfEntryPoint + KernelBase; 01001 /* Write the state of the mae mode */ 01002 Common->PaeModeEnabled = __readcr4() & CR4_PAE ? 1 : 0; 01003 01004 DPRINT1("%x %x %x %x\n", Common->Stack, Common->PageDirectory, Common->NtProcessStartup, Common->PaeModeEnabled); 01005 01006 DPRINT("Cpu %d got stack at 0x%X\n", Cpu, Common->Stack); 01007 #if 0 01008 for (j = 0; j < 16; j++) 01009 { 01010 Common->Debug[j] = 0; 01011 } 01012 #endif 01013 01014 maxlvt = APICGetMaxLVT(); 01015 01016 /* Is this a local APIC or an 82489DX? */ 01017 StartupCount = (APIC_INTEGRATED(CPUMap[Cpu].APICVersion)) ? 2 : 0; 01018 01019 for (i = 1; i <= StartupCount; i++) 01020 { 01021 /* It's a local APIC, so send STARTUP IPI */ 01022 DPRINT("Sending startup signal %d\n", i); 01023 /* Clear errors */ 01024 APICWrite(APIC_ESR, 0); 01025 APICRead(APIC_ESR); 01026 01027 APICSendIPI(Cpu, APIC_DM_STARTUP | ((COMMON_AREA + PAGE_SIZE) >> 12)|APIC_ICR0_LEVEL_DEASSERT); 01028 01029 /* Wait up to 10ms for IPI to be delivered */ 01030 j = 0; 01031 do 01032 { 01033 KeStallExecutionProcessor(10); 01034 01035 /* Check Delivery Status */ 01036 DeliveryStatus = APICRead(APIC_ICR0) & APIC_ICR0_DS; 01037 01038 j++; 01039 } while ((DeliveryStatus) && (j < 1000)); 01040 01041 KeStallExecutionProcessor(200); 01042 01043 /* 01044 * Due to the Pentium erratum 3AP. 01045 */ 01046 if (maxlvt > 3) 01047 { 01048 APICRead(APIC_SIVR); 01049 APICWrite(APIC_ESR, 0); 01050 } 01051 01052 AcceptStatus = APICRead(APIC_ESR) & APIC_ESR_MASK; 01053 01054 if (DeliveryStatus || AcceptStatus) 01055 { 01056 break; 01057 } 01058 } 01059 01060 if (DeliveryStatus) 01061 { 01062 DPRINT("STARTUP IPI for CPU %d was never delivered.\n", Cpu); 01063 } 01064 01065 if (AcceptStatus) 01066 { 01067 DPRINT("STARTUP IPI for CPU %d was never accepted.\n", Cpu); 01068 } 01069 01070 if (!(DeliveryStatus || AcceptStatus)) 01071 { 01072 01073 /* Wait no more than 5 seconds for processor to boot */ 01074 DPRINT("Waiting for 5 seconds for CPU %d to boot\n", Cpu); 01075 01076 /* Wait no more than 5 seconds */ 01077 for (j = 0; j < 50000; j++) 01078 { 01079 if (CPUMap[Cpu].Flags & CPU_ENABLED) 01080 { 01081 break; 01082 } 01083 KeStallExecutionProcessor(100); 01084 } 01085 } 01086 01087 if (CPUMap[Cpu].Flags & CPU_ENABLED) 01088 { 01089 DbgPrint("CPU %d is now running\n", Cpu); 01090 } 01091 else 01092 { 01093 DbgPrint("Initialization of CPU %d failed\n", Cpu); 01094 } 01095 01096 #if 0 01097 DPRINT("Debug bytes are:\n"); 01098 01099 for (j = 0; j < 4; j++) 01100 { 01101 DPRINT("0x%08X 0x%08X 0x%08X 0x%08X.\n", 01102 Common->Debug[j*4+0], 01103 Common->Debug[j*4+1], 01104 Common->Debug[j*4+2], 01105 Common->Debug[j*4+3]); 01106 } 01107 01108 #endif 01109 } 01110 01111 #endif 01112 01113 VOID 01114 FASTCALL 01115 DECLSPEC_NORETURN 01116 HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame) 01117 { 01118 /* Set up a fake INT Stack */ 01119 TrapFrame->EFlags = __readeflags(); 01120 TrapFrame->SegCs = KGDT_R0_CODE; 01121 TrapFrame->Eip = TrapFrame->Eax; 01122 01123 /* Build the trap frame */ 01124 KiEnterInterruptTrap(TrapFrame); 01125 01126 /* unimplemented */ 01127 UNIMPLEMENTED; 01128 01129 /* Exit the interrupt */ 01130 KiEoiHelper(TrapFrame); 01131 01132 } 01133 01134 /* EOF */ Generated on Fri May 25 2012 04:26:58 for ReactOS by
1.7.6.1
|