Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3232 lines
85 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. kernlini.c
  5. Abstract:
  6. This module contains the code to initialize the kernel data structures
  7. and to initialize the idle thread, its process, and the processor control
  8. block.
  9. For the i386, it also contains code to initialize the PCR.
  10. Author:
  11. David N. Cutler (davec) 21-Apr-1989
  12. Environment:
  13. Kernel mode only.
  14. Revision History:
  15. 24-Jan-1990 shielin
  16. Changed for NT386
  17. 20-Mar-1990 bryanwi
  18. Added KiInitializePcr
  19. --*/
  20. #include "ki.h"
  21. #include "fastsys.inc"
  22. #pragma warning(disable:4725) // instruction may be inaccurate on some Pentiums
  23. #define TRAP332_GATE 0xEF00
  24. VOID
  25. KiSetProcessorType(
  26. VOID
  27. );
  28. VOID
  29. KiSetCR0Bits(
  30. VOID
  31. );
  32. BOOLEAN
  33. KiIsNpxPresent(
  34. VOID
  35. );
  36. VOID
  37. KiI386PentiumLockErrataFixup (
  38. VOID
  39. );
  40. VOID
  41. KiInitializeDblFaultTSS(
  42. IN PKTSS Tss,
  43. IN ULONG Stack,
  44. IN PKGDTENTRY TssDescriptor
  45. );
  46. VOID
  47. KiInitializeTSS2 (
  48. IN PKTSS Tss,
  49. IN PKGDTENTRY TssDescriptor
  50. );
  51. VOID
  52. KiSwapIDT (
  53. VOID
  54. );
  55. VOID
  56. KeSetup80387OrEmulate (
  57. IN PVOID *R3EmulatorTable
  58. );
  59. VOID
  60. KiGetCacheInformation(
  61. VOID
  62. );
  63. ULONG
  64. KiGetCpuVendor(
  65. VOID
  66. );
  67. ULONG
  68. KiGetFeatureBits (
  69. VOID
  70. );
  71. NTSTATUS
  72. KiMoveRegTree(
  73. HANDLE Source,
  74. HANDLE Dest
  75. );
  76. VOID
  77. Ki386EnableDE (
  78. IN volatile PLONG Number
  79. );
  80. VOID
  81. Ki386EnableFxsr (
  82. IN volatile PLONG Number
  83. );
  84. VOID
  85. Ki386EnableXMMIExceptions (
  86. IN volatile PLONG Number
  87. );
  88. VOID
  89. Ki386EnableGlobalPage (
  90. IN volatile PLONG Number
  91. );
  92. BOOLEAN
  93. KiInitMachineDependent (
  94. VOID
  95. );
  96. VOID
  97. KiInitializeMTRR (
  98. IN BOOLEAN LastProcessor
  99. );
  100. VOID
  101. KiInitializePAT (
  102. VOID
  103. );
  104. VOID
  105. KiAmdK6InitializeMTRR(
  106. VOID
  107. );
  108. VOID
  109. KiRestoreFastSyscallReturnState(
  110. VOID
  111. );
  112. #ifdef ALLOC_PRAGMA
  113. #pragma alloc_text(INIT,KiInitializeKernel)
  114. #pragma alloc_text(INIT,KiInitializePcr)
  115. #pragma alloc_text(INIT,KiInitializeDblFaultTSS)
  116. #pragma alloc_text(INIT,KiInitializeTSS2)
  117. #pragma alloc_text(INIT,KiSwapIDT)
  118. #pragma alloc_text(INIT,KeSetup80387OrEmulate)
  119. #pragma alloc_text(INIT,KiGetFeatureBits)
  120. #pragma alloc_text(INIT,KiGetCacheInformation)
  121. #pragma alloc_text(INIT,KiGetCpuVendor)
  122. #pragma alloc_text(INIT,KiMoveRegTree)
  123. #pragma alloc_text(INIT,KiInitMachineDependent)
  124. #pragma alloc_text(INIT,KiI386PentiumLockErrataFixup)
  125. #endif
  126. BOOLEAN KiI386PentiumLockErrataPresent = FALSE;
  127. BOOLEAN KiIgnoreUnexpectedTrap07 = FALSE;
  128. ULONG KiFastSystemCallDisable;
  129. ULONG KiXMMIZeroingEnable;
  130. extern PVOID Ki387RoundModeTable;
  131. extern PVOID Ki386IopmSaveArea;
  132. extern ULONG KeI386ForceNpxEmulation;
  133. extern WCHAR CmDisabledFloatingPointProcessor[];
  134. extern CHAR CmpCyrixID[];
  135. extern CHAR CmpIntelID[];
  136. extern CHAR CmpAmdID[];
  137. extern CHAR CmpTransmetaID[];
  138. extern CHAR CmpCentaurID[];
  139. extern BOOLEAN KiFastSystemCallIsIA32;
  140. extern ULONG KiTimeLimitIsrMicroseconds;
  141. extern BOOLEAN KiSMTProcessorsPresent;
  142. extern BOOLEAN KiUnlicensedProcessorPresent;
  143. //
  144. // Declare routines who's addresses are taken but that are not otherwise
  145. // referenced in this module.
  146. //
  147. VOID FASTCALL KiTimedChainedDispatch2ndLvl(PVOID);
  148. VOID FASTCALL KiTimedInterruptDispatch(PVOID);
  149. VOID KiChainedDispatch2ndLvl(VOID);
  150. //
  151. // Declare KiGetInterruptDispatchPatchAddresses.
  152. //
  153. VOID
  154. KiGetInterruptDispatchPatchAddresses(
  155. PULONG_PTR Address1,
  156. PULONG_PTR Address2
  157. );
  158. #ifndef NT_UP
  159. extern PVOID ScPatchFxb;
  160. extern PVOID ScPatchFxe;
  161. #endif
  162. typedef enum {
  163. CPU_NONE,
  164. CPU_INTEL,
  165. CPU_AMD,
  166. CPU_CYRIX,
  167. CPU_TRANSMETA,
  168. CPU_CENTAUR,
  169. CPU_UNKNOWN
  170. } CPU_VENDORS;
  171. //
  172. // If this processor does XMMI, take advantage of it. Default is
  173. // no XMMI.
  174. //
  175. BOOLEAN KeI386XMMIPresent;
  176. //
  177. // x86 statically provides the idle process and idle thread for
  178. // processor 0.
  179. //
  180. EPROCESS KiIdleProcess;
  181. ETHREAD KiIdleThread0;
  182. //
  183. // Define prototypes and static initialization for the fast zero
  184. // page routines.
  185. //
  186. VOID
  187. FASTCALL
  188. KiZeroPages (
  189. IN PVOID PageBase,
  190. IN SIZE_T NumberOfBytes
  191. );
  192. VOID
  193. FASTCALL
  194. KiXMMIZeroPages (
  195. IN PVOID PageBase,
  196. IN SIZE_T NumberOfBytes
  197. );
  198. VOID
  199. FASTCALL
  200. KiXMMIZeroPagesNoSave (
  201. IN PVOID PageBase,
  202. IN SIZE_T NumberOfBytes
  203. );
  204. KE_ZERO_PAGE_ROUTINE KeZeroPages = KiZeroPages;
  205. KE_ZERO_PAGE_ROUTINE KeZeroPagesFromIdleThread = KiZeroPages;
  206. //
  207. // Line size of the d-cache closest to the processor. Used by machine
  208. // dependent prefetch routines. Default to 32.
  209. //
  210. ULONG KePrefetchNTAGranularity = 32;
  211. VOID
  212. FASTCALL
  213. RtlPrefetchMemoryNonTemporal(
  214. PVOID Memory,
  215. SIZE_T Length
  216. );
  217. //
  218. // The following spinlock is for compatiblity with 486 systems that don't
  219. // have a cmpxchg8b instruction and therefore need to synchronize using a
  220. // spinlock. NOTE: This spinlock should be initialized on x86 systems.
  221. //
  222. ULONG Ki486CompatibilityLock;
  223. //
  224. // Profile vars
  225. //
  226. extern KIDTENTRY IDT[];
  227. VOID
  228. KiInitializeKernel (
  229. IN PKPROCESS Process,
  230. IN PKTHREAD Thread,
  231. IN PVOID IdleStack,
  232. IN PKPRCB Prcb,
  233. IN CCHAR Number,
  234. PLOADER_PARAMETER_BLOCK LoaderBlock
  235. )
  236. /*++
  237. Routine Description:
  238. This function gains control after the system has been bootstrapped and
  239. before the system has been initialized. Its function is to initialize
  240. the kernel data structures, initialize the idle thread and process objects,
  241. initialize the processor control block, call the executive initialization
  242. routine, and then return to the system startup routine. This routine is
  243. also called to initialize the processor specific structures when a new
  244. processor is brought on line.
  245. Arguments:
  246. Process - Supplies a pointer to a control object of type process for
  247. the specified processor.
  248. Thread - Supplies a pointer to a dispatcher object of type thread for
  249. the specified processor.
  250. IdleStack - Supplies a pointer the base of the real kernel stack for
  251. idle thread on the specified processor.
  252. Prcb - Supplies a pointer to a processor control block for the specified
  253. processor.
  254. Number - Supplies the number of the processor that is being
  255. initialized.
  256. LoaderBlock - Supplies a pointer to the loader parameter block.
  257. Return Value:
  258. None.
  259. --*/
  260. {
  261. ULONG DirectoryTableBase[2];
  262. KIRQL OldIrql;
  263. PKPCR Pcr;
  264. BOOLEAN NpxFlag;
  265. #if !defined(NT_UP)
  266. BOOLEAN FxsrPresent;
  267. BOOLEAN XMMIPresent;
  268. #endif
  269. ULONG FeatureBits;
  270. #if defined(KE_MULTINODE)
  271. LONG Index;
  272. #endif
  273. KiSetProcessorType();
  274. KiSetCR0Bits();
  275. NpxFlag = KiIsNpxPresent();
  276. Pcr = KeGetPcr();
  277. //
  278. // Initialize processor's PowerState
  279. //
  280. PoInitializePrcb (Prcb);
  281. //
  282. // Check for unsupported processor revision
  283. //
  284. if (Prcb->CpuType == 3) {
  285. KeBugCheckEx(UNSUPPORTED_PROCESSOR,0x386,0,0,0);
  286. }
  287. //
  288. // Get the processor FeatureBits for this processor.
  289. //
  290. FeatureBits = KiGetFeatureBits();
  291. Prcb->FeatureBits = FeatureBits;
  292. //
  293. // Do one time initialization of the ProcesorControlSpace in the PRCB
  294. // so local kernel debugger can get things like the GDT
  295. //
  296. KiSaveProcessorControlState(&Prcb->ProcessorState);
  297. //
  298. // Get processor Cache Size information.
  299. //
  300. KiGetCacheInformation();
  301. //
  302. // Initialize the per processor lock data.
  303. //
  304. KiInitSpinLocks(Prcb, Number);
  305. //
  306. // If the initial processor is being initialized, then initialize the
  307. // per system data structures.
  308. //
  309. if (Number == 0) {
  310. //
  311. // If any loader options were specified, then upper case the options.
  312. //
  313. if (LoaderBlock->LoadOptions != NULL) {
  314. _strupr(LoaderBlock->LoadOptions);
  315. }
  316. //
  317. // Set default node. Used in non-multinode systems and in
  318. // multinode systems until the node topology is available.
  319. //
  320. KeNodeBlock[0] = &KiNode0;
  321. #if defined(KE_MULTINODE)
  322. for (Index = 1; Index < MAXIMUM_CCNUMA_NODES; Index++) {
  323. //
  324. // Set temporary node.
  325. //
  326. KeNodeBlock[Index] = &KiNodeInit[Index];
  327. }
  328. #endif
  329. Prcb->ParentNode = KeNodeBlock[0];
  330. KeNodeBlock[0]->ProcessorMask = Prcb->SetMember;
  331. //
  332. // Initial setting for global Cpu & Stepping levels
  333. //
  334. KeI386NpxPresent = NpxFlag;
  335. KeI386CpuType = Prcb->CpuType;
  336. KeI386CpuStep = Prcb->CpuStep;
  337. KeProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
  338. KeProcessorLevel = (USHORT)Prcb->CpuType;
  339. if (Prcb->CpuID == 0) {
  340. KeProcessorRevision = 0xFF00 |
  341. (((Prcb->CpuStep >> 4) + 0xa0 ) & 0x0F0) |
  342. (Prcb->CpuStep & 0xf);
  343. } else {
  344. KeProcessorRevision = Prcb->CpuStep;
  345. }
  346. KeFeatureBits = FeatureBits;
  347. KeI386FxsrPresent = ((KeFeatureBits & KF_FXSR) ? TRUE:FALSE);
  348. KeI386XMMIPresent = ((KeFeatureBits & KF_XMMI) ? TRUE:FALSE);
  349. //
  350. // As of Whistler, cmpxchg8b is a required instruction.
  351. //
  352. if ((KeFeatureBits & KF_CMPXCHG8B) == 0) {
  353. ULONG Vendor[3];
  354. //
  355. // Argument 1:
  356. // bits 31-24: Unique value for missing feature.
  357. // bits 23-0 : Family/Model/Stepping (this could compress).
  358. // Arguments 2 thru 4:
  359. // Vendor Id string.
  360. //
  361. RtlCopyMemory(Vendor, Prcb->VendorString, sizeof(Vendor));
  362. KeBugCheckEx(UNSUPPORTED_PROCESSOR,
  363. (1 << 24 ) // rev this for other required features
  364. | (Prcb->CpuType << 16) | Prcb->CpuStep,
  365. Vendor[0],
  366. Vendor[1],
  367. Vendor[2]
  368. );
  369. }
  370. //
  371. // Lower IRQL to APC level.
  372. //
  373. KeLowerIrql(APC_LEVEL);
  374. //
  375. // Initialize kernel internal spinlocks
  376. //
  377. KeInitializeSpinLock(&KiFreezeExecutionLock);
  378. //
  379. // Initialize 486 compatibility lock
  380. //
  381. KeInitializeSpinLock(&Ki486CompatibilityLock);
  382. #if !defined(NT_UP)
  383. //
  384. // Set this processor as the master (ie first found) processor
  385. // in this SMT set (whether or not it is actually SMT).
  386. //
  387. Prcb->MultiThreadSetMaster = Prcb;
  388. //
  389. // During Text Mode setup, it is possible the system is
  390. // running with an MP kernel and a UP HAL. On X86 systems,
  391. // spinlocks are implemented in both the kernel and the HAL
  392. // with the verisons that alter IRQL in the HAL. If the
  393. // HAL is UP, it will not actually acquire/release locks
  394. // while the MP kernel will which will cause the system to
  395. // hang (or crash). As this can only occur during text
  396. // mode setup, we will detect the situation and disable
  397. // the kernel only versions of queued spinlocks if the HAL
  398. // is UP (and the kernel MP).
  399. //
  400. // We need to patch 3 routines, two of them are void and
  401. // the other returns a boolean (must be true (and ZF must be
  402. // clear) in a UP case).
  403. //
  404. // Determine if the HAL us UP by acquiring the dispatcher
  405. // lock and examining it to see if the HAL actually did
  406. // anything to it.
  407. //
  408. OldIrql = KfAcquireSpinLock(&Ki486CompatibilityLock);
  409. if (Ki486CompatibilityLock == 0) {
  410. //
  411. // KfAcquireSpinLock is in the HAL and it did not
  412. // change the value of the lock. This is a UP HAL.
  413. //
  414. extern UCHAR KeTryToAcquireQueuedSpinLockAtRaisedIrqlUP;
  415. PUCHAR PatchTarget, PatchSource;
  416. UCHAR Byte;
  417. #define RET 0xc3
  418. *(PUCHAR)(ULONG_PTR)(KeAcquireQueuedSpinLockAtDpcLevel) = RET;
  419. *(PUCHAR)(ULONG_PTR)(KeReleaseQueuedSpinLockFromDpcLevel) = RET;
  420. //
  421. // Copy the UP version of KeTryToAcquireQueuedSpinLockAtRaisedIrql
  422. // over the top of the MP versin.
  423. //
  424. PatchSource = (PUCHAR)(ULONG_PTR)&(KeTryToAcquireQueuedSpinLockAtRaisedIrqlUP);
  425. PatchTarget = (PUCHAR)(ULONG_PTR)(KeTryToAcquireQueuedSpinLockAtRaisedIrql);
  426. do {
  427. Byte = *PatchSource++;
  428. *PatchTarget++ = Byte;
  429. } while (Byte != RET);
  430. #undef RET
  431. }
  432. KeReleaseSpinLock(&Ki486CompatibilityLock, OldIrql);
  433. #endif
  434. //
  435. // Performance architecture independent initialization.
  436. //
  437. KiInitSystem();
  438. //
  439. // Initialize idle thread process object and then set:
  440. //
  441. // 1. all the quantum values to the maximum possible.
  442. // 2. the process in the balance set.
  443. // 3. the active processor mask to the specified process.
  444. //
  445. DirectoryTableBase[0] = 0;
  446. DirectoryTableBase[1] = 0;
  447. KeInitializeProcess(Process,
  448. (KPRIORITY)0,
  449. (KAFFINITY)(0xffffffff),
  450. &DirectoryTableBase[0],
  451. FALSE);
  452. Process->ThreadQuantum = MAXCHAR;
  453. #if !defined(NT_UP)
  454. } else {
  455. //
  456. // Adjust global cpu setting to represent lowest of all processors
  457. //
  458. FxsrPresent = ((FeatureBits & KF_FXSR) ? TRUE:FALSE);
  459. if (FxsrPresent != KeI386FxsrPresent) {
  460. //
  461. // FXSR support must be available on all processors or on none
  462. //
  463. KeBugCheckEx (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED, KF_FXSR, 0, 0, 0);
  464. }
  465. XMMIPresent = ((FeatureBits & KF_XMMI) ? TRUE:FALSE);
  466. if (XMMIPresent != KeI386XMMIPresent) {
  467. //
  468. // XMMI support must be available on all processors or on none
  469. //
  470. KeBugCheckEx (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED, KF_XMMI, 0, 0, 0);
  471. }
  472. if (NpxFlag != KeI386NpxPresent) {
  473. //
  474. // NPX support must be available on all processors or on none
  475. //
  476. KeBugCheckEx (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED, 0x387, 0, 0, 0);
  477. }
  478. if ((ULONG)(Prcb->CpuType) != KeI386CpuType) {
  479. if ((ULONG)(Prcb->CpuType) < KeI386CpuType) {
  480. //
  481. // What is the lowest CPU type
  482. //
  483. KeI386CpuType = (ULONG)Prcb->CpuType;
  484. KeProcessorLevel = (USHORT)Prcb->CpuType;
  485. }
  486. }
  487. if ((KiBootFeatureBits & KF_CMPXCHG8B) && !(FeatureBits & KF_CMPXCHG8B)) {
  488. //
  489. // cmpxchg8b must be available on all processors, if installed at boot
  490. //
  491. KeBugCheckEx (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED, KF_CMPXCHG8B, 0, 0, 0);
  492. }
  493. if ((KeFeatureBits & KF_GLOBAL_PAGE) && !(FeatureBits & KF_GLOBAL_PAGE)) {
  494. //
  495. // Global page support must be available on all processors, if on boot processor
  496. //
  497. KeBugCheckEx (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED, KF_GLOBAL_PAGE, 0, 0, 0);
  498. }
  499. if ((KeFeatureBits & KF_PAT) && !(FeatureBits & KF_PAT)) {
  500. //
  501. // PAT must be available on all processors, if on boot processor
  502. //
  503. KeBugCheckEx (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED, KF_PAT, 0, 0, 0);
  504. }
  505. if ((KeFeatureBits & KF_MTRR) && !(FeatureBits & KF_MTRR)) {
  506. //
  507. // MTRR must be available on all processors, if on boot processor
  508. //
  509. KeBugCheckEx (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED, KF_MTRR, 0, 0, 0);
  510. }
  511. if ((KeFeatureBits & KF_FAST_SYSCALL) != (FeatureBits & KF_FAST_SYSCALL)) {
  512. //
  513. // If this feature is not available on all processors
  514. // don't use it at all.
  515. //
  516. KiFastSystemCallDisable = 1;
  517. }
  518. if ((KeFeatureBits & KF_XMMI64) != (FeatureBits & KF_XMMI64)) {
  519. //
  520. // If not all processors support Streaming SIMD Extensions
  521. // 64bit FP don't use it at all.
  522. //
  523. KeFeatureBits &= ~KF_XMMI64;
  524. }
  525. //
  526. // Use lowest stepping value
  527. //
  528. if (Prcb->CpuStep < KeI386CpuStep) {
  529. KeI386CpuStep = Prcb->CpuStep;
  530. if (Prcb->CpuID == 0) {
  531. KeProcessorRevision = 0xFF00 |
  532. ((Prcb->CpuStep >> 8) + 'A') |
  533. (Prcb->CpuStep & 0xf);
  534. } else {
  535. KeProcessorRevision = Prcb->CpuStep;
  536. }
  537. }
  538. //
  539. // Use subset of all NT feature bits available on each processor
  540. //
  541. KeFeatureBits &= FeatureBits;
  542. //
  543. // Lower IRQL to DISPATCH level.
  544. //
  545. KeLowerIrql(DISPATCH_LEVEL);
  546. #endif
  547. }
  548. //
  549. // Update processor features
  550. //
  551. SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] =
  552. (KeFeatureBits & KF_MMX) ? TRUE : FALSE;
  553. SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] =
  554. (KeFeatureBits & KF_CMPXCHG8B) ? TRUE : FALSE;
  555. SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] =
  556. ((KeFeatureBits & KF_FXSR) && (KeFeatureBits & KF_XMMI)) ? TRUE : FALSE;
  557. SharedUserData->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE] =
  558. ((KeFeatureBits & KF_FXSR) && (KeFeatureBits & KF_XMMI64)) ? TRUE : FALSE;
  559. SharedUserData->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] =
  560. (KeFeatureBits & KF_3DNOW) ? TRUE : FALSE;
  561. SharedUserData->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE] =
  562. (KeFeatureBits & KF_RDTSC) ? TRUE : FALSE;
  563. //
  564. // Initialize idle thread object and then set:
  565. //
  566. // 1. the initial kernel stack to the specified idle stack.
  567. // 2. the next processor number to the specified processor.
  568. // 3. the thread priority to the highest possible value.
  569. // 4. the state of the thread to running.
  570. // 5. the thread affinity to the specified processor.
  571. // 6. the specified processor member in the process active processors
  572. // set.
  573. //
  574. KeInitializeThread(Thread, (PVOID)((ULONG)IdleStack),
  575. (PKSYSTEM_ROUTINE)NULL, (PKSTART_ROUTINE)NULL,
  576. (PVOID)NULL, (PCONTEXT)NULL, (PVOID)NULL, Process);
  577. Thread->NextProcessor = Number;
  578. Thread->Priority = HIGH_PRIORITY;
  579. Thread->State = Running;
  580. Thread->Affinity = (KAFFINITY)(1<<Number);
  581. Thread->WaitIrql = DISPATCH_LEVEL;
  582. SetMember(Number, Process->ActiveProcessors);
  583. //
  584. // Initialize the processor block. (Note that some fields have been
  585. // initialized at KiInitializePcr().
  586. //
  587. Prcb->CurrentThread = Thread;
  588. Prcb->NextThread = (PKTHREAD)NULL;
  589. Prcb->IdleThread = Thread;
  590. //
  591. // call the executive initialization routine.
  592. //
  593. try {
  594. ExpInitializeExecutive(Number, LoaderBlock);
  595. } except(KeBugCheckEx(PHASE0_EXCEPTION,
  596. (ULONG)GetExceptionCode(),
  597. (ULONG_PTR)GetExceptionInformation(),
  598. 0,0), EXCEPTION_EXECUTE_HANDLER) {
  599. ; // should never get here
  600. }
  601. //
  602. // If the initial processor is being initialized, then compute the
  603. // timer table reciprocal value and reset the PRCB values for the
  604. // controllable DPC behavior in order to reflect any registry
  605. // overrides.
  606. //
  607. if (Number == 0) {
  608. ULONG i, j;
  609. ULONGLONG Temp1;
  610. Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth;
  611. Prcb->MinimumDpcRate = KiMinimumDpcRate;
  612. Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
  613. i = 1;
  614. j = KeMaximumIncrement;
  615. while ((1UI64<<i) <= KeMaximumIncrement) {
  616. i++;
  617. }
  618. KiLog2MaximumIncrement = i;
  619. ASSERT ((1UL<<KiLog2MaximumIncrement) >= KeMaximumIncrement);
  620. ASSERT ((1UL<<KiLog2MaximumIncrement) <= KeMaximumIncrement * 2 - 1);
  621. Temp1 = 1UI64 << (KiLog2MaximumIncrement + 32);
  622. Temp1 /= KeMaximumIncrement;
  623. Temp1 -= 1UI64<<32;
  624. Temp1 += 1;
  625. KiMaximumIncrementReciprocal = (ULONG) Temp1;
  626. KeTimerReductionModulus = KeMaximumIncrement * TIMER_TABLE_SIZE;
  627. ASSERT ((KeTimerReductionModulus / TIMER_TABLE_SIZE) == KeMaximumIncrement);
  628. Temp1 = 1UI64<<32;
  629. Temp1 %= KeTimerReductionModulus;
  630. KiUpperModMul = (ULONG) Temp1;
  631. }
  632. if (Number == 0) {
  633. //
  634. // Processor 0's DPC stack was temporarily allocated on
  635. // the Double Fault Stack, switch to a proper kernel
  636. // stack now.
  637. //
  638. PVOID DpcStack;
  639. DpcStack = MmCreateKernelStack(FALSE, 0);
  640. if (DpcStack == NULL) {
  641. KeBugCheckEx(NO_PAGES_AVAILABLE, 1, 0, 0, 0);
  642. }
  643. Prcb->DpcStack = DpcStack;
  644. //
  645. // Allocate 8k IOPM bit map saved area to allow BiosCall swap
  646. // bit maps.
  647. //
  648. Ki386IopmSaveArea = ExAllocatePoolWithTag(PagedPool,
  649. PAGE_SIZE * 2,
  650. ' eK');
  651. if (Ki386IopmSaveArea == NULL) {
  652. KeBugCheckEx(NO_PAGES_AVAILABLE, 2, PAGE_SIZE * 2, 0, 0);
  653. }
  654. }
  655. //
  656. // Set the priority of the specified idle thread to zero, set appropriate
  657. // member in KiIdleSummary and return to the system start up routine.
  658. //
  659. KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
  660. KeSetPriorityThread(Thread, (KPRIORITY)0);
  661. //
  662. // if a thread has not been selected to run on the current processors,
  663. // check to see if there are any ready threads; otherwise add this
  664. // processors to the IdleSummary
  665. //
  666. KiAcquirePrcbLock(Prcb);
  667. if (Prcb->NextThread == NULL) {
  668. SetMember(Number, KiIdleSummary);
  669. }
  670. KiReleasePrcbLock(Prcb);
  671. KeRaiseIrql(HIGH_LEVEL, &OldIrql);
  672. //
  673. // This processor has initialized
  674. //
  675. LoaderBlock->Prcb = (ULONG)NULL;
  676. return;
  677. }
  678. VOID
  679. KiInitializePcr (
  680. IN ULONG Processor,
  681. IN PKPCR Pcr,
  682. IN PKIDTENTRY Idt,
  683. IN PKGDTENTRY Gdt,
  684. IN PKTSS Tss,
  685. IN PKTHREAD Thread,
  686. IN PVOID DpcStack
  687. )
  688. /*++
  689. Routine Description:
  690. This function is called to initialize the PCR for a processor. It
  691. simply stuffs values into the PCR. (The PCR is not inited statically
  692. because the number varies with the number of processors.)
  693. Note that each processor has its own IDT, GDT, and TSS as well as PCR!
  694. Arguments:
  695. Processor - Processor whose PCR to initialize.
  696. Pcr - Linear address of PCR.
  697. Idt - Linear address of i386 IDT.
  698. Gdt - Linear address of i386 GDT.
  699. Tss - Linear address (NOT SELECTOR!) of the i386 TSS.
  700. Thread - Dummy thread object to use very early on.
  701. Return Value:
  702. None.
  703. --*/
  704. {
  705. // set version values
  706. Pcr->MajorVersion = PCR_MAJOR_VERSION;
  707. Pcr->MinorVersion = PCR_MINOR_VERSION;
  708. Pcr->PrcbData.MajorVersion = PRCB_MAJOR_VERSION;
  709. Pcr->PrcbData.MinorVersion = PRCB_MINOR_VERSION;
  710. Pcr->PrcbData.BuildType = 0;
  711. #if DBG
  712. Pcr->PrcbData.BuildType |= PRCB_BUILD_DEBUG;
  713. #endif
  714. #ifdef NT_UP
  715. Pcr->PrcbData.BuildType |= PRCB_BUILD_UNIPROCESSOR;
  716. #endif
  717. #if defined (_X86PAE_)
  718. if (Processor == 0) {
  719. //
  720. // PAE feature must be initialized prior to the first HAL call.
  721. //
  722. SharedUserData->ProcessorFeatures[PF_PAE_ENABLED] = TRUE;
  723. }
  724. #endif
  725. // Basic addressing fields
  726. Pcr->SelfPcr = Pcr;
  727. Pcr->Prcb = &(Pcr->PrcbData);
  728. // Thread control fields
  729. Pcr->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
  730. Pcr->NtTib.StackBase = NULL;
  731. Pcr->PerfGlobalGroupMask = NULL;
  732. Pcr->NtTib.Self = NULL;
  733. Pcr->PrcbData.CurrentThread = Thread;
  734. //
  735. // Init Prcb.Number and ProcessorBlock such that Ipi will work
  736. // as early as possible.
  737. //
  738. Pcr->PrcbData.Number = (UCHAR)Processor;
  739. Pcr->PrcbData.SetMember = 1 << Processor;
  740. KiProcessorBlock[Processor] = Pcr->Prcb;
  741. Pcr->Irql = 0;
  742. // Machine structure addresses
  743. Pcr->GDT = Gdt;
  744. Pcr->IDT = Idt;
  745. Pcr->TSS = Tss;
  746. Pcr->TssCopy = Tss;
  747. Pcr->PrcbData.DpcStack = DpcStack;
  748. //
  749. // Initially, set this processor as only member of SMT set.
  750. //
  751. Pcr->PrcbData.MultiThreadProcessorSet = Pcr->PrcbData.SetMember;
  752. return;
  753. }
  754. #if 0
  755. VOID
  756. KiInitializeDblFaultTSS(
  757. IN PKTSS Tss,
  758. IN ULONG Stack,
  759. IN PKGDTENTRY TssDescriptor
  760. )
  761. /*++
  762. Routine Description:
  763. This function is called to initialize the double-fault TSS for a
  764. processor. It will set the static fields of the TSS to point to
  765. the double-fault handler and the appropriate double-fault stack.
  766. Note that the IOPM for the double-fault TSS grants access to all
  767. ports. This is so the standard HAL's V86-mode callback to reset
  768. the display to text mode will work.
  769. Arguments:
  770. Tss - Supplies a pointer to the double-fault TSS
  771. Stack - Supplies a pointer to the double-fault stack.
  772. TssDescriptor - Linear address of the descriptor for the TSS.
  773. Return Value:
  774. None.
  775. --*/
  776. {
  777. PUCHAR p;
  778. ULONG i;
  779. ULONG j;
  780. //
  781. // Set limit for TSS
  782. //
  783. if (TssDescriptor != NULL) {
  784. TssDescriptor->LimitLow = sizeof(KTSS) - 1;
  785. TssDescriptor->HighWord.Bits.LimitHi = 0;
  786. }
  787. //
  788. // Initialize IOPMs
  789. //
  790. for (i = 0; i < IOPM_COUNT; i++) {
  791. p = (PUCHAR)(Tss->IoMaps[i]);
  792. for (j = 0; j < PIOPM_SIZE; j++) {
  793. p[j] = 0;
  794. }
  795. }
  796. // Set IO Map base address to indicate no IO map present.
  797. // N.B. -1 does not seem to be a valid value for the map base. If this
  798. // value is used, byte immediate in's and out's will actually go
  799. // the hardware when executed in V86 mode.
  800. Tss->IoMapBase = KiComputeIopmOffset(IO_ACCESS_MAP_NONE);
  801. // Set flags to 0, which in particular disables traps on task switches.
  802. Tss->Flags = 0;
  803. // Set LDT and Ss0 to constants used by NT.
  804. Tss->LDT = 0;
  805. Tss->Ss0 = KGDT_R0_DATA;
  806. Tss->Esp0 = Stack;
  807. Tss->Eip = (ULONG)KiTrap08;
  808. Tss->Cs = KGDT_R0_CODE || RPL_MASK;
  809. Tss->Ds = KGDT_R0_DATA;
  810. Tss->Es = KGDT_R0_DATA;
  811. Tss->Fs = KGDT_R0_DATA;
  812. return;
  813. }
  814. #endif
  815. VOID
  816. KiInitializeTSS (
  817. IN PKTSS Tss
  818. )
  819. /*++
  820. Routine Description:
  821. This function is called to initialize the TSS for a processor.
  822. It will set the static fields of the TSS. (ie Those fields that
  823. the part reads, and for which NT uses constant values.)
  824. The dynamic fields (Esp0 and CR3) are set in the context swap
  825. code.
  826. Arguments:
  827. Tss - Linear address of the Task State Segment.
  828. Return Value:
  829. None.
  830. --*/
  831. {
  832. // Set IO Map base address to indicate no IO map present.
  833. // N.B. -1 does not seem to be a valid value for the map base. If this
  834. // value is used, byte immediate in's and out's will actually go
  835. // the hardware when executed in V86 mode.
  836. Tss->IoMapBase = KiComputeIopmOffset(IO_ACCESS_MAP_NONE);
  837. // Set flags to 0, which in particular disables traps on task switches.
  838. Tss->Flags = 0;
  839. // Set LDT and Ss0 to constants used by NT.
  840. Tss->LDT = 0;
  841. Tss->Ss0 = KGDT_R0_DATA;
  842. return;
  843. }
  844. VOID
  845. KiInitializeTSS2 (
  846. IN PKTSS Tss,
  847. IN PKGDTENTRY TssDescriptor
  848. )
  849. /*++
  850. Routine Description:
  851. Do part of TSS init we do only once.
  852. Arguments:
  853. Tss - Linear address of the Task State Segment.
  854. TssDescriptor - Linear address of the descriptor for the TSS.
  855. Return Value:
  856. None.
  857. --*/
  858. {
  859. PUCHAR p;
  860. ULONG i;
  861. ULONG j;
  862. //
  863. // Set limit for TSS
  864. //
  865. if (TssDescriptor != NULL) {
  866. TssDescriptor->LimitLow = sizeof(KTSS) - 1;
  867. TssDescriptor->HighWord.Bits.LimitHi = 0;
  868. }
  869. //
  870. // Initialize IOPMs
  871. //
  872. for (i = 0; i < IOPM_COUNT; i++) {
  873. p = (PUCHAR)(Tss->IoMaps[i].IoMap);
  874. for (j = 0; j < PIOPM_SIZE; j++) {
  875. p[j] = (UCHAR)-1;
  876. }
  877. }
  878. //
  879. // Initialize Software Interrupt Direction Maps
  880. //
  881. for (i = 0; i < IOPM_COUNT; i++) {
  882. p = (PUCHAR)(Tss->IoMaps[i].DirectionMap);
  883. for (j = 0; j < INT_DIRECTION_MAP_SIZE; j++) {
  884. p[j] = 0;
  885. }
  886. // dpmi requires special case for int 2, 1b, 1c, 23, 24
  887. p[0] = 4;
  888. p[3] = 0x18;
  889. p[4] = 0x18;
  890. }
  891. //
  892. // Initialize the map for IO_ACCESS_MAP_NONE
  893. //
  894. p = (PUCHAR)(Tss->IntDirectionMap);
  895. for (j = 0; j < INT_DIRECTION_MAP_SIZE; j++) {
  896. p[j] = 0;
  897. }
  898. // dpmi requires special case for int 2, 1b, 1c, 23, 24
  899. p[0] = 4;
  900. p[3] = 0x18;
  901. p[4] = 0x18;
  902. return;
  903. }
  904. VOID
  905. KiSwapIDT (
  906. )
  907. /*++
  908. Routine Description:
  909. This function is called to edit the IDT. It swaps words of the address
  910. and access fields around into the format the part actually needs.
  911. This allows for easy static init of the IDT.
  912. Note that this procedure edits the current IDT.
  913. Arguments:
  914. None.
  915. Return Value:
  916. None.
  917. --*/
  918. {
  919. LONG Index;
  920. USHORT Temp;
  921. //
  922. // Rearrange the entries of IDT to match i386 interrupt gate structure
  923. //
  924. for (Index = 0; Index <= MAXIMUM_IDTVECTOR; Index += 1) {
  925. Temp = IDT[Index].Selector;
  926. IDT[Index].Selector = IDT[Index].ExtendedOffset;
  927. IDT[Index].ExtendedOffset = Temp;
  928. }
  929. }
  930. ULONG
  931. KiGetCpuVendor(
  932. VOID
  933. )
  934. /*++
  935. Routine Description:
  936. (Try to) Determine the manufacturer of this processor based on
  937. data returned by the CPUID instruction (if present).
  938. Arguments:
  939. None.
  940. Return Value:
  941. One of the members of the enumeration CPU_VENDORS (defined above).
  942. --*/
  943. {
  944. PKPRCB Prcb;
  945. ULONG Junk;
  946. ULONG Buffer[4];
  947. Prcb = KeGetCurrentPrcb();
  948. Prcb->VendorString[0] = 0;
  949. if (!Prcb->CpuID) {
  950. return CPU_NONE;
  951. }
  952. CPUID(0, &Junk, Buffer+0, Buffer+2, Buffer+1);
  953. Buffer[3] = 0;
  954. //
  955. // Copy vendor string to Prcb for debugging (ensure it's NULL
  956. // terminated).
  957. //
  958. RtlCopyMemory(
  959. Prcb->VendorString,
  960. Buffer,
  961. sizeof(Prcb->VendorString) - 1
  962. );
  963. Prcb->VendorString[sizeof(Prcb->VendorString) - 1] = '\0';
  964. if (strcmp((PCHAR)Buffer, CmpIntelID) == 0) {
  965. return CPU_INTEL;
  966. } else if (strcmp((PCHAR)Buffer, CmpAmdID) == 0) {
  967. return CPU_AMD;
  968. } else if (strcmp((PCHAR)Buffer, CmpCyrixID) == 0) {
  969. return CPU_CYRIX;
  970. } else if (strcmp((PCHAR)Buffer, CmpTransmetaID) == 0) {
  971. return CPU_TRANSMETA;
  972. } else if (strcmp((PCHAR)Buffer, CmpCentaurID) == 0) {
  973. return CPU_CENTAUR;
  974. }
  975. return CPU_UNKNOWN;
  976. }
  977. ULONG
  978. KiGetFeatureBits (
  979. VOID
  980. )
  981. /*++
  982. Routine Description:
  983. Examine the processor specific feature bits to determine the
  984. Windows supported features supported by this processor.
  985. Arguments:
  986. None.
  987. Return Value:
  988. Returns a Windows normalized set of processor features.
  989. --*/
  990. {
  991. ULONG Junk;
  992. ULONG Temp;
  993. ULONG ProcessorFeatures;
  994. ULONG NtBits;
  995. ULONG ExtendedProcessorFeatures;
  996. ULONG ProcessorSignature;
  997. ULONG CpuVendor;
  998. PKPRCB Prcb;
  999. BOOLEAN ExtendedCPUIDSupport = TRUE;
  1000. Prcb = KeGetCurrentPrcb();
  1001. NtBits = KF_WORKING_PTE;
  1002. //
  1003. // Determine the processor type
  1004. //
  1005. CpuVendor = KiGetCpuVendor();
  1006. //
  1007. // If this processor does not support the CPUID instruction,
  1008. // don't try to use it.
  1009. //
  1010. if (CpuVendor == CPU_NONE) {
  1011. return NtBits;
  1012. }
  1013. //
  1014. // Determine which NT compatible features are present
  1015. //
  1016. CPUID (1, &ProcessorSignature, &Temp, &Junk, &ProcessorFeatures);
  1017. //
  1018. // CPUID(1) now returns information in EBX. On the grounds that
  1019. // the low functions are supposed to be standard, we record the
  1020. // information regardless of processor vendor even though it may
  1021. // be 0 or undefined on older implementations.
  1022. //
  1023. Prcb->InitialApicId = (UCHAR)(Temp >> 24);
  1024. //
  1025. // AMD specific stuff
  1026. //
  1027. if (CpuVendor == CPU_AMD) {
  1028. //
  1029. // Check for K5 and above.
  1030. //
  1031. if ((ProcessorSignature & 0x0F00) >= 0x0500) {
  1032. if ((ProcessorSignature & 0x0F00) == 0x0500) {
  1033. switch (ProcessorSignature & 0x00F0) {
  1034. case 0x0010: // K5 Model 1
  1035. //
  1036. // for K5 Model 1 stepping 0 or 1 don't set global page
  1037. //
  1038. if ((ProcessorSignature & 0x000F) > 0x03) {
  1039. //
  1040. // K5 Model 1 stepping 2 or greater
  1041. //
  1042. break;
  1043. }
  1044. //
  1045. // K5 Model 1 stepping 0 or 1, FALL THRU.
  1046. //
  1047. case 0x0000: // K5 Model 0
  1048. //
  1049. // for K5 Model 0 or model unknown don't set global page
  1050. //
  1051. ProcessorFeatures &= ~0x2000;
  1052. break;
  1053. case 0x0080: // K6 Model 8 (K6-2)
  1054. //
  1055. // All steppings >= 8 support MTRRs.
  1056. //
  1057. if ((ProcessorSignature & 0x000F) >= 0x8) {
  1058. NtBits |= KF_AMDK6MTRR;
  1059. }
  1060. break;
  1061. case 0x0090: // K6 Model 9 (K6-3)
  1062. NtBits |= KF_AMDK6MTRR;
  1063. break;
  1064. default: // anything else, nothing to do.
  1065. break;
  1066. }
  1067. }
  1068. } else {
  1069. //
  1070. // Less than family 5, don't set GLOBAL PAGE, LARGE
  1071. // PAGE or CMOV. (greater than family 5 will have the
  1072. // bits set correctly).
  1073. //
  1074. ProcessorFeatures &= ~(0x08 | 0x2000 | 0x8000);
  1075. //
  1076. // We don't know what this processor returns if we
  1077. // probe for extended CPUID support.
  1078. //
  1079. ExtendedCPUIDSupport = FALSE;
  1080. }
  1081. }
  1082. //
  1083. // Intel specific stuff
  1084. //
  1085. if (CpuVendor == CPU_INTEL) {
  1086. if (Prcb->CpuType >= 6) {
  1087. WRMSR (0x8B, 0);
  1088. CPUID (1, &Junk, &Junk, &Junk, &ProcessorFeatures);
  1089. Prcb->UpdateSignature.QuadPart = RDMSR (0x8B);
  1090. }
  1091. else if (Prcb->CpuType == 5) {
  1092. KiI386PentiumLockErrataPresent = TRUE;
  1093. }
  1094. if ( ((ProcessorSignature & 0x0FF0) == 0x0610 &&
  1095. (ProcessorSignature & 0x000F) <= 0x9) ||
  1096. ((ProcessorSignature & 0x0FF0) == 0x0630 &&
  1097. (ProcessorSignature & 0x000F) <= 0x4)) {
  1098. //
  1099. // If the boot processor has PII spec A27 errata (also present in
  1100. // early Pentium Pro chips), then use only one processor to avoid
  1101. // unpredictable eflags corruption.
  1102. //
  1103. NtBits &= ~KF_WORKING_PTE;
  1104. }
  1105. //
  1106. // Don't support prior attempts at implementing syscall/sysexit
  1107. // instructions.
  1108. //
  1109. if ((Prcb->CpuType < 6) ||
  1110. ((Prcb->CpuType == 6) && (Prcb->CpuStep < 0x0303))) {
  1111. ProcessorFeatures &= ~KI_FAST_SYSCALL_SUPPORTED;
  1112. }
  1113. }
  1114. //
  1115. // Cyrix specific stuff
  1116. //
  1117. if (CpuVendor == CPU_CYRIX) {
  1118. //
  1119. // Workaround bug 324467 which is caused by INTR being
  1120. // held high too long during an FP instruction and causing
  1121. // random Trap07 with no exception bits.
  1122. //
  1123. extern BOOLEAN KiIgnoreUnexpectedTrap07;
  1124. KiIgnoreUnexpectedTrap07 = TRUE;
  1125. //
  1126. // Workaround CMPXCHG bug to Cyrix processors where
  1127. // Family = 6, Model = 0, Stepping <= 1. Note that
  1128. // Prcb->CpuStep contains both model and stepping.
  1129. //
  1130. // Disable Locking in one of processor specific registers
  1131. // (accessible via i/o space index/data pair).
  1132. //
  1133. if ((Prcb->CpuType == 6) &&
  1134. (Prcb->CpuStep <= 1)) {
  1135. #define CRC_NDX (PUCHAR)0x22
  1136. #define CRC_DAT (CRC_NDX + 1)
  1137. #define CCR1 0xc1
  1138. UCHAR ValueCCR1;
  1139. //
  1140. // Get current setting.
  1141. //
  1142. WRITE_PORT_UCHAR(CRC_NDX, CCR1);
  1143. ValueCCR1 = READ_PORT_UCHAR(CRC_DAT);
  1144. //
  1145. // Set the NO_LOCK bit and write it back.
  1146. //
  1147. ValueCCR1 |= 0x10;
  1148. WRITE_PORT_UCHAR(CRC_NDX, CCR1);
  1149. WRITE_PORT_UCHAR(CRC_DAT, ValueCCR1);
  1150. #undef CCR1
  1151. #undef CRC_DAT
  1152. #undef CRC_NDX
  1153. }
  1154. }
  1155. //
  1156. // Check the standard CPUID feature bits.
  1157. //
  1158. // The following bits are known to work on Intel, AMD and Cyrix.
  1159. // We hope (and assume) the clone makers will follow suit.
  1160. //
  1161. if (ProcessorFeatures & 0x00000002) {
  1162. NtBits |= KF_V86_VIS | KF_CR4;
  1163. }
  1164. if (ProcessorFeatures & 0x00000008) {
  1165. NtBits |= KF_LARGE_PAGE | KF_CR4;
  1166. }
  1167. if (ProcessorFeatures & 0x00000010) {
  1168. NtBits |= KF_RDTSC;
  1169. }
  1170. //
  1171. // N.B. CMPXCHG8B MUST be done in a generic manner or clone processors
  1172. // will not be able to boot if they set this feature bit.
  1173. //
  1174. // This was incorrect in NT4 and resulted processor vendors claiming
  1175. // not to support cmpxchg8b even if they did. Whistler requires
  1176. // cmpxchg8b, work around this problems for the cases we know about.
  1177. //
  1178. // Because cmpxchg8b is a requirement for whistler, winnt32 needs to
  1179. // be modified if new processors are added to the following list.
  1180. // Also, setupldr. Both executables were modified so as to warn
  1181. // the user rather than installing an unbootable system.
  1182. //
  1183. if ((ProcessorFeatures & 0x00000100) == 0) {
  1184. ULONGLONG MsrValue;
  1185. if ((CpuVendor == CPU_TRANSMETA) &&
  1186. (Prcb->CpuType >= 5) &&
  1187. (Prcb->CpuStep >= 0x402)) {
  1188. //
  1189. // Transmeta processors have a cpuid feature bit 'mask' in
  1190. // msr 80860004. Unmask the cmpxchg8b bit.
  1191. //
  1192. MsrValue = RDMSR(0x80860004);
  1193. MsrValue |= 0x100;
  1194. WRMSR(0x80860004, MsrValue);
  1195. ProcessorFeatures |= 0x100;
  1196. } else if ((CpuVendor == CPU_CENTAUR) &&
  1197. (Prcb->CpuType >= 5)) {
  1198. //
  1199. // Centaur/IDT processors turn on the cmpxchg8b
  1200. // feature bit by setting bit 1 in MSR 107.
  1201. //
  1202. ULONG CentaurFeatureControlMSR = 0x107;
  1203. if (Prcb->CpuType >= 6) {
  1204. //
  1205. // Centaur processors (Cyrix III) turn on the cmpxchg8b
  1206. // feature bit by setting bit 1 in MSR 1107.
  1207. //
  1208. CentaurFeatureControlMSR = 0x1107;
  1209. }
  1210. MsrValue = RDMSR(CentaurFeatureControlMSR);
  1211. MsrValue |= 2;
  1212. WRMSR(CentaurFeatureControlMSR, MsrValue);
  1213. ProcessorFeatures |= 0x100;
  1214. }
  1215. }
  1216. if (ProcessorFeatures & 0x00000100) {
  1217. NtBits |= KF_CMPXCHG8B;
  1218. }
  1219. if (ProcessorFeatures & KI_FAST_SYSCALL_SUPPORTED) {
  1220. NtBits |= KF_FAST_SYSCALL;
  1221. KiFastSystemCallIsIA32 = TRUE;
  1222. }
  1223. if (ProcessorFeatures & 0x00001000) {
  1224. NtBits |= KF_MTRR;
  1225. }
  1226. if (ProcessorFeatures & 0x00002000) {
  1227. NtBits |= KF_GLOBAL_PAGE | KF_CR4;
  1228. }
  1229. if (ProcessorFeatures & 0x00008000) {
  1230. NtBits |= KF_CMOV;
  1231. }
  1232. if (ProcessorFeatures & 0x00010000) {
  1233. NtBits |= KF_PAT;
  1234. }
  1235. if (ProcessorFeatures & 0x00200000) {
  1236. NtBits |= KF_DTS;
  1237. }
  1238. if (ProcessorFeatures & 0x00800000) {
  1239. NtBits |= KF_MMX;
  1240. }
  1241. if (ProcessorFeatures & 0x01000000) {
  1242. NtBits |= KF_FXSR;
  1243. }
  1244. if (ProcessorFeatures & 0x02000000) {
  1245. NtBits |= KF_XMMI;
  1246. }
  1247. if (ProcessorFeatures & 0x04000000) {
  1248. NtBits |= KF_XMMI64;
  1249. }
  1250. //
  1251. // Test for SMT and determine the number of logical processors the
  1252. // underlying physical processor supports.
  1253. //
  1254. if (ProcessorFeatures & 0x10000000) {
  1255. Prcb->LogicalProcessorsPerPhysicalProcessor = (UCHAR)(Temp >> 16);
  1256. if (Prcb->LogicalProcessorsPerPhysicalProcessor > 1) {
  1257. KiSMTProcessorsPresent = TRUE;
  1258. } else {
  1259. Prcb->LogicalProcessorsPerPhysicalProcessor = 1;
  1260. }
  1261. } else {
  1262. Prcb->LogicalProcessorsPerPhysicalProcessor = 1;
  1263. }
  1264. //
  1265. // Check extended functions. First, check for existance,
  1266. // then check extended function 0x80000001 (Extended Processor
  1267. // Features) if present.
  1268. //
  1269. // Note: Intel guarantees that no processor that doesn't support
  1270. // extended CPUID functions will ever return a value with the
  1271. // most significant bit set. Microsoft asks all CPU vendors
  1272. // to make the same guarantee.
  1273. //
  1274. if (ExtendedCPUIDSupport != FALSE) {
  1275. CPUID(0x80000000, &Temp, &Junk, &Junk, &Junk);
  1276. //
  1277. // Sanity check the result, assuming there are no more
  1278. // than 256 extended feature functions (should be valid
  1279. // for a little while).
  1280. //
  1281. if ((Temp & 0xffffff00) == 0x80000000) {
  1282. //
  1283. // Check extended processor features. These, by definition,
  1284. // can vary on a processor by processor basis.
  1285. //
  1286. if (Temp >= 0x80000001) {
  1287. CPUID(0x80000001, &Temp, &Junk, &Junk, &ExtendedProcessorFeatures);
  1288. //
  1289. // With these, we can only do what we're told.
  1290. //
  1291. switch (CpuVendor) {
  1292. case CPU_AMD:
  1293. if (ExtendedProcessorFeatures & 0x80000000) {
  1294. NtBits |= KF_3DNOW;
  1295. }
  1296. #if 0
  1297. //
  1298. // There is a security hole with this implementation
  1299. // of fast system call such that it is possible to
  1300. // end up in the trap01 handler running on the user
  1301. // stack (ie not kernel stack). Unfortunately this
  1302. // prohibits use of this instruction pair.
  1303. //
  1304. if (ExtendedProcessorFeatures & 0x00000800) {
  1305. //
  1306. // This processor supports AMD's implementation
  1307. // of SYSENTER/SYSEXIT (SYSCALL/SYSRET). Use this
  1308. // unless it also supports the IA32 version.
  1309. //
  1310. if ((NtBits & KF_FAST_SYSCALL) == 0) {
  1311. NtBits |= KF_FAST_SYSCALL;
  1312. }
  1313. }
  1314. #endif
  1315. //
  1316. // If the host processor supports no execute protection,
  1317. // then it is a K8 chip and it also supports 40-bits of
  1318. // physical address. For this case the MTRR register
  1319. // variables must be initialized to support 40-bits of
  1320. // physical memory.
  1321. //
  1322. if (ExtendedProcessorFeatures & 0x00100000) {
  1323. KiMtrrMaskBase = 0x000000fffffff000;
  1324. KiMtrrMaskMask = 0x000000fffffff000;
  1325. KiMtrrOverflowMask = (~0x10000000000);
  1326. KiMtrrResBitMask = 0xffffffffff;
  1327. KiMtrrMaxRangeShift = 40;
  1328. }
  1329. #if defined(_X86PAE_)
  1330. //
  1331. // Enable no execute protection if the host processor
  1332. // supports the feature and it is enabled via a loader
  1333. // option.
  1334. //
  1335. if (ExtendedProcessorFeatures & 0x00100000) {
  1336. Temp = (ULONG)RDMSR(0xc0000080);
  1337. Temp |= 0x800;
  1338. WRMSR(0xc0000080, (ULONGLONG)Temp);
  1339. if ((KeLoaderBlock->LoadOptions != NULL) &&
  1340. (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE") != NULL)) {
  1341. KeErrorMask = 0x9;
  1342. MmPaeErrMask = 0x8;
  1343. MmPaeMask = 0x8000000000000000UI64;
  1344. }
  1345. }
  1346. #endif
  1347. break;
  1348. }
  1349. }
  1350. }
  1351. }
  1352. return NtBits;
  1353. }
  1354. VOID
  1355. KiGetCacheInformation(
  1356. VOID
  1357. )
  1358. {
  1359. #define CPUID_REG_COUNT 4
  1360. ULONG CpuidData[CPUID_REG_COUNT];
  1361. ULONG Line = 64;
  1362. ULONG Size = 0;
  1363. ULONG AdjustedSize = 0;
  1364. UCHAR Assoc = 0;
  1365. ULONG CpuVendor;
  1366. PKPCR Pcr;
  1367. //
  1368. // Set default.
  1369. //
  1370. Pcr = KeGetPcr();
  1371. Pcr->SecondLevelCacheSize = 0;
  1372. //
  1373. // Determine the processor manufacturer
  1374. //
  1375. CpuVendor = KiGetCpuVendor();
  1376. if (CpuVendor == CPU_NONE) {
  1377. return;
  1378. }
  1379. //
  1380. // Obtain Cache size information for those processors on which
  1381. // we know how.
  1382. //
  1383. switch (CpuVendor) {
  1384. case CPU_INTEL:
  1385. CPUID(0, CpuidData, CpuidData+1, CpuidData+2, CpuidData+3);
  1386. //
  1387. // Check this processor supports CPUID function 2 which is the
  1388. // one that returns cache size info.
  1389. //
  1390. if (CpuidData[0] >= 2) {
  1391. //
  1392. // The above returns a series of bytes. (In EAX, EBX, ECX
  1393. // and EDX). The least significant byte (of EAX) gives the
  1394. // number of times CPUID(2 ...) should be issued to return
  1395. // the complete set of data. The bytes are self describing
  1396. // data.
  1397. //
  1398. // In particular, the bytes describing the L2 cache size
  1399. // will be in the following set (and meaning)
  1400. //
  1401. // 0x40 0 bytes
  1402. // 0x41 128K bytes
  1403. // 0x42 256K bytes
  1404. // 0x43 512K bytes
  1405. // 0x44 1024K bytes
  1406. // 0x45 2048K bytes
  1407. // 0x46 4096K bytes
  1408. //
  1409. // I am extrapolating the above as anything in the range
  1410. // 0x41 thru 0x4f can be computed as
  1411. //
  1412. // 128KB << (descriptor - 0x41)
  1413. //
  1414. // The Intel folks say keep it to a reasonable upper bound,
  1415. // eg 49.
  1416. //
  1417. // N.B. the range 0x80 .. 0x86 indicates the same cache
  1418. // sizes but 8 way associative.
  1419. //
  1420. // Also, the most significant bit of each register indicates
  1421. // whether not the register contains valid information.
  1422. // 0 == Valid, 1 == InValid.
  1423. //
  1424. ULONG CpuidIterations = 0; // satisfy no_opt compilation
  1425. ULONG i;
  1426. ULONG CpuidReg;
  1427. BOOLEAN FirstPass = TRUE;
  1428. do {
  1429. CPUID(2, CpuidData, CpuidData+1, CpuidData+2, CpuidData+3);
  1430. if (FirstPass) {
  1431. //
  1432. // Get the iteration count from the first byte
  1433. // of the returned data then replace that byte
  1434. // with 0 (a null descriptor).
  1435. //
  1436. CpuidIterations = CpuidData[0] & 0xff;
  1437. CpuidData[0] &= 0xffffff00;
  1438. FirstPass = FALSE;
  1439. }
  1440. for (i = 0; i < CPUID_REG_COUNT; i++) {
  1441. CpuidReg = CpuidData[i];
  1442. if (CpuidReg & 0x80000000) {
  1443. //
  1444. // Register doesn't contain valid data,
  1445. // skip it.
  1446. //
  1447. continue;
  1448. }
  1449. while (CpuidReg) {
  1450. //
  1451. // Get LS Byte from this DWORD and remove the
  1452. // byte.
  1453. //
  1454. UCHAR Descriptor = (UCHAR)(CpuidReg & 0xff);
  1455. CpuidReg >>= 8;
  1456. if (Descriptor == 0) {
  1457. //
  1458. // NULL descriptor
  1459. //
  1460. continue;
  1461. }
  1462. if (((Descriptor > 0x40) && (Descriptor <= 0x47)) ||
  1463. ((Descriptor > 0x78) && (Descriptor <= 0x7c)) ||
  1464. ((Descriptor > 0x80) && (Descriptor <= 0x87))) {
  1465. //
  1466. // L2 descriptor.
  1467. //
  1468. // To date, for all the descriptors we know
  1469. // about those above 0x78 are 8 way and those
  1470. // below are 4 way.
  1471. //
  1472. Assoc = Descriptor >= 0x79 ? 8 : 4;
  1473. if (((Descriptor & 0xf8) == 0x78) &&
  1474. (Line < 128)) {
  1475. Line = 128;
  1476. }
  1477. Descriptor &= 0x07;
  1478. //
  1479. // There are cache descriptors in this
  1480. // range that we don't understand
  1481. // accurately yet e.g on Banias
  1482. //
  1483. Size = 0x10000 << Descriptor;
  1484. if ((Size / Assoc) > AdjustedSize) {
  1485. AdjustedSize = Size / Assoc;
  1486. Pcr->SecondLevelCacheSize = Size;
  1487. Pcr->SecondLevelCacheAssociativity = Assoc;
  1488. }
  1489. } else if ((Descriptor > 0x21) && (Descriptor <= 0x29)) {
  1490. if (Line < 128) {
  1491. Line = 128;
  1492. }
  1493. Assoc = 8;
  1494. switch (Descriptor) {
  1495. case 0x22:
  1496. Size = 512 * 1024;
  1497. Assoc = 4;
  1498. break;
  1499. case 0x23:
  1500. Size = 1024 * 1024;
  1501. break;
  1502. case 0x25:
  1503. Size = 2048 * 1024;
  1504. break;
  1505. case 0x29:
  1506. Size = 4096 * 1024;
  1507. break;
  1508. default:
  1509. Size = 0;
  1510. break;
  1511. }
  1512. if ((Size / Assoc) > AdjustedSize) {
  1513. AdjustedSize = Size / Assoc;
  1514. Pcr->SecondLevelCacheSize = Size;
  1515. Pcr->SecondLevelCacheAssociativity = Assoc;
  1516. }
  1517. } else if (((Descriptor > 0x65) && (Descriptor < 0x69)) ||
  1518. (Descriptor == 0x2C) ||
  1519. (Descriptor == 0xF0)) {
  1520. //
  1521. // L1 Descriptor with line size of 64
  1522. // bytes or an explicit prefetch
  1523. // descriptor indicating 64 bytes.
  1524. //
  1525. KePrefetchNTAGranularity = 64;
  1526. } else if (Descriptor == 0xF1) {
  1527. //
  1528. // Explicit prefetch descriptor indicating
  1529. // 128 bytes.
  1530. //
  1531. KePrefetchNTAGranularity = 128;
  1532. }
  1533. //
  1534. // else if (do other descriptors)
  1535. //
  1536. } // while more bytes in this register
  1537. } // for each register
  1538. //
  1539. // Note: Always run thru all iterations indicated by
  1540. // the first to ensure a subsequent call won't start
  1541. // part way thru.
  1542. //
  1543. } while (--CpuidIterations);
  1544. }
  1545. break;
  1546. case CPU_AMD:
  1547. //
  1548. // Get L1 Cache Data.
  1549. //
  1550. CPUID(0x80000000, CpuidData, CpuidData+1, CpuidData+2, CpuidData+3);
  1551. if (CpuidData[0] < 0x80000005) {
  1552. //
  1553. // This processor doesn't support L1 cache details.
  1554. //
  1555. break;
  1556. }
  1557. CPUID(0x80000005, CpuidData, CpuidData+1, CpuidData+2, CpuidData+3);
  1558. KePrefetchNTAGranularity = CpuidData[2] & 0xff;
  1559. //
  1560. // Get L2 data.
  1561. //
  1562. CPUID(0x80000000, CpuidData, CpuidData+1, CpuidData+2, CpuidData+3);
  1563. if (CpuidData[0] < 0x80000006) {
  1564. //
  1565. // This processor doesn't support L2 cache details.
  1566. //
  1567. break;
  1568. }
  1569. CPUID(0x80000006, CpuidData, CpuidData+1, CpuidData+2, CpuidData+3);
  1570. Line = CpuidData[2] & 0xff;
  1571. switch ((CpuidData[2] >> 12) & 0xf) {
  1572. case 0x2: Assoc = 2; break;
  1573. case 0x4: Assoc = 4; break;
  1574. case 0x6: Assoc = 8; break;
  1575. case 0x8: Assoc = 16; break;
  1576. //
  1577. // ff is really fully associative, just represent as 16 way.
  1578. //
  1579. case 0xf: Assoc = 16; break;
  1580. default: Assoc = 1; break;
  1581. }
  1582. Size = (CpuidData[2] >> 16) << 10;
  1583. if ((Pcr->PrcbData.CpuType == 0x6) &&
  1584. (Pcr->PrcbData.CpuStep == 0x300)) {
  1585. //
  1586. // Model 6,3,0 uses a different algorithm to report cache
  1587. // size.
  1588. //
  1589. Size = 64 * 1024;
  1590. }
  1591. Pcr->SecondLevelCacheAssociativity = Assoc;
  1592. Pcr->SecondLevelCacheSize = Size;
  1593. break;
  1594. }
  1595. if (Line > KeLargestCacheLine) {
  1596. KeLargestCacheLine = Line;
  1597. }
  1598. #undef CPUID_REG_COUNT
  1599. }
  1600. #define MAX_ATTEMPTS 10
  1601. VOID
  1602. KiLockStepProcessor(
  1603. PKIPI_CONTEXT SignalDone,
  1604. IN PVOID Arg1,
  1605. IN PVOID Arg2,
  1606. IN PVOID Proceed
  1607. )
  1608. {
  1609. UNREFERENCED_PARAMETER(Arg1);
  1610. UNREFERENCED_PARAMETER(Arg2);
  1611. //
  1612. // Tell initiating processor that this processor is now waiting
  1613. // and wait until the initial processor signals this processor
  1614. // to continue.
  1615. //
  1616. KiIpiSignalPacketDoneAndStall(SignalDone, Proceed);
  1617. }
  1618. VOID
  1619. KiLockStepOtherProcessors(
  1620. PULONG Proceed
  1621. )
  1622. {
  1623. PKPRCB Prcb;
  1624. KAFFINITY TargetProcessors;
  1625. ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
  1626. Prcb = KeGetCurrentPrcb();
  1627. TargetProcessors = KeActiveProcessors & ~Prcb->SetMember;
  1628. if (TargetProcessors != 0) {
  1629. KeAcquireSpinLockAtDpcLevel (&KiReverseStallIpiLock);
  1630. KiIpiSendSynchronousPacket(Prcb,
  1631. TargetProcessors,
  1632. KiLockStepProcessor,
  1633. NULL,
  1634. NULL,
  1635. Proceed);
  1636. KiIpiStallOnPacketTargets(TargetProcessors);
  1637. KeReleaseSpinLockFromDpcLevel (&KiReverseStallIpiLock);
  1638. }
  1639. }
  1640. VOID
  1641. KiUnlockStepOtherProcessors(
  1642. PULONG Proceed
  1643. )
  1644. {
  1645. (*Proceed) += 1;
  1646. }
  1647. BOOLEAN
  1648. KiInitMachineDependent (
  1649. VOID
  1650. )
  1651. {
  1652. PKPRCB Prcb;
  1653. KAFFINITY ActiveProcessors, CurrentAffinity;
  1654. ULONG NumberProcessors;
  1655. IDENTITY_MAP IdentityMap;
  1656. ULONG Index;
  1657. ULONG Average;
  1658. ULONG Junk;
  1659. struct {
  1660. LARGE_INTEGER PerfStart;
  1661. LARGE_INTEGER PerfEnd;
  1662. LONGLONG PerfDelta;
  1663. LARGE_INTEGER PerfFreq;
  1664. LONGLONG TSCStart;
  1665. LONGLONG TSCEnd;
  1666. LONGLONG TSCDelta;
  1667. ULONG MHz;
  1668. } Samples[MAX_ATTEMPTS], *pSamp;
  1669. #ifndef NT_UP
  1670. PUCHAR PatchLocation;
  1671. #endif
  1672. Prcb = KeGetCurrentPrcb();
  1673. //
  1674. // If we've got unlicensed processors dependent on previous page
  1675. // table state, don't enable large page support otherwise an SMI
  1676. // can cause those unlicensed processors to reset.
  1677. //
  1678. if (KiUnlicensedProcessorPresent) {
  1679. KeFeatureBits &= ~KF_LARGE_PAGE;
  1680. }
  1681. //
  1682. // If PDE large page is supported, enable it.
  1683. //
  1684. // We enable large pages before global pages to make TLB invalidation
  1685. // easier while turning on large pages.
  1686. //
  1687. if (KeFeatureBits & KF_LARGE_PAGE) {
  1688. if (Ki386CreateIdentityMap(&IdentityMap,
  1689. (PVOID) (ULONG_PTR) &Ki386EnableCurrentLargePage,
  1690. (PVOID) (ULONG_PTR) &Ki386EnableCurrentLargePageEnd )) {
  1691. KeIpiGenericCall (
  1692. (PKIPI_BROADCAST_WORKER) Ki386EnableTargetLargePage,
  1693. (ULONG)(&IdentityMap)
  1694. );
  1695. }
  1696. //
  1697. // Always call Ki386ClearIdentityMap() to free any memory allocated
  1698. //
  1699. Ki386ClearIdentityMap(&IdentityMap);
  1700. }
  1701. //
  1702. // If PDE/PTE global page is supported, enable it
  1703. //
  1704. if (KeFeatureBits & KF_GLOBAL_PAGE) {
  1705. NumberProcessors = KeNumberProcessors;
  1706. KeIpiGenericCall (
  1707. (PKIPI_BROADCAST_WORKER) Ki386EnableGlobalPage,
  1708. (ULONG)(&NumberProcessors)
  1709. );
  1710. }
  1711. //
  1712. // If PAT or MTRR supported but the HAL indicates it shouldn't
  1713. // be used (eg on a Shared Memory Cluster), drop the feature.
  1714. //
  1715. if (KeFeatureBits & (KF_PAT | KF_MTRR)) {
  1716. NTSTATUS Status;
  1717. BOOLEAN UseFrameBufferCaching;
  1718. ULONG Size;
  1719. Status = HalQuerySystemInformation(
  1720. HalFrameBufferCachingInformation,
  1721. sizeof(UseFrameBufferCaching),
  1722. &UseFrameBufferCaching,
  1723. &Size
  1724. );
  1725. if (NT_SUCCESS(Status) &&
  1726. (UseFrameBufferCaching == FALSE)) {
  1727. //
  1728. // Hal says don't use.
  1729. //
  1730. KeFeatureBits &= ~(KF_PAT | KF_MTRR);
  1731. }
  1732. }
  1733. //
  1734. // If PAT is supported then initialize it.
  1735. //
  1736. if (KeFeatureBits & KF_PAT) {
  1737. KiInitializePAT();
  1738. }
  1739. //
  1740. // Check to see if the floating point emulator should be used.
  1741. //
  1742. SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] =
  1743. FALSE;
  1744. switch (KeI386ForceNpxEmulation) {
  1745. case 0:
  1746. //
  1747. // Use the emulator based on the value in KeI386NpxPresent
  1748. //
  1749. break;
  1750. case 1:
  1751. //
  1752. // Only use the emulator if any processor has the known
  1753. // Pentium floating point division problem.
  1754. //
  1755. if (KeI386NpxPresent) {
  1756. //
  1757. // A coprocessor is present, check to see if the precision
  1758. // errata exists.
  1759. //
  1760. double Dividend, Divisor;
  1761. BOOLEAN PrecisionErrata = FALSE;
  1762. ActiveProcessors = KeActiveProcessors;
  1763. for (CurrentAffinity = 1; ActiveProcessors; CurrentAffinity <<= 1) {
  1764. if (ActiveProcessors & CurrentAffinity) {
  1765. ActiveProcessors &= ~CurrentAffinity;
  1766. //
  1767. // Run calculation on each processor.
  1768. //
  1769. KeSetSystemAffinityThread(CurrentAffinity);
  1770. _asm {
  1771. ;
  1772. ; This is going to destroy the state in the coprocesssor,
  1773. ; but we know that there's no state currently in it.
  1774. ;
  1775. cli
  1776. mov eax, cr0
  1777. mov ecx, eax ; hold original cr0 value
  1778. and eax, not (CR0_TS+CR0_MP+CR0_EM)
  1779. mov cr0, eax
  1780. fninit ; to known state
  1781. }
  1782. Dividend = 4195835.0;
  1783. Divisor = 3145727.0;
  1784. _asm {
  1785. fld Dividend
  1786. fdiv Divisor ; test known faulty divison
  1787. fmul Divisor ; Multiple quotient by divisor
  1788. fcomp Dividend ; Compare product and dividend
  1789. fstsw ax ; Move float conditions to ax
  1790. sahf ; move to eflags
  1791. mov cr0, ecx ; restore cr0
  1792. sti
  1793. jc short em10
  1794. jz short em20
  1795. em10: mov PrecisionErrata, TRUE
  1796. em20:
  1797. }
  1798. if (PrecisionErrata) {
  1799. KeI386NpxPresent = FALSE;
  1800. SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] = TRUE;
  1801. break;
  1802. }
  1803. }
  1804. }
  1805. }
  1806. break;
  1807. default:
  1808. //
  1809. // Unknown setting - use the emulator
  1810. //
  1811. KeI386NpxPresent = FALSE;
  1812. break;
  1813. }
  1814. //
  1815. // Setup processor features, and install emulator if needed
  1816. //
  1817. SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_EMULATED] =
  1818. !KeI386NpxPresent;
  1819. if (!KeI386NpxPresent) {
  1820. //
  1821. // MMx, fast save/restore, streaming SIMD not available when
  1822. // emulator is used. (Nor FP errata).
  1823. //
  1824. KeFeatureBits &= ~(KF_MMX | KF_FXSR | KF_XMMI | KF_XMMI64);
  1825. KeI386XMMIPresent = FALSE;
  1826. KeI386FxsrPresent = FALSE;
  1827. SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] =
  1828. SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] =
  1829. SharedUserData->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] =
  1830. SharedUserData->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE] =
  1831. SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] =
  1832. FALSE;
  1833. }
  1834. //
  1835. // If CR4 exists, enable DE extensions for IO breakpoints
  1836. //
  1837. if (KeFeatureBits & KF_CR4) {
  1838. NumberProcessors = KeNumberProcessors;
  1839. KeIpiGenericCall (
  1840. (PKIPI_BROADCAST_WORKER) Ki386EnableDE,
  1841. (ULONG)(&NumberProcessors)
  1842. );
  1843. }
  1844. //
  1845. // If FXSR feature is supported, set OSFXSR (bit 9) in CR4
  1846. //
  1847. if (KeFeatureBits & KF_FXSR) {
  1848. NumberProcessors = KeNumberProcessors;
  1849. KeIpiGenericCall (
  1850. (PKIPI_BROADCAST_WORKER) Ki386EnableFxsr,
  1851. (ULONG)(&NumberProcessors)
  1852. );
  1853. //
  1854. // If XMMI feature is supported,
  1855. // a. Hook int 19 handler
  1856. // b. Set OSXMMEXCPT (bit 10) in CR4
  1857. // c. Enable use of fast XMMI based zero page routines.
  1858. // d. Remove return instruction at start of prefetch routine.
  1859. //
  1860. if (KeFeatureBits & KF_XMMI) {
  1861. KeIpiGenericCall (
  1862. (PKIPI_BROADCAST_WORKER) Ki386EnableXMMIExceptions,
  1863. (ULONG)(&NumberProcessors)
  1864. );
  1865. #if !defined(NT_UP)
  1866. //
  1867. // Enable non-temporal zeroing on all machines except MP
  1868. // Pentium 4 machines. Pentium 4 machines can explicitly
  1869. // request this functionality via registry key. This was
  1870. // done to address a livelock issue.
  1871. //
  1872. if ((strcmp((PCHAR)Prcb->VendorString, CmpIntelID) != 0) ||
  1873. (Prcb->CpuType != 15) || KiXMMIZeroingEnable)
  1874. #endif
  1875. {
  1876. KeZeroPages = KiXMMIZeroPages;
  1877. KeZeroPagesFromIdleThread = KiXMMIZeroPagesNoSave;
  1878. }
  1879. *(PUCHAR)(ULONG_PTR)&RtlPrefetchMemoryNonTemporal = 0x90;
  1880. }
  1881. } else {
  1882. #ifndef NT_UP
  1883. //
  1884. // Patch the fxsave instruction in SwapContext to use
  1885. // "fnsave {dd, 31}, fwait {9b}"
  1886. //
  1887. ASSERT( ((ULONG)&ScPatchFxe-(ULONG)&ScPatchFxb) >= 3);
  1888. PatchLocation = (PUCHAR)&ScPatchFxb;
  1889. *PatchLocation++ = 0xdd;
  1890. *PatchLocation++ = 0x31;
  1891. *PatchLocation++ = 0x9b;
  1892. while (PatchLocation < (PUCHAR)&ScPatchFxe) {
  1893. //
  1894. // Put nop's in the remaining bytes
  1895. //
  1896. *PatchLocation++ = 0x90;
  1897. }
  1898. #endif
  1899. }
  1900. //
  1901. // If the system (ie all processors) supports fast system
  1902. // call/return, initialize the machine specific registers
  1903. // required to support it.
  1904. //
  1905. KiRestoreFastSyscallReturnState();
  1906. ActiveProcessors = KeActiveProcessors;
  1907. for (CurrentAffinity=1; ActiveProcessors; CurrentAffinity <<= 1) {
  1908. if (ActiveProcessors & CurrentAffinity) {
  1909. //
  1910. // Switch to that processor, and remove it from the
  1911. // remaining set of processors
  1912. //
  1913. ActiveProcessors &= ~CurrentAffinity;
  1914. KeSetSystemAffinityThread(CurrentAffinity);
  1915. //
  1916. // Determine the MHz for the processor
  1917. //
  1918. KeGetCurrentPrcb()->MHz = 0;
  1919. if (KeFeatureBits & KF_RDTSC) {
  1920. Index = 0;
  1921. pSamp = Samples;
  1922. for (; ;) {
  1923. //
  1924. // Collect a new sample
  1925. // Delay the thread a "long" amount and time it with
  1926. // a time source and RDTSC.
  1927. //
  1928. CPUID (0, &Junk, &Junk, &Junk, &Junk);
  1929. pSamp->PerfStart = KeQueryPerformanceCounter (NULL);
  1930. pSamp->TSCStart = RDTSC();
  1931. pSamp->PerfFreq.QuadPart = -50000;
  1932. KeDelayExecutionThread (KernelMode, FALSE, &pSamp->PerfFreq);
  1933. CPUID (0, &Junk, &Junk, &Junk, &Junk);
  1934. pSamp->PerfEnd = KeQueryPerformanceCounter (&pSamp->PerfFreq);
  1935. pSamp->TSCEnd = RDTSC();
  1936. //
  1937. // Calculate processors MHz
  1938. //
  1939. pSamp->PerfDelta = pSamp->PerfEnd.QuadPart - pSamp->PerfStart.QuadPart;
  1940. pSamp->TSCDelta = pSamp->TSCEnd - pSamp->TSCStart;
  1941. pSamp->MHz = (ULONG) ((pSamp->TSCDelta * pSamp->PerfFreq.QuadPart + 500000L) /
  1942. (pSamp->PerfDelta * 1000000L));
  1943. //
  1944. // If last 2 samples matched within a MHz, done
  1945. //
  1946. if (Index) {
  1947. if (pSamp->MHz == pSamp[-1].MHz ||
  1948. pSamp->MHz == pSamp[-1].MHz + 1 ||
  1949. pSamp->MHz == pSamp[-1].MHz - 1) {
  1950. break;
  1951. }
  1952. }
  1953. //
  1954. // Advance to next sample
  1955. //
  1956. pSamp += 1;
  1957. Index += 1;
  1958. //
  1959. // If too many samples, then something is wrong
  1960. //
  1961. if (Index >= MAX_ATTEMPTS) {
  1962. #if DBG
  1963. //
  1964. // Temp breakpoint to see where this is failing
  1965. // and why
  1966. //
  1967. DbgBreakPoint();
  1968. #endif
  1969. Average = 0;
  1970. for (Index = 0; Index < MAX_ATTEMPTS; Index++) {
  1971. Average += Samples[Index].MHz;
  1972. }
  1973. pSamp[-1].MHz = Average / MAX_ATTEMPTS;
  1974. break;
  1975. }
  1976. }
  1977. KeGetCurrentPrcb()->MHz = (USHORT) pSamp[-1].MHz;
  1978. }
  1979. //
  1980. // If MTRRs are supported and PAT not supported, initialize MTRRs
  1981. // per processor
  1982. //
  1983. if (KeFeatureBits & KF_MTRR) {
  1984. KiInitializeMTRR ( (BOOLEAN) (ActiveProcessors ? FALSE : TRUE));
  1985. }
  1986. //
  1987. // If the processor is a AMD K6 with MTRR support then
  1988. // perform processor specific initialization.
  1989. //
  1990. if (KeFeatureBits & KF_AMDK6MTRR) {
  1991. KiAmdK6InitializeMTRR();
  1992. }
  1993. //
  1994. // Apply Pentium workaround if needed
  1995. //
  1996. if (KiI386PentiumLockErrataPresent) {
  1997. KiI386PentiumLockErrataFixup ();
  1998. }
  1999. //
  2000. // If this processor supports fast floating save/restore,
  2001. // determine the MXCSR mask value that should be used.
  2002. //
  2003. if (KeFeatureBits & KF_FXSR) {
  2004. //
  2005. // Get base of NPX save area.
  2006. //
  2007. //
  2008. PFX_SAVE_AREA NpxFrame;
  2009. ULONG MXCsrMask = 0xFFBF;
  2010. NpxFrame = (PFX_SAVE_AREA)
  2011. (((ULONG)(KeGetCurrentThread()->InitialStack) -
  2012. sizeof(FX_SAVE_AREA)));
  2013. NpxFrame->U.FxArea.MXCsrMask = 0;
  2014. Kix86FxSave(NpxFrame);
  2015. //
  2016. // If the processor supplied a mask value, use
  2017. // that, otherwise set the default value.
  2018. //
  2019. if (NpxFrame->U.FxArea.MXCsrMask != 0) {
  2020. MXCsrMask = NpxFrame->U.FxArea.MXCsrMask;
  2021. }
  2022. //
  2023. // All processors must use the same (most restrictive)
  2024. // value.
  2025. //
  2026. if (KiMXCsrMask == 0) {
  2027. KiMXCsrMask = MXCsrMask;
  2028. } else if (KiMXCsrMask != MXCsrMask) {
  2029. KeBugCheckEx(MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED,
  2030. KF_FXSR,
  2031. KiMXCsrMask,
  2032. MXCsrMask,
  2033. 0);
  2034. }
  2035. KiMXCsrMask &= MXCsrMask;
  2036. }
  2037. }
  2038. }
  2039. KeRevertToUserAffinityThread();
  2040. //
  2041. // If ISR time limits are being enforced, modify KiDispatchInterrupt
  2042. // and KiChainedDispatch2ndLvl to call into the appropriate equivalent
  2043. // timing routines.
  2044. //
  2045. if (KiTimeLimitIsrMicroseconds != 0) {
  2046. ULONG_PTR Target;
  2047. ULONG_PTR Source;
  2048. ULONG_PTR SourceEnd;
  2049. PUCHAR Code;
  2050. KIRQL OldIrql;
  2051. ULONG Proceed = 0;
  2052. OldIrql = KfRaiseIrql(SYNCH_LEVEL);
  2053. Target = (ULONG_PTR)&KiTimedChainedDispatch2ndLvl;
  2054. Source = (ULONG_PTR)&KiChainedDispatch2ndLvl;
  2055. //
  2056. // Compute offset from end of branch instruction to new instruction
  2057. // stream. N.B. The end of the branch instruction will be 7 bytes in.
  2058. //
  2059. Target = Target - (Source + 7);
  2060. //
  2061. // Freeze the other processors.
  2062. //
  2063. KiLockStepOtherProcessors(&Proceed);
  2064. //
  2065. // Patch KiChainedDispatch2ndLvl to branch into
  2066. // KiTimedChainedDispatch2ndLvl.
  2067. //
  2068. KfRaiseIrql(HIGH_LEVEL);
  2069. Code = (PUCHAR)Source;
  2070. *Code++ = 0x8b; // mov ecx, edi ; pass int obj as argument
  2071. *Code++ = 0xcf;
  2072. *Code++ = 0xe9; // jmp xxxxxxxx
  2073. *(PULONG)Code = Target;
  2074. //
  2075. // Get addresses of code to patch in KiInterruptDispatch
  2076. //
  2077. KiGetInterruptDispatchPatchAddresses(&Source, &SourceEnd);
  2078. //
  2079. // Patch KiInterruptDispatch to call into KiTimedInterruptDispatch.
  2080. // Resulting code looks like-
  2081. //
  2082. // mov ecx, edi ; set interrupt object address
  2083. // call @KiTimedInterruptDispatch@4
  2084. // jmp xxx ; skip unpatched excess code.
  2085. //
  2086. Target = (ULONG_PTR)&KiTimedInterruptDispatch;
  2087. Target = Target - (Source + 7);
  2088. Code = (PUCHAR)Source;
  2089. *Code++ = 0x8b; // mov ecx, edi ; pass int obj as argument
  2090. *Code++ = 0xcf;
  2091. *Code++ = 0xe8; // call xxxxxxxx
  2092. *(PULONG)Code = Target;
  2093. Code += sizeof(ULONG);
  2094. *Code++ = 0xeb; // jmp short yyy
  2095. *Code++ = (UCHAR)(SourceEnd - (ULONG_PTR)Code - 1);
  2096. //
  2097. // Unfreeze other processors.
  2098. //
  2099. KiUnlockStepOtherProcessors(&Proceed);
  2100. KfLowerIrql(OldIrql);
  2101. }
  2102. return TRUE;
  2103. }
  2104. VOID
  2105. KeOptimizeProcessorControlState (
  2106. VOID
  2107. )
  2108. {
  2109. Ke386ConfigureCyrixProcessor ();
  2110. }
  2111. VOID
  2112. KeSetup80387OrEmulate (
  2113. IN PVOID *R3EmulatorTable
  2114. )
  2115. /*++
  2116. Routine Description:
  2117. This routine is called by PS initialization after loading NTDLL.
  2118. If this is a 386 system without 387s (all processors must be
  2119. symmetrical) then this function will set the trap 07 vector on all
  2120. processors to point to the address passed in (which should be the
  2121. entry point of the 80387 emulator in NTDLL, NPXNPHandler).
  2122. Arguments:
  2123. HandlerAddress - Supplies the address of the trap07 handler.
  2124. Return Value:
  2125. None.
  2126. --*/
  2127. {
  2128. PKINTERRUPT_ROUTINE HandlerAddress;
  2129. KAFFINITY ActiveProcessors, CurrentAffinity;
  2130. KIRQL OldIrql;
  2131. ULONG disposition;
  2132. HANDLE SystemHandle, SourceHandle, DestHandle;
  2133. NTSTATUS Status;
  2134. UNICODE_STRING unicodeString;
  2135. OBJECT_ATTRIBUTES ObjectAttributes;
  2136. if (!KeI386NpxPresent) {
  2137. //
  2138. // Use the user mode floating point emulator
  2139. //
  2140. HandlerAddress = (PKINTERRUPT_ROUTINE) ((PULONG) R3EmulatorTable)[0];
  2141. Ki387RoundModeTable = (PVOID) ((PULONG) R3EmulatorTable)[1];
  2142. ActiveProcessors = KeActiveProcessors;
  2143. for (CurrentAffinity = 1; ActiveProcessors; CurrentAffinity <<= 1) {
  2144. if (ActiveProcessors & CurrentAffinity) {
  2145. ActiveProcessors &= ~CurrentAffinity;
  2146. //
  2147. // Run this code on each processor.
  2148. //
  2149. KeSetSystemAffinityThread(CurrentAffinity);
  2150. //
  2151. // Raise IRQL and lock dispatcher database.
  2152. //
  2153. KiLockDispatcherDatabase(&OldIrql);
  2154. //
  2155. // Make the trap 07 IDT entry point at the passed-in handler
  2156. //
  2157. KiSetHandlerAddressToIDT(I386_80387_NP_VECTOR, HandlerAddress);
  2158. KeGetPcr()->IDT[I386_80387_NP_VECTOR].Selector = KGDT_R3_CODE;
  2159. KeGetPcr()->IDT[I386_80387_NP_VECTOR].Access = TRAP332_GATE;
  2160. //
  2161. // Unlock dispatcher database and lower IRQL to its previous value.
  2162. //
  2163. KiUnlockDispatcherDatabase(OldIrql);
  2164. }
  2165. }
  2166. //
  2167. // Set affinity back to the original value.
  2168. //
  2169. KeRevertToUserAffinityThread();
  2170. //
  2171. // Move any entries from ..\System\FloatingPointProcessor to
  2172. // ..\System\DisabledFloatingPointProcessor.
  2173. //
  2174. //
  2175. // Open system tree
  2176. //
  2177. InitializeObjectAttributes(
  2178. &ObjectAttributes,
  2179. &CmRegistryMachineHardwareDescriptionSystemName,
  2180. OBJ_CASE_INSENSITIVE,
  2181. NULL,
  2182. NULL
  2183. );
  2184. Status = ZwOpenKey( &SystemHandle,
  2185. KEY_ALL_ACCESS,
  2186. &ObjectAttributes
  2187. );
  2188. if (NT_SUCCESS(Status)) {
  2189. //
  2190. // Open FloatingPointProcessor key
  2191. //
  2192. InitializeObjectAttributes(
  2193. &ObjectAttributes,
  2194. &CmTypeName[FloatingPointProcessor],
  2195. OBJ_CASE_INSENSITIVE,
  2196. SystemHandle,
  2197. NULL
  2198. );
  2199. Status = ZwOpenKey ( &SourceHandle,
  2200. KEY_ALL_ACCESS,
  2201. &ObjectAttributes
  2202. );
  2203. if (NT_SUCCESS(Status)) {
  2204. //
  2205. // Create DisabledFloatingPointProcessor key
  2206. //
  2207. RtlInitUnicodeString (
  2208. &unicodeString,
  2209. CmDisabledFloatingPointProcessor
  2210. );
  2211. InitializeObjectAttributes(
  2212. &ObjectAttributes,
  2213. &unicodeString,
  2214. OBJ_CASE_INSENSITIVE,
  2215. SystemHandle,
  2216. NULL
  2217. );
  2218. Status = ZwCreateKey( &DestHandle,
  2219. KEY_ALL_ACCESS,
  2220. &ObjectAttributes,
  2221. 0,
  2222. NULL,
  2223. REG_OPTION_VOLATILE,
  2224. &disposition
  2225. );
  2226. if (NT_SUCCESS(Status)) {
  2227. //
  2228. // Move it
  2229. //
  2230. KiMoveRegTree (SourceHandle, DestHandle);
  2231. ZwClose (DestHandle);
  2232. }
  2233. ZwClose (SourceHandle);
  2234. }
  2235. ZwClose (SystemHandle);
  2236. }
  2237. }
  2238. }
  2239. NTSTATUS
  2240. KiMoveRegTree(
  2241. HANDLE Source,
  2242. HANDLE Dest
  2243. )
  2244. {
  2245. NTSTATUS Status;
  2246. PKEY_BASIC_INFORMATION KeyInformation;
  2247. PKEY_VALUE_FULL_INFORMATION KeyValue;
  2248. OBJECT_ATTRIBUTES ObjectAttributes;
  2249. HANDLE SourceChild;
  2250. HANDLE DestChild;
  2251. ULONG ResultLength;
  2252. UCHAR buffer[1024]; // hmm....
  2253. UNICODE_STRING ValueName;
  2254. UNICODE_STRING KeyName;
  2255. KeyValue = (PKEY_VALUE_FULL_INFORMATION)buffer;
  2256. //
  2257. // Move values from source node to dest node
  2258. //
  2259. for (; ;) {
  2260. //
  2261. // Get first value
  2262. //
  2263. Status = ZwEnumerateValueKey(Source,
  2264. 0,
  2265. KeyValueFullInformation,
  2266. buffer,
  2267. sizeof (buffer),
  2268. &ResultLength);
  2269. if (!NT_SUCCESS(Status)) {
  2270. break;
  2271. }
  2272. //
  2273. // Write value to dest node
  2274. //
  2275. ValueName.Buffer = KeyValue->Name;
  2276. ValueName.Length = (USHORT) KeyValue->NameLength;
  2277. ZwSetValueKey( Dest,
  2278. &ValueName,
  2279. KeyValue->TitleIndex,
  2280. KeyValue->Type,
  2281. buffer+KeyValue->DataOffset,
  2282. KeyValue->DataLength
  2283. );
  2284. //
  2285. // Delete value and get first value again
  2286. //
  2287. Status = ZwDeleteValueKey (Source, &ValueName);
  2288. if (!NT_SUCCESS(Status)) {
  2289. break;
  2290. }
  2291. }
  2292. //
  2293. // Enumerate node's children and apply ourselves to each one
  2294. //
  2295. KeyInformation = (PKEY_BASIC_INFORMATION)buffer;
  2296. for (; ;) {
  2297. //
  2298. // Open node's first key
  2299. //
  2300. Status = ZwEnumerateKey(
  2301. Source,
  2302. 0,
  2303. KeyBasicInformation,
  2304. KeyInformation,
  2305. sizeof (buffer),
  2306. &ResultLength
  2307. );
  2308. if (!NT_SUCCESS(Status)) {
  2309. break;
  2310. }
  2311. KeyName.Buffer = KeyInformation->Name;
  2312. KeyName.Length = (USHORT) KeyInformation->NameLength;
  2313. InitializeObjectAttributes(
  2314. &ObjectAttributes,
  2315. &KeyName,
  2316. OBJ_CASE_INSENSITIVE,
  2317. Source,
  2318. NULL
  2319. );
  2320. Status = ZwOpenKey(
  2321. &SourceChild,
  2322. KEY_ALL_ACCESS,
  2323. &ObjectAttributes
  2324. );
  2325. if (!NT_SUCCESS(Status)) {
  2326. break;
  2327. }
  2328. //
  2329. // Create key in dest tree
  2330. //
  2331. InitializeObjectAttributes(
  2332. &ObjectAttributes,
  2333. &KeyName,
  2334. OBJ_CASE_INSENSITIVE,
  2335. Dest,
  2336. NULL
  2337. );
  2338. Status = ZwCreateKey(
  2339. &DestChild,
  2340. KEY_ALL_ACCESS,
  2341. &ObjectAttributes,
  2342. 0,
  2343. NULL,
  2344. REG_OPTION_VOLATILE,
  2345. NULL
  2346. );
  2347. if (!NT_SUCCESS(Status)) {
  2348. break;
  2349. }
  2350. //
  2351. // Move subtree
  2352. //
  2353. Status = KiMoveRegTree(SourceChild, DestChild);
  2354. ZwClose(DestChild);
  2355. ZwClose(SourceChild);
  2356. if (!NT_SUCCESS(Status)) {
  2357. break;
  2358. }
  2359. //
  2360. // Loop and get first key. (old first key was deleted by the
  2361. // call to KiMoveRegTree).
  2362. //
  2363. }
  2364. //
  2365. // Remove source node
  2366. //
  2367. return NtDeleteKey (Source);
  2368. }
  2369. VOID
  2370. KiI386PentiumLockErrataFixup (
  2371. VOID
  2372. )
  2373. /*++
  2374. Routine Description:
  2375. This routine is called once on every processor when
  2376. KiI386PentiumLockErrataPresent is TRUE.
  2377. This routine replaces the local IDT with an IDT that has the first 7 IDT
  2378. entries on their own page and returns the first page to the caller to
  2379. be marked as read-only. This causes the processor to trap-0e fault when
  2380. the errata occurs. Special code in the trap-0e handler detects the
  2381. problem and performs the proper fixup.
  2382. Arguments:
  2383. FixupPage - Returns a virtual address of a page to be marked read-only
  2384. Return Value:
  2385. None.
  2386. --*/
  2387. {
  2388. KDESCRIPTOR IdtDescriptor;
  2389. PUCHAR NewBase, BasePage;
  2390. BOOLEAN Enable;
  2391. BOOLEAN Status;
  2392. #define IDT_SKIP (7 * sizeof (KIDTENTRY))
  2393. //
  2394. // Allocate memory for a new copy of the processor's IDT
  2395. //
  2396. BasePage = MmAllocateIndependentPages (2*PAGE_SIZE, 0);
  2397. //
  2398. // The IDT base is such that the first 7 entries are on the
  2399. // first (read-only) page, and the remaining entries are on the
  2400. // second (read-write) page
  2401. //
  2402. NewBase = BasePage + PAGE_SIZE - IDT_SKIP;
  2403. //
  2404. // Disable interrupts on this processor while updating the IDT base
  2405. //
  2406. Enable = KeDisableInterrupts();
  2407. //
  2408. // Copy Old IDT to new IDT
  2409. //
  2410. _asm {
  2411. sidt IdtDescriptor.Limit
  2412. }
  2413. RtlCopyMemory ((PVOID) NewBase,
  2414. (PVOID) IdtDescriptor.Base,
  2415. IdtDescriptor.Limit + 1
  2416. );
  2417. IdtDescriptor.Base = (ULONG) NewBase;
  2418. //
  2419. // Set the new IDT
  2420. //
  2421. _asm {
  2422. lidt IdtDescriptor.Limit
  2423. }
  2424. //
  2425. // Update the PCR
  2426. //
  2427. KeGetPcr()->IDT = (PKIDTENTRY) NewBase;
  2428. //
  2429. // Restore interrupts
  2430. //
  2431. KeEnableInterrupts(Enable);
  2432. //
  2433. // Mark the first page which contains IDT entries 0-6 as read-only
  2434. //
  2435. Status = MmSetPageProtection (BasePage, PAGE_SIZE, PAGE_READONLY);
  2436. ASSERT (Status);
  2437. }