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.

973 lines
17 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. ixcmos.c
  5. Abstract:
  6. Procedures necessary to access CMOS/ECMOS information.
  7. Author:
  8. David Risner (o-ncrdr) 20 Apr 1992
  9. Revision History:
  10. Landy Wang (corollary!landy) 04 Dec 1992
  11. - Move much code from ixclock.asm to here so different HALs
  12. can reuse the common functionality.
  13. Forrest Foltz (forrestf) 24-Oct-2000
  14. Ported ixcmos.asm to ixcmos.c
  15. --*/
  16. #include "halcmn.h"
  17. ULONG HalpHardwareLockFlags;
  18. //
  19. // Module-specific types
  20. //
  21. typedef UCHAR (*READ_CMOS_CHAR)(ULONG Address);
  22. typedef VOID (*WRITE_CMOS_CHAR)(ULONG Address, UCHAR Data);
  23. typedef struct _CMOS_BUS_PARAMETERS {
  24. ULONG MaximumAddress;
  25. READ_CMOS_CHAR ReadFunction;
  26. WRITE_CMOS_CHAR WriteFunction;
  27. } CMOS_BUS_PARAMETERS, *PCMOS_BUS_PARAMETERS;
  28. //
  29. // External data
  30. //
  31. extern KSPIN_LOCK HalpSystemHardwareLock;
  32. //
  33. // Local prototypes
  34. //
  35. UCHAR
  36. HalpCmosReadByte(
  37. ULONG Address
  38. );
  39. VOID
  40. HalpCmosWriteByte(
  41. ULONG Address,
  42. UCHAR Data
  43. );
  44. UCHAR
  45. HalpECmosReadByte(
  46. ULONG Address
  47. );
  48. VOID
  49. HalpECmosWriteByte(
  50. ULONG Address,
  51. UCHAR Data
  52. );
  53. UCHAR
  54. HalpGetCmosCenturyByte (
  55. VOID
  56. );
  57. ULONG
  58. HalpGetSetCmosData (
  59. IN ULONG SourceLocation,
  60. IN ULONG SourceAddress,
  61. IN PVOID ReturnBuffer,
  62. IN ULONG ByteCount,
  63. IN BOOLEAN Write
  64. );
  65. VOID
  66. HalpSetCmosCenturyByte (
  67. UCHAR Century
  68. );
  69. //
  70. // Local data
  71. //
  72. //
  73. // Describes each of the CMOS types
  74. //
  75. CMOS_BUS_PARAMETERS HalpCmosBusParameterTable[] = {
  76. { 0xFF, HalpCmosReadByte, HalpCmosWriteByte },
  77. { 0xFFFF, HalpECmosReadByte, HalpECmosWriteByte }
  78. };
  79. //
  80. // Contains the offset to the CMOS century information
  81. //
  82. ULONG HalpCmosCenturyOffset;
  83. //
  84. // HalpRebootNow is a reboot vector. Set in an MP system to cause any
  85. // processors that might be looping in HalpAcquireCmosSpinLock to transfer
  86. // control to the vector in HalpRebootNow.
  87. //
  88. VOID (*HalpRebootNow)(VOID);
  89. ULONG
  90. HalpGetCmosData (
  91. IN ULONG SourceLocation,
  92. IN ULONG SourceAddress,
  93. IN PVOID ReturnBuffer,
  94. IN ULONG ByteCount
  95. )
  96. /*++
  97. Routine Description:
  98. This routine reads the requested number of bytes from CMOS/ECMOS and
  99. stores the data read into the supplied buffer in system memory. If
  100. the requested data amount exceeds the allowable extent of the source
  101. location, the return data is truncated.
  102. Arguments:
  103. SourceLocation - where data is to be read from CMOS or ECMOS
  104. 0 - CMOS, 1 - ECMOS
  105. SourceAddress - address in CMOS/ECMOS where data is to be transferred
  106. ReturnBuffer - address in system memory for data to transfer
  107. ByteCount - number of bytes to be read
  108. Returns:
  109. Number of byte actually read.
  110. --*/
  111. {
  112. return HalpGetSetCmosData(SourceLocation,
  113. SourceAddress,
  114. ReturnBuffer,
  115. ByteCount,
  116. FALSE);
  117. }
  118. ULONG
  119. HalpSetCmosData (
  120. IN ULONG SourceLocation,
  121. IN ULONG SourceAddress,
  122. IN PVOID ReturnBuffer,
  123. IN ULONG ByteCount
  124. )
  125. /*++
  126. Routine Description:
  127. This routine writes the requested number of bytes to CMOS/ECMOS.
  128. Arguments:
  129. SourceLocation - where data is to be written from CMOS or ECMOS
  130. 0 - CMOS, 1 - ECMOS
  131. SourceAddress - address in CMOS/ECMOS where data is to be transferred
  132. ReturnBuffer - address in system memory for data to transfer
  133. ByteCount - number of bytes to be written
  134. Returns:
  135. Number of byte actually read.
  136. --*/
  137. {
  138. return HalpGetSetCmosData(SourceLocation,
  139. SourceAddress,
  140. ReturnBuffer,
  141. ByteCount,
  142. TRUE);
  143. }
  144. ULONG
  145. HalpGetSetCmosData (
  146. IN ULONG SourceLocation,
  147. IN ULONG RangeStart,
  148. IN PVOID Buffer,
  149. IN ULONG ByteCount,
  150. IN BOOLEAN Write
  151. )
  152. /*++
  153. Routine Description:
  154. This routine reads the requested number of bytes from CMOS/ECMOS and
  155. stores the data read into the supplied buffer in system memory. If
  156. the requested data amount exceeds the allowable extent of the source
  157. location, the return data is truncated.
  158. Arguments:
  159. SourceLocation - where data is to be read from CMOS or ECMOS
  160. 0 - CMOS, 1 - ECMOS
  161. RangeStart - address in CMOS/ECMOS where data is to be transferred
  162. Buffer - address in system memory for data to transfer
  163. ByteCount - number of bytes to be transferred
  164. Write - Indicates whether the operation is a read or a write
  165. Returns:
  166. Number of byte actually transferred
  167. --*/
  168. {
  169. ULONG address;
  170. PCHAR buffer;
  171. ULONG last;
  172. PCMOS_BUS_PARAMETERS cmosParameters;
  173. //
  174. // Validate the "bus type" and get a pointer to the parameters
  175. // for the corresponding CMOS "bus".
  176. //
  177. if (SourceLocation != 0 && SourceLocation != 1) {
  178. return 0;
  179. }
  180. cmosParameters = &HalpCmosBusParameterTable[SourceLocation];
  181. //
  182. // Limit the range of bytes to that which the cmos bus can accomodate.
  183. //
  184. address = RangeStart;
  185. buffer = Buffer;
  186. last = address + ByteCount - 1;
  187. if (last > cmosParameters->MaximumAddress) {
  188. last = cmosParameters->MaximumAddress;
  189. }
  190. //
  191. // Take the cmos spin lock, perform the transfer, and release the lock.
  192. //
  193. HalpAcquireCmosSpinLock();
  194. while (address <= last) {
  195. if (Write == FALSE) {
  196. *buffer = cmosParameters->ReadFunction(address);
  197. } else {
  198. cmosParameters->WriteFunction(address,*buffer);
  199. }
  200. address += 1;
  201. buffer += 1;
  202. }
  203. HalpReleaseCmosSpinLock();
  204. //
  205. // Calculate and return the number of bytes trasferred.
  206. //
  207. return last - RangeStart;
  208. }
  209. UCHAR
  210. HalpCmosReadByte(
  211. ULONG Address
  212. )
  213. /*++
  214. Routine Description:
  215. This routine reads a single byte from cmos.
  216. Arguments:
  217. Address - The CMOS address from which to retrieve the byte.
  218. Returns:
  219. The byte that was read.
  220. --*/
  221. {
  222. return CMOS_READ((UCHAR)Address);
  223. }
  224. VOID
  225. HalpCmosWriteByte(
  226. ULONG Address,
  227. UCHAR Data
  228. )
  229. /*++
  230. Routine Description:
  231. This routine writes a single byte to cmos.
  232. Arguments:
  233. Address - The CMOS address at which to write the byte
  234. Data - The byte to write
  235. Returns:
  236. Nothing
  237. --*/
  238. {
  239. CMOS_WRITE((UCHAR)Address,Data);
  240. }
  241. UCHAR
  242. HalpECmosReadByte(
  243. ULONG Address
  244. )
  245. /*++
  246. Routine Description:
  247. This routine reads a single byte from extended cmos (ECMOS).
  248. Arguments:
  249. Address - The CMOS address from which to retrieve the byte.
  250. Returns:
  251. The byte that was read.
  252. --*/
  253. {
  254. UCHAR data;
  255. WRITE_PORT_USHORT_PAIR (ECMOS_ADDRESS_PORT_LSB,
  256. ECMOS_ADDRESS_PORT_MSB,
  257. (USHORT)Address);
  258. IO_DELAY();
  259. data = READ_PORT_UCHAR(ECMOS_DATA_PORT);
  260. IO_DELAY();
  261. return data;
  262. }
  263. VOID
  264. HalpECmosWriteByte(
  265. ULONG Address,
  266. UCHAR Data
  267. )
  268. /*++
  269. Routine Description:
  270. This routine writes a single byte to extended cmos (ECMOS).
  271. Arguments:
  272. Address - The CMOS address at which to write the byte
  273. Data - The byte to write
  274. Returns:
  275. Nothing
  276. --*/
  277. {
  278. WRITE_PORT_USHORT_PAIR (ECMOS_ADDRESS_PORT_LSB,
  279. ECMOS_ADDRESS_PORT_MSB,
  280. (USHORT)Address);
  281. IO_DELAY();
  282. WRITE_PORT_UCHAR(ECMOS_DATA_PORT,Data);
  283. IO_DELAY();
  284. }
  285. VOID
  286. HalpReadCmosTime(
  287. PTIME_FIELDS TimeFields
  288. )
  289. /*++
  290. Routine Description:
  291. This routine reads current time from CMOS memory and stores it
  292. in the TIME_FIELDS structure passed in by caller.
  293. Arguments:
  294. TimeFields - A pointer to the TIME_FIELDS structure.
  295. Return Value:
  296. None.
  297. --*/
  298. {
  299. USHORT year;
  300. HalpAcquireCmosSpinLockAndWait();
  301. //
  302. // The RTC is only accurate to within one second. So add a
  303. // half a second so that we are closer, on average, to the right
  304. // answer.
  305. //
  306. TimeFields->Milliseconds = 500;
  307. TimeFields->Second = CMOS_READ_BCD(RTC_OFFSET_SECOND);
  308. TimeFields->Minute = CMOS_READ_BCD(RTC_OFFSET_MINUTE);
  309. TimeFields->Hour = CMOS_READ_BCD(RTC_OFFSET_HOUR);
  310. TimeFields->Weekday = CMOS_READ_BCD(RTC_OFFSET_DAY_OF_WEEK);
  311. TimeFields->Day = CMOS_READ_BCD(RTC_OFFSET_DATE_OF_MONTH);
  312. TimeFields->Month = CMOS_READ_BCD(RTC_OFFSET_MONTH);
  313. year = BCD_TO_BIN(HalpGetCmosCenturyByte());
  314. year = year * 100 + CMOS_READ_BCD(RTC_OFFSET_YEAR);
  315. if (year >= 1900 && year < 1920) {
  316. //
  317. // Compensate for the century field
  318. //
  319. year += 100;
  320. }
  321. TimeFields->Year = year;
  322. HalpReleaseCmosSpinLock();
  323. }
  324. VOID
  325. HalpWriteCmosTime (
  326. PTIME_FIELDS TimeFields
  327. )
  328. /*++
  329. Routine Description:
  330. This routine writes current time from TIME_FIELDS structure
  331. to CMOS memory.
  332. Arguments:
  333. TimeFields - A pointer to the TIME_FIELDS structure.
  334. Return Value:
  335. None.
  336. --*/
  337. {
  338. ULONG year;
  339. HalpAcquireCmosSpinLockAndWait();
  340. CMOS_WRITE_BCD(RTC_OFFSET_SECOND,(UCHAR)TimeFields->Second);
  341. CMOS_WRITE_BCD(RTC_OFFSET_MINUTE,(UCHAR)TimeFields->Minute);
  342. CMOS_WRITE_BCD(RTC_OFFSET_HOUR,(UCHAR)TimeFields->Hour);
  343. CMOS_WRITE_BCD(RTC_OFFSET_DAY_OF_WEEK,(UCHAR)TimeFields->Weekday);
  344. CMOS_WRITE_BCD(RTC_OFFSET_DATE_OF_MONTH,(UCHAR)TimeFields->Day);
  345. CMOS_WRITE_BCD(RTC_OFFSET_MONTH,(UCHAR)TimeFields->Month);
  346. year = TimeFields->Year;
  347. if (year > 9999) {
  348. year = 9999;
  349. }
  350. HalpSetCmosCenturyByte(BIN_TO_BCD((UCHAR)(year / 100)));
  351. CMOS_WRITE_BCD(RTC_OFFSET_YEAR,(UCHAR)(year % 100));
  352. HalpReleaseCmosSpinLock();
  353. }
  354. VOID
  355. HalpAcquireCmosSpinLockAndWait (
  356. VOID
  357. )
  358. /*++
  359. Routine Description:
  360. This routine acquires the CMOS spinlock, then waits for the CMOS
  361. BUSY flag to be clear.
  362. Arguments:
  363. None.
  364. Return Value:
  365. None.
  366. --*/
  367. {
  368. ULONG count;
  369. ULONG value;
  370. //
  371. // Acquire the cmos spinlock and wait until it is not busy. While
  372. // waiting, periodically release and re-acquire the spinlock.
  373. //
  374. HalpAcquireCmosSpinLock();
  375. count = 0;
  376. while (TRUE) {
  377. value = CMOS_READ(CMOS_STATUS_A);
  378. if ((value & CMOS_STATUS_BUSY) == 0) {
  379. return;
  380. }
  381. count += 1;
  382. if (count == 100) {
  383. count = 0;
  384. HalpReleaseCmosSpinLock();
  385. HalpAcquireCmosSpinLock();
  386. }
  387. }
  388. }
  389. VOID
  390. HalpReleaseCmosSpinLock (
  391. VOID
  392. )
  393. /*++
  394. Routine Description:
  395. This routine acquires the spin lock used to protect access to various
  396. pieces of hardware.
  397. Arguments:
  398. None
  399. Returns:
  400. Nothing
  401. --*/
  402. {
  403. ULONG flags;
  404. flags = HalpHardwareLockFlags;
  405. #if !defined(NT_UP)
  406. KeReleaseSpinLockFromDpcLevel(&HalpSystemHardwareLock);
  407. #endif
  408. HalpRestoreInterrupts(flags);
  409. }
  410. VOID
  411. HalpAcquireCmosSpinLock (
  412. VOID
  413. )
  414. /*++
  415. Routine Description:
  416. This routine acquires the spin lock used to protect access to various
  417. pieces of hardware.
  418. Arguments:
  419. None
  420. Returns:
  421. Nothing
  422. --*/
  423. {
  424. BOOLEAN acquired;
  425. ULONG flags;
  426. KIRQL oldIrql;
  427. #if defined(NT_UP)
  428. HalpHardwareLockFlags = HalpDisableInterrupts();
  429. #else
  430. while (TRUE) {
  431. flags = HalpDisableInterrupts();
  432. acquired = KeTryToAcquireSpinLockAtDpcLevel(&HalpSystemHardwareLock);
  433. if (acquired != FALSE) {
  434. break;
  435. }
  436. HalpRestoreInterrupts(flags);
  437. while (KeTestSpinLock(&HalpSystemHardwareLock) == FALSE) {
  438. if (HalpRebootNow != NULL) {
  439. HalpRebootNow();
  440. }
  441. PAUSE_PROCESSOR;
  442. }
  443. }
  444. HalpHardwareLockFlags = flags;
  445. #endif
  446. }
  447. VOID
  448. HalpAcquireSystemHardwareSpinLock (
  449. VOID
  450. )
  451. /*++
  452. Routine Description:
  453. This routine acquires the spin lock used to protect access to various
  454. pieces of hardware. It is a synonym of HalpAcquireCmosSpinLock().
  455. Arguments:
  456. None
  457. Returns:
  458. Nothing
  459. --*/
  460. {
  461. HalpAcquireCmosSpinLock();
  462. }
  463. VOID
  464. HalpReleaseSystemHardwareSpinLock (
  465. VOID
  466. )
  467. /*++
  468. Routine Description:
  469. This routine releases the spin lock used to protect access to various
  470. pieces of hardware. It is a synonym of HalpReleaseCmosSpinLock().
  471. Arguments:
  472. None
  473. Returns:
  474. Nothing
  475. --*/
  476. {
  477. HalpReleaseCmosSpinLock();
  478. }
  479. UCHAR
  480. HalpGetCmosCenturyByte (
  481. VOID
  482. )
  483. /*++
  484. Routine Description:
  485. This routine retrieves the century byte from the CMOS.
  486. N.B. The cmos spinlock must be acquired before calling this function.
  487. Arguments:
  488. None
  489. Returns:
  490. The century byte.
  491. --*/
  492. {
  493. UCHAR value;
  494. UCHAR oldStatus;
  495. UCHAR centuryByte;
  496. //
  497. // Make sure the century offset is initialized
  498. //
  499. ASSERT(HalpCmosCenturyOffset != 0);
  500. if ((HalpCmosCenturyOffset & CMOS_BANK_1) != 0) {
  501. //
  502. // Perform a bank 1 read
  503. //
  504. oldStatus = CMOS_READ(CMOS_STATUS_A);
  505. value = oldStatus | CMOS_STATUS_BANK1;
  506. CMOS_WRITE(CMOS_STATUS_A,value);
  507. centuryByte = CMOS_READ((UCHAR)HalpCmosCenturyOffset);
  508. CMOS_WRITE(CMOS_STATUS_A,oldStatus);
  509. } else {
  510. centuryByte = CMOS_READ((UCHAR)HalpCmosCenturyOffset);
  511. }
  512. return centuryByte;
  513. }
  514. VOID
  515. HalpSetCmosCenturyByte (
  516. UCHAR Century
  517. )
  518. /*++
  519. Routine Description:
  520. This routine sets the century byte in the CMOS.
  521. N.B. The cmos spinlock must be acquired before calling this function.
  522. Arguments:
  523. Century - The century byte to set
  524. Returns:
  525. Nothing
  526. --*/
  527. {
  528. UCHAR value;
  529. UCHAR oldStatus;
  530. //
  531. // Make sure the century offset is initialized
  532. //
  533. ASSERT(HalpCmosCenturyOffset != 0);
  534. if ((HalpCmosCenturyOffset & CMOS_BANK_1) != 0) {
  535. //
  536. // Perform a bank 1 write
  537. //
  538. oldStatus = CMOS_READ(CMOS_STATUS_A);
  539. value = oldStatus | CMOS_STATUS_BANK1;
  540. CMOS_WRITE(CMOS_STATUS_A,value);
  541. CMOS_WRITE((UCHAR)HalpCmosCenturyOffset,Century);
  542. CMOS_WRITE(CMOS_STATUS_A,oldStatus);
  543. } else {
  544. CMOS_WRITE((UCHAR)HalpCmosCenturyOffset,Century);
  545. }
  546. }
  547. VOID
  548. HalpFlushTLB (
  549. VOID
  550. )
  551. /*++
  552. Routine Description:
  553. Flushes the current TLB.
  554. Arguments:
  555. None.
  556. Return Value:
  557. None.
  558. --*/
  559. {
  560. ULONG flags;
  561. PKPCR pcr;
  562. PKPRCB prcb;
  563. ULONG64 cr3;
  564. ULONG64 cr4;
  565. ULONG64 oldCr4;
  566. flags = HalpDisableInterrupts();
  567. cr3 = ReadCR3();
  568. pcr = KeGetPcr();
  569. prcb = pcr->CurrentPrcb;
  570. //
  571. // Note: the original code (ixcmos.asm) had differing behavior based
  572. // on whether this was CPU 0. That behavior is mimicked here.
  573. // It would be good to find out why this is done.
  574. //
  575. if (prcb->Number == 0) {
  576. WriteCR3(cr3);
  577. } else {
  578. cr4 = ReadCR4();
  579. WriteCR4(cr4 & ~CR4_PGE);
  580. WriteCR3(cr3);
  581. WriteCR4(cr4);
  582. }
  583. HalpRestoreInterrupts(flags);
  584. }
  585. VOID
  586. HalpCpuID (
  587. IN ULONG Function,
  588. OUT PULONG Eax,
  589. OUT PULONG Ebx,
  590. OUT PULONG Ecx,
  591. OUT PULONG Edx
  592. )
  593. /*++
  594. Routine Description:
  595. This function executes a cpu id and returns the result as found in
  596. registers eax, ebx, ecx and edx.
  597. Arguments:
  598. Function - supplies the CPUID function to execute.
  599. Eax - supplies a pointer to the storage to contain the contents of eax.
  600. Eax - supplies a pointer to the storage to contain the contents of ebx.
  601. Eax - supplies a pointer to the storage to contain the contents of ecx.
  602. Eax - supplies a pointer to the storage to contain the contents of edx.
  603. Return Value:
  604. None.
  605. --*/
  606. {
  607. CPU_INFO cpuInfo;
  608. KiCpuId (Function,&cpuInfo);
  609. *Eax = cpuInfo.Eax;
  610. *Ebx = cpuInfo.Ebx;
  611. *Ecx = cpuInfo.Ecx;
  612. *Edx = cpuInfo.Edx;
  613. }
  614. UCHAR
  615. CMOS_READ_BCD (
  616. UCHAR Address
  617. )
  618. /*++
  619. Routine Description:
  620. This function reads a CMOS byte as a two-digit packed BCD value and
  621. returns its binary representation.
  622. Arguments:
  623. Address - supplies the CMOS address of the BCD value to retrieve.
  624. Return Value:
  625. Returns the binary representation of the BCD value residing in CMOS
  626. at Address.
  627. --*/
  628. {
  629. UCHAR value;
  630. value = CMOS_READ(Address);
  631. return BCD_TO_BIN(value);
  632. }
  633. VOID
  634. CMOS_WRITE_BCD (
  635. UCHAR Address,
  636. UCHAR Value
  637. )
  638. /*++
  639. Routine Description:
  640. This function writes a CMOS byte as a two-digit packed BCD value.
  641. Arguments:
  642. Address - supplies the CMOS address of the BCD value to write.
  643. Value - supplies the binary representation of the value to write in
  644. CMOS.
  645. Return Value:
  646. None.
  647. --*/
  648. {
  649. UCHAR value;
  650. ASSERT(Value <= 99);
  651. value = BIN_TO_BCD(Value);
  652. CMOS_WRITE(Address,value);
  653. }