test: kernlini.c Source File

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 }