Source code of Windows XP (NT5)
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.

1157 lines
26 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Copyright (c) 1992 Intel Corporation
  4. All rights reserved
  5. INTEL CORPORATION PROPRIETARY INFORMATION
  6. This software is supplied to Microsoft under the terms
  7. of a license agreement with Intel Corporation and may not be
  8. copied nor disclosed except in accordance with the terms
  9. of that agreement.
  10. Module Name:
  11. mphal.c
  12. Abstract:
  13. This module implements the initialization of the system dependent
  14. functions that define the Hardware Architecture Layer (HAL) for a
  15. PC+MP system.
  16. Author:
  17. David N. Cutler (davec) 25-Apr-1991
  18. Environment:
  19. Kernel mode only.
  20. Revision History:
  21. Ron Mosgrove (Intel) - Modified to support the PC+MP Spec
  22. Jake Oshins (jakeo) - Modified to support the ACPI Spec
  23. */
  24. #include "halp.h"
  25. #include "pcmp_nt.inc"
  26. #include "string.h"
  27. #include "stdlib.h"
  28. #include "stdio.h"
  29. ULONG HalpBusType;
  30. extern ADDRESS_USAGE HalpDefaultPcIoSpace;
  31. extern ADDRESS_USAGE HalpEisaIoSpace;
  32. extern ADDRESS_USAGE HalpImcrIoSpace;
  33. extern struct HalpMpInfo HalpMpInfoTable;
  34. extern UCHAR rgzRTCNotFound[];
  35. extern USHORT HalpVectorToINTI[];
  36. extern UCHAR HalpGenuineIntel[];
  37. extern const UCHAR HalName[];
  38. extern BOOLEAN HalpDoingCrashDump;
  39. extern PULONG KiEnableTimerWatchdog;
  40. extern ULONG HalpTimerWatchdogEnabled;
  41. extern PCHAR HalpTimerWatchdogStorage;
  42. extern PVOID HalpTimerWatchdogCurFrame;
  43. extern PVOID HalpTimerWatchdogLastFrame;
  44. extern ULONG HalpTimerWatchdogStorageOverflow;
  45. extern KSPIN_LOCK HalpDmaAdapterListLock;
  46. extern LIST_ENTRY HalpDmaAdapterList;
  47. extern ULONG HalpProc0TSCHz;
  48. #ifdef ACPI_HAL
  49. extern ULONG HalpPicVectorRedirect[];
  50. #define ADJUSTED_VECTOR(x) \
  51. HalpPicVectorRedirect[x]
  52. #else
  53. #define ADJUSTED_VECTOR(x) x
  54. #endif
  55. VOID
  56. HalpInitMP(
  57. IN ULONG Phase,
  58. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  59. );
  60. KSPIN_LOCK HalpSystemHardwareLock;
  61. VOID
  62. HalpInitBusHandlers (
  63. VOID
  64. );
  65. VOID
  66. HalpClockInterruptPn(
  67. VOID
  68. );
  69. VOID
  70. HalpClockInterruptStub(
  71. VOID
  72. );
  73. BOOLEAN
  74. HalpmmTimer(
  75. VOID
  76. );
  77. VOID
  78. HalpmmTimerClockInit(
  79. VOID
  80. );
  81. VOID
  82. HalpmmTimerClockInterruptStub(
  83. VOID
  84. );
  85. ULONG
  86. HalpScaleTimers(
  87. VOID
  88. );
  89. BOOLEAN
  90. HalpPmTimerScaleTimers(
  91. VOID
  92. );
  93. VOID
  94. HalpApicRebootService(
  95. VOID
  96. );
  97. VOID
  98. HalpBroadcastCallService(
  99. VOID
  100. );
  101. VOID
  102. HalpDispatchInterrupt(
  103. VOID
  104. );
  105. VOID
  106. HalpApcInterrupt(
  107. VOID
  108. );
  109. VOID
  110. HalpIpiHandler(
  111. VOID
  112. );
  113. VOID
  114. HalpInitializeIOUnits (
  115. VOID
  116. );
  117. VOID
  118. HalpInitIntiInfo (
  119. VOID
  120. );
  121. VOID
  122. HalpGetParameters (
  123. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  124. );
  125. VOID
  126. HalpInitializeTimerResolution (
  127. ULONG Rate
  128. );
  129. ULONG
  130. HalpGetFeatureBits (
  131. VOID
  132. );
  133. VOID
  134. HalpInitializeApicAddressing(
  135. UCHAR Number
  136. );
  137. VOID
  138. HalpInitReservedPages(
  139. VOID
  140. );
  141. VOID
  142. HalpAcpiTimerPerfCountHack(
  143. VOID
  144. );
  145. BOOLEAN
  146. HalpFindBusAddressTranslation(
  147. IN PHYSICAL_ADDRESS BusAddress,
  148. IN OUT PULONG AddressSpace,
  149. OUT PPHYSICAL_ADDRESS TranslatedAddress,
  150. IN OUT PULONG_PTR Context,
  151. IN BOOLEAN NextBus
  152. );
  153. #ifdef DEBUGGING
  154. extern void HalpDisplayLocalUnit(void);
  155. extern void HalpDisplayConfigTable(void);
  156. extern void HalpDisplayExtConfigTable(void);
  157. #endif // DEBUGGING
  158. BOOLEAN HalpStaticIntAffinity = FALSE;
  159. BOOLEAN HalpClockMode = Latched;
  160. UCHAR HalpMaxProcsPerCluster = 0;
  161. extern BOOLEAN HalpUse8254;
  162. extern UCHAR HalpSzInterruptAffinity[];
  163. extern BOOLEAN HalpPciLockSettings;
  164. extern UCHAR HalpVectorToIRQL[];
  165. extern ULONG HalpDontStartProcessors;
  166. extern UCHAR HalpSzOneCpu[];
  167. extern UCHAR HalpSzNoIoApic[];
  168. extern UCHAR HalpSzBreak[];
  169. extern UCHAR HalpSzPciLock[];
  170. extern UCHAR HalpSzTimerRes[];
  171. extern UCHAR HalpSzClockLevel[];
  172. extern UCHAR HalpSzUse8254[];
  173. extern UCHAR HalpSzForceClusterMode[];
  174. ULONG UserSpecifiedCpuCount = 0;
  175. KSPIN_LOCK HalpAccountingLock;
  176. #ifdef ACPI_HAL
  177. extern KEVENT HalpNewAdapter;
  178. #endif
  179. #ifdef ALLOC_PRAGMA
  180. VOID
  181. HalpInitTimerWatchdog(
  182. IN ULONG Phase
  183. );
  184. #pragma alloc_text(INIT,HalpGetParameters)
  185. #pragma alloc_text(INIT,HalpInitTimerWatchdog)
  186. #pragma alloc_text(INIT,HalInitSystem)
  187. #pragma alloc_text(INIT,HalpGetFeatureBits)
  188. #endif // ALLOC_PRAGMA
  189. #ifndef NT_UP
  190. KIRQL
  191. FASTCALL
  192. KeAcquireSpinLockRaiseToSynchMCE(
  193. IN PKSPIN_LOCK SpinLock
  194. );
  195. KIRQL
  196. FASTCALL
  197. KeAcquireSpinLockRaiseToSynch (
  198. IN PKSPIN_LOCK SpinLock
  199. );
  200. #endif
  201. //
  202. // Define bug check callback record.
  203. //
  204. KBUGCHECK_CALLBACK_RECORD HalpCallbackRecord;
  205. VOID
  206. HalpBugCheckCallback (
  207. IN PVOID Buffer,
  208. IN ULONG Length
  209. )
  210. /*++
  211. Routine Description:
  212. This function is called when a bug check occurs. Its function is
  213. to perform anything the HAL needs done as the system bugchecks.
  214. Arguments: (Unused in this callback).
  215. Buffer - Supplies a pointer to the bug check buffer.
  216. Length - Supplies the length of the bug check buffer in bytes.
  217. Return Value:
  218. None.
  219. --*/
  220. {
  221. //
  222. // Make sure the HAL won't spin waiting on other processors
  223. // during a crashdump.
  224. //
  225. HalpDoingCrashDump = TRUE;
  226. }
  227. VOID
  228. HalpGetParameters (
  229. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  230. )
  231. /*++
  232. Routine Description:
  233. This gets any parameters from the boot.ini invocation line.
  234. Arguments:
  235. None.
  236. Return Value:
  237. None
  238. --*/
  239. {
  240. PCHAR Options;
  241. PCHAR p;
  242. if (LoaderBlock != NULL && LoaderBlock->LoadOptions != NULL) {
  243. Options = LoaderBlock->LoadOptions;
  244. //
  245. // Has the user set the debug flag?
  246. //
  247. //
  248. // Has the user requested a particular number of CPU's?
  249. //
  250. if (strstr(Options, HalpSzOneCpu)) {
  251. HalpDontStartProcessors++;
  252. }
  253. //
  254. // Check if PCI settings are locked down
  255. //
  256. if (strstr(Options, HalpSzPciLock)) {
  257. HalpPciLockSettings = TRUE;
  258. }
  259. #ifndef ACPI_HAL
  260. //
  261. // Check if CLKLVL setting
  262. //
  263. if (strstr(Options, HalpSzClockLevel)) {
  264. HalpClockMode = LevelSensitive;
  265. }
  266. //
  267. // Check if 8254 is to be used as high resolution counter
  268. //
  269. if (strstr(Options, HalpSzUse8254)) {
  270. HalpUse8254 = TRUE;
  271. }
  272. #endif
  273. //
  274. // Check if user wants device ints to go to highest numbered processor
  275. //
  276. if (strstr(Options, HalpSzInterruptAffinity)) {
  277. HalpStaticIntAffinity = TRUE;
  278. }
  279. #ifndef ACPI_HAL
  280. //
  281. // Check for TIMERES setting
  282. //
  283. p = strstr(Options, HalpSzTimerRes);
  284. if (p) {
  285. // skip to value
  286. while (*p && *p != ' ' && (*p < '0' || *p > '9')) {
  287. p++;
  288. }
  289. HalpInitializeTimerResolution (atoi(p));
  290. }
  291. #endif
  292. //
  293. // Has the user asked for an initial BreakPoint?
  294. //
  295. if (strstr(Options, HalpSzBreak)) {
  296. DbgBreakPoint();
  297. }
  298. //
  299. // Does the user want to force Cluster mode APIC addressing?
  300. //
  301. p = strstr(Options, HalpSzForceClusterMode);
  302. if (p) {
  303. // skip to value
  304. while (*p && *p != ' ' && (*p < '0' || *p > '9')) {
  305. p++;
  306. }
  307. HalpMaxProcsPerCluster = (UCHAR)atoi(p);
  308. //
  309. // Current processors support maximum 4 processors per cluster.
  310. //
  311. if(HalpMaxProcsPerCluster > 4) {
  312. HalpMaxProcsPerCluster = 4;
  313. }
  314. if (HalpMpInfoTable.ApicVersion == APIC_82489DX) {
  315. //
  316. // Ignore user's attempt to force cluster mode if running
  317. // on 82489DX external APIC interrupt controller.
  318. //
  319. HalpMaxProcsPerCluster = 0;
  320. }
  321. //
  322. // Hack to reprogram the boot processor to use Cluster mode APIC
  323. // addressing if the user supplied a boot.ini switch
  324. // (/MAXPROCSPERCLUSTER=n) to force this. The boot.ini switch is
  325. // parsed after the boot processor's APIC is programmed originally
  326. // but before other non-boot processors were woken up.
  327. //
  328. HalpInitializeApicAddressing(0);
  329. }
  330. }
  331. return ;
  332. }
  333. VOID
  334. HalpInitTimerWatchdog(
  335. IN ULONG Phase
  336. )
  337. /*++
  338. Routine Description:
  339. Determines if the system is running on a GenuineIntel part and initializes
  340. HalpTimerWatchdogEnabled accordingly.
  341. Arguments:
  342. None.
  343. Return Value:
  344. None.
  345. --*/
  346. {
  347. if (Phase == 0) {
  348. ULONG GenuinePentiumOrLater = FALSE, Junk;
  349. PKPRCB Prcb;
  350. Prcb = KeGetCurrentPrcb();
  351. if (Prcb->CpuID) {
  352. UCHAR Buffer[50];
  353. //
  354. // Determine the processor type
  355. //
  356. HalpCpuID (0, &Junk, (PULONG) Buffer+0, (PULONG) Buffer+2, (PULONG) Buffer+1);
  357. Buffer[12] = 0;
  358. GenuinePentiumOrLater =
  359. ((strcmp(Buffer, HalpGenuineIntel) == 0) && (Prcb->CpuType >= 5));
  360. HalpTimerWatchdogEnabled = *KiEnableTimerWatchdog && GenuinePentiumOrLater;
  361. }
  362. } else if (HalpTimerWatchdogEnabled) {
  363. //
  364. // Allocate 2 pages for stack snapshots, each snapshot is 64 DWORDs.
  365. //
  366. if (HalpTimerWatchdogStorage =
  367. ExAllocatePoolWithTag( NonPagedPool, PAGE_SIZE * 2, HAL_POOL_TAG )) {
  368. HalpTimerWatchdogLastFrame =
  369. HalpTimerWatchdogStorage + (PAGE_SIZE * 2 - 64*4);
  370. HalpTimerWatchdogStorageOverflow = 0;
  371. HalpTimerWatchdogCurFrame = HalpTimerWatchdogStorage;
  372. } else {
  373. HalpTimerWatchdogEnabled = FALSE;
  374. }
  375. }
  376. }
  377. BOOLEAN
  378. HalInitSystem (
  379. IN ULONG Phase,
  380. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  381. )
  382. /*++
  383. Routine Description:
  384. This function initializes the Hardware Architecture Layer (HAL) for an
  385. x86 system.
  386. Arguments:
  387. None.
  388. Return Value:
  389. A value of TRUE is returned is the initialization was successfully
  390. complete. Otherwise a value of FALSE is returend.
  391. --*/
  392. {
  393. PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
  394. PLIST_ENTRY NextMd;
  395. PKPRCB pPRCB;
  396. PKPCR pPCR;
  397. BOOLEAN Found;
  398. USHORT RTCInti;
  399. USHORT mmTInti;
  400. ULONG mapBufferSize;
  401. ULONG mapBufferAddress;
  402. #ifdef DEBUGGING
  403. extern ULONG HalpUseDbgPrint;
  404. #endif // DEBUGGING
  405. pPRCB = KeGetCurrentPrcb();
  406. if (Phase == 0) {
  407. HalpBusType = LoaderBlock->u.I386.MachineType & 0x00ff;
  408. HalpGetParameters (LoaderBlock);
  409. //
  410. // Verify Prcb version and build flags conform to
  411. // this image
  412. //
  413. #if DBG
  414. if (!(pPRCB->BuildType & PRCB_BUILD_DEBUG)) {
  415. // This checked hal requires a checked kernel
  416. KeBugCheckEx (MISMATCHED_HAL,
  417. 2, pPRCB->BuildType, PRCB_BUILD_DEBUG, 0);
  418. }
  419. #else
  420. if (pPRCB->BuildType & PRCB_BUILD_DEBUG) {
  421. // This free hal requires a free kernel
  422. KeBugCheckEx (MISMATCHED_HAL, 2, pPRCB->BuildType, 0, 0);
  423. }
  424. #endif
  425. #ifndef NT_UP
  426. if (pPRCB->BuildType & PRCB_BUILD_UNIPROCESSOR) {
  427. // This MP hal requires an MP kernel
  428. KeBugCheckEx (MISMATCHED_HAL, 2, pPRCB->BuildType, 0, 0);
  429. }
  430. #endif
  431. if (pPRCB->MajorVersion != PRCB_MAJOR_VERSION) {
  432. KeBugCheckEx (MISMATCHED_HAL,
  433. 1, pPRCB->MajorVersion, PRCB_MAJOR_VERSION, 0);
  434. }
  435. KeInitializeSpinLock(&HalpAccountingLock);
  436. #ifdef ACPI_HAL
  437. //
  438. // Make sure that this is really an ACPI machine and initialize
  439. // the ACPI structures.
  440. //
  441. HalpSetupAcpiPhase0(LoaderBlock);
  442. #endif
  443. //
  444. // Fill in handlers for APIs which this hal supports
  445. //
  446. #ifndef NT_35
  447. HalQuerySystemInformation = HaliQuerySystemInformation;
  448. HalSetSystemInformation = HalpSetSystemInformation;
  449. #endif
  450. //
  451. // check to see whether the kernel supports these calls
  452. //
  453. if (HALDISPATCH->Version >= HAL_DISPATCH_VERSION) {
  454. HalInitPnpDriver = HaliInitPnpDriver;
  455. HalGetDmaAdapter = HaliGetDmaAdapter;
  456. HalLocateHiberRanges = HaliLocateHiberRanges;
  457. HalResetDisplay = HalpBiosDisplayReset;
  458. #ifdef ACPI_HAL
  459. HalInitPowerManagement = HaliInitPowerManagement;
  460. HalGetInterruptTranslator = HalacpiGetInterruptTranslator;
  461. HalHaltSystem = HaliHaltSystem;
  462. #else
  463. HalGetInterruptTranslator = HaliGetInterruptTranslator;
  464. #endif
  465. }
  466. //
  467. // Phase 0 initialization only called by P0
  468. //
  469. #ifdef DEBUGGING
  470. HalpUseDbgPrint++;
  471. HalpDisplayLocalUnit();
  472. #ifndef ACPI_HAL
  473. HalpDisplayConfigTable();
  474. HalpDisplayExtConfigTable();
  475. #endif
  476. #endif // DEBUGGING
  477. //
  478. // Keep track of which IRQs are level triggered.
  479. //
  480. #if !defined(MCA) && !defined(ACPI_HAL)
  481. if (HalpBusType == MACHINE_TYPE_EISA) {
  482. HalpRecordEisaInterruptVectors();
  483. }
  484. #endif
  485. //
  486. // Register PC style IO space used by hal
  487. //
  488. HalpRegisterAddressUsage (&HalpDefaultPcIoSpace);
  489. if (HalpBusType == MACHINE_TYPE_EISA) {
  490. HalpRegisterAddressUsage (&HalpEisaIoSpace);
  491. }
  492. if (HalpMpInfoTable.IMCRPresent) {
  493. HalpRegisterAddressUsage (&HalpImcrIoSpace);
  494. }
  495. //
  496. // initialize the APIC IO unit, this could be a NOP if none exist
  497. //
  498. HalpInitIntiInfo ();
  499. HalpInitializeIOUnits();
  500. HalpInitializePICs(TRUE);
  501. //
  502. // Initialize CMOS
  503. //
  504. HalpInitializeCmos();
  505. //
  506. // Find the RTC interrupt.
  507. //
  508. Found = HalpGetApicInterruptDesc (
  509. DEFAULT_PC_BUS,
  510. 0,
  511. ADJUSTED_VECTOR(RTC_IRQ),
  512. &RTCInti
  513. );
  514. if (!Found) {
  515. HalDisplayString (rgzRTCNotFound);
  516. return FALSE;
  517. }
  518. //
  519. // Initialize timers
  520. //
  521. //
  522. // We can cut down the boot time using the PM timer to scale,
  523. // but there are so many broken ACPI timers this might not work
  524. //
  525. #ifdef SPEEDY_BOOT
  526. if (!HalpPmTimerScaleTimers())
  527. #endif
  528. HalpScaleTimers();
  529. HalpProc0TSCHz = ((PHALPCR)(KeGetPcr()->HalReserved))->TSCHz;
  530. //
  531. // Initialize the reboot handler
  532. //
  533. HalpSetInternalVector(APIC_REBOOT_VECTOR, HalpApicRebootService);
  534. HalpSetInternalVector(APIC_GENERIC_VECTOR, HalpBroadcastCallService);
  535. //
  536. // Initialize the clock for the processor that keeps
  537. // the system time. This uses a stub ISR until Phase 1
  538. //
  539. KiSetHandlerAddressToIDT(APIC_CLOCK_VECTOR, HalpClockInterruptStub );
  540. HalpVectorToINTI[APIC_CLOCK_VECTOR] = RTCInti;
  541. HalEnableSystemInterrupt(APIC_CLOCK_VECTOR, CLOCK2_LEVEL, HalpClockMode);
  542. //
  543. // Init timer watchdog if enabled.
  544. //
  545. HalpInitTimerWatchdog( Phase );
  546. #ifdef MMTIMER_DEV
  547. //
  548. // Set up the multi media event timer to interrupt on P0 at
  549. // CLOCK2_LEVEL
  550. //
  551. #define MMT_VECTOR 0xD3
  552. #define MMT_IRQ 10
  553. HalpGetApicInterruptDesc(
  554. DEFAULT_PC_BUS,
  555. 0,
  556. ADJUSTED_VECTOR(MMT_IRQ),
  557. &mmTInti
  558. );
  559. KiSetHandlerAddressToIDT(MMT_VECTOR, HalpmmTimerClockInterruptStub);
  560. HalpVectorToINTI[MMT_VECTOR] = mmTInti;
  561. HalEnableSystemInterrupt(MMT_VECTOR, CLOCK2_LEVEL, HalpClockMode);
  562. HalpRegisterVector(
  563. DeviceUsage | InterruptLatched,
  564. ADJUSTED_VECTOR(MMT_IRQ),
  565. MMT_VECTOR,
  566. HalpVectorToIRQL[MMT_VECTOR >> 4]
  567. );
  568. #endif // MMTIMER_DEV
  569. HalpInitializeClock();
  570. #ifndef ACPI_HAL
  571. HalpRegisterVector (
  572. DeviceUsage | InterruptLatched,
  573. ADJUSTED_VECTOR(RTC_IRQ),
  574. APIC_CLOCK_VECTOR,
  575. HalpVectorToIRQL [APIC_CLOCK_VECTOR >> 4]
  576. );
  577. #endif
  578. //
  579. // Register NMI vector
  580. //
  581. HalpRegisterVector (
  582. InternalUsage,
  583. NMI_VECTOR,
  584. NMI_VECTOR,
  585. HIGH_LEVEL
  586. );
  587. //
  588. // Register spurious IDTs as in use
  589. //
  590. HalpRegisterVector (
  591. InternalUsage,
  592. APIC_SPURIOUS_VECTOR,
  593. APIC_SPURIOUS_VECTOR,
  594. HIGH_LEVEL
  595. );
  596. //
  597. // Initialize the profile interrupt vector.
  598. //
  599. KeSetProfileIrql(HIGH_LEVEL);
  600. HalStopProfileInterrupt(0);
  601. HalpSetInternalVector(APIC_PROFILE_VECTOR, HalpProfileInterrupt);
  602. //
  603. // Set performance interrupt vector
  604. //
  605. HalpSetInternalVector(APIC_PERF_VECTOR, HalpPerfInterrupt);
  606. //
  607. // Initialize the IPI, APC and DPC handlers
  608. //
  609. HalpSetInternalVector(DPC_VECTOR, HalpDispatchInterrupt);
  610. HalpSetInternalVector(APC_VECTOR, HalpApcInterrupt);
  611. HalpSetInternalVector(APIC_IPI_VECTOR, HalpIpiHandler);
  612. //
  613. // HALMPS doesn't actually do address translation on a
  614. // bus. Register the quick version of FindBusAddressTranslation.
  615. //
  616. HALPDISPATCH->HalFindBusAddressTranslation =
  617. HalpFindBusAddressTranslation;
  618. //
  619. // Initialize spinlock used by HalGetBusData hardware access routines
  620. //
  621. KeInitializeSpinLock(&HalpSystemHardwareLock);
  622. //
  623. // Initialize data structures used to chain dma adapters
  624. // together for debugging purposes
  625. //
  626. KeInitializeSpinLock(&HalpDmaAdapterListLock);
  627. InitializeListHead(&HalpDmaAdapterList);
  628. #ifdef ACPI_HAL
  629. //
  630. // Initialize synchronzation event used to serialize
  631. // new adapter events on the ACPI HAL (which has no notion of bus
  632. // handlers)
  633. //
  634. KeInitializeEvent (&HalpNewAdapter, SynchronizationEvent, TRUE);
  635. #endif
  636. //
  637. // Determine if there is physical memory above 16 MB.
  638. //
  639. LessThan16Mb = TRUE;
  640. NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
  641. while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {
  642. Descriptor = CONTAINING_RECORD( NextMd,
  643. MEMORY_ALLOCATION_DESCRIPTOR,
  644. ListEntry );
  645. if (Descriptor->MemoryType != LoaderFirmwarePermanent &&
  646. Descriptor->MemoryType != LoaderSpecialMemory &&
  647. Descriptor->BasePage + Descriptor->PageCount > 0x1000) {
  648. LessThan16Mb = FALSE;
  649. break;
  650. }
  651. NextMd = Descriptor->ListEntry.Flink;
  652. }
  653. #if !defined(_HALPAE_)
  654. HalpMapBufferSize = INITIAL_MAP_BUFFER_SMALL_SIZE;
  655. //
  656. // Allocate map buffers for the adapter objects
  657. //
  658. HalpMapBufferPhysicalAddress.LowPart =
  659. HalpAllocPhysicalMemory (LoaderBlock, MAXIMUM_PHYSICAL_ADDRESS,
  660. HalpMapBufferSize >> PAGE_SHIFT, TRUE);
  661. HalpMapBufferPhysicalAddress.HighPart = 0;
  662. if (!HalpMapBufferPhysicalAddress.LowPart) {
  663. //
  664. // There was not a satisfactory block. Clear the allocation.
  665. //
  666. HalpMapBufferSize = 0;
  667. }
  668. #else
  669. //
  670. // Initialize and allocate map buffers for the 24bit master adapter
  671. // object.
  672. //
  673. MasterAdapter24.MaxBufferPages =
  674. MAXIMUM_ISA_MAP_BUFFER_SIZE / PAGE_SIZE;
  675. mapBufferSize = INITIAL_MAP_BUFFER_SMALL_SIZE;
  676. mapBufferAddress =
  677. HalpAllocPhysicalMemory (LoaderBlock,
  678. MAXIMUM_PHYSICAL_ADDRESS,
  679. mapBufferSize >> PAGE_SHIFT,
  680. TRUE);
  681. if (mapBufferAddress == 0) {
  682. mapBufferSize = 0;
  683. }
  684. MasterAdapter24.MapBufferPhysicalAddress.LowPart = mapBufferAddress;
  685. MasterAdapter24.MapBufferPhysicalAddress.HighPart = 0;
  686. MasterAdapter24.MapBufferSize = mapBufferSize;
  687. if (HalPaeEnabled() != FALSE) {
  688. //
  689. // Initialize and allocate map buffers for the 32bit master adapter
  690. // object. This should only be needed on a PAE-enabled system.
  691. //
  692. MasterAdapter32.MaxBufferPages =
  693. MAXIMUM_PCI_MAP_BUFFER_SIZE / PAGE_SIZE;
  694. mapBufferSize = INITIAL_MAP_BUFFER_LARGE_SIZE;
  695. mapBufferAddress =
  696. HalpAllocPhysicalMemory (LoaderBlock,
  697. (ULONG)-1,
  698. mapBufferSize >> PAGE_SHIFT,
  699. TRUE);
  700. if (mapBufferAddress == 0) {
  701. mapBufferSize = 0;
  702. }
  703. MasterAdapter32.MapBufferPhysicalAddress.LowPart = mapBufferAddress;
  704. MasterAdapter32.MapBufferPhysicalAddress.HighPart = 0;
  705. MasterAdapter32.MapBufferSize = mapBufferSize;
  706. }
  707. #endif
  708. //
  709. // Initialize and register a bug check callback record.
  710. //
  711. KeInitializeCallbackRecord(&HalpCallbackRecord);
  712. KeRegisterBugCheckCallback(&HalpCallbackRecord,
  713. HalpBugCheckCallback,
  714. NULL,
  715. 0,
  716. (PUCHAR)HalName);
  717. } else {
  718. //
  719. // Phase 1 initialization
  720. //
  721. pPCR = KeGetPcr();
  722. if (pPCR->Number == 0) {
  723. //
  724. // Back-pocket some PTEs for DMA during low mem
  725. //
  726. HalpInitReservedPages();
  727. #ifdef ACPI_HAL
  728. HalpInitNonBusHandler ();
  729. #else
  730. HalpRegisterInternalBusHandlers ();
  731. #endif
  732. #ifdef MMTIMER_DEV
  733. //
  734. // Fire up the multi media event timer clock interrupt
  735. //
  736. if (HalpmmTimer()) {
  737. HalpmmTimerClockInit();
  738. }
  739. #endif
  740. //
  741. // Init timer watchdog if enabled (allocate snapshot buffer).
  742. //
  743. HalpInitTimerWatchdog( Phase );
  744. //
  745. // Initialize the clock for the processor
  746. // that keeps the system time.
  747. //
  748. KiSetHandlerAddressToIDT(APIC_CLOCK_VECTOR, HalpClockInterrupt );
  749. //
  750. // Set initial feature bits
  751. //
  752. HalpFeatureBits = HalpGetFeatureBits();
  753. #if DBG_SPECIAL_IRQL
  754. //
  755. // Do Special IRQL initialization.
  756. //
  757. HalpInitializeSpecialIrqlSupport();
  758. #endif
  759. //
  760. // Point to new movnti routine if Movnti is detected
  761. //
  762. if(HalpFeatureBits & HAL_WNI_PRESENT) {
  763. HalpMoveMemory = HalpMovntiCopyBuffer;
  764. }
  765. #ifdef ACPI_HAL
  766. #ifdef NT_UP
  767. //
  768. // Perf counter patch for non-compliant ACPI machines
  769. //
  770. HalpAcpiTimerPerfCountHack();
  771. #endif
  772. #endif
  773. } else {
  774. //
  775. // Initialization needed only on non BSP processors
  776. //
  777. #ifdef SPEEDY_BOOT
  778. if (!HalpPmTimerScaleTimers())
  779. #endif
  780. HalpScaleTimers();
  781. //
  782. // Hack. Make all processors have the same value for
  783. // the timestamp counter frequency.
  784. //
  785. ((PHALPCR)(KeGetPcr()->HalReserved))->TSCHz = HalpProc0TSCHz;
  786. //
  787. // Initialize the clock for all other processors
  788. //
  789. KiSetHandlerAddressToIDT(APIC_CLOCK_VECTOR, HalpClockInterruptPn );
  790. //
  791. // Reduce feature bits to be a subset
  792. //
  793. HalpFeatureBits &= HalpGetFeatureBits();
  794. }
  795. }
  796. HalpInitMP (Phase, LoaderBlock);
  797. if (Phase == 1) {
  798. //
  799. // Enable system NMIs on Pn
  800. //
  801. HalpEnableNMI ();
  802. }
  803. return TRUE;
  804. }
  805. ULONG
  806. HalpGetFeatureBits (
  807. VOID
  808. )
  809. {
  810. UCHAR Buffer[50];
  811. ULONG Junk, ProcessorStepping, ProcessorFeatures, Bits;
  812. PULONG p1, p2;
  813. PUCHAR OrgRoutineAddress;
  814. PUCHAR MCERoutineAddress;
  815. ULONG newop;
  816. PKPRCB Prcb;
  817. Bits = 0;
  818. Prcb = KeGetCurrentPrcb();
  819. if (!Prcb->CpuID) {
  820. Bits |= HAL_NO_SPECULATION;
  821. return Bits;
  822. }
  823. //
  824. // Determine the processor type
  825. //
  826. HalpCpuID (0, &Junk, (PULONG) Buffer+0, (PULONG) Buffer+2, (PULONG) Buffer+1);
  827. Buffer[12] = 0;
  828. //
  829. // Determine which features are present
  830. //
  831. HalpCpuID (1, &ProcessorStepping, &Junk, &Junk, &ProcessorFeatures);
  832. if (ProcessorFeatures & CPUID_MCA_MASK) {
  833. Bits |= HAL_MCA_PRESENT;
  834. }
  835. if (ProcessorFeatures & CPUID_MCE_MASK) {
  836. Bits |= HAL_MCE_PRESENT;
  837. }
  838. if (ProcessorFeatures & CPUID_VME_MASK) {
  839. Bits |= HAL_CR4_PRESENT;
  840. }
  841. if(ProcessorFeatures & CPUID_WNI_MASK) {
  842. Bits |= HAL_WNI_PRESENT;
  843. }
  844. //
  845. // Check Intel feature bits for HAL features needed
  846. //
  847. if (strcmp (Buffer, HalpGenuineIntel) == 0) {
  848. if ((Prcb->CpuType == 6) || (Prcb->CpuType == 0xf)) {
  849. Bits |= HAL_PERF_EVENTS;
  850. }
  851. if (Prcb->CpuType < 6) {
  852. Bits |= HAL_NO_SPECULATION;
  853. }
  854. #ifndef NT_UP
  855. //
  856. // Check if IFU errata workaround is required
  857. //
  858. if (Prcb->Number == 0 && (Bits & HAL_MCA_PRESENT) &&
  859. ((ProcessorStepping & 0x700) == 0x600) &&
  860. ((ProcessorStepping & 0xF0) == 0x10) &&
  861. ((ProcessorStepping & 0xF) <= 0x7) ) {
  862. //
  863. // If the stepping is 617 or earlier, provide software workaround
  864. //
  865. p1 = (PULONG) (KeAcquireSpinLockRaiseToSynch);
  866. p2 = (PULONG) (KeAcquireSpinLockRaiseToSynchMCE);
  867. newop = (ULONG) p2 - (ULONG) p1 - 2; // compute offset
  868. ASSERT (newop < 0x7f); // verify within range
  869. newop = 0xeb | (newop << 8); // short-jmp
  870. *(p1) = newop; // patch it
  871. }
  872. #endif
  873. }
  874. return Bits;
  875. }