Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

kernlini.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 kernlini.c 00008 00009 Abstract: 00010 00011 This module contains the code to initialize the kernel data structures 00012 and to initialize the idle thread, its process, and the processor control 00013 block. 00014 00015 For the i386, it also contains code to initialize the PCR. 00016 00017 Author: 00018 00019 David N. Cutler (davec) 21-Apr-1989 00020 00021 Environment: 00022 00023 Kernel mode only. 00024 00025 Revision History: 00026 00027 24-Jan-1990 shielin 00028 00029 Changed for NT386 00030 00031 20-Mar-1990 bryanwi 00032 00033 Added KiInitializePcr 00034 00035 --*/ 00036 00037 #include "ki.h" 00038 #include "ki386.h" 00039 #include "fastsys.inc" 00040 00041 #define TRAP332_GATE 0xEF00 00042 00043 // 00044 // External data. 00045 // 00046 00047 extern KSPIN_LOCK CcMasterSpinLock; 00048 extern KSPIN_LOCK CcVacbSpinLock; 00049 extern KSPIN_LOCK MmPfnLock; 00050 extern KSPIN_LOCK MmSystemSpaceLock; 00051 00052 VOID 00053 KiSetProcessorType( 00054 VOID 00055 ); 00056 00057 VOID 00058 KiSetCR0Bits( 00059 VOID 00060 ); 00061 00062 BOOLEAN 00063 KiIsNpxPresent( 00064 VOID 00065 ); 00066 00067 VOID 00068 KiI386PentiumLockErrataFixup ( 00069 VOID 00070 ); 00071 00072 VOID 00073 KiInitializeDblFaultTSS( 00074 IN PKTSS Tss, 00075 IN ULONG Stack, 00076 IN PKGDTENTRY TssDescriptor 00077 ); 00078 00079 VOID 00080 KiInitializeTSS2 ( 00081 IN PKTSS Tss, 00082 IN PKGDTENTRY TssDescriptor 00083 ); 00084 00085 VOID 00086 KiSwapIDT ( 00087 VOID 00088 ); 00089 00090 VOID 00091 KeSetup80387OrEmulate ( 00092 IN PVOID *R3EmulatorTable 00093 ); 00094 00095 VOID 00096 KiGetCacheInformation( 00097 VOID 00098 ); 00099 00100 ULONG 00101 KiGetCpuVendor( 00102 VOID 00103 ); 00104 00105 ULONG 00106 KiGetFeatureBits ( 00107 VOID 00108 ); 00109 00110 NTSTATUS 00111 KiMoveRegTree( 00112 HANDLE Source, 00113 HANDLE Dest 00114 ); 00115 00116 VOID 00117 Ki386EnableFxsr ( 00118 IN volatile PLONG Number 00119 ); 00120 00121 00122 VOID 00123 Ki386EnableXMMIExceptions ( 00124 IN volatile PLONG Number 00125 ); 00126 00127 00128 VOID 00129 Ki386EnableGlobalPage ( 00130 IN volatile PLONG Number 00131 ); 00132 00133 VOID 00134 Ki386UseSynchronousTbFlush ( 00135 IN volatile PLONG Number 00136 ); 00137 00138 BOOLEAN 00139 KiInitMachineDependent ( 00140 VOID 00141 ); 00142 00143 VOID 00144 KiInitializeMTRR ( 00145 IN BOOLEAN LastProcessor 00146 ); 00147 00148 VOID 00149 KiInitializePAT ( 00150 VOID 00151 ); 00152 00153 VOID 00154 KiAmdK6InitializeMTRR( 00155 VOID 00156 ); 00157 00158 #ifdef ALLOC_PRAGMA 00159 #pragma alloc_text(INIT,KiInitializeKernel) 00160 #pragma alloc_text(INIT,KiInitializePcr) 00161 #pragma alloc_text(INIT,KiInitializeDblFaultTSS) 00162 #pragma alloc_text(INIT,KiInitializeTSS2) 00163 #pragma alloc_text(INIT,KiSwapIDT) 00164 #pragma alloc_text(INIT,KeSetup80387OrEmulate) 00165 #pragma alloc_text(INIT,KiGetFeatureBits) 00166 #pragma alloc_text(INIT,KiGetCacheInformation) 00167 #pragma alloc_text(INIT,KiGetCpuVendor) 00168 #pragma alloc_text(INIT,KiMoveRegTree) 00169 #pragma alloc_text(INIT,KiInitMachineDependent) 00170 #pragma alloc_text(INIT,KiI386PentiumLockErrataFixup) 00171 #endif 00172 00173 BOOLEAN KiI386PentiumLockErrataPresent = FALSE; 00174 BOOLEAN KiIgnoreUnexpectedTrap07 = FALSE; 00175 00176 00177 #if 0 00178 PVOID KiTrap08; 00179 #endif 00180 00181 extern PVOID Ki387RoundModeTable; 00182 extern PVOID Ki386IopmSaveArea; 00183 extern ULONG KeI386ForceNpxEmulation; 00184 extern WCHAR CmDisabledFloatingPointProcessor[]; 00185 extern UCHAR CmpCyrixID[]; 00186 extern UCHAR CmpIntelID[]; 00187 extern UCHAR CmpAmdID[]; 00188 00189 #ifndef NT_UP 00190 extern PVOID ScPatchFxb; 00191 extern PVOID ScPatchFxe; 00192 #endif 00193 00194 typedef enum { 00195 CPU_NONE, 00196 CPU_INTEL, 00197 CPU_AMD, 00198 CPU_CYRIX, 00199 CPU_UNKNOWN 00200 } CPU_VENDORS; 00201 00202 00203 // 00204 // If this processor does XMMI, take advantage of it. Default is 00205 // no XMMI. 00206 // 00207 00208 BOOLEAN KeI386XMMIPresent; 00209 00210 VOID 00211 FASTCALL 00212 KiZeroPage ( 00213 PVOID PageBase 00214 ); 00215 00216 VOID 00217 FASTCALL 00218 KiXMMIZeroPage ( 00219 PVOID PageBase 00220 ); 00221 00222 VOID 00223 FASTCALL 00224 KiXMMIZeroPageNoSave ( 00225 PVOID PageBase 00226 ); 00227 00228 KE_ZERO_PAGE_ROUTINE KeZeroPage = KiZeroPage; 00229 KE_ZERO_PAGE_ROUTINE KeZeroPageFromIdleThread = KiZeroPage; 00230 00231 // 00232 // The following spinlock is for compatiblity with 486 systems that don't 00233 // have a cmpxchg8b instruction and therefore need to synchronize using a 00234 // spinlock. NOTE: This spinlock should be initialized on x86 systems. 00235 // 00236 00237 ULONG Ki486CompatibilityLock; 00238 00239 // 00240 // Profile vars 00241 // 00242 00243 extern KIDTENTRY IDT[]; 00244 00245 VOID 00246 KiInitializeKernel ( 00247 IN PKPROCESS Process, 00248 IN PKTHREAD Thread, 00249 IN PVOID IdleStack, 00250 IN PKPRCB Prcb, 00251 IN CCHAR Number, 00252 PLOADER_PARAMETER_BLOCK LoaderBlock 00253 ) 00254 00255 /*++ 00256 00257 Routine Description: 00258 00259 This function gains control after the system has been bootstrapped and 00260 before the system has been initialized. Its function is to initialize 00261 the kernel data structures, initialize the idle thread and process objects, 00262 initialize the processor control block, call the executive initialization 00263 routine, and then return to the system startup routine. This routine is 00264 also called to initialize the processor specific structures when a new 00265 processor is brought on line. 00266 00267 Arguments: 00268 00269 Process - Supplies a pointer to a control object of type process for 00270 the specified processor. 00271 00272 Thread - Supplies a pointer to a dispatcher object of type thread for 00273 the specified processor. 00274 00275 IdleStack - Supplies a pointer the base of the real kernel stack for 00276 idle thread on the specified processor. 00277 00278 Prcb - Supplies a pointer to a processor control block for the specified 00279 processor. 00280 00281 Number - Supplies the number of the processor that is being 00282 initialized. 00283 00284 LoaderBlock - Supplies a pointer to the loader parameter block. 00285 00286 Return Value: 00287 00288 None. 00289 00290 --*/ 00291 00292 { 00293 LONG Index; 00294 ULONG DirectoryTableBase[2]; 00295 KIRQL OldIrql; 00296 PKPCR Pcr; 00297 BOOLEAN NpxFlag; 00298 BOOLEAN FxsrPresent; 00299 BOOLEAN XMMIPresent; 00300 ULONG FeatureBits; 00301 00302 KiSetProcessorType(); 00303 KiSetCR0Bits(); 00304 NpxFlag = KiIsNpxPresent(); 00305 00306 Pcr = KeGetPcr(); 00307 00308 // 00309 // Initialize DPC listhead and lock. 00310 // 00311 00312 InitializeListHead(&Prcb->DpcListHead); 00313 KeInitializeSpinLock(&Prcb->DpcLock); 00314 Prcb->DpcRoutineActive = 0; 00315 Prcb->DpcQueueDepth = 0; 00316 Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth; 00317 Prcb->MinimumDpcRate = KiMinimumDpcRate; 00318 Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold; 00319 PoInitializePrcb (Prcb); 00320 00321 // 00322 // Check for unsupported processor revision 00323 // 00324 00325 if (Prcb->CpuType == 3) { 00326 KeBugCheckEx(UNSUPPORTED_PROCESSOR,0x386,0,0,0); 00327 } 00328 00329 // 00330 // Get the processor FeatureBits for this processor. 00331 // 00332 00333 FeatureBits = KiGetFeatureBits(); 00334 Prcb->FeatureBits = FeatureBits; 00335 00336 // 00337 // Get processor Cache Size information. 00338 // 00339 00340 KiGetCacheInformation(); 00341 00342 // 00343 // initialize the per processor lock queue entry for implemented locks. 00344 // 00345 00346 #if !defined(NT_UP) 00347 00348 Prcb->LockQueue[LockQueueDispatcherLock].Next = NULL; 00349 Prcb->LockQueue[LockQueueDispatcherLock].Lock = &KiDispatcherLock; 00350 Prcb->LockQueue[LockQueueContextSwapLock].Next = NULL; 00351 Prcb->LockQueue[LockQueueContextSwapLock].Lock = &KiContextSwapLock; 00352 Prcb->LockQueue[LockQueuePfnLock].Next = NULL; 00353 Prcb->LockQueue[LockQueuePfnLock].Lock = &MmPfnLock; 00354 Prcb->LockQueue[LockQueueSystemSpaceLock].Next = NULL; 00355 Prcb->LockQueue[LockQueueSystemSpaceLock].Lock = &MmSystemSpaceLock; 00356 Prcb->LockQueue[LockQueueMasterLock].Next = NULL; 00357 Prcb->LockQueue[LockQueueMasterLock].Lock = &CcMasterSpinLock; 00358 Prcb->LockQueue[LockQueueVacbLock].Next = NULL; 00359 Prcb->LockQueue[LockQueueVacbLock].Lock = &CcVacbSpinLock; 00360 00361 #endif 00362 00363 // 00364 // If the initial processor is being initialized, then initialize the 00365 // per system data structures. 00366 // 00367 00368 if (Number == 0) { 00369 00370 // 00371 // Initial setting for global Cpu & Stepping levels 00372 // 00373 00374 KeI386NpxPresent = NpxFlag; 00375 KeI386CpuType = Prcb->CpuType; 00376 KeI386CpuStep = Prcb->CpuStep; 00377 00378 KeProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL; 00379 KeProcessorLevel = (USHORT)Prcb->CpuType; 00380 if (Prcb->CpuID == 0) { 00381 KeProcessorRevision = 0xFF00 | 00382 (((Prcb->CpuStep >> 4) + 0xa0 ) & 0x0F0) | 00383 (Prcb->CpuStep & 0xf); 00384 } else { 00385 KeProcessorRevision = Prcb->CpuStep; 00386 } 00387 00388 KeFeatureBits = FeatureBits; 00389 00390 KeI386FxsrPresent = ((KeFeatureBits & KF_FXSR) ? TRUE:FALSE); 00391 00392 KeI386XMMIPresent = ((KeFeatureBits & KF_XMMI) ? TRUE:FALSE); 00393 00394 // 00395 // If cmpxchg8b was available at boot, verify its still available 00396 // 00397 00398 if ((KiBootFeatureBits & KF_CMPXCHG8B) && !(KeFeatureBits & KF_CMPXCHG8B)) { 00399 KeBugCheckEx (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED, KF_CMPXCHG8B, 0, 0, 0); 00400 } 00401 00402 // 00403 // Lower IRQL to APC level. 00404 // 00405 00406 KeLowerIrql(APC_LEVEL); 00407 00408 00409 // 00410 // Initialize kernel internal spinlocks 00411 // 00412 00413 KeInitializeSpinLock(&KiContextSwapLock); 00414 KeInitializeSpinLock(&KiDispatcherLock); 00415 KeInitializeSpinLock(&KiFreezeExecutionLock); 00416 00417 // 00418 // Initialize 486 compatibility lock 00419 // 00420 00421 KeInitializeSpinLock(&Ki486CompatibilityLock); 00422 00423 #if !defined(NT_UP) 00424 00425 // 00426 // During Text Mode setup, it is possible the system is 00427 // running with an MP kernel and a UP HAL. On X86 systems, 00428 // spinlocks are implemented in both the kernel and the HAL 00429 // with the verisons that alter IRQL in the HAL. If the 00430 // HAL is UP, it will not actually acquire/release locks 00431 // while the MP kernel will which will cause the system to 00432 // hang (or crash). As this can only occur during text 00433 // mode setup, we will detect the situation and disable 00434 // the kernel only versions of queued spinlocks if the HAL 00435 // is UP (and the kernel MP). 00436 // 00437 // We need to patch 3 routines, two of them are void and 00438 // the other returns a boolean (must be true (and ZF must be 00439 // clear) in a UP case). 00440 // 00441 // Determine if the HAL us UP by acquiring the dispatcher 00442 // lock and examining it to see if the HAL actually did 00443 // anything to it. 00444 // 00445 00446 OldIrql = KfAcquireSpinLock(&KiDispatcherLock); 00447 if (KiDispatcherLock == 0) { 00448 00449 // 00450 // KfAcquireSpinLock is in the HAL and it did not 00451 // change the value of the lock. This is a UP HAL. 00452 // 00453 00454 extern UCHAR KiTryToAcquireQueuedSpinLockUP; 00455 PUCHAR PatchTarget, PatchSource; 00456 UCHAR Byte; 00457 00458 #define RET 0xc3 00459 00460 *(PUCHAR)(KiAcquireQueuedSpinLock) = RET; 00461 *(PUCHAR)(KiReleaseQueuedSpinLock) = RET; 00462 00463 // 00464 // Copy the UP version of KiTryToAcquireQueuedSpinLock 00465 // over the top of the MP versin. 00466 // 00467 00468 PatchSource = &(KiTryToAcquireQueuedSpinLockUP); 00469 PatchTarget = (PUCHAR)(KiTryToAcquireQueuedSpinLock); 00470 00471 do { 00472 Byte = *PatchSource++; 00473 *PatchTarget++ = Byte; 00474 } while (Byte != RET); 00475 00476 #undef RET 00477 } 00478 KeReleaseSpinLock(&KiDispatcherLock, OldIrql); 00479 00480 #endif 00481 00482 // 00483 // Performance architecture independent initialization. 00484 // 00485 00486 KiInitSystem(); 00487 00488 // 00489 // Initialize idle thread process object and then set: 00490 // 00491 // 1. all the quantum values to the maximum possible. 00492 // 2. the process in the balance set. 00493 // 3. the active processor mask to the specified process. 00494 // 00495 00496 DirectoryTableBase[0] = 0; 00497 DirectoryTableBase[1] = 0; 00498 KeInitializeProcess(Process, 00499 (KPRIORITY)0, 00500 (KAFFINITY)(0xffffffff), 00501 &DirectoryTableBase[0], 00502 FALSE); 00503 00504 Process->ThreadQuantum = MAXCHAR; 00505 00506 } else { 00507 00508 // 00509 // Adjust global cpu setting to represent lowest of all processors 00510 // 00511 00512 FxsrPresent = ((FeatureBits & KF_FXSR) ? TRUE:FALSE); 00513 if (FxsrPresent != KeI386FxsrPresent) { 00514 // 00515 // FXSR support must be available on all processors or on none 00516 // 00517 KeBugCheckEx (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED, KF_FXSR, 0, 0, 0); 00518 } 00519 00520 XMMIPresent = ((FeatureBits & KF_XMMI) ? TRUE:FALSE); 00521 if (XMMIPresent != KeI386XMMIPresent) { 00522 // 00523 // XMMI support must be available on all processors or on none 00524 // 00525 KeBugCheckEx (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED, KF_XMMI, 0, 0, 0); 00526 } 00527 00528 if (NpxFlag != KeI386NpxPresent) { 00529 // 00530 // NPX support must be available on all processors or on none 00531 // 00532 00533 KeBugCheckEx (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED, 0x387, 0, 0, 0); 00534 } 00535 00536 if ((ULONG)(Prcb->CpuType) != KeI386CpuType) { 00537 00538 if ((ULONG)(Prcb->CpuType) < KeI386CpuType) { 00539 00540 // 00541 // What is the lowest CPU type 00542 // 00543 00544 KeI386CpuType = (ULONG)Prcb->CpuType; 00545 KeProcessorLevel = (USHORT)Prcb->CpuType; 00546 } 00547 } 00548 00549 if ((KiBootFeatureBits & KF_CMPXCHG8B) && !(FeatureBits & KF_CMPXCHG8B)) { 00550 // 00551 // cmpxchg8b must be available on all processors, if installed at boot 00552 // 00553 00554 KeBugCheckEx (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED, KF_CMPXCHG8B, 0, 0, 0); 00555 } 00556 00557 if ((KeFeatureBits & KF_GLOBAL_PAGE) && !(FeatureBits & KF_GLOBAL_PAGE)) { 00558 // 00559 // Global page support must be available on all processors, if on boot processor 00560 // 00561 00562 KeBugCheckEx (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED, KF_GLOBAL_PAGE, 0, 0, 0); 00563 } 00564 00565 if ((KeFeatureBits & KF_PAT) && !(FeatureBits & KF_PAT)) { 00566 // 00567 // PAT must be available on all processors, if on boot processor 00568 // 00569 00570 KeBugCheckEx (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED, KF_PAT, 0, 0, 0); 00571 } 00572 00573 if ((KeFeatureBits & KF_MTRR) && !(FeatureBits & KF_MTRR)) { 00574 // 00575 // MTRR must be available on all processors, if on boot processor 00576 // 00577 00578 KeBugCheckEx (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED, KF_MTRR, 0, 0, 0); 00579 } 00580 00581 // 00582 // Use lowest stepping value 00583 // 00584 00585 if (Prcb->CpuStep < KeI386CpuStep) { 00586 KeI386CpuStep = Prcb->CpuStep; 00587 if (Prcb->CpuID == 0) { 00588 KeProcessorRevision = 0xFF00 | 00589 ((Prcb->CpuStep >> 8) + 'A') | 00590 (Prcb->CpuStep & 0xf); 00591 } else { 00592 KeProcessorRevision = Prcb->CpuStep; 00593 } 00594 } 00595 00596 // 00597 // Use subset of all NT feature bits available on each processor 00598 // 00599 00600 KeFeatureBits &= FeatureBits; 00601 00602 // 00603 // Lower IRQL to DISPATCH level. 00604 // 00605 00606 KeLowerIrql(DISPATCH_LEVEL); 00607 00608 } 00609 00610 // 00611 // Update processor features 00612 // 00613 00614 SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] = 00615 (KeFeatureBits & KF_MMX) ? TRUE : FALSE; 00616 00617 SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] = 00618 (KeFeatureBits & KF_CMPXCHG8B) ? TRUE : FALSE; 00619 00620 SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] = 00621 ((KeFeatureBits & KF_FXSR) && (KeFeatureBits & KF_XMMI)) ? TRUE : FALSE; 00622 00623 SharedUserData->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] = 00624 (KeFeatureBits & KF_3DNOW) ? TRUE : FALSE; 00625 00626 SharedUserData->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE] = 00627 (KeFeatureBits & KF_RDTSC) ? TRUE : FALSE; 00628 // 00629 // Initialize idle thread object and then set: 00630 // 00631 // 1. the initial kernel stack to the specified idle stack. 00632 // 2. the next processor number to the specified processor. 00633 // 3. the thread priority to the highest possible value. 00634 // 4. the state of the thread to running. 00635 // 5. the thread affinity to the specified processor. 00636 // 6. the specified processor member in the process active processors 00637 // set. 00638 // 00639 00640 KeInitializeThread(Thread, (PVOID)((ULONG)IdleStack), 00641 (PKSYSTEM_ROUTINE)NULL, (PKSTART_ROUTINE)NULL, 00642 (PVOID)NULL, (PCONTEXT)NULL, (PVOID)NULL, Process); 00643 Thread->NextProcessor = Number; 00644 Thread->Priority = HIGH_PRIORITY; 00645 Thread->State = Running; 00646 Thread->Affinity = (KAFFINITY)(1<<Number); 00647 Thread->WaitIrql = DISPATCH_LEVEL; 00648 SetMember(Number, Process->ActiveProcessors); 00649 00650 // 00651 // Initialize the processor block. (Note that some fields have been 00652 // initialized at KiInitializePcr(). 00653 // 00654 00655 Prcb->CurrentThread = Thread; 00656 Prcb->NextThread = (PKTHREAD)NULL; 00657 Prcb->IdleThread = Thread; 00658 Pcr->NtTib.StackBase = Thread->InitialStack; 00659 00660 // 00661 // call the executive initialization routine. 00662 // 00663 00664 try { 00665 ExpInitializeExecutive(Number, LoaderBlock); 00666 00667 } except (EXCEPTION_EXECUTE_HANDLER) { 00668 KeBugCheck (PHASE0_EXCEPTION); 00669 } 00670 00671 // 00672 // If the initial processor is being initialized, then compute the 00673 // timer table reciprocal value and reset the PRCB values for the 00674 // controllable DPC behavior in order to reflect any registry 00675 // overrides. 00676 // 00677 00678 if (Number == 0) { 00679 KiTimeIncrementReciprocal = KiComputeReciprocal((LONG)KeMaximumIncrement, 00680 &KiTimeIncrementShiftCount); 00681 00682 Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth; 00683 Prcb->MinimumDpcRate = KiMinimumDpcRate; 00684 Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold; 00685 } 00686 00687 if (Number == 0) { 00688 00689 // 00690 // Processor 0's DPC stack was temporarily allocated on 00691 // the Double Fault Stack, switch to a proper kernel 00692 // stack now. 00693 // 00694 00695 PVOID DpcStack; 00696 00697 DpcStack = MmCreateKernelStack(FALSE); 00698 00699 if (DpcStack == NULL) { 00700 KeBugCheckEx(NO_PAGES_AVAILABLE, 1, 0, 0, 0); 00701 } 00702 Prcb->DpcStack = DpcStack; 00703 00704 // 00705 // Allocate 8k IOPM bit map saved area to allow BiosCall swap 00706 // bit maps. 00707 // 00708 00709 Ki386IopmSaveArea = ExAllocatePoolWithTag(PagedPool, 00710 PAGE_SIZE * 2, 00711 ' eK'); 00712 if (Ki386IopmSaveArea == NULL) { 00713 KeBugCheckEx(NO_PAGES_AVAILABLE, 2, PAGE_SIZE * 2, 0, 0); 00714 } 00715 } 00716 00717 // 00718 // Set the priority of the specified idle thread to zero, set appropriate 00719 // member in KiIdleSummary and return to the system start up routine. 00720 // 00721 00722 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); 00723 KeSetPriorityThread(Thread, (KPRIORITY)0); 00724 00725 // 00726 // if a thread has not been selected to run on the current processors, 00727 // check to see if there are any ready threads; otherwise add this 00728 // processors to the IdleSummary 00729 // 00730 00731 KiAcquireQueuedSpinLock(KiQueuedSpinLockContext(LockQueueDispatcherLock)); 00732 if (Prcb->NextThread == (PKTHREAD)NULL) { 00733 SetMember(Number, KiIdleSummary); 00734 } 00735 KiReleaseQueuedSpinLock(KiQueuedSpinLockContext(LockQueueDispatcherLock)); 00736 00737 KeRaiseIrql(HIGH_LEVEL, &OldIrql); 00738 00739 // 00740 // This processor has initialized 00741 // 00742 00743 LoaderBlock->Prcb = (ULONG)NULL; 00744 00745 return; 00746 } 00747 00748 VOID 00749 KiInitializePcr ( 00750 IN ULONG Processor, 00751 IN PKPCR Pcr, 00752 IN PKIDTENTRY Idt, 00753 IN PKGDTENTRY Gdt, 00754 IN PKTSS Tss, 00755 IN PKTHREAD Thread, 00756 IN PVOID DpcStack 00757 ) 00758 00759 /*++ 00760 00761 Routine Description: 00762 00763 This function is called to initialize the PCR for a processor. It 00764 simply stuffs values into the PCR. (The PCR is not inited statically 00765 because the number varies with the number of processors.) 00766 00767 Note that each processor has its own IDT, GDT, and TSS as well as PCR! 00768 00769 Arguments: 00770 00771 Processor - Processor whose PCR to initialize. 00772 00773 Pcr - Linear address of PCR. 00774 00775 Idt - Linear address of i386 IDT. 00776 00777 Gdt - Linear address of i386 GDT. 00778 00779 Tss - Linear address (NOT SELECTOR!) of the i386 TSS. 00780 00781 Thread - Dummy thread object to use very early on. 00782 00783 Return Value: 00784 00785 None. 00786 00787 --*/ 00788 { 00789 // set version values 00790 00791 Pcr->MajorVersion = PCR_MAJOR_VERSION; 00792 Pcr->MinorVersion = PCR_MINOR_VERSION; 00793 00794 Pcr->PrcbData.MajorVersion = PRCB_MAJOR_VERSION; 00795 Pcr->PrcbData.MinorVersion = PRCB_MINOR_VERSION; 00796 00797 Pcr->PrcbData.BuildType = 0; 00798 00799 #if DBG 00800 Pcr->PrcbData.BuildType |= PRCB_BUILD_DEBUG; 00801 #endif 00802 00803 #ifdef NT_UP 00804 Pcr->PrcbData.BuildType |= PRCB_BUILD_UNIPROCESSOR; 00805 #endif 00806 00807 #if defined (_X86PAE_) 00808 if (Processor == 0) { 00809 // 00810 // PAE feature must be initialized prior to the first HAL call. 00811 // 00812 00813 SharedUserData->ProcessorFeatures[PF_PAE_ENABLED] = TRUE; 00814 } 00815 #endif 00816 00817 // Basic addressing fields 00818 00819 Pcr->SelfPcr = Pcr; 00820 Pcr->Prcb = &(Pcr->PrcbData); 00821 00822 // Thread control fields 00823 00824 Pcr->NtTib.ExceptionList = EXCEPTION_CHAIN_END; 00825 Pcr->NtTib.StackBase = 0; 00826 Pcr->NtTib.StackLimit = 0; 00827 Pcr->NtTib.Self = 0; 00828 00829 Pcr->PrcbData.CurrentThread = Thread; 00830 00831 // 00832 // Init Prcb.Number and ProcessorBlock such that Ipi will work 00833 // as early as possible. 00834 // 00835 00836 Pcr->PrcbData.Number = (UCHAR)Processor; 00837 Pcr->PrcbData.SetMember = 1 << Processor; 00838 KiProcessorBlock[Processor] = Pcr->Prcb; 00839 00840 Pcr->Irql = 0; 00841 00842 // Machine structure addresses 00843 00844 Pcr->GDT = Gdt; 00845 Pcr->IDT = Idt; 00846 Pcr->TSS = Tss; 00847 Pcr->PrcbData.DpcStack = DpcStack; 00848 00849 return; 00850 } 00851 00852 #if 0 00853 VOID 00854 KiInitializeDblFaultTSS( 00855 IN PKTSS Tss, 00856 IN ULONG Stack, 00857 IN PKGDTENTRY TssDescriptor 00858 ) 00859 00860 /*++ 00861 00862 Routine Description: 00863 00864 This function is called to initialize the double-fault TSS for a 00865 processor. It will set the static fields of the TSS to point to 00866 the double-fault handler and the appropriate double-fault stack. 00867 00868 Note that the IOPM for the double-fault TSS grants access to all 00869 ports. This is so the standard HAL's V86-mode callback to reset 00870 the display to text mode will work. 00871 00872 Arguments: 00873 00874 Tss - Supplies a pointer to the double-fault TSS 00875 00876 Stack - Supplies a pointer to the double-fault stack. 00877 00878 TssDescriptor - Linear address of the descriptor for the TSS. 00879 00880 Return Value: 00881 00882 None. 00883 00884 --*/ 00885 00886 { 00887 PUCHAR p; 00888 ULONG i; 00889 ULONG j; 00890 00891 // 00892 // Set limit for TSS 00893 // 00894 00895 if (TssDescriptor != NULL) { 00896 TssDescriptor->LimitLow = sizeof(KTSS) - 1; 00897 TssDescriptor->HighWord.Bits.LimitHi = 0; 00898 } 00899 00900 // 00901 // Initialize IOPMs 00902 // 00903 00904 for (i = 0; i < IOPM_COUNT; i++) { 00905 p = (PUCHAR)(Tss->IoMaps[i]); 00906 00907 for (j = 0; j < PIOPM_SIZE; j++) { 00908 p[j] = 0; 00909 } 00910 } 00911 00912 // Set IO Map base address to indicate no IO map present. 00913 00914 // N.B. -1 does not seem to be a valid value for the map base. If this 00915 // value is used, byte immediate in's and out's will actually go 00916 // the hardware when executed in V86 mode. 00917 00918 Tss->IoMapBase = KiComputeIopmOffset(IO_ACCESS_MAP_NONE); 00919 00920 // Set flags to 0, which in particular disables traps on task switches. 00921 00922 Tss->Flags = 0; 00923 00924 00925 // Set LDT and Ss0 to constants used by NT. 00926 00927 Tss->LDT = 0; 00928 Tss->Ss0 = KGDT_R0_DATA; 00929 Tss->Esp0 = Stack; 00930 Tss->Eip = (ULONG)KiTrap08; 00931 Tss->Cs = KGDT_R0_CODE || RPL_MASK; 00932 Tss->Ds = KGDT_R0_DATA; 00933 Tss->Es = KGDT_R0_DATA; 00934 Tss->Fs = KGDT_R0_DATA; 00935 00936 00937 return; 00938 00939 } 00940 #endif 00941 00942 00943 VOID 00944 KiInitializeTSS ( 00945 IN PKTSS Tss 00946 ) 00947 00948 /*++ 00949 00950 Routine Description: 00951 00952 This function is called to initialize the TSS for a processor. 00953 It will set the static fields of the TSS. (ie Those fields that 00954 the part reads, and for which NT uses constant values.) 00955 00956 The dynamic fields (Esp0 and CR3) are set in the context swap 00957 code. 00958 00959 Arguments: 00960 00961 Tss - Linear address of the Task State Segment. 00962 00963 Return Value: 00964 00965 None. 00966 00967 --*/ 00968 { 00969 00970 // Set IO Map base address to indicate no IO map present. 00971 00972 // N.B. -1 does not seem to be a valid value for the map base. If this 00973 // value is used, byte immediate in's and out's will actually go 00974 // the hardware when executed in V86 mode. 00975 00976 Tss->IoMapBase = KiComputeIopmOffset(IO_ACCESS_MAP_NONE); 00977 00978 // Set flags to 0, which in particular disables traps on task switches. 00979 00980 Tss->Flags = 0; 00981 00982 00983 // Set LDT and Ss0 to constants used by NT. 00984 00985 Tss->LDT = 0; 00986 Tss->Ss0 = KGDT_R0_DATA; 00987 00988 return; 00989 } 00990 00991 VOID 00992 KiInitializeTSS2 ( 00993 IN PKTSS Tss, 00994 IN PKGDTENTRY TssDescriptor 00995 ) 00996 00997 /*++ 00998 00999 Routine Description: 01000 01001 Do part of TSS init we do only once. 01002 01003 Arguments: 01004 01005 Tss - Linear address of the Task State Segment. 01006 01007 TssDescriptor - Linear address of the descriptor for the TSS. 01008 01009 Return Value: 01010 01011 None. 01012 01013 --*/ 01014 { 01015 PUCHAR p; 01016 ULONG i; 01017 ULONG j; 01018 01019 // 01020 // Set limit for TSS 01021 // 01022 01023 if (TssDescriptor != NULL) { 01024 TssDescriptor->LimitLow = sizeof(KTSS) - 1; 01025 TssDescriptor->HighWord.Bits.LimitHi = 0; 01026 } 01027 01028 // 01029 // Initialize IOPMs 01030 // 01031 01032 for (i = 0; i < IOPM_COUNT; i++) { 01033 p = (PUCHAR)(Tss->IoMaps[i].IoMap); 01034 01035 for (j = 0; j < PIOPM_SIZE; j++) { 01036 p[j] = (UCHAR)-1; 01037 } 01038 } 01039 01040 // 01041 // Initialize Software Interrupt Direction Maps 01042 // 01043 01044 for (i = 0; i < IOPM_COUNT; i++) { 01045 p = (PUCHAR)(Tss->IoMaps[i].DirectionMap); 01046 for (j = 0; j < INT_DIRECTION_MAP_SIZE; j++) { 01047 p[j] = 0; 01048 } 01049 // dpmi requires special case for int 2, 1b, 1c, 23, 24 01050 p[0] = 4; 01051 p[3] = 0x18; 01052 p[4] = 0x18; 01053 } 01054 01055 // 01056 // Initialize the map for IO_ACCESS_MAP_NONE 01057 // 01058 p = (PUCHAR)(Tss->IntDirectionMap); 01059 for (j = 0; j < INT_DIRECTION_MAP_SIZE; j++) { 01060 p[j] = 0; 01061 } 01062 01063 // dpmi requires special case for int 2, 1b, 1c, 23, 24 01064 p[0] = 4; 01065 p[3] = 0x18; 01066 p[4] = 0x18; 01067 01068 return; 01069 } 01070 01071 VOID 01072 KiSwapIDT ( 01073 ) 01074 01075 /*++ 01076 01077 Routine Description: 01078 01079 This function is called to edit the IDT. It swaps words of the address 01080 and access fields around into the format the part actually needs. 01081 This allows for easy static init of the IDT. 01082 01083 Note that this procedure edits the current IDT. 01084 01085 Arguments: 01086 01087 None. 01088 01089 Return Value: 01090 01091 None. 01092 01093 --*/ 01094 { 01095 LONG Index; 01096 USHORT Temp; 01097 01098 // 01099 // Rearrange the entries of IDT to match i386 interrupt gate structure 01100 // 01101 01102 for (Index = 0; Index <= MAXIMUM_IDTVECTOR; Index += 1) { 01103 Temp = IDT[Index].Selector; 01104 IDT[Index].Selector = IDT[Index].ExtendedOffset; 01105 IDT[Index].ExtendedOffset = Temp; 01106 } 01107 } 01108 01109 ULONG 01110 KiGetCpuVendor( 01111 VOID 01112 ) 01113 01114 /*++ 01115 01116 Routine Description: 01117 01118 (Try to) Determine the manufacturer of this processor based on 01119 data returned by the CPUID instruction (if present). 01120 01121 Arguments: 01122 01123 None. 01124 01125 Return Value: 01126 01127 One of the members of the enumeration CPU_VENDORS (defined above). 01128 01129 --*/ 01130 { 01131 PKPRCB Prcb; 01132 ULONG Junk; 01133 ULONG Buffer[4]; 01134 01135 Prcb = KeGetCurrentPrcb(); 01136 Prcb->VendorString[0] = 0; 01137 01138 if (!Prcb->CpuID) { 01139 return CPU_NONE; 01140 } 01141 01142 CPUID(0, &Junk, Buffer+0, Buffer+2, Buffer+1); 01143 Buffer[3] = 0; 01144 01145 // 01146 // Copy vendor string to Prcb for debugging (ensure it's NULL 01147 // terminated). 01148 // 01149 01150 RtlCopyMemory( 01151 Prcb->VendorString, 01152 Buffer, 01153 sizeof(Prcb->VendorString) - 1 01154 ); 01155 01156 Prcb->VendorString[sizeof(Prcb->VendorString) - 1] = '\0'; 01157 01158 if (strcmp((PVOID)Buffer, CmpIntelID) == 0) { 01159 return CPU_INTEL; 01160 } else if (strcmp((PVOID)Buffer, CmpAmdID) == 0) { 01161 return CPU_AMD; 01162 } else if (strcmp((PVOID)Buffer, CmpCyrixID) == 0) { 01163 return CPU_CYRIX; 01164 } 01165 return CPU_UNKNOWN; 01166 } 01167 01168 ULONG 01169 KiGetFeatureBits ( 01170 VOID 01171 ) 01172 01173 /*++ 01174 01175 Routine Description: 01176 01177 Examine the processor specific feature bits to determine the 01178 Windows 2000 supported features supported by this processor. 01179 01180 Arguments: 01181 01182 None. 01183 01184 Return Value: 01185 01186 Returns a Windows 2000 normalized set of processor features. 01187 01188 --*/ 01189 01190 { 01191 ULONG Junk; 01192 ULONG Junk2; 01193 ULONG ProcessorFeatures; 01194 ULONG NtBits; 01195 ULONG ExtendedProcessorFeatures; 01196 ULONG ProcessorSignature; 01197 ULONG CpuVendor; 01198 PKPRCB Prcb; 01199 BOOLEAN ExtendedCPUIDSupport = TRUE; 01200 01201 Prcb = KeGetCurrentPrcb(); 01202 01203 NtBits = KF_WORKING_PTE; 01204 01205 // 01206 // Determine the processor type 01207 // 01208 01209 CpuVendor = KiGetCpuVendor(); 01210 01211 // 01212 // If this processor does not support the CPUID instruction, 01213 // don't try to use it. 01214 // 01215 01216 if (CpuVendor == CPU_NONE) { 01217 return NtBits; 01218 } 01219 01220 // 01221 // Determine which NT compatible features are present 01222 // 01223 01224 CPUID (1, &ProcessorSignature, &Junk, &Junk, &ProcessorFeatures); 01225 01226 // 01227 // AMD specific stuff 01228 // 01229 01230 if (CpuVendor == CPU_AMD) { 01231 01232 // 01233 // Check for K5 and above. 01234 // 01235 01236 if ((ProcessorSignature & 0x0F00) >= 0x0500) { 01237 01238 if ((ProcessorSignature & 0x0F00) == 0x0500) { 01239 01240 switch (ProcessorSignature & 0x00F0) { 01241 01242 case 0x0010: // K5 Model 1 01243 01244 // 01245 // for K5 Model 1 stepping 0 or 1 don't set global page 01246 // 01247 01248 if ((ProcessorSignature & 0x000F) > 0x03) { 01249 01250 // 01251 // K5 Model 1 stepping 2 or greater 01252 // 01253 01254 break; 01255 } 01256 01257 // 01258 // K5 Model 1 stepping 0 or 1, FALL THRU. 01259 // 01260 01261 case 0x0000: // K5 Model 0 01262 01263 // 01264 // for K5 Model 0 or model unknown don't set global page 01265 // 01266 01267 ProcessorFeatures &= ~0x2000; 01268 break; 01269 01270 case 0x0080: // K6 Model 8 (K6-2) 01271 01272 // 01273 // All steppings >= 8 support MTRRs. 01274 // 01275 01276 if ((ProcessorSignature & 0x000F) >= 0x8) { 01277 NtBits |= KF_AMDK6MTRR; 01278 } 01279 break; 01280 01281 case 0x0090: // K6 Model 9 (K6-3) 01282 01283 NtBits |= KF_AMDK6MTRR; 01284 break; 01285 01286 default: // anything else, nothing to do. 01287 01288 break; 01289 } 01290 } 01291 01292 } else { 01293 01294 // 01295 // Less than family 5, don't set GLOBAL PAGE, LARGE 01296 // PAGE or CMOV. (greater than family 5 will have the 01297 // bits set correctly). 01298 // 01299 01300 ProcessorFeatures &= ~(0x08 | 0x2000 | 0x8000); 01301 01302 // 01303 // We don't know what this processor returns if we 01304 // probe for extended CPUID support. 01305 // 01306 01307 ExtendedCPUIDSupport = FALSE; 01308 } 01309 } 01310 01311 // 01312 // Intel specific stuff 01313 // 01314 01315 if (CpuVendor == CPU_INTEL) { 01316 if (Prcb->CpuType == 6) { 01317 WRMSR (0x8B, 0); 01318 CPUID (1, &Junk, &Junk, &Junk, &ProcessorFeatures); 01319 Prcb->UpdateSignature.QuadPart = RDMSR (0x8B); 01320 } 01321 01322 else if (Prcb->CpuType == 5) { 01323 KiI386PentiumLockErrataPresent = TRUE; 01324 } 01325 01326 if ( ((ProcessorSignature & 0x0FF0) == 0x0610 && 01327 (ProcessorSignature & 0x000F) <= 0x9) || 01328 01329 ((ProcessorSignature & 0x0FF0) == 0x0630 && 01330 (ProcessorSignature & 0x000F) <= 0x4)) { 01331 01332 NtBits &= ~KF_WORKING_PTE; 01333 } 01334 01335 if ( (Prcb->CpuType == 6) && 01336 (Prcb->CpuStep >= 0x0303) && 01337 (ProcessorFeatures & KI_FAST_SYSCALL_SUPPORTED) ) { 01338 01339 // BUGBUG: Disable as it's preventing hibernate from working 01340 // NtBits |= KF_FAST_SYSCALL; 01341 } 01342 } 01343 01344 // 01345 // Cyrix specific stuff 01346 // 01347 01348 if (CpuVendor == CPU_CYRIX) { 01349 01350 // 01351 // Workaround bug 324467 which is caused by INTR being 01352 // held high too long during an FP instruction and causing 01353 // random Trap07 with no exception bits. 01354 // 01355 01356 extern BOOLEAN KiIgnoreUnexpectedTrap07; 01357 01358 KiIgnoreUnexpectedTrap07 = TRUE; 01359 01360 // 01361 // Workaround CMPXCHG bug to Cyrix processors where 01362 // Family = 6, Model = 0, Stepping <= 1. Note that 01363 // Prcb->CpuStep contains both model and stepping. 01364 // 01365 // Disable Locking in one of processor specific registers 01366 // (accessible via i/o space index/data pair). 01367 // 01368 01369 if ((Prcb->CpuType == 6) && 01370 (Prcb->CpuStep <= 1)) { 01371 01372 #define CRC_NDX (PUCHAR)0x22 01373 #define CRC_DAT (CRC_NDX + 1) 01374 #define CCR1 0xc1 01375 01376 UCHAR ValueCCR1; 01377 01378 // 01379 // Get current setting. 01380 // 01381 01382 WRITE_PORT_UCHAR(CRC_NDX, CCR1); 01383 01384 ValueCCR1 = READ_PORT_UCHAR(CRC_DAT); 01385 01386 // 01387 // Set the NO_LOCK bit and write it back. 01388 // 01389 01390 ValueCCR1 |= 0x10; 01391 01392 WRITE_PORT_UCHAR(CRC_NDX, CCR1); 01393 WRITE_PORT_UCHAR(CRC_DAT, ValueCCR1); 01394 01395 #undef CCR1 01396 #undef CRC_DAT 01397 #undef CRC_NDX 01398 } 01399 } 01400 01401 // 01402 // Check the standard CPUID feature bits. 01403 // 01404 // The following bits are known to work on Intel, AMD and Cyrix. 01405 // We hope (and assume) the clone makers will follow suit. 01406 // 01407 01408 if (ProcessorFeatures & 0x00000002) { 01409 NtBits |= KF_V86_VIS | KF_CR4; 01410 } 01411 01412 if (ProcessorFeatures & 0x00000008) { 01413 NtBits |= KF_LARGE_PAGE | KF_CR4; 01414 } 01415 01416 if (ProcessorFeatures & 0x00000010) { 01417 NtBits |= KF_RDTSC; 01418 } 01419 01420 // 01421 // N.B. CMPXCHG8B MUST be done in a generic manner or clone processors 01422 // will not be able to boot if they set this feature bit. 01423 // 01424 01425 if (ProcessorFeatures & 0x00000100) { 01426 NtBits |= KF_CMPXCHG8B; 01427 } 01428 01429 if (ProcessorFeatures & 0x00001000) { 01430 NtBits |= KF_MTRR; 01431 } 01432 01433 if (ProcessorFeatures & 0x00002000) { 01434 NtBits |= KF_GLOBAL_PAGE | KF_CR4; 01435 } 01436 01437 if (ProcessorFeatures & 0x00008000) { 01438 NtBits |= KF_CMOV; 01439 } 01440 01441 if (ProcessorFeatures & 0x00010000) { 01442 NtBits |= KF_PAT; 01443 } 01444 01445 if (ProcessorFeatures & 0x00800000) { 01446 NtBits |= KF_MMX; 01447 } 01448 01449 if (ProcessorFeatures & 0x01000000) { 01450 NtBits |= KF_FXSR; 01451 } 01452 01453 if (ProcessorFeatures & 0x02000000) { 01454 NtBits |= KF_XMMI; 01455 } 01456 01457 // 01458 // Check extended functions. First, check for existance, 01459 // then check extended function 0x80000001 (Extended Processor 01460 // Features) if present. 01461 // 01462 // Note: Intel guarantees that no processor that doesn't support 01463 // extended CPUID functions will ever return a value with the 01464 // most significant bit set. Microsoft asks all CPU vendors 01465 // to make the same guarantee. 01466 // 01467 01468 if (ExtendedCPUIDSupport != FALSE) { 01469 01470 CPUID(0x80000000, &Junk2, &Junk, &Junk, &Junk); 01471 01472 // 01473 // Sanity check the result, assuming there are no more 01474 // than 256 extended feature functions (should be valid 01475 // for a little while). 01476 // 01477 01478 if ((Junk2 & 0xffffff00) == 0x80000000) { 01479 01480 // 01481 // Check extended processor features. These, by definition, 01482 // can vary on a processor by processor basis. 01483 // 01484 01485 if (Junk2 >= 0x80000001) { 01486 01487 CPUID(0x80000001, &Junk2, &Junk, &Junk, &ExtendedProcessorFeatures); 01488 01489 // 01490 // With these, we can only do what we're told. 01491 // 01492 01493 switch (CpuVendor) { 01494 case CPU_AMD: 01495 01496 if (ExtendedProcessorFeatures & 0x80000000) { 01497 NtBits |= KF_3DNOW; 01498 } 01499 break; 01500 } 01501 } 01502 } 01503 } 01504 01505 return NtBits; 01506 } 01507 01508 VOID 01509 KiGetCacheInformation( 01510 VOID 01511 ) 01512 { 01513 #define CPUID_REG_COUNT 4 01514 ULONG CpuidData[CPUID_REG_COUNT]; 01515 01516 ULONG CpuVendor; 01517 PKPCR Pcr; 01518 01519 // 01520 // Set default. 01521 // 01522 01523 Pcr = KeGetPcr(); 01524 01525 Pcr->SecondLevelCacheSize = 0; 01526 01527 // 01528 // Determine the processor manufacturer 01529 // 01530 01531 CpuVendor = KiGetCpuVendor(); 01532 01533 if (CpuVendor == CPU_NONE) { 01534 return; 01535 } 01536 01537 // 01538 // Obtain Cache size information for those processors on which 01539 // we know how. 01540 // 01541 01542 switch (CpuVendor) { 01543 case CPU_INTEL: 01544 01545 CPUID(0, CpuidData, CpuidData+1, CpuidData+2, CpuidData+3); 01546 01547 // 01548 // Check this processor supports CPUID function 2 which is the 01549 // one that returns cache size info. 01550 // 01551 01552 if (CpuidData[0] >= 2) { 01553 01554 // 01555 // The above returns a series of bytes. (In EAX, EBX, ECX 01556 // and EDX). The least significant byte (of EAX) gives the 01557 // number of times CPUID(2 ...) should be issued to return 01558 // the complete set of data. The bytes are self describing 01559 // data. 01560 // 01561 // In particular, the bytes describing the L2 cache size 01562 // will be in the following set (and meaning) 01563 // 01564 // 0x40 0 bytes 01565 // 0x41 128K bytes 01566 // 0x42 256K bytes 01567 // 0x43 512K bytes 01568 // 0x44 1024K bytes 01569 // 0x45 2048K bytes 01570 // 0x46 4096K bytes 01571 // 01572 // I am extrapolating the above as anything in the range 01573 // 0x41 thru 0x4f can be computed as 01574 // 01575 // 128KB << (descriptor - 0x41) 01576 // 01577 // The Intel folks say keep it to a reasonable upper bound, 01578 // eg 49. 01579 // 01580 // N.B. the range 0x80 .. 0x86 indicates the same cache 01581 // sizes but 8 way associative. 01582 // 01583 // Also, the most significant bit of each register indicates 01584 // whether not the register contains valid information. 01585 // 0 == Valid, 1 == InValid. 01586 // 01587 01588 ULONG CpuidIterations; 01589 ULONG i; 01590 ULONG CpuidReg; 01591 01592 BOOLEAN FirstPass = TRUE; 01593 01594 do { 01595 CPUID(2, CpuidData, CpuidData+1, CpuidData+2, CpuidData+3); 01596 01597 if (FirstPass) { 01598 01599 // 01600 // Get the iteration count from the first byte 01601 // of the returned data then replace that byte 01602 // with 0 (a null descriptor). 01603 // 01604 01605 CpuidIterations = CpuidData[0] & 0xff; 01606 CpuidData[0] &= 0xffffff00; 01607 01608 FirstPass = FALSE; 01609 } 01610 01611 for (i = 0; i < CPUID_REG_COUNT; i++) { 01612 01613 CpuidReg = CpuidData[i]; 01614 01615 if (CpuidReg & 0x80000000) { 01616 01617 // 01618 // Register doesn't contain valid data, 01619 // skip it. 01620 // 01621 01622 continue; 01623 } 01624 01625 while (CpuidReg) { 01626 01627 // 01628 // Get LS Byte from this DWORD and remove the 01629 // byte. 01630 // 01631 01632 UCHAR Descriptor = (UCHAR)(CpuidReg & 0xff); 01633 CpuidReg >>= 8; 01634 01635 if (Descriptor == 0) { 01636 01637 // 01638 // NULL descriptor 01639 // 01640 01641 continue; 01642 } 01643 01644 if (((Descriptor > 0x40) && (Descriptor <= 0x49)) || 01645 ((Descriptor > 0x80) && (Descriptor <= 0x89))) { 01646 01647 // 01648 // L2 descriptor. 01649 // 01650 01651 Descriptor &= 0x0f; 01652 01653 // 01654 // Assert the descriptor is in the range we 01655 // officially know about. If this hits on 01656 // a checked build, check with Intel about 01657 // the interpretation. 01658 // 01659 01660 ASSERT(Descriptor <= 0x6); 01661 01662 Pcr->SecondLevelCacheSize = 0x10000 << Descriptor; 01663 } 01664 01665 // 01666 // else if (do other descriptors) 01667 // 01668 01669 } // while more bytes in this register 01670 01671 } // for each register 01672 01673 // 01674 // Note: Always run thru all iterations indicated by 01675 // the first to ensure a subsequent call won't start 01676 // part way thru. 01677 // 01678 01679 } while (--CpuidIterations); 01680 } 01681 break; 01682 case CPU_AMD: 01683 break; 01684 } 01685 #undef CPUID_REG_COUNT 01686 } 01687 01688 #define MAX_ATTEMPTS 10 01689 01690 BOOLEAN 01691 KiInitMachineDependent ( 01692 VOID 01693 ) 01694 { 01695 KAFFINITY ActiveProcessors, CurrentAffinity; 01696 ULONG NumberProcessors; 01697 IDENTITY_MAP IdentityMap; 01698 ULONG Index; 01699 ULONG Average; 01700 ULONG Junk; 01701 struct { 01702 LARGE_INTEGER PerfStart; 01703 LARGE_INTEGER PerfEnd; 01704 LONGLONG PerfDelta; 01705 LARGE_INTEGER PerfFreq; 01706 LONGLONG TSCStart; 01707 LONGLONG TSCEnd; 01708 LONGLONG TSCDelta; 01709 ULONG MHz; 01710 } Samples[MAX_ATTEMPTS], *pSamp; 01711 PUCHAR PatchLocation; 01712 01713 // 01714 // If PDE large page is supported, enable it. 01715 // 01716 // We enable large pages before global pages to make TLB invalidation 01717 // easier while turning on large pages. 01718 // 01719 01720 if (KeFeatureBits & KF_LARGE_PAGE) { 01721 if (Ki386CreateIdentityMap(&IdentityMap, 01722 &Ki386EnableCurrentLargePage, 01723 &Ki386EnableCurrentLargePageEnd )) { 01724 01725 KiIpiGenericCall ( 01726 (PKIPI_BROADCAST_WORKER) Ki386EnableTargetLargePage, 01727 (ULONG)(&IdentityMap) 01728 ); 01729 } 01730 01731 // 01732 // Always call Ki386ClearIdentityMap() to free any memory allocated 01733 // 01734 01735 Ki386ClearIdentityMap(&IdentityMap); 01736 } 01737 01738 // 01739 // If PDE/PTE global page is supported, enable it 01740 // 01741 01742 if (KeFeatureBits & KF_GLOBAL_PAGE) { 01743 NumberProcessors = KeNumberProcessors; 01744 KiIpiGenericCall ( 01745 (PKIPI_BROADCAST_WORKER) Ki386EnableGlobalPage, 01746 (ULONG)(&NumberProcessors) 01747 ); 01748 } 01749 01750 #if !defined(NT_UP) 01751 01752 // 01753 // If some processor doesn't have proper MP PTE implementation, 01754 // then use a synchronous TB shoot down handler 01755 // 01756 01757 if (!(KeFeatureBits & KF_WORKING_PTE)) { 01758 NumberProcessors = KeNumberProcessors; 01759 KiIpiGenericCall ( 01760 (PKIPI_BROADCAST_WORKER) Ki386UseSynchronousTbFlush, 01761 (ULONG)(&NumberProcessors) 01762 ); 01763 } 01764 01765 #endif 01766 01767 // 01768 // If PAT or MTRR supported but the HAL indicates it shouldn't 01769 // be used (eg on a Shared Memory Cluster), drop the feature. 01770 // 01771 01772 if (KeFeatureBits & (KF_PAT | KF_MTRR)) { 01773 01774 NTSTATUS Status; 01775 BOOLEAN UseFrameBufferCaching; 01776 ULONG Size; 01777 01778 Status = HalQuerySystemInformation( 01779 HalFrameBufferCachingInformation, 01780 sizeof(UseFrameBufferCaching), 01781 &UseFrameBufferCaching, 01782 &Size 01783 ); 01784 01785 if (NT_SUCCESS(Status) && 01786 (UseFrameBufferCaching == FALSE)) { 01787 01788 // 01789 // Hal says don't use. 01790 // 01791 01792 KeFeatureBits &= ~(KF_PAT | KF_MTRR); 01793 } 01794 } 01795 01796 01797 // 01798 // If PAT is supported then initialize it. 01799 // 01800 01801 if (KeFeatureBits & KF_PAT) { 01802 KiInitializePAT(); 01803 } 01804 01805 // 01806 // Compute each processors approximate mhz 01807 // 01808 01809 // 01810 // If FXSR feature is supported, set OSFXSR (bit 9) in CR4 01811 // 01812 01813 if (KeFeatureBits & KF_FXSR) { 01814 NumberProcessors = KeNumberProcessors; 01815 01816 KiIpiGenericCall ( 01817 (PKIPI_BROADCAST_WORKER) Ki386EnableFxsr, 01818 (ULONG)(&NumberProcessors) 01819 ); 01820 01821 01822 // 01823 // If XMMI feature is supported, 01824 // a. Hook int 19 handler 01825 // b. Set OSXMMEXCPT (bit 10) in CR4 01826 // c. Enable use of fast XMMI based zero page routines. 01827 // 01828 01829 if (KeFeatureBits & KF_XMMI) { 01830 KiIpiGenericCall ( 01831 (PKIPI_BROADCAST_WORKER) Ki386EnableXMMIExceptions, 01832 (ULONG)(&NumberProcessors) 01833 ); 01834 01835 KeZeroPage = KiXMMIZeroPage; 01836 KeZeroPageFromIdleThread = KiXMMIZeroPageNoSave; 01837 } 01838 01839 01840 } else { 01841 #ifndef NT_UP 01842 // 01843 // Patch the fxsave instruction in SwapContext to use 01844 // "fnsave {dd, 31}, fwait {9b}" 01845 // 01846 ASSERT( ((ULONG)&ScPatchFxe-(ULONG)&ScPatchFxb) >= 3); 01847 01848 PatchLocation = (PUCHAR)&ScPatchFxb; 01849 01850 *PatchLocation++ = 0xdd; 01851 *PatchLocation++ = 0x31; 01852 *PatchLocation++ = 0x9b; 01853 01854 while (PatchLocation < (PUCHAR)&ScPatchFxe) { 01855 // 01856 // Put nop's in the remaining bytes 01857 // 01858 *PatchLocation++ = 0x90; 01859 } 01860 #endif 01861 } 01862 01863 ActiveProcessors = KeActiveProcessors; 01864 for (CurrentAffinity=1; ActiveProcessors; CurrentAffinity <<= 1) { 01865 01866 if (ActiveProcessors & CurrentAffinity) { 01867 01868 // 01869 // Switch to that processor, and remove it from the 01870 // remaining set of processors 01871 // 01872 01873 ActiveProcessors &= ~CurrentAffinity; 01874 KeSetSystemAffinityThread(CurrentAffinity); 01875 01876 // 01877 // Determine the MHz for the processor 01878 // 01879 01880 KeGetCurrentPrcb()->MHz = 0; 01881 01882 if (KeFeatureBits & KF_RDTSC) { 01883 01884 Index = 0; 01885 pSamp = Samples; 01886 01887 for (; ;) { 01888 01889 // 01890 // Collect a new sample 01891 // Delay the thread a "long" amount and time it with 01892 // a time source and RDTSC. 01893 // 01894 01895 CPUID (0, &Junk, &Junk, &Junk, &Junk); 01896 pSamp->PerfStart = KeQueryPerformanceCounter (NULL); 01897 pSamp->TSCStart = RDTSC(); 01898 pSamp->PerfFreq.QuadPart = -50000; 01899 01900 KeDelayExecutionThread (KernelMode, FALSE, &pSamp->PerfFreq); 01901 01902 CPUID (0, &Junk, &Junk, &Junk, &Junk); 01903 pSamp->PerfEnd = KeQueryPerformanceCounter (&pSamp->PerfFreq); 01904 pSamp->TSCEnd = RDTSC(); 01905 01906 // 01907 // Calculate processors MHz 01908 // 01909 01910 pSamp->PerfDelta = pSamp->PerfEnd.QuadPart - pSamp->PerfStart.QuadPart; 01911 pSamp->TSCDelta = pSamp->TSCEnd - pSamp->TSCStart; 01912 01913 pSamp->MHz = (ULONG) ((pSamp->TSCDelta * pSamp->PerfFreq.QuadPart + 500000L) / 01914 (pSamp->PerfDelta * 1000000L)); 01915 01916 01917 // 01918 // If last 2 samples matched within a MHz, done 01919 // 01920 01921 if (Index) { 01922 if (pSamp->MHz == pSamp[-1].MHz || 01923 pSamp->MHz == pSamp[-1].MHz + 1 || 01924 pSamp->MHz == pSamp[-1].MHz - 1) { 01925 break; 01926 } 01927 } 01928 01929 // 01930 // Advance to next sample 01931 // 01932 01933 pSamp += 1; 01934 Index += 1; 01935 01936 // 01937 // If too many samples, then something is wrong 01938 // 01939 01940 if (Index >= MAX_ATTEMPTS) { 01941 01942 #if DBG 01943 // 01944 // Temp breakpoint to see where this is failing 01945 // and why 01946 // 01947 01948 DbgBreakPoint(); 01949 #endif 01950 01951 Average = 0; 01952 for (Index = 0; Index < MAX_ATTEMPTS; Index++) { 01953 Average += Samples[Index].MHz; 01954 } 01955 pSamp[-1].MHz = Average / MAX_ATTEMPTS; 01956 break; 01957 } 01958 01959 } 01960 01961 KeGetCurrentPrcb()->MHz = (USHORT) pSamp[-1].MHz; 01962 } 01963 01964 // 01965 // If MTRRs are supported and PAT not supported, initialize MTRRs 01966 // per processor 01967 // 01968 01969 if (!(KeFeatureBits & KF_PAT) && (KeFeatureBits & KF_MTRR)) { 01970 KiInitializeMTRR ( (BOOLEAN) (ActiveProcessors ? FALSE : TRUE)); 01971 } 01972 01973 // 01974 // If the processor is a AMD K6 with MTRR support then 01975 // perform processor specific initialization. 01976 // 01977 01978 if (KeFeatureBits & KF_AMDK6MTRR) { 01979 KiAmdK6InitializeMTRR(); 01980 } 01981 01982 // 01983 // Apply Pentium workaround if needed 01984 // 01985 01986 if (KiI386PentiumLockErrataPresent) { 01987 KiI386PentiumLockErrataFixup (); 01988 } 01989 } 01990 } 01991 01992 KeRevertToUserAffinityThread(); 01993 return TRUE; 01994 } 01995 01996 01997 VOID 01998 KeOptimizeProcessorControlState ( 01999 VOID 02000 ) 02001 { 02002 Ke386ConfigureCyrixProcessor (); 02003 } 02004 02005 02006 02007 VOID 02008 KeSetup80387OrEmulate ( 02009 IN PVOID *R3EmulatorTable 02010 ) 02011 02012 /*++ 02013 02014 Routine Description: 02015 02016 This routine is called by PS initialization after loading NTDLL. 02017 02018 If this is a 386 system without 387s (all processors must be 02019 symmetrical) then this function will set the trap 07 vector on all 02020 processors to point to the address passed in (which should be the 02021 entry point of the 80387 emulator in NTDLL, NPXNPHandler). 02022 02023 Arguments: 02024 02025 HandlerAddress - Supplies the address of the trap07 handler. 02026 02027 Return Value: 02028 02029 None. 02030 02031 --*/ 02032 02033 { 02034 PKINTERRUPT_ROUTINE HandlerAddress; 02035 KAFFINITY ActiveProcessors, CurrentAffinity; 02036 KIRQL OldIrql; 02037 ULONG disposition; 02038 HANDLE SystemHandle, SourceHandle, DestHandle; 02039 NTSTATUS Status; 02040 UNICODE_STRING unicodeString; 02041 OBJECT_ATTRIBUTES ObjectAttributes; 02042 double Dividend, Divisor; 02043 BOOLEAN PrecisionErrata; 02044 02045 if (KeI386NpxPresent) { 02046 02047 // 02048 // A coprocessor is present - check to see if the precision errata exists 02049 // 02050 02051 PrecisionErrata = FALSE; 02052 02053 ActiveProcessors = KeActiveProcessors; 02054 for (CurrentAffinity = 1; ActiveProcessors; CurrentAffinity <<= 1) { 02055 02056 if (ActiveProcessors & CurrentAffinity) { 02057 ActiveProcessors &= ~CurrentAffinity; 02058 02059 // 02060 // Run calculation on each processor. 02061 // 02062 02063 KeSetSystemAffinityThread(CurrentAffinity); 02064 _asm { 02065 02066 ; 02067 ; This is going to destroy the state in the coprocesssor, 02068 ; but we know that there's no state currently in it. 02069 ; 02070 02071 cli 02072 mov eax, cr0 02073 mov ecx, eax ; hold original cr0 value 02074 and eax, not (CR0_TS+CR0_MP+CR0_EM) 02075 mov cr0, eax 02076 02077 fninit ; to known state 02078 } 02079 02080 Dividend = 4195835.0; 02081 Divisor = 3145727.0; 02082 02083 _asm { 02084 fld Dividend 02085 fdiv Divisor ; test known faulty divison 02086 fmul Divisor ; Multiple quotient by divisor 02087 fcomp Dividend ; Compare product and dividend 02088 fstsw ax ; Move float conditions to ax 02089 sahf ; move to eflags 02090 02091 mov cr0, ecx ; restore cr0 02092 sti 02093 02094 jc short em10 02095 jz short em20 02096 em10: mov PrecisionErrata, TRUE 02097 em20: 02098 } 02099 } 02100 } 02101 02102 02103 // 02104 // Check to see if the emulator should be used anyway 02105 // 02106 02107 switch (KeI386ForceNpxEmulation) { 02108 case 0: 02109 // 02110 // Use the emulator based on the value in KeI386NpxPresent 02111 // 02112 02113 break; 02114 02115 case 1: 02116 // 02117 // Only use the emulator if any processor has the known 02118 // Pentium floating point division problem. 02119 // 02120 02121 if (PrecisionErrata) { 02122 KeI386NpxPresent = FALSE; 02123 } 02124 break; 02125 02126 default: 02127 02128 // 02129 // Unknown setting - use the emulator 02130 // 02131 02132 KeI386NpxPresent = FALSE; 02133 break; 02134 } 02135 } 02136 02137 // 02138 // Setup processor features, and install emulator if needed 02139 // 02140 02141 SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_EMULATED] = !KeI386NpxPresent; 02142 SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] = PrecisionErrata; 02143 02144 if (!KeI386NpxPresent) { 02145 02146 // 02147 // MMx not available when emulator is used 02148 // 02149 02150 KeFeatureBits &= ~(KF_MMX|KF_FXSR|KF_XMMI); 02151 SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] = FALSE; 02152 SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] = FALSE; 02153 SharedUserData->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] = FALSE; 02154 02155 // 02156 // Errata not present when using emulator 02157 // 02158 02159 SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] = FALSE; 02160 02161 // 02162 // Use the user mode floating point emulator 02163 // 02164 02165 HandlerAddress = (PKINTERRUPT_ROUTINE) ((PULONG) R3EmulatorTable)[0]; 02166 Ki387RoundModeTable = (PVOID) ((PULONG) R3EmulatorTable)[1]; 02167 02168 ActiveProcessors = KeActiveProcessors; 02169 for (CurrentAffinity = 1; ActiveProcessors; CurrentAffinity <<= 1) { 02170 02171 if (ActiveProcessors & CurrentAffinity) { 02172 ActiveProcessors &= ~CurrentAffinity; 02173 02174 // 02175 // Run this code on each processor. 02176 // 02177 02178 KeSetSystemAffinityThread(CurrentAffinity); 02179 02180 // 02181 // Raise IRQL and lock dispatcher database. 02182 // 02183 02184 KiLockDispatcherDatabase(&OldIrql); 02185 02186 // 02187 // Make the trap 07 IDT entry point at the passed-in handler 02188 // 02189 02190 KiSetHandlerAddressToIDT(I386_80387_NP_VECTOR, HandlerAddress); 02191 KeGetPcr()->IDT[I386_80387_NP_VECTOR].Selector = KGDT_R3_CODE; 02192 KeGetPcr()->IDT[I386_80387_NP_VECTOR].Access = TRAP332_GATE; 02193 02194 02195 // 02196 // Unlock dispatcher database and lower IRQL to its previous value. 02197 // 02198 02199 KiUnlockDispatcherDatabase(OldIrql); 02200 } 02201 } 02202 02203 // 02204 // Move any entries from ..\System\FloatingPointProcessor to 02205 // ..\System\DisabledFloatingPointProcessor. 02206 // 02207 02208 // 02209 // Open system tree 02210 // 02211 02212 InitializeObjectAttributes( 02213 &ObjectAttributes, 02214 &CmRegistryMachineHardwareDescriptionSystemName, 02215 OBJ_CASE_INSENSITIVE, 02216 NULL, 02217 NULL 02218 ); 02219 02220 Status = ZwOpenKey( &SystemHandle, 02221 KEY_ALL_ACCESS, 02222 &ObjectAttributes 02223 ); 02224 02225 if (NT_SUCCESS(Status)) { 02226 02227 // 02228 // Open FloatingPointProcessor key 02229 // 02230 02231 InitializeObjectAttributes( 02232 &ObjectAttributes, 02233 &CmTypeName[FloatingPointProcessor], 02234 OBJ_CASE_INSENSITIVE, 02235 SystemHandle, 02236 NULL 02237 ); 02238 02239 Status = ZwOpenKey ( &SourceHandle, 02240 KEY_ALL_ACCESS, 02241 &ObjectAttributes 02242 ); 02243 02244 if (NT_SUCCESS(Status)) { 02245 02246 // 02247 // Create DisabledFloatingPointProcessor key 02248 // 02249 02250 RtlInitUnicodeString ( 02251 &unicodeString, 02252 CmDisabledFloatingPointProcessor 02253 ); 02254 02255 InitializeObjectAttributes( 02256 &ObjectAttributes, 02257 &unicodeString, 02258 OBJ_CASE_INSENSITIVE, 02259 SystemHandle, 02260 NULL 02261 ); 02262 02263 Status = ZwCreateKey( &DestHandle, 02264 KEY_ALL_ACCESS, 02265 &ObjectAttributes, 02266 0, 02267 NULL, 02268 REG_OPTION_VOLATILE, 02269 &disposition 02270 ); 02271 02272 if (NT_SUCCESS(Status)) { 02273 02274 // 02275 // Move it 02276 // 02277 02278 KiMoveRegTree (SourceHandle, DestHandle); 02279 ZwClose (DestHandle); 02280 } 02281 ZwClose (SourceHandle); 02282 } 02283 ZwClose (SystemHandle); 02284 } 02285 } 02286 02287 // 02288 // Set affinity back to the original value. 02289 // 02290 02291 KeRevertToUserAffinityThread(); 02292 } 02293 02294 02295 02296 NTSTATUS 02297 KiMoveRegTree( 02298 HANDLE Source, 02299 HANDLE Dest 02300 ) 02301 { 02302 NTSTATUS Status; 02303 PKEY_BASIC_INFORMATION KeyInformation; 02304 PKEY_VALUE_FULL_INFORMATION KeyValue; 02305 OBJECT_ATTRIBUTES ObjectAttributes; 02306 HANDLE SourceChild; 02307 HANDLE DestChild; 02308 ULONG ResultLength; 02309 UCHAR buffer[1024]; // hmm.... 02310 UNICODE_STRING ValueName; 02311 UNICODE_STRING KeyName; 02312 02313 02314 KeyValue = (PKEY_VALUE_FULL_INFORMATION)buffer; 02315 02316 // 02317 // Move values from source node to dest node 02318 // 02319 02320 for (; ;) { 02321 // 02322 // Get first value 02323 // 02324 02325 Status = ZwEnumerateValueKey(Source, 02326 0, 02327 KeyValueFullInformation, 02328 buffer, 02329 sizeof (buffer), 02330 &ResultLength); 02331 02332 if (!NT_SUCCESS(Status)) { 02333 break; 02334 } 02335 02336 02337 // 02338 // Write value to dest node 02339 // 02340 02341 ValueName.Buffer = KeyValue->Name; 02342 ValueName.Length = (USHORT) KeyValue->NameLength; 02343 ZwSetValueKey( Dest, 02344 &ValueName, 02345 KeyValue->TitleIndex, 02346 KeyValue->Type, 02347 buffer+KeyValue->DataOffset, 02348 KeyValue->DataLength 02349 ); 02350 02351 // 02352 // Delete value and get first value again 02353 // 02354 02355 Status = ZwDeleteValueKey (Source, &ValueName); 02356 if (!NT_SUCCESS(Status)) { 02357 break; 02358 } 02359 } 02360 02361 02362 // 02363 // Enumerate node's children and apply ourselves to each one 02364 // 02365 02366 KeyInformation = (PKEY_BASIC_INFORMATION)buffer; 02367 for (; ;) { 02368 02369 // 02370 // Open node's first key 02371 // 02372 02373 Status = ZwEnumerateKey( 02374 Source, 02375 0, 02376 KeyBasicInformation, 02377 KeyInformation, 02378 sizeof (buffer), 02379 &ResultLength 02380 ); 02381 02382 if (!NT_SUCCESS(Status)) { 02383 break; 02384 } 02385 02386 KeyName.Buffer = KeyInformation->Name; 02387 KeyName.Length = (USHORT) KeyInformation->NameLength; 02388 02389 InitializeObjectAttributes( 02390 &ObjectAttributes, 02391 &KeyName, 02392 OBJ_CASE_INSENSITIVE, 02393 Source, 02394 NULL 02395 ); 02396 02397 Status = ZwOpenKey( 02398 &SourceChild, 02399 KEY_ALL_ACCESS, 02400 &ObjectAttributes 02401 ); 02402 02403 if (!NT_SUCCESS(Status)) { 02404 break; 02405 } 02406 02407 // 02408 // Create key in dest tree 02409 // 02410 02411 InitializeObjectAttributes( 02412 &ObjectAttributes, 02413 &KeyName, 02414 OBJ_CASE_INSENSITIVE, 02415 Dest, 02416 NULL 02417 ); 02418 02419 Status = ZwCreateKey( 02420 &DestChild, 02421 KEY_ALL_ACCESS, 02422 &ObjectAttributes, 02423 0, 02424 NULL, 02425 REG_OPTION_VOLATILE, 02426 NULL 02427 ); 02428 02429 if (!NT_SUCCESS(Status)) { 02430 break; 02431 } 02432 02433 // 02434 // Move subtree 02435 // 02436 02437 Status = KiMoveRegTree(SourceChild, DestChild); 02438 02439 ZwClose(DestChild); 02440 ZwClose(SourceChild); 02441 02442 if (!NT_SUCCESS(Status)) { 02443 break; 02444 } 02445 02446 // 02447 // Loop and get first key. (old first key was delete by the 02448 // call to KiMoveRegTree). 02449 // 02450 } 02451 02452 // 02453 // Remove source node 02454 // 02455 02456 return NtDeleteKey (Source); 02457 } 02458 02459 VOID 02460 KiI386PentiumLockErrataFixup ( 02461 VOID 02462 ) 02463 02464 /*++ 02465 02466 Routine Description: 02467 02468 This routine is called once on every processor when 02469 KiI386PentiumLockErrataPresent is TRUE. 02470 02471 This routine replaces the local IDT with an IDT that has the first 7 IDT 02472 entries on their own page and returns the first page to the caller to 02473 be marked as read-only. This causes the processor to trap-0e fault when 02474 the errata occurs. Special code in the trap-0e handler detects the 02475 problem and performs the proper fixup. 02476 02477 Arguments: 02478 02479 FixupPage - Returns a virtual address of a page to be marked read-only 02480 02481 Return Value: 02482 02483 None. 02484 02485 --*/ 02486 02487 { 02488 KDESCRIPTOR IdtDescriptor; 02489 ULONG OrginalBase; 02490 PUCHAR NewBase, BasePage; 02491 BOOLEAN Enable; 02492 BOOLEAN Status; 02493 02494 02495 #define IDT_SKIP (7 * sizeof (KIDTENTRY)) 02496 02497 // 02498 // Allocate memory for a new copy of the processors IDT 02499 // 02500 02501 BasePage = MmAllocateIndependentPages (2*PAGE_SIZE); 02502 02503 // 02504 // The IDT base is such that the first 7 entries are on the 02505 // first (read-only) page, and the remaining entries are on the 02506 // second (read-write) page 02507 // 02508 02509 NewBase = BasePage + PAGE_SIZE - IDT_SKIP; 02510 02511 // 02512 // Disable interrupts on this processor while updating the IDT base 02513 // 02514 02515 Enable = KiDisableInterrupts(); 02516 02517 // 02518 // Copy Old IDT to new IDT 02519 // 02520 02521 _asm { 02522 sidt IdtDescriptor.Limit 02523 } 02524 02525 RtlMoveMemory ((PVOID) NewBase, 02526 (PVOID) IdtDescriptor.Base, 02527 IdtDescriptor.Limit + 1 02528 ); 02529 02530 IdtDescriptor.Base = (ULONG) NewBase; 02531 02532 // 02533 // Set the new IDT 02534 // 02535 02536 _asm { 02537 lidt IdtDescriptor.Limit 02538 } 02539 02540 // 02541 // Update the PCR 02542 // 02543 02544 KeGetPcr()->IDT = (PKIDTENTRY) NewBase; 02545 02546 // 02547 // Restore interrupts 02548 // 02549 02550 KiRestoreInterrupts(Enable); 02551 02552 // 02553 // Mark the first page which contains IDT entries 0-6 as read-only 02554 // 02555 02556 Status = MmSetPageProtection (BasePage, PAGE_SIZE, PAGE_READONLY); 02557 ASSERT (Status); 02558 }

Generated on Sat May 15 19:40:35 2004 for test by doxygen 1.3.7