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.

606 lines
14 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. xxinithl.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. Alpha machine
  9. Author:
  10. David N. Cutler (davec) 25-Apr-1991
  11. Miche Baker-Harvey (miche) 18-May-1992
  12. Environment:
  13. Kernel mode only.
  14. Revision History:
  15. 28-Jul-1992 Jeff McLeman (mcleman)
  16. Add code to allocate a mapping buffer for buffered DMA
  17. 14-Jul-1992 Jeff McLeman (mcleman)
  18. Add call to HalpCachePcrValues, which will call the PALcode to
  19. cache values of the PCR that need fast access.
  20. 10-Jul-1992 Jeff McLeman (mcleman)
  21. Remove reference to initializing the fixed TB entries, since Alpha
  22. does not have fixed TB entries.
  23. --*/
  24. #include "halp.h"
  25. #include "eisa.h"
  26. #include "jxisa.h"
  27. #include "jnsnrtc.h"
  28. ULONG HalpBusType = MACHINE_TYPE_EISA;
  29. ULONG HalpMapBufferSize;
  30. PHYSICAL_ADDRESS HalpMapBufferPhysicalAddress;
  31. typedef
  32. BOOLEAN
  33. KBUS_ERROR_ROUTINE (
  34. IN struct _EXCEPTION_RECORD *ExceptionRecord,
  35. IN struct _KEXCEPTION_FRAME *ExceptionFrame,
  36. IN struct _KTRAP_FRAME *TrapFrame
  37. );
  38. KBUS_ERROR_ROUTINE HalMachineCheck;
  39. //
  40. // HalpClockFrequency is the processor cycle counter frequency in units
  41. // of cycles per second (Hertz). It is a large number (e.g., 125,000,000)
  42. // but will still fit in a ULONG.
  43. //
  44. // HalpClockMegaHertz is the processor cycle counter frequency in units
  45. // of megahertz. It is a small number (e.g., 125) and is also the number
  46. // of cycles per microsecond. The assumption here is that clock rates will
  47. // always be an integral number of megahertz.
  48. //
  49. // Having the frequency available in both units avoids multiplications, or
  50. // especially divisions in time critical code.
  51. //
  52. ULONG HalpClockFrequency;
  53. ULONG HalpClockMegaHertz;
  54. //
  55. // Use the square wave mode of the PIT to measure the processor
  56. // speed. The timer has a frequency of 1.193MHz. We want a
  57. // square wave with a period of 50ms so we must initialize the
  58. // pit with a count of:
  59. // 50ms*1.193MHz = 59650 cycles
  60. //
  61. #define TIMER_REF_VALUE 59650
  62. ULONG
  63. HalpQuerySystemFrequency(
  64. ULONG SampleTime
  65. );
  66. BOOLEAN
  67. HalInitSystem (
  68. IN ULONG Phase,
  69. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  70. )
  71. /*++
  72. Routine Description:
  73. This function initializes the Hardware Architecture Layer (HAL) for an
  74. Alpha system.
  75. Arguments:
  76. Phase - Supplies the initialization phase (zero or one).
  77. LoaderBlock - Supplies a pointer to a loader parameter block.
  78. Return Value:
  79. A value of TRUE is returned is the initialization was successfully
  80. complete. Otherwise a value of FALSE is returend.
  81. --*/
  82. {
  83. PKPRCB Prcb;
  84. if (Phase == 0) {
  85. //
  86. // Phase 0 initialization.
  87. //
  88. //
  89. // Set the time increment value.
  90. //
  91. HalpCurrentTimeIncrement = MAXIMUM_INCREMENT;
  92. HalpNextTimeIncrement = MAXIMUM_INCREMENT;
  93. HalpNextRateSelect = 0;
  94. KeSetTimeIncrement( MAXIMUM_INCREMENT, MINIMUM_INCREMENT );
  95. HalpMapIoSpace();
  96. HalpInitializeInterrupts();
  97. HalpCreateDmaStructures();
  98. HalpInitializeDisplay(LoaderBlock);
  99. HalpCachePcrValues();
  100. //
  101. // Fill in handlers for APIs which this HAL supports
  102. //
  103. HalQuerySystemInformation = HaliQuerySystemInformation;
  104. HalSetSystemInformation = HaliSetSystemInformation;
  105. //
  106. // Establish the machine check handler for in the PCR.
  107. //
  108. PCR->MachineCheckError = HalMachineCheck;
  109. //
  110. // Verify Prcb major version number, and build options are
  111. // all conforming to this binary image
  112. //
  113. Prcb = KeGetCurrentPrcb();
  114. #if DBG
  115. if (!(Prcb->BuildType & PRCB_BUILD_DEBUG)) {
  116. // This checked hal requires a checked kernel
  117. KeBugCheckEx (MISMATCHED_HAL, 2, Prcb->BuildType, PRCB_BUILD_DEBUG, 0);
  118. }
  119. #else
  120. if (Prcb->BuildType & PRCB_BUILD_DEBUG) {
  121. // This free hal requires a free kernel
  122. KeBugCheckEx (MISMATCHED_HAL, 2, Prcb->BuildType, 0, 0);
  123. }
  124. #endif
  125. #ifndef NT_UP
  126. if (Prcb->BuildType & PRCB_BUILD_UNIPROCESSOR) {
  127. // This MP hal requires an MP kernel
  128. KeBugCheckEx (MISMATCHED_HAL, 2, Prcb->BuildType, 0, 0);
  129. }
  130. #endif
  131. if (Prcb->MajorVersion != PRCB_MAJOR_VERSION) {
  132. KeBugCheckEx (MISMATCHED_HAL,
  133. 1, Prcb->MajorVersion, PRCB_MAJOR_VERSION, 0);
  134. }
  135. //
  136. // Now alocate a mapping buffer for buffered DMA.
  137. //
  138. LessThan16Mb = FALSE;
  139. HalpMapBufferSize = INITIAL_MAP_BUFFER_LARGE_SIZE;
  140. HalpMapBufferPhysicalAddress.LowPart =
  141. HalpAllocPhysicalMemory (LoaderBlock, MAXIMUM_ISA_PHYSICAL_ADDRESS,
  142. HalpMapBufferSize >> PAGE_SHIFT, TRUE);
  143. HalpMapBufferPhysicalAddress.HighPart = 0;
  144. if (!HalpMapBufferPhysicalAddress.LowPart) {
  145. HalpMapBufferSize = 0;
  146. }
  147. //
  148. // Setup special memory AFTER we've allocated our COMMON BUFFER!
  149. //
  150. HalpInitializeSpecialMemory( LoaderBlock );
  151. return TRUE;
  152. } else {
  153. //
  154. // Phase 1 initialization.
  155. //
  156. HalpCalibrateStall();
  157. //
  158. // Initialize the existing bus handlers.
  159. //
  160. HalpRegisterInternalBusHandlers();
  161. //
  162. // Allocate pool for evnironment variable support
  163. //
  164. if (HalpEnvironmentInitialize() != 0) {
  165. HalDisplayString(" No pool available for Environment Variables\n");
  166. }
  167. return TRUE;
  168. }
  169. }
  170. VOID
  171. HalInitializeProcessor (
  172. IN ULONG Number
  173. )
  174. /*++
  175. Routine Description:
  176. This function is called early in the initialization of the kernel
  177. to perform platform dependent initialization for each processor
  178. before the HAL Is fully functional.
  179. N.B. When this routine is called, the PCR is present but is not
  180. fully initialized.
  181. Arguments:
  182. Number - Supplies the number of the processor to initialize.
  183. Return Value:
  184. None.
  185. --*/
  186. {
  187. return;
  188. }
  189. BOOLEAN
  190. HalStartNextProcessor (
  191. IN PLOADER_PARAMETER_BLOCK LoaderBlock,
  192. IN PKPROCESSOR_STATE ProcessorState
  193. )
  194. /*++
  195. Routine Description:
  196. This function is called to start the next processor.
  197. Arguments:
  198. LoaderBlock - Supplies a pointer to the loader parameter block.
  199. ProcessorState - Supplies a pointer to the processor state to be
  200. used to start the processor.
  201. Return Value:
  202. If a processor is successfully started, then a value of TRUE is
  203. returned. Otherwise a value of FALSE is returned.
  204. --*/
  205. {
  206. return FALSE;
  207. }
  208. VOID
  209. HalpVerifyPrcbVersion ()
  210. {
  211. }
  212. ULONG
  213. HalpQuerySystemFrequency(
  214. ULONG SampleTime
  215. )
  216. /*++
  217. Routine Description:
  218. This routine returns the speed at which the system is running in hertz.
  219. The system frequency is calculated by counting the number of processor
  220. cycles that occur during 500ms, using the Programmable Interval Timer
  221. (PIT) as the reference time. The PIT is used to generate a square
  222. wave with a 50ms Period. We use the Speaker counter since we can
  223. enable and disable the count from software. The output of the
  224. speaker is obtained from the SIO NmiStatus register.
  225. Arguments:
  226. None.
  227. Return Value:
  228. The system frequency in Hertz.
  229. --*/
  230. {
  231. TIMER_CONTROL TimerControlSetup;
  232. TIMER_CONTROL TimerControlReadStatus;
  233. TIMER_STATUS TimerStatus;
  234. NMI_STATUS NmiStatus;
  235. PEISA_CONTROL controlBase;
  236. ULONGLONG Count1;
  237. ULONGLONG Count2;
  238. ULONG NumberOfIntervals;
  239. ULONG SquareWaveState = 0;
  240. // mdbfix - move this into eisa.h one day
  241. #define SB_READ_STATUS_ONLY 2
  242. controlBase = HalpEisaControlBase;
  243. //
  244. // Disable the speaker counter.
  245. //
  246. *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
  247. NmiStatus.SpeakerGate = 0;
  248. NmiStatus.SpeakerData = 0;
  249. // these are MBZ when writing to NMIMISC
  250. NmiStatus.RefreshToggle = 0;
  251. NmiStatus.SpeakerTimer = 0;
  252. NmiStatus.IochkNmi = 0;
  253. WRITE_PORT_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus));
  254. //
  255. // Number of Square Wave transitions to count.
  256. // at 50ms period, count the number of 25ms
  257. // square wave transitions for a sample reference
  258. // time to against which we measure processor cycle count.
  259. //
  260. NumberOfIntervals = (SampleTime/50) * 2;
  261. //
  262. // Set the timer for counter 0 in binary mode, square wave output
  263. //
  264. TimerControlSetup.BcdMode = 0;
  265. TimerControlSetup.Mode = TM_SQUARE_WAVE;
  266. TimerControlSetup.SelectByte = SB_LSB_THEN_MSB;
  267. TimerControlSetup.SelectCounter = SELECT_COUNTER_2;
  268. //
  269. // Set the counter for a latched read of the status.
  270. // We will poll the PIT for the state of the square
  271. // wave output.
  272. //
  273. TimerControlReadStatus.BcdMode = 0;
  274. TimerControlReadStatus.Mode = (1 << SELECT_COUNTER_2);
  275. TimerControlReadStatus.SelectByte = SB_READ_STATUS_ONLY;
  276. TimerControlReadStatus.SelectCounter = SELECT_READ_BACK;
  277. //
  278. // Write the count value LSB and MSB for a 50ms clock period
  279. //
  280. WRITE_PORT_UCHAR( &controlBase->CommandMode1,
  281. *(PUCHAR)&TimerControlSetup );
  282. WRITE_PORT_UCHAR( &controlBase->SpeakerTone,
  283. TIMER_REF_VALUE & 0xff );
  284. WRITE_PORT_UCHAR( &controlBase->SpeakerTone,
  285. (TIMER_REF_VALUE >> 8) & 0xff );
  286. //
  287. // Enable the speaker counter but disable the SPKR output signal.
  288. //
  289. *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
  290. NmiStatus.SpeakerGate = 1;
  291. NmiStatus.SpeakerData = 0;
  292. // these are MBZ when writing to NMIMISC
  293. NmiStatus.RefreshToggle = 0;
  294. NmiStatus.SpeakerTimer = 0;
  295. NmiStatus.IochkNmi = 0;
  296. WRITE_PORT_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus));
  297. //
  298. // Synchronize with the counter before taking the first
  299. // sample of the Processor Cycle Count (PCC). Since we
  300. // are using the Square Wave Mode, wait until the next
  301. // state change and then observe half a cycle before
  302. // sampling.
  303. //
  304. //
  305. // observe the low transition of the square wave output.
  306. //
  307. do {
  308. *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
  309. } while (NmiStatus.SpeakerTimer != SquareWaveState);
  310. SquareWaveState ^= 1;
  311. //
  312. // observe the next transition of the square wave output and then
  313. // take the first cycle counter sample.
  314. //
  315. do {
  316. *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
  317. } while (NmiStatus.SpeakerTimer != SquareWaveState);
  318. Count1 = __RCC();
  319. //
  320. // Wait for the 500ms time period to pass and then take the
  321. // second sample of the PCC. For a 50ms period, we have to
  322. // observe eight wave transitions (25ms each).
  323. //
  324. do {
  325. SquareWaveState ^= 1;
  326. //
  327. // wait for wave transition
  328. //
  329. do {
  330. *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
  331. } while (NmiStatus.SpeakerTimer != SquareWaveState);
  332. } while (--NumberOfIntervals);
  333. Count2 = __RCC();
  334. //
  335. // Disable the speaker counter.
  336. //
  337. *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
  338. NmiStatus.SpeakerGate = 0;
  339. NmiStatus.SpeakerData = 0;
  340. WRITE_PORT_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus));
  341. //
  342. // Calculate the Hz by the number of processor cycles
  343. // elapsed during 1s.
  344. //
  345. // Hz = PCC/SampleTime * 1000ms/s
  346. // = PCC * (1000/SampleTime)
  347. //
  348. // did the counter wrap? if so add 2^32
  349. if (Count1 > Count2) {
  350. Count2 += (ULONGLONG)(1 << 32);
  351. }
  352. return ((Count2 - Count1)*(((ULONG)1000)/SampleTime));
  353. }
  354. VOID
  355. HalpInitializeProcessorParameters(
  356. VOID
  357. )
  358. /*++
  359. Routine Description:
  360. This routine initalize the performance counter parameters
  361. HalpClockFrequency and HalpClockMegaHertz based on the
  362. estimated CPU speed. A 1s reference time is used for
  363. the estimation.
  364. Arguments:
  365. None.
  366. Return Value:
  367. None.
  368. --*/
  369. {
  370. HalpClockFrequency = HalpQuerySystemFrequency(1000);
  371. HalpClockMegaHertz = (HalpClockFrequency + 500000)/ 1000000;
  372. }
  373. #if 0
  374. VOID
  375. HalpGatherProcessorParameterStats(
  376. VOID
  377. )
  378. /*++
  379. Routine Description:
  380. This routine gathers statistics on the method for
  381. estimating the system frequency.
  382. Arguments:
  383. None.
  384. Return Value:
  385. None.
  386. --*/
  387. {
  388. ULONG Index;
  389. ULONG Hertz[32];
  390. ULONGLONG Mean = 0;
  391. ULONGLONG Variance = 0;
  392. ULONGLONG TempHertz;
  393. //
  394. // take 32 samples of estimated CPU speed,
  395. // calculating the mean in the process.
  396. //
  397. DbgPrint("Sample\tFrequency\tMegaHertz\n\n");
  398. for (Index = 0; Index < 32; Index++) {
  399. Hertz[Index] = HalpQuerySystemFrequency(500);
  400. Mean += Hertz[Index];
  401. DbgPrint(
  402. "%d\t%d\t%d\n",
  403. Index,
  404. Hertz[Index],
  405. (ULONG)((Hertz[Index] + 500000)/1000000)
  406. );
  407. }
  408. //
  409. // calculate the mean
  410. //
  411. Mean /= 32;
  412. //
  413. // calculate the variance
  414. //
  415. for (Index = 0; Index < 32; Index++) {
  416. TempHertz = (Mean > Hertz[Index])?
  417. (Mean - Hertz[Index]) : (Hertz[Index] - Mean);
  418. TempHertz = TempHertz*TempHertz;
  419. Variance += TempHertz;
  420. }
  421. Variance /= 32;
  422. DbgPrint("\nResults\n\n");
  423. DbgPrint(
  424. "Mean = %d\nVariance = %d\nMegaHertz (derived) = %d\n",
  425. Mean,
  426. Variance,
  427. (Mean + 500000)/ 1000000
  428. );
  429. }
  430. #endif