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.

697 lines
16 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. xxhal.c
  5. Abstract:
  6. This module implements the initialization of the system dependent
  7. functions that define the Hardware Architecture Layer (HAL) for an
  8. x86 system.
  9. Author:
  10. David N. Cutler (davec) 25-Apr-1991
  11. Environment:
  12. Kernel mode only.
  13. Revision History:
  14. --*/
  15. #include "halp.h"
  16. ULONG HalpBusType;
  17. extern ADDRESS_USAGE HalpDefaultPcIoSpace;
  18. extern ADDRESS_USAGE HalpEisaIoSpace;
  19. extern UCHAR HalpSzPciLock[];
  20. extern UCHAR HalpSzBreak[];
  21. extern BOOLEAN HalpPciLockSettings;
  22. extern UCHAR HalpGenuineIntel[];
  23. extern PULONG KiEnableTimerWatchdog;
  24. extern ULONG HalpTimerWatchdogEnabled;
  25. extern PCHAR HalpTimerWatchdogStorage;
  26. extern PVOID HalpTimerWatchdogCurFrame;
  27. extern PVOID HalpTimerWatchdogLastFrame;
  28. extern ULONG HalpTimerWatchdogStorageOverflow;
  29. extern KSPIN_LOCK HalpDmaAdapterListLock;
  30. extern LIST_ENTRY HalpDmaAdapterList;
  31. #ifdef ACPI_HAL
  32. extern KEVENT HalpNewAdapter;
  33. #endif
  34. VOID
  35. HalpGetParameters (
  36. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  37. );
  38. ULONG
  39. HalpGetFeatureBits (
  40. VOID
  41. );
  42. VOID
  43. HalpInitReservedPages(
  44. VOID
  45. );
  46. VOID
  47. HalpAcpiTimerPerfCountHack(
  48. VOID
  49. );
  50. #ifndef NT_UP
  51. ULONG
  52. HalpInitMP(
  53. IN ULONG Phase,
  54. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  55. );
  56. #endif
  57. KSPIN_LOCK HalpSystemHardwareLock;
  58. #ifdef ALLOC_PRAGMA
  59. #pragma alloc_text(INIT,HalpGetParameters)
  60. #pragma alloc_text(INIT,HalInitSystem)
  61. #pragma alloc_text(INIT,HalpGetFeatureBits)
  62. #endif
  63. VOID
  64. HalpGetParameters (
  65. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  66. )
  67. /*++
  68. Routine Description:
  69. This gets any parameters from the boot.ini invocation line.
  70. Arguments:
  71. None.
  72. Return Value:
  73. None
  74. --*/
  75. {
  76. PCHAR Options;
  77. if (LoaderBlock != NULL && LoaderBlock->LoadOptions != NULL) {
  78. Options = LoaderBlock->LoadOptions;
  79. //
  80. // Check if PCI settings are locked down
  81. //
  82. if (strstr(Options, HalpSzPciLock)) {
  83. HalpPciLockSettings = TRUE;
  84. }
  85. //
  86. // Has the user asked for an initial BreakPoint?
  87. //
  88. if (strstr(Options, HalpSzBreak)) {
  89. DbgBreakPoint();
  90. }
  91. }
  92. return;
  93. }
  94. VOID
  95. HalpInitTimerWatchdog(
  96. IN ULONG Phase
  97. )
  98. /*++
  99. Routine Description:
  100. Determines if the system is running on a GenuineIntel part and initializes
  101. HalpTimerWatchdogEnabled accordingly.
  102. Arguments:
  103. None.
  104. Return Value:
  105. None.
  106. --*/
  107. {
  108. if (Phase == 0) {
  109. ULONG GenuinePentiumOrLater = FALSE, Junk;
  110. PKPRCB Prcb;
  111. Prcb = KeGetCurrentPrcb();
  112. if (Prcb->CpuID) {
  113. UCHAR Buffer[50];
  114. //
  115. // Determine the processor type
  116. //
  117. HalpCpuID (0, &Junk, (PULONG) Buffer+0, (PULONG) Buffer+2, (PULONG) Buffer+1);
  118. Buffer[12] = 0;
  119. GenuinePentiumOrLater =
  120. ((strcmp(Buffer, HalpGenuineIntel) == 0) && (Prcb->CpuType >= 5));
  121. HalpTimerWatchdogEnabled = GenuinePentiumOrLater;
  122. }
  123. } else if (HalpTimerWatchdogEnabled) {
  124. //
  125. // Allocate 2 pages for stack snapshots, each snapshot is 64 DWORDs.
  126. //
  127. if (HalpTimerWatchdogStorage =
  128. ExAllocatePoolWithTag( NonPagedPool, PAGE_SIZE * 2, HAL_POOL_TAG )) {
  129. HalpTimerWatchdogLastFrame =
  130. HalpTimerWatchdogStorage + (PAGE_SIZE * 2 - 64*4);
  131. HalpTimerWatchdogStorageOverflow = 0;
  132. HalpTimerWatchdogCurFrame = HalpTimerWatchdogStorage;
  133. } else {
  134. HalpTimerWatchdogEnabled = FALSE;
  135. }
  136. }
  137. }
  138. BOOLEAN
  139. HalInitSystem (
  140. IN ULONG Phase,
  141. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  142. )
  143. /*++
  144. Routine Description:
  145. This function initializes the Hardware Architecture Layer (HAL) for an
  146. x86 system.
  147. Arguments:
  148. None.
  149. Return Value:
  150. A value of TRUE is returned is the initialization was successfully
  151. complete. Otherwise a value of FALSE is returend.
  152. --*/
  153. {
  154. PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
  155. PLIST_ENTRY NextMd;
  156. KIRQL CurrentIrql;
  157. PKPRCB pPRCB;
  158. ULONG mapBufferSize;
  159. ULONG mapBufferAddress;
  160. pPRCB = KeGetCurrentPrcb();
  161. if (Phase == 0) {
  162. HalpBusType = LoaderBlock->u.I386.MachineType & 0x00ff;
  163. HalpGetParameters (LoaderBlock);
  164. //
  165. // Verify Prcb version and build flags conform to
  166. // this image
  167. //
  168. #if DBG
  169. if (!(pPRCB->BuildType & PRCB_BUILD_DEBUG)) {
  170. // This checked hal requires a checked kernel
  171. KeBugCheckEx (MISMATCHED_HAL,
  172. 2, pPRCB->BuildType, PRCB_BUILD_DEBUG, 0);
  173. }
  174. #else
  175. if (pPRCB->BuildType & PRCB_BUILD_DEBUG) {
  176. // This free hal requires a free kernel
  177. KeBugCheckEx (MISMATCHED_HAL, 2, pPRCB->BuildType, 0, 0);
  178. }
  179. #endif
  180. #ifndef NT_UP
  181. if (pPRCB->BuildType & PRCB_BUILD_UNIPROCESSOR) {
  182. // This MP hal requires an MP kernel
  183. KeBugCheckEx (MISMATCHED_HAL, 2, pPRCB->BuildType, 0, 0);
  184. }
  185. #endif
  186. if (pPRCB->MajorVersion != PRCB_MAJOR_VERSION) {
  187. KeBugCheckEx (MISMATCHED_HAL,
  188. 1, pPRCB->MajorVersion, PRCB_MAJOR_VERSION, 0);
  189. }
  190. //
  191. // Phase 0 initialization
  192. // only called by P0
  193. //
  194. //
  195. // Check to make sure the MCA HAL is not running on an ISA/EISA
  196. // system, and vice-versa.
  197. //
  198. #if MCA
  199. if (HalpBusType != MACHINE_TYPE_MCA) {
  200. KeBugCheckEx (MISMATCHED_HAL,
  201. 3, HalpBusType, MACHINE_TYPE_MCA, 0);
  202. }
  203. #else
  204. if (HalpBusType == MACHINE_TYPE_MCA) {
  205. KeBugCheckEx (MISMATCHED_HAL,
  206. 3, HalpBusType, 0, 0);
  207. }
  208. #endif
  209. #ifdef ACPI_HAL
  210. //
  211. // Make sure that this is really an ACPI machine and initialize
  212. // the ACPI structures.
  213. //
  214. HalpSetupAcpiPhase0(LoaderBlock);
  215. #endif
  216. HalpInitializePICs(TRUE);
  217. //
  218. // Now that the PICs are initialized, we need to mask them to
  219. // reflect the current Irql
  220. //
  221. CurrentIrql = KeGetCurrentIrql();
  222. CurrentIrql = KfRaiseIrql(CurrentIrql);
  223. //
  224. // Initialize CMOS
  225. //
  226. HalpInitializeCmos();
  227. //
  228. // Fill in handlers for APIs which this hal supports
  229. //
  230. HalQuerySystemInformation = HaliQuerySystemInformation;
  231. HalSetSystemInformation = HaliSetSystemInformation;
  232. HalInitPnpDriver = HaliInitPnpDriver;
  233. HalGetDmaAdapter = HaliGetDmaAdapter;
  234. HalHaltSystem = HaliHaltSystem;
  235. HalResetDisplay = HalpBiosDisplayReset;
  236. #if !defined( HAL_SP )
  237. #ifdef ACPI_HAL
  238. HalGetInterruptTranslator = HalacpiGetInterruptTranslator;
  239. #else
  240. HalGetInterruptTranslator = HaliGetInterruptTranslator;
  241. #endif
  242. #endif
  243. #if !defined( HAL_SP ) && !(MCA)
  244. HalInitPowerManagement = HaliInitPowerManagement;
  245. HalLocateHiberRanges = HaliLocateHiberRanges;
  246. #endif
  247. //
  248. // Register cascade vector
  249. //
  250. HalpRegisterVector (
  251. InternalUsage,
  252. PIC_SLAVE_IRQ + PRIMARY_VECTOR_BASE,
  253. PIC_SLAVE_IRQ + PRIMARY_VECTOR_BASE,
  254. HIGH_LEVEL );
  255. //
  256. // Keep track of which IRQs are level triggered.
  257. //
  258. if (HalpBusType == MACHINE_TYPE_EISA) {
  259. HalpRecordEisaInterruptVectors();
  260. }
  261. //
  262. // Register base IO space used by hal
  263. //
  264. HalpRegisterAddressUsage (&HalpDefaultPcIoSpace);
  265. if (HalpBusType == MACHINE_TYPE_EISA) {
  266. HalpRegisterAddressUsage (&HalpEisaIoSpace);
  267. }
  268. //
  269. // Note that HalpInitializeClock MUST be called after
  270. // HalpInitializeStallExecution, because HalpInitializeStallExecution
  271. // reprograms the timer.
  272. //
  273. HalpInitializeStallExecution(0);
  274. //
  275. // Init timer watchdog if enabled.
  276. //
  277. HalpInitTimerWatchdog(Phase);
  278. //
  279. // Setup the clock
  280. //
  281. HalpInitializeClock();
  282. //
  283. // Make sure profile is disabled
  284. //
  285. HalStopProfileInterrupt(0);
  286. //
  287. // Remove this for the sake of the graphical boot driver. There is
  288. // no negative effect of this. If the display isn't initialized, it
  289. // will be initialized during HalDisplayString.
  290. //
  291. // HalpInitializeDisplay();
  292. //
  293. // Initialize spinlock used by HalGetBusData hardware access routines
  294. //
  295. KeInitializeSpinLock(&HalpSystemHardwareLock);
  296. //
  297. // Initialize data structures used to chain dma adapters
  298. // together for debugging purposes
  299. //
  300. KeInitializeSpinLock(&HalpDmaAdapterListLock);
  301. InitializeListHead(&HalpDmaAdapterList);
  302. #ifdef ACPI_HAL
  303. //
  304. // Initialize synchronzation event used to serialize
  305. // new adapter events on the ACPI HAL (which has no notion of bus
  306. // handlers)
  307. //
  308. KeInitializeEvent (&HalpNewAdapter, SynchronizationEvent, TRUE);
  309. #endif
  310. //
  311. // Determine if there is physical memory above 16 MB.
  312. //
  313. LessThan16Mb = TRUE;
  314. NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
  315. while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {
  316. Descriptor = CONTAINING_RECORD( NextMd,
  317. MEMORY_ALLOCATION_DESCRIPTOR,
  318. ListEntry );
  319. if (Descriptor->MemoryType != LoaderFirmwarePermanent &&
  320. Descriptor->MemoryType != LoaderSpecialMemory &&
  321. Descriptor->BasePage + Descriptor->PageCount > 0x1000) {
  322. LessThan16Mb = FALSE;
  323. break;
  324. }
  325. NextMd = Descriptor->ListEntry.Flink;
  326. }
  327. #if !defined(_HALPAE_)
  328. HalpMapBufferSize = INITIAL_MAP_BUFFER_SMALL_SIZE;
  329. //
  330. // Allocate map buffers for the adapter objects
  331. //
  332. HalpMapBufferPhysicalAddress.LowPart =
  333. HalpAllocPhysicalMemory (LoaderBlock, MAXIMUM_PHYSICAL_ADDRESS,
  334. HalpMapBufferSize >> PAGE_SHIFT, TRUE);
  335. HalpMapBufferPhysicalAddress.HighPart = 0;
  336. if (!HalpMapBufferPhysicalAddress.LowPart) {
  337. //
  338. // There was not a satisfactory block. Clear the allocation.
  339. //
  340. HalpMapBufferSize = 0;
  341. }
  342. #else
  343. //
  344. // Initialize and allocate map buffers for the 24bit master adapter
  345. // object.
  346. //
  347. MasterAdapter24.MaxBufferPages =
  348. MAXIMUM_ISA_MAP_BUFFER_SIZE / PAGE_SIZE;
  349. mapBufferSize = INITIAL_MAP_BUFFER_SMALL_SIZE;
  350. mapBufferAddress =
  351. HalpAllocPhysicalMemory (LoaderBlock,
  352. MAXIMUM_PHYSICAL_ADDRESS,
  353. mapBufferSize >> PAGE_SHIFT,
  354. TRUE);
  355. if (mapBufferAddress == 0) {
  356. mapBufferSize = 0;
  357. }
  358. MasterAdapter24.MapBufferPhysicalAddress.LowPart = mapBufferAddress;
  359. MasterAdapter24.MapBufferPhysicalAddress.HighPart = 0;
  360. MasterAdapter24.MapBufferSize = mapBufferSize;
  361. if (HalPaeEnabled() != FALSE) {
  362. //
  363. // Initialize and allocate map buffers for the 32bit master adapter
  364. // object. This should only be needed on a PAE-enabled system.
  365. //
  366. MasterAdapter32.MaxBufferPages =
  367. MAXIMUM_PCI_MAP_BUFFER_SIZE / PAGE_SIZE;
  368. mapBufferSize = INITIAL_MAP_BUFFER_LARGE_SIZE;
  369. mapBufferAddress =
  370. HalpAllocPhysicalMemory (LoaderBlock,
  371. (ULONG)-1,
  372. mapBufferSize >> PAGE_SHIFT,
  373. TRUE);
  374. if (mapBufferAddress == 0) {
  375. mapBufferSize = 0;
  376. }
  377. MasterAdapter32.MapBufferPhysicalAddress.LowPart = mapBufferAddress;
  378. MasterAdapter32.MapBufferPhysicalAddress.HighPart = 0;
  379. MasterAdapter32.MapBufferSize = mapBufferSize;
  380. }
  381. #endif
  382. } else {
  383. //
  384. // Phase 1 initialization
  385. //
  386. if (pPRCB->Number == 0) {
  387. //
  388. // Back-pocket some PTEs for DMA during low mem
  389. //
  390. HalpInitReservedPages();
  391. #ifndef ACPI_HAL
  392. //
  393. // If P0, then setup global vectors
  394. //
  395. HalpRegisterInternalBusHandlers ();
  396. #else
  397. HalpInitNonBusHandler();
  398. #endif
  399. //
  400. // Set feature bits
  401. //
  402. HalpFeatureBits = HalpGetFeatureBits();
  403. //
  404. // Use movnti routine to copy memory if Movnti support is detected
  405. //
  406. #if !defined(_WIN64)
  407. if (HalpFeatureBits & HAL_WNI_PRESENT) {
  408. HalpMoveMemory = HalpMovntiCopyBuffer;
  409. }
  410. #endif
  411. //
  412. // Init timer watchdog if enabled (allocate stack snapshot buffer).
  413. //
  414. HalpInitTimerWatchdog(Phase);
  415. HalpEnableInterruptHandler (
  416. DeviceUsage | InterruptLatched, // Report as device vector
  417. V2I (CLOCK_VECTOR), // Bus interrupt level
  418. CLOCK_VECTOR, // System IDT
  419. CLOCK2_LEVEL, // System Irql
  420. HalpClockInterrupt, // ISR
  421. Latched );
  422. HalpEnableInterruptHandler (
  423. DeviceUsage | InterruptLatched, // Report as device vector
  424. V2I (PROFILE_VECTOR), // Bus interrupt level
  425. PROFILE_VECTOR, // System IDT
  426. PROFILE_LEVEL, // System Irql
  427. HalpProfileInterrupt, // ISR
  428. Latched );
  429. #ifdef ACPI_HAL
  430. //
  431. // Perf counter patch for non-compliant ACPI machines
  432. //
  433. HalpAcpiTimerPerfCountHack();
  434. #endif
  435. #if !defined(_WIN64)
  436. //
  437. // If 486, the FP error will be routed via trap10. So we
  438. // don't enable irq13. Otherwise (CPU=386), we will enable irq13
  439. // to handle FP error.
  440. //
  441. if (pPRCB->CpuType == 3) {
  442. HalpEnableInterruptHandler (
  443. DeviceUsage, // Report as device vector
  444. V2I (I386_80387_VECTOR), // Bus interrupt level
  445. I386_80387_VECTOR, // System IDT
  446. I386_80387_IRQL, // System Irql
  447. HalpIrq13Handler, // ISR
  448. Latched );
  449. }
  450. #endif
  451. }
  452. }
  453. #ifndef NT_UP
  454. HalpInitMP (Phase, LoaderBlock);
  455. #endif
  456. return TRUE;
  457. }
  458. ULONG
  459. HalpGetFeatureBits (
  460. VOID
  461. )
  462. {
  463. UCHAR Buffer[50];
  464. ULONG Junk, ProcessorFeatures, Bits;
  465. PKPRCB Prcb;
  466. ULONGLONG ApicBits;
  467. Bits = 0;
  468. Prcb = KeGetCurrentPrcb();
  469. if (!Prcb->CpuID) {
  470. Bits |= HAL_NO_SPECULATION;
  471. return Bits;
  472. }
  473. //
  474. // Determine the processor type
  475. //
  476. HalpCpuID (0, &Junk, (PULONG) Buffer+0, (PULONG) Buffer+2, (PULONG) Buffer+1);
  477. Buffer[12] = 0;
  478. HalpCpuID (1, &Junk, &Junk, &Junk, &ProcessorFeatures);
  479. //
  480. // Determine which features are present.
  481. //
  482. if (strcmp (Buffer, HalpGenuineIntel) == 0) {
  483. //
  484. // Check Intel feature bits for HAL features needed
  485. //
  486. if (Prcb->CpuType == 6) {
  487. Bits |= HAL_PERF_EVENTS;
  488. //
  489. // Workaround for Pentium Pro Local APIC trap 0x0F and trap 0x00
  490. // spurious interrupt errata 5AP and 6AP. Disable the Local APIC
  491. // on UP Pentium Pro Systems. Interrupts are routed directly from
  492. // 8259 PIC to CPU.
  493. //
  494. ApicBits = RDMSR(APIC_BASE_MSR);
  495. if (ApicBits & APIC_ENABLED) {
  496. //
  497. // Local APIC is enabled - Disable it.
  498. //
  499. WRMSR(APIC_BASE_MSR, (ApicBits & ~APIC_ENABLED));
  500. }
  501. }
  502. if (Prcb->CpuType < 6) {
  503. Bits |= HAL_NO_SPECULATION;
  504. }
  505. }
  506. if (ProcessorFeatures & CPUID_MCA_MASK) {
  507. Bits |= HAL_MCA_PRESENT;
  508. }
  509. if (ProcessorFeatures & CPUID_MCE_MASK) {
  510. Bits |= HAL_MCE_PRESENT;
  511. }
  512. if (ProcessorFeatures & CPUID_VME_MASK) {
  513. Bits |= HAL_CR4_PRESENT;
  514. }
  515. if (ProcessorFeatures & CPUID_WNI_MASK) {
  516. Bits |= HAL_WNI_PRESENT;
  517. }
  518. return Bits;
  519. }