Windows NT 4.0 source code leak
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.

880 lines
18 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1993 Digital Equipment Corporation
  3. Module Name:
  4. ebinitnt.c
  5. Abstract:
  6. This module implements the platform-specific initialization for
  7. an EB64+ system.
  8. Author:
  9. Joe Notarangelo 25-Oct-1993
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. Dick Bissen [DEC] 30-Jun-1994
  14. Added code to support new PCI memory configuration.
  15. Dick Bissen [DEC] 12-May-1994
  16. Added code to support both passes of the EB64Plus modules.
  17. --*/
  18. #include "halp.h"
  19. #include "pcrtc.h"
  20. #include "eb64pdef.h"
  21. #include "halpcsl.h"
  22. #include "eisa.h"
  23. #include "pci.h"
  24. #include "pcip.h"
  25. #include "iousage.h"
  26. #include "flash8k.h"
  27. #include "fwcallbk.h"
  28. #include <ntverp.h> // to get the product build number.
  29. //
  30. // Define extern global buffer for the Uncorrectable Error Frame.
  31. // declared in halalpha\inithal.c
  32. //
  33. extern PERROR_FRAME PUncorrectableError;
  34. //
  35. // Define global data for builtin device interrupt enables.
  36. //
  37. USHORT HalpBuiltinInterruptEnable;
  38. //
  39. //
  40. //
  41. BOOLEAN SystemIsAlphaPC64;
  42. PVOID INTERRUPT_MASK0_QVA;
  43. PVOID INTERRUPT_MASK1_QVA;
  44. PVOID INTERRUPT_MASK2_QVA;
  45. ULONG SIO_INTERRUPT_MASK;
  46. // irql mask and tables
  47. //
  48. // irql 0 - passive
  49. // irql 1 - sfw apc level
  50. // irql 2 - sfw dispatch level
  51. // irql 3 - device low
  52. // irql 4 - device high
  53. // irql 5 - clock
  54. // irql 6 - real time, ipi, performance counters
  55. // irql 7 - error, mchk, nmi, halt
  56. //
  57. //
  58. // IDT mappings:
  59. // For the built-ins, GetInterruptVector will need more info,
  60. // or it will have to be built-in to the routines, since
  61. // these don't match IRQL levels in any meaningful way.
  62. //
  63. // 0 passive 8 perf cntr 1
  64. // 1 apc 9
  65. // 2 dispatch 10 PIC
  66. // 3 11
  67. // 4 12 errors
  68. // 5 clock 13
  69. // 6 perf cntr 0 14 halt
  70. // 7 nmi 15
  71. //
  72. // This is assuming the following prioritization:
  73. // nmi
  74. // halt
  75. // errors
  76. // performance counters
  77. // clock
  78. // pic
  79. //
  80. // The hardware interrupt pins are used as follows for EB64+
  81. //
  82. // IRQ_H[0] = PIC
  83. // IRQ_H[1] = Clock
  84. // IRQ_H[2] = NMI
  85. // IRQ_H[3] = unused
  86. // IRQ_H[4] = unused
  87. // IRQ_H[5] = unused
  88. //
  89. // For information purposes: here is what the IDT division looks like:
  90. //
  91. // 000-015 Built-ins (we only use 8 entries; NT wants 10)
  92. // 016-031 ISA
  93. // 048-063 EISA
  94. // 080-095 PCI
  95. // 112-127 Turbo Channel
  96. // 128-255 unused, as are all other holes
  97. //
  98. //
  99. // These globals make available the specifics of the Eb64 platform
  100. // we're running in.
  101. //
  102. BOOLEAN SioCStep;
  103. //
  104. // This is the PCI Sparse Memory space that cannot be used by anyone
  105. // and therefore the HAL says it is reserved for itself.
  106. //
  107. //
  108. // This is the PCI Memory space that cannot be used by anyone
  109. // and therefore the HAL says it is reserved for itself
  110. //
  111. ADDRESS_USAGE
  112. EB64pPCIMemorySpace = {
  113. NULL, CmResourceTypeMemory, PCIUsage,
  114. {
  115. __8MB, __32MB - __8MB, // Start=8MB; Length=24Mb (8 through 32)
  116. 0,0
  117. }
  118. };
  119. //
  120. // Define the bus type, this value allows us to distinguish between
  121. // EISA and ISA systems.
  122. //
  123. ULONG HalpBusType = MACHINE_TYPE_ISA;
  124. //
  125. // Define global data used to communicate new clock rates to the clock
  126. // interrupt service routine.
  127. //
  128. ULONG HalpCurrentTimeIncrement;
  129. ULONG HalpNextRateSelect;
  130. ULONG HalpNextTimeIncrement;
  131. ULONG HalpNewTimeIncrement;
  132. VOID
  133. HalpInitializeHAERegisters(
  134. VOID
  135. );
  136. VOID
  137. HalpParseLoaderBlock(
  138. PLOADER_PARAMETER_BLOCK LoaderBlock
  139. );
  140. VOID
  141. HalpClearInterrupts(
  142. );
  143. BOOLEAN
  144. HalpInitializeInterrupts (
  145. VOID
  146. )
  147. /*++
  148. Routine Description:
  149. This function initializes interrupts for an Alpha system.
  150. Arguments:
  151. None.
  152. Return Value:
  153. A value of TRUE is returned if the initialization is successfully
  154. completed. Otherwise a value of FALSE is returned.
  155. --*/
  156. {
  157. UCHAR DataByte;
  158. ULONG DataLong;
  159. ULONG Index;
  160. ULONG Irq;
  161. KIRQL Irql;
  162. UCHAR Priority;
  163. ULONG Vector;
  164. //
  165. // Initialize HAL processor parameters based on estimated CPU speed.
  166. // This must be done before HalpStallExecution is called. Compute integral
  167. // megahertz first to avoid rounding errors due to imprecise cycle clock
  168. // period values.
  169. //
  170. HalpInitializeProcessorParameters();
  171. //
  172. // Connect the Stall interrupt vector to the clock. When the
  173. // profile count is calculated, we then connect the normal
  174. // clock.
  175. PCR->InterruptRoutine[CLOCK2_LEVEL] = HalpStallInterrupt;
  176. //
  177. // Clear all pending interrupts
  178. //
  179. HalpClearInterrupts();
  180. //
  181. // Start the periodic interrupt from the RTC
  182. //
  183. HalpProgramIntervalTimer(MAXIMUM_RATE_SELECT);
  184. //
  185. // Initialize the PCI/ISA interrupt controller.
  186. //
  187. HalpInitializePCIInterrupts();
  188. //
  189. // Initialize the 21064 interrupts.
  190. //
  191. HalpInitialize21064Interrupts();
  192. HalpEnable21064SoftwareInterrupt( Irql = APC_LEVEL );
  193. HalpEnable21064SoftwareInterrupt( Irql = DISPATCH_LEVEL );
  194. HalpEnable21064HardwareInterrupt(Irq = 0,
  195. Irql = DEVICE_LEVEL,
  196. Vector = PIC_VECTOR,
  197. Priority = 0 );
  198. HalpEnable21064HardwareInterrupt(Irq = 1,
  199. Irql = CLOCK_LEVEL,
  200. Vector = CLOCK_VECTOR,
  201. Priority = 0 );
  202. HalpEnable21064HardwareInterrupt(Irq = 2,
  203. Irql = HIGH_LEVEL,
  204. Vector = EISA_NMI_VECTOR,
  205. Priority = 0 );
  206. return TRUE;
  207. }
  208. VOID
  209. HalpClearInterrupts(
  210. )
  211. /*++
  212. Routine Description:
  213. This function no longer does anything.
  214. Arguments:
  215. None.
  216. Return Value:
  217. None.
  218. --*/
  219. {
  220. return;
  221. }
  222. VOID
  223. HalpSetTimeIncrement(
  224. VOID
  225. )
  226. /*++
  227. Routine Description:
  228. This routine is responsible for setting the time increment for an EV4
  229. based machine via a call into the kernel.
  230. Arguments:
  231. None.
  232. Return Value:
  233. None.
  234. --*/
  235. {
  236. //
  237. // Set the time increment value.
  238. //
  239. HalpCurrentTimeIncrement = MAXIMUM_INCREMENT;
  240. HalpNextTimeIncrement = MAXIMUM_INCREMENT;
  241. HalpNextRateSelect = 0;
  242. KeSetTimeIncrement( MAXIMUM_INCREMENT, MINIMUM_INCREMENT );
  243. }
  244. //
  245. // Define global data used to calibrate and stall processor execution.
  246. //
  247. ULONG HalpProfileCountRate;
  248. VOID
  249. HalpInitializeClockInterrupts(
  250. VOID
  251. )
  252. /*++
  253. Routine Description:
  254. This function is called during phase 1 initialization to complete
  255. the initialization of clock interrupts. For EV4, this function
  256. connects the true clock interrupt handler and initializes the values
  257. required to handle profile interrupts.
  258. Arguments:
  259. None.
  260. Return Value:
  261. None.
  262. --*/
  263. {
  264. //
  265. // Compute the profile interrupt rate.
  266. //
  267. HalpProfileCountRate = ((1000 * 1000 * 10) / KeQueryTimeIncrement());
  268. //
  269. // Set the time increment value and connect the real clock interrupt
  270. // routine.
  271. //
  272. PCR->InterruptRoutine[CLOCK2_LEVEL] = HalpClockInterrupt;
  273. return;
  274. }
  275. VOID
  276. HalpEstablishErrorHandler(
  277. VOID
  278. )
  279. /*++
  280. Routine Description:
  281. This routine performs the initialization necessary for the HAL to
  282. begin servicing machine checks.
  283. Arguments:
  284. None.
  285. Return Value:
  286. None.
  287. --*/
  288. {
  289. BOOLEAN ReportCorrectables;
  290. //
  291. // Connect the machine check handler via the PCR. The machine check
  292. // handler for EV4 is the default EV4 parity-mode handler.
  293. //
  294. PCR->MachineCheckError = HalMachineCheck;
  295. //
  296. // Initialize error handling for APECS.
  297. //
  298. HalpInitializeMachineChecks ( ReportCorrectables = FALSE );
  299. return;
  300. }
  301. VOID
  302. HalpInitializeMachineDependent(
  303. IN ULONG Phase,
  304. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  305. )
  306. /*++
  307. Routine Description:
  308. This function performs any EV4-specific initialization based on
  309. the current phase on initialization.
  310. Arguments:
  311. Phase - Supplies an indicator for phase of initialization, phase 0 or
  312. phase 1.
  313. LoaderBlock - supplies a pointer to the loader block.
  314. Return Value:
  315. None.
  316. --*/
  317. {
  318. ULONG PciBridgeHeaderOffset;
  319. ULONG SioRevision;
  320. if ( Phase == 0 ) {
  321. //
  322. // Phase 0 Initialization.
  323. //
  324. HalpFlashDriver = HalpInitializeFlashDriver((PCHAR)ALPHAPC64_ENVIRONMENT_QVA);
  325. if (HalpFlashDriver != NULL) {
  326. //
  327. // The flash device was found, so we must be running on an
  328. // AlphaPC64
  329. //
  330. SystemIsAlphaPC64 = TRUE;
  331. HalpCMOSRamBase = (PVOID)ALPHAPC64_ENVIRONMENT_QVA;
  332. INTERRUPT_MASK0_QVA = ALPHAPC64_INTERRUPT_MASK0_QVA;
  333. INTERRUPT_MASK1_QVA = ALPHAPC64_INTERRUPT_MASK1_QVA;
  334. INTERRUPT_MASK2_QVA = ALPHAPC64_INTERRUPT_MASK2_QVA;
  335. SIO_INTERRUPT_MASK = ALPHAPC64_SIO_INTERRUPT_MASK;
  336. } else {
  337. SystemIsAlphaPC64 = FALSE;
  338. INTERRUPT_MASK0_QVA = EB64P_INTERRUPT_MASK0_QVA;
  339. INTERRUPT_MASK1_QVA = EB64P_INTERRUPT_MASK1_QVA;
  340. INTERRUPT_MASK2_QVA = EB64P_INTERRUPT_MASK2_QVA;
  341. SIO_INTERRUPT_MASK = EB64P_SIO_INTERRUPT_MASK;
  342. }
  343. #ifdef HALDBG
  344. DbgPrint("HalpInitializeMachineDependent: SystemIsAlphaPC64 is %x\n",
  345. SystemIsAlphaPC64);
  346. DbgPrint("HalpInitializeMachineDependent: HalpCMOSRamBase is %x\n",
  347. HalpCMOSRamBase);
  348. DbgPrint("HalpInitializeMachineDependent: INTERRUPT_MASK0_QVA is %x\n",
  349. INTERRUPT_MASK0_QVA);
  350. DbgPrint("HalpInitializeMachineDependent: INTERRUPT_MASK1_QVA is %x\n",
  351. INTERRUPT_MASK1_QVA);
  352. DbgPrint("HalpInitializeMachineDependent: INTERRUPT_MASK2_QVA is %x\n",
  353. INTERRUPT_MASK2_QVA);
  354. DbgPrint("HalpInitializeMachineDependent: SIO_INTERRUPT_MASK is %x\n",
  355. SIO_INTERRUPT_MASK);
  356. #endif
  357. //
  358. // Parse the Loader Parameter block looking for PCI entry to determine
  359. // if PCI parity should be disabled
  360. //
  361. HalpParseLoaderBlock( LoaderBlock );
  362. //
  363. // Re-establish the error handler, to reflect the parity checking
  364. //
  365. HalpEstablishErrorHandler();
  366. PciBridgeHeaderOffset = PCI_ISA_BRIDGE_HEADER_OFFSET_P2;
  367. SioRevision = READ_CONFIG_UCHAR((PCHAR)(PCI_CONFIGURATION_BASE_QVA |
  368. PciBridgeHeaderOffset |
  369. PCI_REVISION),
  370. PCI_CONFIG_CYCLE_TYPE_0);
  371. SioCStep = (SioRevision == 0x3 ? TRUE : FALSE);
  372. #ifdef HALDBG
  373. DbgPrint("HalpInitializeMachineDependent: SioCStep is %x\n",SioCStep);
  374. #endif
  375. HalpInitializeHAERegisters();
  376. } else {
  377. //
  378. // Phase 1 Initialization.
  379. //
  380. //
  381. // Initialize the existing bus handlers.
  382. //
  383. HalpRegisterInternalBusHandlers();
  384. //
  385. // Initialize the PCI bus.
  386. //
  387. HalpInitializePCIBus (LoaderBlock);
  388. //
  389. // Initialize the profiler.
  390. //
  391. HalpInitializeProfiler();
  392. }
  393. return;
  394. }
  395. VOID
  396. HalpStallInterrupt (
  397. VOID
  398. )
  399. /*++
  400. Routine Description:
  401. This function serves as the stall calibration interrupt service
  402. routine. It is executed in response to system clock interrupts
  403. during the initialization of the HAL layer.
  404. Arguments:
  405. None.
  406. Return Value:
  407. None.
  408. --*/
  409. {
  410. HalpAcknowledgeClockInterrupt();
  411. return;
  412. }
  413. ULONG
  414. HalSetTimeIncrement (
  415. IN ULONG DesiredIncrement
  416. )
  417. /*++
  418. Routine Description:
  419. This function is called to set the clock interrupt rate to the frequency
  420. required by the specified time increment value.
  421. Arguments:
  422. DesiredIncrement - Supplies desired number of 100ns units between clock
  423. interrupts.
  424. Return Value:
  425. The actual time increment in 100ns units.
  426. --*/
  427. {
  428. ULONG NewTimeIncrement;
  429. ULONG NextRateSelect;
  430. KIRQL OldIrql;
  431. //
  432. // Raise IRQL to the highest level, set the new clock interrupt
  433. // parameters, lower IRQl, and return the new time increment value.
  434. //
  435. KeRaiseIrql(HIGH_LEVEL, &OldIrql);
  436. if (DesiredIncrement < MINIMUM_INCREMENT) {
  437. DesiredIncrement = MINIMUM_INCREMENT;
  438. }
  439. if (DesiredIncrement > MAXIMUM_INCREMENT) {
  440. DesiredIncrement = MAXIMUM_INCREMENT;
  441. }
  442. //
  443. // Find the allowed increment that is less than or equal to
  444. // the desired increment.
  445. //
  446. if (DesiredIncrement >= RTC_PERIOD_IN_CLUNKS4) {
  447. NewTimeIncrement = RTC_PERIOD_IN_CLUNKS4;
  448. NextRateSelect = RTC_RATE_SELECT4;
  449. } else if (DesiredIncrement >= RTC_PERIOD_IN_CLUNKS3) {
  450. NewTimeIncrement = RTC_PERIOD_IN_CLUNKS3;
  451. NextRateSelect = RTC_RATE_SELECT3;
  452. } else if (DesiredIncrement >= RTC_PERIOD_IN_CLUNKS2) {
  453. NewTimeIncrement = RTC_PERIOD_IN_CLUNKS2;
  454. NextRateSelect = RTC_RATE_SELECT2;
  455. } else {
  456. NewTimeIncrement = RTC_PERIOD_IN_CLUNKS1;
  457. NextRateSelect = RTC_RATE_SELECT1;
  458. }
  459. HalpNextRateSelect = NextRateSelect;
  460. HalpNewTimeIncrement = NewTimeIncrement;
  461. KeLowerIrql(OldIrql);
  462. return NewTimeIncrement;
  463. }
  464. VOID
  465. HalpInitializeHAERegisters(
  466. VOID
  467. )
  468. /*++
  469. Routine Description:
  470. This function initializes the HAE registers in the EPIC/APECS chipset.
  471. It also register the holes in the PCI memory space if any.
  472. Arguments:
  473. none
  474. Return Value:
  475. none
  476. --*/
  477. {
  478. //
  479. // Set HAXR1 to 0, which means no address extension
  480. //
  481. WRITE_EPIC_REGISTER (&((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->Haxr1, 0);
  482. //
  483. // We set HAXR2 to MB. Which means we have the following
  484. // PCI IO addresses:
  485. // 0 to 64KB VALID. HAXR2 Not used in address translation
  486. // 64K to 16MB VALID. HAXR2 is used in the address translation
  487. //
  488. WRITE_EPIC_REGISTER ( &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->Haxr2, 0);
  489. //
  490. // Report that the apecs mapping to the Io subsystem
  491. //
  492. HalpRegisterAddressUsage (&EB64pPCIMemorySpace);
  493. }
  494. VOID
  495. HalpResetHAERegisters(
  496. VOID
  497. )
  498. /*++
  499. Routine Description:
  500. This function resets the HAE registers in the EPIC/APECS chipset to 0.
  501. This is routine called during a shutdown so that the prom
  502. gets a predictable environment.
  503. Arguments:
  504. none
  505. Return Value:
  506. none
  507. --*/
  508. {
  509. WRITE_EPIC_REGISTER( &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->Haxr1, 0 );
  510. WRITE_EPIC_REGISTER( &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->Haxr2, 0 );
  511. return;
  512. }
  513. VOID
  514. HalpGetMachineDependentErrorFrameSizes(
  515. PULONG RawProcessorSize,
  516. PULONG RawSystemInfoSize
  517. )
  518. /*++
  519. Routine Description:
  520. This function returns the size of the system specific structures.
  521. Arguments:
  522. RawProcessorSize - Pointer to a buffer that will receive the
  523. size of the processor specific error information buffer.
  524. RawSystemInfoSize - Pointer to a buffer that will receive the
  525. size of the system specific error information buffer.
  526. Return Value:
  527. none
  528. --*/
  529. {
  530. *RawProcessorSize = sizeof(PROCESSOR_EV4_UNCORRECTABLE);
  531. *RawSystemInfoSize = sizeof(APECS_UNCORRECTABLE_FRAME);
  532. return;
  533. }
  534. VOID
  535. HalpGetSystemInfo(SYSTEM_INFORMATION *SystemInfo)
  536. /*++
  537. Routine Description:
  538. This function fills in the System information.
  539. Arguments:
  540. SystemInfo - Pointer to the SYSTEM_INFORMATION buffer that needs
  541. to be filled in.
  542. Return Value:
  543. none
  544. --*/
  545. {
  546. char systemtype[] = "eb64p";
  547. EXTENDED_SYSTEM_INFORMATION FwExtSysInfo;
  548. VenReturnExtendedSystemInformation(&FwExtSysInfo);
  549. RtlCopyMemory(SystemInfo->FirmwareRevisionId,
  550. FwExtSysInfo.FirmwareVersion,
  551. 16);
  552. RtlCopyMemory(SystemInfo->SystemType,systemtype, 8);
  553. SystemInfo->ClockSpeed =
  554. ((1000 * 1000) + (PCR->CycleClockPeriod >> 1)) / PCR->CycleClockPeriod;
  555. SystemInfo->SystemRevision = PCR->SystemRevision;
  556. RtlCopyMemory(SystemInfo->SystemSerialNumber,
  557. PCR->SystemSerialNumber,
  558. 16);
  559. SystemInfo->SystemVariant = PCR->SystemVariant;
  560. SystemInfo->PalMajorVersion = PCR->PalMajorVersion;
  561. SystemInfo->PalMinorVersion = PCR->PalMinorVersion;
  562. SystemInfo->OsRevisionId = VER_PRODUCTBUILD;
  563. //
  564. // For now fill in dummy values.
  565. //
  566. SystemInfo->ModuleVariant = 1UL;
  567. SystemInfo->ModuleRevision = 1UL;
  568. SystemInfo->ModuleSerialNumber = 0;
  569. return;
  570. }
  571. VOID
  572. HalpInitializeUncorrectableErrorFrame (
  573. VOID
  574. )
  575. /*++
  576. Routine Description:
  577. This function Allocates an Uncorrectable Error frame for this
  578. system and initializes the frame with certain constant/global
  579. values.
  580. This is routine called during machine dependent system
  581. Initialization.
  582. Arguments:
  583. none
  584. Return Value:
  585. none
  586. --*/
  587. {
  588. PROCESSOR_EV4_UNCORRECTABLE processorFrame;
  589. //
  590. // If the Uncorrectable error buffer is not set then simply return
  591. //
  592. if(PUncorrectableError == NULL)
  593. return;
  594. PUncorrectableError->Signature = ERROR_FRAME_SIGNATURE;
  595. PUncorrectableError->FrameType = UncorrectableFrame;
  596. //
  597. // ERROR_FRAME_VERSION is define in errframe.h and will
  598. // change as and when there is a change in the errframe.h.
  599. // This Version number helps the service, that reads this
  600. // information from the dumpfile, to check if it knows about
  601. // this frmae version type to decode. If it doesn't know, it
  602. // will dump the entire frame to the EventLog with a message
  603. // "Error Frame Version Mismatch".
  604. //
  605. PUncorrectableError->VersionNumber = ERROR_FRAME_VERSION;
  606. //
  607. // The sequence number will always be 1 for Uncorrectable errors.
  608. //
  609. PUncorrectableError->SequenceNumber = 1;
  610. //
  611. // The PerformanceCounterValue field is not used for Uncorrectable
  612. // errors.
  613. //
  614. PUncorrectableError->PerformanceCounterValue = 0;
  615. //
  616. // We will fill in the UncorrectableFrame.SystemInfo here.
  617. //
  618. HalpGetSystemInfo(&PUncorrectableError->UncorrectableFrame.System);
  619. PUncorrectableError->UncorrectableFrame.Flags.SystemInformationValid = 1;
  620. return;
  621. }