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.

858 lines
22 KiB

  1. /*++
  2. Copyright (c) 1990-2000 Microsoft Corporation
  3. Module Name:
  4. bootvid.c
  5. Abstract:
  6. This is the device independent portion of the graphical boot dll.
  7. Author:
  8. Erick Smith (ericks) Oct. 1997
  9. Environment:
  10. kernel mode only
  11. Revision History:
  12. --*/
  13. #include <nthal.h>
  14. #include <hal.h>
  15. #include "cmdcnst.h"
  16. #include <bootvid.h>
  17. #include "vga.h"
  18. extern USHORT VGA_640x480[];
  19. extern USHORT AT_Initialization[];
  20. extern int curr_x;
  21. extern int curr_y;
  22. PUCHAR VgaBase;
  23. PUCHAR VgaRegisterBase;
  24. NTSTATUS
  25. InitBusCallback(
  26. IN PVOID Context,
  27. IN PUNICODE_STRING PathName,
  28. IN INTERFACE_TYPE BusType,
  29. IN ULONG BusNumber,
  30. IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
  31. IN CONFIGURATION_TYPE ControllerType,
  32. IN ULONG ControllerNumber,
  33. IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
  34. IN CONFIGURATION_TYPE PeripheralType,
  35. IN ULONG PeripheralNumber,
  36. IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
  37. )
  38. {
  39. return STATUS_SUCCESS;
  40. }
  41. BOOLEAN
  42. VidInitialize(
  43. BOOLEAN SetMode
  44. )
  45. /*++
  46. Routine Description:
  47. This routine checks for the existance of a VGA chip, and initializes
  48. it.
  49. Arguments:
  50. SetMode - Set to true if you want this routine to initialize mode.
  51. Return Value:
  52. TRUE - if the boot driver found vga and initialized correctly,
  53. FALSE - otherwise.
  54. --*/
  55. {
  56. PHYSICAL_ADDRESS IoAddress;
  57. PHYSICAL_ADDRESS MemoryAddress;
  58. ULONG AddressSpace;
  59. PHYSICAL_ADDRESS TranslatedAddress;
  60. PUCHAR mappedAddress;
  61. ULONG_PTR TranslateContext;
  62. //
  63. // Saftey check. Allows migration from old HalDisplayString
  64. // support to bootvid, if the HAL didn't supply the routine
  65. //
  66. // HALPDISPATCH->HalFindBusAddressTranslation
  67. //
  68. // this routine cannot succeed.
  69. //
  70. if (!HALPDISPATCH->HalFindBusAddressTranslation) {
  71. return FALSE;
  72. }
  73. //
  74. // Start search with "no previous" context.
  75. //
  76. TranslateContext = 0;
  77. //
  78. // Set up the addresses we need to translate.
  79. //
  80. IoAddress.LowPart = 0x0;
  81. IoAddress.HighPart = 0;
  82. MemoryAddress.LowPart = 0xa0000;
  83. MemoryAddress.HighPart = 0;
  84. //
  85. // While there are more busses to examine try to map the VGA
  86. // registers.
  87. //
  88. while (TRUE) {
  89. AddressSpace = 1; // we are requesting IO space.
  90. if (!HALPDISPATCH->HalFindBusAddressTranslation(
  91. IoAddress,
  92. &AddressSpace,
  93. &TranslatedAddress,
  94. &TranslateContext,
  95. TRUE)) {
  96. //
  97. // Failed to find a bus with the VGA device on it.
  98. //
  99. return FALSE;
  100. }
  101. //
  102. // We were able to translate the address. Now, map the
  103. // translated address.
  104. //
  105. if (AddressSpace & 0x1) {
  106. VgaRegisterBase = (PUCHAR)(DWORD_PTR) TranslatedAddress.QuadPart;
  107. } else {
  108. VgaRegisterBase = (PUCHAR) MmMapIoSpace(TranslatedAddress,
  109. 0x400,
  110. FALSE);
  111. }
  112. //
  113. // Now that we have the VGA I/O ports, check to see if a VGA
  114. // device is present.
  115. //
  116. if (!VgaIsPresent()) {
  117. if (!(AddressSpace & 0x1)) {
  118. MmUnmapIoSpace(VgaRegisterBase, 0x400);
  119. }
  120. //
  121. // Continue on next bus that has this IO address.
  122. //
  123. continue;
  124. }
  125. //
  126. //
  127. // Map the frame buffer.
  128. //
  129. AddressSpace = 0; // we are requesting memory not IO.
  130. //
  131. // Map the video memory so that we can write to the screen after
  132. // setting a mode.
  133. //
  134. // Note: We assume the memory will be on the same bus as the IO.
  135. //
  136. if (HALPDISPATCH->HalFindBusAddressTranslation(
  137. MemoryAddress,
  138. &AddressSpace,
  139. &TranslatedAddress,
  140. &TranslateContext,
  141. FALSE)) {
  142. //
  143. // We were able to translate the address. Now, map the
  144. // translated address.
  145. //
  146. if (AddressSpace & 0x1) {
  147. VgaBase = (PUCHAR)(DWORD_PTR) TranslatedAddress.QuadPart;
  148. } else {
  149. VgaBase = (PUCHAR) MmMapIoSpace(TranslatedAddress,
  150. 0x20000, // 128k
  151. FALSE);
  152. }
  153. //
  154. // Life is good.
  155. //
  156. break;
  157. }
  158. }
  159. //
  160. // Initialize the display
  161. //
  162. if (SetMode) {
  163. curr_x = curr_y = 0;
  164. HalResetDisplay();
  165. VgaInterpretCmdStream(AT_Initialization);
  166. }
  167. return TRUE;
  168. }
  169. VOID
  170. VidResetDisplay(
  171. BOOLEAN SetMode
  172. )
  173. {
  174. curr_x = curr_y = 0;
  175. if (SetMode) {
  176. HalResetDisplay();
  177. }
  178. VgaInterpretCmdStream(AT_Initialization);
  179. InitializePalette();
  180. VidSolidColorFill(0,0,639,479,0);
  181. }
  182. BOOLEAN
  183. VgaInterpretCmdStream(
  184. PUSHORT pusCmdStream
  185. )
  186. /*++
  187. Routine Description:
  188. Interprets the appropriate command array to set up VGA registers for the
  189. requested mode. Typically used to set the VGA into a particular mode by
  190. programming all of the registers
  191. Arguments:
  192. pusCmdStream - array of commands to be interpreted.
  193. Return Value:
  194. The status of the operation (can only fail on a bad command); TRUE for
  195. success, FALSE for failure.
  196. --*/
  197. {
  198. ULONG ulCmd;
  199. ULONG_PTR ulPort;
  200. UCHAR jValue;
  201. USHORT usValue;
  202. ULONG culCount;
  203. ULONG ulIndex;
  204. ULONG_PTR ulBase;
  205. if (pusCmdStream == NULL) {
  206. //KdPrint(("VgaInterpretCmdStream: pusCmdStream == NULL\n"));
  207. return TRUE;
  208. }
  209. ulBase = (ULONG_PTR) VgaRegisterBase;
  210. //
  211. // Now set the adapter to the desired mode.
  212. //
  213. while ((ulCmd = *pusCmdStream++) != EOD) {
  214. //
  215. // Determine major command type
  216. //
  217. switch (ulCmd & 0xF0) {
  218. //
  219. // Basic input/output command
  220. //
  221. case INOUT:
  222. //
  223. // Determine type of inout instruction
  224. //
  225. if (!(ulCmd & IO)) {
  226. //
  227. // Out instruction. Single or multiple outs?
  228. //
  229. if (!(ulCmd & MULTI)) {
  230. //
  231. // Single out. Byte or word out?
  232. //
  233. if (!(ulCmd & BW)) {
  234. //
  235. // Single byte out
  236. //
  237. ulPort = *pusCmdStream++;
  238. jValue = (UCHAR) *pusCmdStream++;
  239. WRITE_PORT_UCHAR((PUCHAR)(ulBase+ulPort),
  240. jValue);
  241. } else {
  242. //
  243. // Single word out
  244. //
  245. ulPort = *pusCmdStream++;
  246. usValue = *pusCmdStream++;
  247. WRITE_PORT_USHORT((PUSHORT)(ulBase+ulPort),
  248. usValue);
  249. }
  250. } else {
  251. //
  252. // Output a string of values
  253. // Byte or word outs?
  254. //
  255. if (!(ulCmd & BW)) {
  256. //
  257. // String byte outs. Do in a loop; can't use
  258. // VideoPortWritePortBufferUchar because the data
  259. // is in USHORT form
  260. //
  261. ulPort = ulBase + *pusCmdStream++;
  262. culCount = *pusCmdStream++;
  263. while (culCount--) {
  264. jValue = (UCHAR) *pusCmdStream++;
  265. WRITE_PORT_UCHAR((PUCHAR)ulPort,
  266. jValue);
  267. }
  268. } else {
  269. //
  270. // String word outs
  271. //
  272. ulPort = *pusCmdStream++;
  273. culCount = *pusCmdStream++;
  274. WRITE_PORT_BUFFER_USHORT((PUSHORT)
  275. (ulBase + ulPort), pusCmdStream, culCount);
  276. pusCmdStream += culCount;
  277. }
  278. }
  279. } else {
  280. // In instruction
  281. //
  282. // Currently, string in instructions aren't supported; all
  283. // in instructions are handled as single-byte ins
  284. //
  285. // Byte or word in?
  286. //
  287. if (!(ulCmd & BW)) {
  288. //
  289. // Single byte in
  290. //
  291. ulPort = *pusCmdStream++;
  292. jValue = READ_PORT_UCHAR((PUCHAR)ulBase+ulPort);
  293. } else {
  294. //
  295. // Single word in
  296. //
  297. ulPort = *pusCmdStream++;
  298. usValue = READ_PORT_USHORT((PUSHORT)
  299. (ulBase+ulPort));
  300. }
  301. }
  302. break;
  303. //
  304. // Higher-level input/output commands
  305. //
  306. case METAOUT:
  307. //
  308. // Determine type of metaout command, based on minor
  309. // command field
  310. //
  311. switch (ulCmd & 0x0F) {
  312. //
  313. // Indexed outs
  314. //
  315. case INDXOUT:
  316. ulPort = ulBase + *pusCmdStream++;
  317. culCount = *pusCmdStream++;
  318. ulIndex = *pusCmdStream++;
  319. while (culCount--) {
  320. usValue = (USHORT) (ulIndex +
  321. (((ULONG)(*pusCmdStream++)) << 8));
  322. WRITE_PORT_USHORT((PUSHORT)ulPort, usValue);
  323. ulIndex++;
  324. }
  325. break;
  326. //
  327. // Masked out (read, AND, XOR, write)
  328. //
  329. case MASKOUT:
  330. ulPort = *pusCmdStream++;
  331. jValue = READ_PORT_UCHAR((PUCHAR)ulBase+ulPort);
  332. jValue &= *pusCmdStream++;
  333. jValue ^= *pusCmdStream++;
  334. WRITE_PORT_UCHAR((PUCHAR)ulBase + ulPort,
  335. jValue);
  336. break;
  337. //
  338. // Attribute Controller out
  339. //
  340. case ATCOUT:
  341. ulPort = ulBase + *pusCmdStream++;
  342. culCount = *pusCmdStream++;
  343. ulIndex = *pusCmdStream++;
  344. while (culCount--) {
  345. // Write Attribute Controller index
  346. WRITE_PORT_UCHAR((PUCHAR)ulPort,
  347. (UCHAR)ulIndex);
  348. // Write Attribute Controller data
  349. jValue = (UCHAR) *pusCmdStream++;
  350. WRITE_PORT_UCHAR((PUCHAR)ulPort, jValue);
  351. ulIndex++;
  352. }
  353. break;
  354. //
  355. // None of the above; error
  356. //
  357. default:
  358. return FALSE;
  359. }
  360. break;
  361. //
  362. // NOP
  363. //
  364. case NCMD:
  365. break;
  366. //
  367. // Unknown command; error
  368. //
  369. default:
  370. return FALSE;
  371. }
  372. }
  373. return TRUE;
  374. } // end VgaInterpretCmdStream()
  375. BOOLEAN
  376. VgaIsPresent(
  377. VOID
  378. )
  379. /*++
  380. Routine Description:
  381. This routine returns TRUE if a VGA is present. Determining whether a VGA
  382. is present is a two-step process. First, this routine walks bits through
  383. the Bit Mask register, to establish that there are readable indexed
  384. registers (EGAs normally don't have readable registers, and other adapters
  385. are unlikely to have indexed registers). This test is done first because
  386. it's a non-destructive EGA rejection test (correctly rejects EGAs, but
  387. doesn't potentially mess up the screen or the accessibility of display
  388. memory). Normally, this would be an adequate test, but some EGAs have
  389. readable registers, so next, we check for the existence of the Chain4 bit
  390. in the Memory Mode register; this bit doesn't exist in EGAs. It's
  391. conceivable that there are EGAs with readable registers and a register bit
  392. where Chain4 is stored, although I don't know of any; if a better test yet
  393. is needed, memory could be written to in Chain4 mode, and then examined
  394. plane by plane in non-Chain4 mode to make sure the Chain4 bit did what it's
  395. supposed to do. However, the current test should be adequate to eliminate
  396. just about all EGAs, and 100% of everything else.
  397. If this function fails to find a VGA, it attempts to undo any damage it
  398. may have inadvertently done while testing. The underlying assumption for
  399. the damage control is that if there's any non-VGA adapter at the tested
  400. ports, it's an EGA or an enhanced EGA, because: a) I don't know of any
  401. other adapters that use 3C4/5 or 3CE/F, and b), if there are other
  402. adapters, I certainly don't know how to restore their original states. So
  403. all error recovery is oriented toward putting an EGA back in a writable
  404. state, so that error messages are visible. The EGA's state on entry is
  405. assumed to be text mode, so the Memory Mode register is restored to the
  406. default state for text mode.
  407. If a VGA is found, the VGA is returned to its original state after
  408. testing is finished.
  409. Arguments:
  410. None.
  411. Return Value:
  412. TRUE if a VGA is present, FALSE if not.
  413. --*/
  414. {
  415. UCHAR originalGCAddr;
  416. UCHAR originalSCAddr;
  417. UCHAR originalBitMask;
  418. UCHAR originalReadMap;
  419. UCHAR originalMemoryMode;
  420. UCHAR testMask;
  421. BOOLEAN returnStatus;
  422. //
  423. // Remember the original state of the Graphics Controller Address register.
  424. //
  425. originalGCAddr = READ_PORT_UCHAR(VgaRegisterBase +
  426. GRAPH_ADDRESS_PORT);
  427. //
  428. // Write the Read Map register with a known state so we can verify
  429. // that it isn't changed after we fool with the Bit Mask. This ensures
  430. // that we're dealing with indexed registers, since both the Read Map and
  431. // the Bit Mask are addressed at GRAPH_DATA_PORT.
  432. //
  433. WRITE_PORT_UCHAR(VgaRegisterBase +
  434. GRAPH_ADDRESS_PORT, IND_READ_MAP);
  435. //
  436. // If we can't read back the Graphics Address register setting we just
  437. // performed, it's not readable and this isn't a VGA.
  438. //
  439. if ((READ_PORT_UCHAR(VgaRegisterBase +
  440. GRAPH_ADDRESS_PORT) & GRAPH_ADDR_MASK) != IND_READ_MAP) {
  441. return FALSE;
  442. }
  443. //
  444. // Set the Read Map register to a known state.
  445. //
  446. originalReadMap = READ_PORT_UCHAR(VgaRegisterBase +
  447. GRAPH_DATA_PORT);
  448. WRITE_PORT_UCHAR(VgaRegisterBase +
  449. GRAPH_DATA_PORT, READ_MAP_TEST_SETTING);
  450. if (READ_PORT_UCHAR(VgaRegisterBase +
  451. GRAPH_DATA_PORT) != READ_MAP_TEST_SETTING) {
  452. //
  453. // The Read Map setting we just performed can't be read back; not a
  454. // VGA. Restore the default Read Map state.
  455. //
  456. WRITE_PORT_UCHAR(VgaRegisterBase +
  457. GRAPH_DATA_PORT, READ_MAP_DEFAULT);
  458. return FALSE;
  459. }
  460. //
  461. // Remember the original setting of the Bit Mask register.
  462. //
  463. WRITE_PORT_UCHAR(VgaRegisterBase +
  464. GRAPH_ADDRESS_PORT, IND_BIT_MASK);
  465. if ((READ_PORT_UCHAR(VgaRegisterBase +
  466. GRAPH_ADDRESS_PORT) & GRAPH_ADDR_MASK) != IND_BIT_MASK) {
  467. //
  468. // The Graphics Address register setting we just made can't be read
  469. // back; not a VGA. Restore the default Read Map state.
  470. //
  471. WRITE_PORT_UCHAR(VgaRegisterBase +
  472. GRAPH_ADDRESS_PORT, IND_READ_MAP);
  473. WRITE_PORT_UCHAR(VgaRegisterBase +
  474. GRAPH_DATA_PORT, READ_MAP_DEFAULT);
  475. return FALSE;
  476. }
  477. originalBitMask = READ_PORT_UCHAR(VgaRegisterBase +
  478. GRAPH_DATA_PORT);
  479. //
  480. // Set up the initial test mask we'll write to and read from the Bit Mask.
  481. //
  482. testMask = 0xBB;
  483. do {
  484. //
  485. // Write the test mask to the Bit Mask.
  486. //
  487. WRITE_PORT_UCHAR(VgaRegisterBase +
  488. GRAPH_DATA_PORT, testMask);
  489. //
  490. // Make sure the Bit Mask remembered the value.
  491. //
  492. if (READ_PORT_UCHAR(VgaRegisterBase +
  493. GRAPH_DATA_PORT) != testMask) {
  494. //
  495. // The Bit Mask is not properly writable and readable; not a VGA.
  496. // Restore the Bit Mask and Read Map to their default states.
  497. //
  498. WRITE_PORT_UCHAR(VgaRegisterBase +
  499. GRAPH_DATA_PORT, BIT_MASK_DEFAULT);
  500. WRITE_PORT_UCHAR(VgaRegisterBase +
  501. GRAPH_ADDRESS_PORT, IND_READ_MAP);
  502. WRITE_PORT_UCHAR(VgaRegisterBase +
  503. GRAPH_DATA_PORT, READ_MAP_DEFAULT);
  504. return FALSE;
  505. }
  506. //
  507. // Cycle the mask for next time.
  508. //
  509. testMask >>= 1;
  510. } while (testMask != 0);
  511. //
  512. // There's something readable at GRAPH_DATA_PORT; now switch back and
  513. // make sure that the Read Map register hasn't changed, to verify that
  514. // we're dealing with indexed registers.
  515. //
  516. WRITE_PORT_UCHAR(VgaRegisterBase +
  517. GRAPH_ADDRESS_PORT, IND_READ_MAP);
  518. if (READ_PORT_UCHAR(VgaRegisterBase +
  519. GRAPH_DATA_PORT) != READ_MAP_TEST_SETTING) {
  520. //
  521. // The Read Map is not properly writable and readable; not a VGA.
  522. // Restore the Bit Mask and Read Map to their default states, in case
  523. // this is an EGA, so subsequent writes to the screen aren't garbled.
  524. //
  525. WRITE_PORT_UCHAR(VgaRegisterBase +
  526. GRAPH_DATA_PORT, READ_MAP_DEFAULT);
  527. WRITE_PORT_UCHAR(VgaRegisterBase +
  528. GRAPH_ADDRESS_PORT, IND_BIT_MASK);
  529. WRITE_PORT_UCHAR(VgaRegisterBase +
  530. GRAPH_DATA_PORT, BIT_MASK_DEFAULT);
  531. return FALSE;
  532. }
  533. //
  534. // We've pretty surely verified the existence of the Bit Mask register.
  535. // Put the Graphics Controller back to the original state.
  536. //
  537. WRITE_PORT_UCHAR(VgaRegisterBase +
  538. GRAPH_DATA_PORT, originalReadMap);
  539. WRITE_PORT_UCHAR(VgaRegisterBase +
  540. GRAPH_ADDRESS_PORT, IND_BIT_MASK);
  541. WRITE_PORT_UCHAR(VgaRegisterBase +
  542. GRAPH_DATA_PORT, originalBitMask);
  543. WRITE_PORT_UCHAR(VgaRegisterBase +
  544. GRAPH_ADDRESS_PORT, originalGCAddr);
  545. //
  546. // Now, check for the existence of the Chain4 bit.
  547. //
  548. //
  549. // Remember the original states of the Sequencer Address and Memory Mode
  550. // registers.
  551. //
  552. originalSCAddr = READ_PORT_UCHAR(VgaRegisterBase +
  553. SEQ_ADDRESS_PORT);
  554. WRITE_PORT_UCHAR(VgaRegisterBase +
  555. SEQ_ADDRESS_PORT, IND_MEMORY_MODE);
  556. if ((READ_PORT_UCHAR(VgaRegisterBase +
  557. SEQ_ADDRESS_PORT) & SEQ_ADDR_MASK) != IND_MEMORY_MODE) {
  558. //
  559. // Couldn't read back the Sequencer Address register setting we just
  560. // performed.
  561. //
  562. return FALSE;
  563. }
  564. originalMemoryMode = READ_PORT_UCHAR(VgaRegisterBase +
  565. SEQ_DATA_PORT);
  566. //
  567. // Toggle the Chain4 bit and read back the result. This must be done during
  568. // sync reset, since we're changing the chaining state.
  569. //
  570. //
  571. // Begin sync reset.
  572. //
  573. WRITE_PORT_USHORT((PUSHORT)(VgaRegisterBase +
  574. SEQ_ADDRESS_PORT),
  575. (IND_SYNC_RESET + (START_SYNC_RESET_VALUE << 8)));
  576. //
  577. // Toggle the Chain4 bit.
  578. //
  579. WRITE_PORT_UCHAR(VgaRegisterBase +
  580. SEQ_ADDRESS_PORT, IND_MEMORY_MODE);
  581. WRITE_PORT_UCHAR(VgaRegisterBase +
  582. SEQ_DATA_PORT, (UCHAR)(originalMemoryMode ^ CHAIN4_MASK));
  583. if (READ_PORT_UCHAR(VgaRegisterBase +
  584. SEQ_DATA_PORT) != (UCHAR) (originalMemoryMode ^ CHAIN4_MASK)) {
  585. //
  586. // Chain4 bit not there; not a VGA.
  587. // Set text mode default for Memory Mode register.
  588. //
  589. WRITE_PORT_UCHAR(VgaRegisterBase +
  590. SEQ_DATA_PORT, MEMORY_MODE_TEXT_DEFAULT);
  591. //
  592. // End sync reset.
  593. //
  594. WRITE_PORT_USHORT((PUSHORT) (VgaRegisterBase +
  595. SEQ_ADDRESS_PORT),
  596. (IND_SYNC_RESET + (END_SYNC_RESET_VALUE << 8)));
  597. returnStatus = FALSE;
  598. } else {
  599. //
  600. // It's a VGA.
  601. //
  602. //
  603. // Restore the original Memory Mode setting.
  604. //
  605. WRITE_PORT_UCHAR(VgaRegisterBase +
  606. SEQ_DATA_PORT, originalMemoryMode);
  607. //
  608. // End sync reset.
  609. //
  610. WRITE_PORT_USHORT((PUSHORT)(VgaRegisterBase +
  611. SEQ_ADDRESS_PORT),
  612. (USHORT)(IND_SYNC_RESET + (END_SYNC_RESET_VALUE << 8)));
  613. //
  614. // Restore the original Sequencer Address setting.
  615. //
  616. WRITE_PORT_UCHAR(VgaRegisterBase +
  617. SEQ_ADDRESS_PORT, originalSCAddr);
  618. returnStatus = TRUE;
  619. }
  620. return returnStatus;
  621. } // VgaIsPresent()