Driver.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011
  1. /** @file
  2. This driver is a sample implementation of the Graphics Output Protocol for
  3. the QEMU (Cirrus Logic 5446) video controller.
  4. Copyright (c) 2006 - 2019 Intel Corporation. All rights reserved. <BR>
  5. SPDX-License-Identifier: BSD-2-Clause-Patent
  6. **/
  7. #include "Simics.h"
  8. #include <IndustryStandard/Acpi.h>
  9. EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = {
  10. QemuVideoControllerDriverSupported,
  11. QemuVideoControllerDriverStart,
  12. QemuVideoControllerDriverStop,
  13. 0x10,
  14. NULL,
  15. NULL
  16. };
  17. QEMU_VIDEO_CARD gQemuVideoCardList[] = {
  18. {
  19. PCI_CLASS_DISPLAY_VGA,
  20. CIRRUS_LOGIC_VENDOR_ID,
  21. CIRRUS_LOGIC_5430_DEVICE_ID,
  22. QEMU_VIDEO_CIRRUS_5430,
  23. L"Cirrus 5430"
  24. },{
  25. PCI_CLASS_DISPLAY_VGA,
  26. CIRRUS_LOGIC_VENDOR_ID,
  27. CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID,
  28. QEMU_VIDEO_CIRRUS_5430,
  29. L"Cirrus 5430"
  30. },{
  31. PCI_CLASS_DISPLAY_VGA,
  32. CIRRUS_LOGIC_VENDOR_ID,
  33. CIRRUS_LOGIC_5446_DEVICE_ID,
  34. QEMU_VIDEO_CIRRUS_5446,
  35. L"Cirrus 5446"
  36. },{
  37. PCI_CLASS_DISPLAY_VGA,
  38. 0x4321,
  39. 0x1111,
  40. QEMU_VIDEO_BOCHS_MMIO,
  41. L"QEMU Standard VGA"
  42. },{
  43. PCI_CLASS_DISPLAY_OTHER,
  44. 0x1234,
  45. 0x1111,
  46. QEMU_VIDEO_BOCHS_MMIO,
  47. L"QEMU Standard VGA (secondary)"
  48. },{
  49. PCI_CLASS_DISPLAY_VGA,
  50. 0x1b36,
  51. 0x0100,
  52. QEMU_VIDEO_BOCHS,
  53. L"QEMU QXL VGA"
  54. },{
  55. PCI_CLASS_DISPLAY_VGA,
  56. 0x1af4,
  57. 0x1050,
  58. QEMU_VIDEO_BOCHS_MMIO,
  59. L"QEMU VirtIO VGA"
  60. },{
  61. 0 /* end of list */
  62. }
  63. };
  64. static QEMU_VIDEO_CARD*
  65. QemuVideoDetect(
  66. IN UINT8 SubClass,
  67. IN UINT16 VendorId,
  68. IN UINT16 DeviceId
  69. )
  70. {
  71. UINTN Index = 0;
  72. while (gQemuVideoCardList[Index].VendorId != 0) {
  73. if (gQemuVideoCardList[Index].SubClass == SubClass &&
  74. gQemuVideoCardList[Index].VendorId == VendorId &&
  75. gQemuVideoCardList[Index].DeviceId == DeviceId) {
  76. return gQemuVideoCardList + Index;
  77. }
  78. Index++;
  79. }
  80. return NULL;
  81. }
  82. /**
  83. Check if this device is supported.
  84. @param This The driver binding protocol.
  85. @param Controller The controller handle to check.
  86. @param RemainingDevicePath The remaining device path.
  87. @retval EFI_SUCCESS The bus supports this controller.
  88. @retval EFI_UNSUPPORTED This device isn't supported.
  89. **/
  90. EFI_STATUS
  91. EFIAPI
  92. QemuVideoControllerDriverSupported (
  93. IN EFI_DRIVER_BINDING_PROTOCOL *This,
  94. IN EFI_HANDLE Controller,
  95. IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
  96. )
  97. {
  98. EFI_STATUS Status;
  99. EFI_PCI_IO_PROTOCOL *PciIo;
  100. PCI_TYPE00 Pci;
  101. QEMU_VIDEO_CARD *Card;
  102. //
  103. // Open the PCI I/O Protocol
  104. //
  105. Status = gBS->OpenProtocol (
  106. Controller,
  107. &gEfiPciIoProtocolGuid,
  108. (VOID **) &PciIo,
  109. This->DriverBindingHandle,
  110. Controller,
  111. EFI_OPEN_PROTOCOL_BY_DRIVER
  112. );
  113. if (EFI_ERROR (Status)) {
  114. return Status;
  115. }
  116. //
  117. // Read the PCI Configuration Header from the PCI Device
  118. //
  119. Status = PciIo->Pci.Read (
  120. PciIo,
  121. EfiPciIoWidthUint32,
  122. 0,
  123. sizeof (Pci) / sizeof (UINT32),
  124. &Pci
  125. );
  126. if (EFI_ERROR (Status)) {
  127. goto Done;
  128. }
  129. Status = EFI_UNSUPPORTED;
  130. if (!IS_PCI_DISPLAY (&Pci)) {
  131. goto Done;
  132. }
  133. Card = QemuVideoDetect(Pci.Hdr.ClassCode[1], Pci.Hdr.VendorId, Pci.Hdr.DeviceId);
  134. if (Card != NULL) {
  135. DEBUG ((EFI_D_INFO, "QemuVideo: %s detected\n", Card->Name));
  136. Status = EFI_SUCCESS;
  137. }
  138. Done:
  139. //
  140. // Close the PCI I/O Protocol
  141. //
  142. gBS->CloseProtocol (
  143. Controller,
  144. &gEfiPciIoProtocolGuid,
  145. This->DriverBindingHandle,
  146. Controller
  147. );
  148. return Status;
  149. }
  150. /**
  151. Start to process the controller.
  152. @param This The USB bus driver binding instance.
  153. @param Controller The controller to check.
  154. @param RemainingDevicePath The remaining device patch.
  155. @retval EFI_SUCCESS The controller is controlled by the usb bus.
  156. @retval EFI_ALREADY_STARTED The controller is already controlled by the usb
  157. bus.
  158. @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
  159. **/
  160. EFI_STATUS
  161. EFIAPI
  162. QemuVideoControllerDriverStart (
  163. IN EFI_DRIVER_BINDING_PROTOCOL *This,
  164. IN EFI_HANDLE Controller,
  165. IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
  166. )
  167. {
  168. EFI_TPL OldTpl;
  169. EFI_STATUS Status;
  170. QEMU_VIDEO_PRIVATE_DATA *Private;
  171. BOOLEAN IsQxl;
  172. EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
  173. ACPI_ADR_DEVICE_PATH AcpiDeviceNode;
  174. PCI_TYPE00 Pci;
  175. QEMU_VIDEO_CARD *Card;
  176. EFI_PCI_IO_PROTOCOL *ChildPciIo;
  177. OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
  178. //
  179. // Allocate Private context data for GOP inteface.
  180. //
  181. Private = AllocateZeroPool (sizeof (QEMU_VIDEO_PRIVATE_DATA));
  182. if (Private == NULL) {
  183. Status = EFI_OUT_OF_RESOURCES;
  184. goto RestoreTpl;
  185. }
  186. //
  187. // Set up context record
  188. //
  189. Private->Signature = QEMU_VIDEO_PRIVATE_DATA_SIGNATURE;
  190. //
  191. // Open PCI I/O Protocol
  192. //
  193. Status = gBS->OpenProtocol (
  194. Controller,
  195. &gEfiPciIoProtocolGuid,
  196. (VOID **) &Private->PciIo,
  197. This->DriverBindingHandle,
  198. Controller,
  199. EFI_OPEN_PROTOCOL_BY_DRIVER
  200. );
  201. if (EFI_ERROR (Status)) {
  202. goto FreePrivate;
  203. }
  204. //
  205. // Read the PCI Configuration Header from the PCI Device
  206. //
  207. Status = Private->PciIo->Pci.Read (
  208. Private->PciIo,
  209. EfiPciIoWidthUint32,
  210. 0,
  211. sizeof (Pci) / sizeof (UINT32),
  212. &Pci
  213. );
  214. if (EFI_ERROR (Status)) {
  215. goto ClosePciIo;
  216. }
  217. //
  218. // Determine card variant.
  219. //
  220. Card = QemuVideoDetect(Pci.Hdr.ClassCode[1], Pci.Hdr.VendorId, Pci.Hdr.DeviceId);
  221. if (Card == NULL) {
  222. Status = EFI_DEVICE_ERROR;
  223. goto ClosePciIo;
  224. }
  225. Private->Variant = Card->Variant;
  226. //
  227. // IsQxl is based on the detected Card->Variant, which at a later point might
  228. // not match Private->Variant.
  229. //
  230. IsQxl = (BOOLEAN)(Card->Variant == QEMU_VIDEO_BOCHS);
  231. //
  232. // Save original PCI attributes
  233. //
  234. Status = Private->PciIo->Attributes (
  235. Private->PciIo,
  236. EfiPciIoAttributeOperationGet,
  237. 0,
  238. &Private->OriginalPciAttributes
  239. );
  240. if (EFI_ERROR (Status)) {
  241. goto ClosePciIo;
  242. }
  243. //
  244. // Set new PCI attributes
  245. //
  246. Status = Private->PciIo->Attributes (
  247. Private->PciIo,
  248. EfiPciIoAttributeOperationEnable,
  249. EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO,
  250. NULL
  251. );
  252. if (EFI_ERROR (Status)) {
  253. goto ClosePciIo;
  254. }
  255. //
  256. // Check whenever the qemu stdvga mmio bar is present (qemu 1.3+).
  257. //
  258. if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
  259. EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *MmioDesc;
  260. Status = Private->PciIo->GetBarAttributes (
  261. Private->PciIo,
  262. PCI_BAR_IDX2,
  263. NULL,
  264. (VOID**) &MmioDesc
  265. );
  266. if (EFI_ERROR (Status) ||
  267. MmioDesc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM) {
  268. DEBUG ((EFI_D_INFO, "QemuVideo: No mmio bar, fallback to port io\n"));
  269. Private->Variant = QEMU_VIDEO_BOCHS;
  270. } else {
  271. DEBUG ((EFI_D_INFO, "QemuVideo: Using mmio bar @ 0x%lx\n",
  272. MmioDesc->AddrRangeMin));
  273. }
  274. if (!EFI_ERROR (Status)) {
  275. FreePool (MmioDesc);
  276. }
  277. }
  278. //
  279. // Check if accessing the bochs interface works.
  280. //
  281. if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO ||
  282. Private->Variant == QEMU_VIDEO_BOCHS) {
  283. UINT16 BochsId;
  284. BochsId = BochsRead(Private, VBE_DISPI_INDEX_ID);
  285. if ((BochsId & 0xFFF0) != VBE_DISPI_ID0) {
  286. DEBUG ((EFI_D_INFO, "QemuVideo: BochsID mismatch (got 0x%x)\n", BochsId));
  287. Status = EFI_DEVICE_ERROR;
  288. goto RestoreAttributes;
  289. }
  290. }
  291. //
  292. // Get ParentDevicePath
  293. //
  294. Status = gBS->HandleProtocol (
  295. Controller,
  296. &gEfiDevicePathProtocolGuid,
  297. (VOID **) &ParentDevicePath
  298. );
  299. if (EFI_ERROR (Status)) {
  300. goto RestoreAttributes;
  301. }
  302. //
  303. // Set Gop Device Path
  304. //
  305. ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));
  306. AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;
  307. AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;
  308. AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);
  309. SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));
  310. Private->GopDevicePath = AppendDevicePathNode (
  311. ParentDevicePath,
  312. (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode
  313. );
  314. if (Private->GopDevicePath == NULL) {
  315. Status = EFI_OUT_OF_RESOURCES;
  316. goto RestoreAttributes;
  317. }
  318. //
  319. // Create new child handle and install the device path protocol on it.
  320. //
  321. Status = gBS->InstallMultipleProtocolInterfaces (
  322. &Private->Handle,
  323. &gEfiDevicePathProtocolGuid,
  324. Private->GopDevicePath,
  325. NULL
  326. );
  327. if (EFI_ERROR (Status)) {
  328. goto FreeGopDevicePath;
  329. }
  330. //
  331. // Construct video mode buffer
  332. //
  333. switch (Private->Variant) {
  334. case QEMU_VIDEO_CIRRUS_5430:
  335. case QEMU_VIDEO_CIRRUS_5446:
  336. Status = QemuVideoCirrusModeSetup (Private);
  337. break;
  338. case QEMU_VIDEO_BOCHS_MMIO:
  339. case QEMU_VIDEO_BOCHS:
  340. Status = QemuVideoBochsModeSetup (Private, IsQxl);
  341. break;
  342. default:
  343. ASSERT (FALSE);
  344. Status = EFI_DEVICE_ERROR;
  345. break;
  346. }
  347. if (EFI_ERROR (Status)) {
  348. goto UninstallGopDevicePath;
  349. }
  350. //
  351. // Start the GOP software stack.
  352. //
  353. Status = QemuVideoGraphicsOutputConstructor (Private);
  354. if (EFI_ERROR (Status)) {
  355. goto FreeModeData;
  356. }
  357. Status = gBS->InstallMultipleProtocolInterfaces (
  358. &Private->Handle,
  359. &gEfiGraphicsOutputProtocolGuid,
  360. &Private->GraphicsOutput,
  361. NULL
  362. );
  363. if (EFI_ERROR (Status)) {
  364. goto DestructQemuVideoGraphics;
  365. }
  366. //
  367. // Reference parent handle from child handle.
  368. //
  369. Status = gBS->OpenProtocol (
  370. Controller,
  371. &gEfiPciIoProtocolGuid,
  372. (VOID **) &ChildPciIo,
  373. This->DriverBindingHandle,
  374. Private->Handle,
  375. EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
  376. );
  377. if (EFI_ERROR (Status)) {
  378. goto UninstallGop;
  379. }
  380. #if defined MDE_CPU_IA32 || defined MDE_CPU_X64
  381. if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO ||
  382. Private->Variant == QEMU_VIDEO_BOCHS) {
  383. InstallVbeShim (Card->Name, Private->GraphicsOutput.Mode->FrameBufferBase);
  384. }
  385. #endif
  386. gBS->RestoreTPL (OldTpl);
  387. return EFI_SUCCESS;
  388. UninstallGop:
  389. gBS->UninstallProtocolInterface (Private->Handle,
  390. &gEfiGraphicsOutputProtocolGuid, &Private->GraphicsOutput);
  391. DestructQemuVideoGraphics:
  392. QemuVideoGraphicsOutputDestructor (Private);
  393. FreeModeData:
  394. FreePool (Private->ModeData);
  395. UninstallGopDevicePath:
  396. gBS->UninstallProtocolInterface (Private->Handle,
  397. &gEfiDevicePathProtocolGuid, Private->GopDevicePath);
  398. FreeGopDevicePath:
  399. FreePool (Private->GopDevicePath);
  400. RestoreAttributes:
  401. Private->PciIo->Attributes (Private->PciIo, EfiPciIoAttributeOperationSet,
  402. Private->OriginalPciAttributes, NULL);
  403. ClosePciIo:
  404. gBS->CloseProtocol (Controller, &gEfiPciIoProtocolGuid,
  405. This->DriverBindingHandle, Controller);
  406. FreePrivate:
  407. FreePool (Private);
  408. RestoreTpl:
  409. gBS->RestoreTPL (OldTpl);
  410. return Status;
  411. }
  412. /**
  413. Stop this device
  414. @param This The USB bus driver binding protocol.
  415. @param Controller The controller to release.
  416. @param NumberOfChildren The number of children of this device that
  417. opened the controller BY_CHILD.
  418. @param ChildHandleBuffer The array of child handle.
  419. @retval EFI_SUCCESS The controller or children are stopped.
  420. @retval EFI_DEVICE_ERROR Failed to stop the driver.
  421. **/
  422. EFI_STATUS
  423. EFIAPI
  424. QemuVideoControllerDriverStop (
  425. IN EFI_DRIVER_BINDING_PROTOCOL *This,
  426. IN EFI_HANDLE Controller,
  427. IN UINTN NumberOfChildren,
  428. IN EFI_HANDLE *ChildHandleBuffer
  429. )
  430. {
  431. EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
  432. EFI_STATUS Status;
  433. QEMU_VIDEO_PRIVATE_DATA *Private;
  434. if (NumberOfChildren == 0) {
  435. //
  436. // Close the PCI I/O Protocol
  437. //
  438. gBS->CloseProtocol (
  439. Controller,
  440. &gEfiPciIoProtocolGuid,
  441. This->DriverBindingHandle,
  442. Controller
  443. );
  444. return EFI_SUCCESS;
  445. }
  446. //
  447. // free all resources for whose access we need the child handle, because the
  448. // child handle is going away
  449. //
  450. ASSERT (NumberOfChildren == 1);
  451. Status = gBS->OpenProtocol (
  452. ChildHandleBuffer[0],
  453. &gEfiGraphicsOutputProtocolGuid,
  454. (VOID **) &GraphicsOutput,
  455. This->DriverBindingHandle,
  456. Controller,
  457. EFI_OPEN_PROTOCOL_GET_PROTOCOL
  458. );
  459. if (EFI_ERROR (Status)) {
  460. return Status;
  461. }
  462. //
  463. // Get our private context information
  464. //
  465. Private = QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput);
  466. ASSERT (Private->Handle == ChildHandleBuffer[0]);
  467. QemuVideoGraphicsOutputDestructor (Private);
  468. //
  469. // Remove the GOP protocol interface from the system
  470. //
  471. Status = gBS->UninstallMultipleProtocolInterfaces (
  472. Private->Handle,
  473. &gEfiGraphicsOutputProtocolGuid,
  474. &Private->GraphicsOutput,
  475. NULL
  476. );
  477. if (EFI_ERROR (Status)) {
  478. return Status;
  479. }
  480. //
  481. // Restore original PCI attributes
  482. //
  483. Private->PciIo->Attributes (
  484. Private->PciIo,
  485. EfiPciIoAttributeOperationSet,
  486. Private->OriginalPciAttributes,
  487. NULL
  488. );
  489. gBS->CloseProtocol (
  490. Controller,
  491. &gEfiPciIoProtocolGuid,
  492. This->DriverBindingHandle,
  493. Private->Handle
  494. );
  495. FreePool (Private->ModeData);
  496. gBS->UninstallProtocolInterface (Private->Handle,
  497. &gEfiDevicePathProtocolGuid, Private->GopDevicePath);
  498. FreePool (Private->GopDevicePath);
  499. //
  500. // Free our instance data
  501. //
  502. gBS->FreePool (Private);
  503. return EFI_SUCCESS;
  504. }
  505. /**
  506. TODO: Add function description
  507. @param Private TODO: add argument description
  508. @param Address TODO: add argument description
  509. @param Data TODO: add argument description
  510. TODO: add return values
  511. **/
  512. VOID
  513. outb (
  514. QEMU_VIDEO_PRIVATE_DATA *Private,
  515. UINTN Address,
  516. UINT8 Data
  517. )
  518. {
  519. EFI_STATUS Status;
  520. VOID *Interface;
  521. Private->PciIo->Io.Write (
  522. Private->PciIo,
  523. EfiPciIoWidthUint8,
  524. EFI_PCI_IO_PASS_THROUGH_BAR,
  525. Address,
  526. 1,
  527. &Data
  528. );
  529. Status = gBS->LocateProtocol(&gEfiDxeSmmReadyToLockProtocolGuid, NULL, &Interface);
  530. if (!EFI_ERROR(Status)) {
  531. return;
  532. }
  533. Status = S3BootScriptSaveIoWrite(
  534. S3BootScriptWidthUint8,
  535. Address,
  536. (UINTN)1,
  537. &Data
  538. );
  539. }
  540. /**
  541. TODO: Add function description
  542. @param Private TODO: add argument description
  543. @param Address TODO: add argument description
  544. @param Data TODO: add argument description
  545. TODO: add return values
  546. **/
  547. VOID
  548. outw (
  549. QEMU_VIDEO_PRIVATE_DATA *Private,
  550. UINTN Address,
  551. UINT16 Data
  552. )
  553. {
  554. EFI_STATUS Status;
  555. VOID *Interface;
  556. Private->PciIo->Io.Write (
  557. Private->PciIo,
  558. EfiPciIoWidthUint16,
  559. EFI_PCI_IO_PASS_THROUGH_BAR,
  560. Address,
  561. 1,
  562. &Data
  563. );
  564. Status = gBS->LocateProtocol(&gEfiDxeSmmReadyToLockProtocolGuid, NULL, &Interface);
  565. if (!EFI_ERROR(Status)) {
  566. return;
  567. }
  568. Status = S3BootScriptSaveIoWrite(
  569. S3BootScriptWidthUint16,
  570. Address,
  571. 1,
  572. &Data
  573. );
  574. }
  575. /**
  576. TODO: Add function description
  577. @param Private TODO: add argument description
  578. @param Address TODO: add argument description
  579. TODO: add return values
  580. **/
  581. UINT8
  582. inb (
  583. QEMU_VIDEO_PRIVATE_DATA *Private,
  584. UINTN Address
  585. )
  586. {
  587. UINT8 Data;
  588. Private->PciIo->Io.Read (
  589. Private->PciIo,
  590. EfiPciIoWidthUint8,
  591. EFI_PCI_IO_PASS_THROUGH_BAR,
  592. Address,
  593. 1,
  594. &Data
  595. );
  596. return Data;
  597. }
  598. /**
  599. TODO: Add function description
  600. @param Private TODO: add argument description
  601. @param Address TODO: add argument description
  602. TODO: add return values
  603. **/
  604. UINT16
  605. inw (
  606. QEMU_VIDEO_PRIVATE_DATA *Private,
  607. UINTN Address
  608. )
  609. {
  610. UINT16 Data;
  611. Private->PciIo->Io.Read (
  612. Private->PciIo,
  613. EfiPciIoWidthUint16,
  614. EFI_PCI_IO_PASS_THROUGH_BAR,
  615. Address,
  616. 1,
  617. &Data
  618. );
  619. return Data;
  620. }
  621. /**
  622. TODO: Add function description
  623. @param Private TODO: add argument description
  624. @param Index TODO: add argument description
  625. @param Red TODO: add argument description
  626. @param Green TODO: add argument description
  627. @param Blue TODO: add argument description
  628. TODO: add return values
  629. **/
  630. VOID
  631. SetPaletteColor (
  632. QEMU_VIDEO_PRIVATE_DATA *Private,
  633. UINTN Index,
  634. UINT8 Red,
  635. UINT8 Green,
  636. UINT8 Blue
  637. )
  638. {
  639. VgaOutb (Private, PALETTE_INDEX_REGISTER, (UINT8) Index);
  640. VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Red >> 2));
  641. VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Green >> 2));
  642. VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Blue >> 2));
  643. }
  644. /**
  645. TODO: Add function description
  646. @param Private TODO: add argument description
  647. TODO: add return values
  648. **/
  649. VOID
  650. SetDefaultPalette (
  651. QEMU_VIDEO_PRIVATE_DATA *Private
  652. )
  653. {
  654. UINTN Index;
  655. UINTN RedIndex;
  656. UINTN GreenIndex;
  657. UINTN BlueIndex;
  658. Index = 0;
  659. for (RedIndex = 0; RedIndex < 8; RedIndex++) {
  660. for (GreenIndex = 0; GreenIndex < 8; GreenIndex++) {
  661. for (BlueIndex = 0; BlueIndex < 4; BlueIndex++) {
  662. SetPaletteColor (Private, Index, (UINT8) (RedIndex << 5), (UINT8) (GreenIndex << 5), (UINT8) (BlueIndex << 6));
  663. Index++;
  664. }
  665. }
  666. }
  667. }
  668. /**
  669. TODO: Add function description
  670. @param Private TODO: add argument description
  671. TODO: add return values
  672. **/
  673. VOID
  674. ClearScreen (
  675. QEMU_VIDEO_PRIVATE_DATA *Private
  676. )
  677. {
  678. UINT32 Color;
  679. Color = 0;
  680. Private->PciIo->Mem.Write (
  681. Private->PciIo,
  682. EfiPciIoWidthFillUint32,
  683. 0,
  684. 0,
  685. 0x400000 >> 2,
  686. &Color
  687. );
  688. }
  689. /**
  690. TODO: Add function description
  691. @param Private TODO: add argument description
  692. TODO: add return values
  693. **/
  694. VOID
  695. DrawLogo (
  696. QEMU_VIDEO_PRIVATE_DATA *Private,
  697. UINTN ScreenWidth,
  698. UINTN ScreenHeight
  699. )
  700. {
  701. }
  702. /**
  703. TODO: Add function description
  704. @param Private TODO: add argument description
  705. @param ModeData TODO: add argument description
  706. TODO: add return values
  707. **/
  708. VOID
  709. InitializeCirrusGraphicsMode (
  710. QEMU_VIDEO_PRIVATE_DATA *Private,
  711. QEMU_VIDEO_CIRRUS_MODES *ModeData
  712. )
  713. {
  714. UINT8 Byte;
  715. UINTN Index;
  716. outw (Private, SEQ_ADDRESS_REGISTER, 0x1206);
  717. outw (Private, SEQ_ADDRESS_REGISTER, 0x0012);
  718. for (Index = 0; Index < 15; Index++) {
  719. outw (Private, SEQ_ADDRESS_REGISTER, ModeData->SeqSettings[Index]);
  720. }
  721. if (Private->Variant == QEMU_VIDEO_CIRRUS_5430) {
  722. outb (Private, SEQ_ADDRESS_REGISTER, 0x0f);
  723. Byte = (UINT8) ((inb (Private, SEQ_DATA_REGISTER) & 0xc7) ^ 0x30);
  724. outb (Private, SEQ_DATA_REGISTER, Byte);
  725. }
  726. outb (Private, MISC_OUTPUT_REGISTER, ModeData->MiscSetting);
  727. outw (Private, GRAPH_ADDRESS_REGISTER, 0x0506);
  728. outw (Private, SEQ_ADDRESS_REGISTER, 0x0300);
  729. outw (Private, CRTC_ADDRESS_REGISTER, 0x2011);
  730. for (Index = 0; Index < 28; Index++) {
  731. outw (Private, CRTC_ADDRESS_REGISTER, (UINT16) ((ModeData->CrtcSettings[Index] << 8) | Index));
  732. }
  733. for (Index = 0; Index < 9; Index++) {
  734. outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((GraphicsController[Index] << 8) | Index));
  735. }
  736. inb (Private, INPUT_STATUS_1_REGISTER);
  737. for (Index = 0; Index < 21; Index++) {
  738. outb (Private, ATT_ADDRESS_REGISTER, (UINT8) Index);
  739. outb (Private, ATT_ADDRESS_REGISTER, AttributeController[Index]);
  740. }
  741. outb (Private, ATT_ADDRESS_REGISTER, 0x20);
  742. outw (Private, GRAPH_ADDRESS_REGISTER, 0x0009);
  743. outw (Private, GRAPH_ADDRESS_REGISTER, 0x000a);
  744. outw (Private, GRAPH_ADDRESS_REGISTER, 0x000b);
  745. outb (Private, DAC_PIXEL_MASK_REGISTER, 0xff);
  746. SetDefaultPalette (Private);
  747. ClearScreen (Private);
  748. }
  749. VOID
  750. BochsWrite (
  751. QEMU_VIDEO_PRIVATE_DATA *Private,
  752. UINT16 Reg,
  753. UINT16 Data
  754. )
  755. {
  756. EFI_STATUS Status;
  757. if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
  758. Status = Private->PciIo->Mem.Write (
  759. Private->PciIo,
  760. EfiPciIoWidthUint16,
  761. PCI_BAR_IDX2,
  762. 0x500 + (Reg << 1),
  763. 1,
  764. &Data
  765. );
  766. ASSERT_EFI_ERROR (Status);
  767. } else {
  768. outw (Private, VBE_DISPI_IOPORT_INDEX, Reg);
  769. outw (Private, VBE_DISPI_IOPORT_DATA, Data);
  770. }
  771. }
  772. UINT16
  773. BochsRead (
  774. QEMU_VIDEO_PRIVATE_DATA *Private,
  775. UINT16 Reg
  776. )
  777. {
  778. EFI_STATUS Status;
  779. UINT16 Data;
  780. if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
  781. Status = Private->PciIo->Mem.Read (
  782. Private->PciIo,
  783. EfiPciIoWidthUint16,
  784. PCI_BAR_IDX2,
  785. 0x500 + (Reg << 1),
  786. 1,
  787. &Data
  788. );
  789. ASSERT_EFI_ERROR (Status);
  790. } else {
  791. outw (Private, VBE_DISPI_IOPORT_INDEX, Reg);
  792. Data = inw (Private, VBE_DISPI_IOPORT_DATA);
  793. }
  794. return Data;
  795. }
  796. VOID
  797. VgaOutb (
  798. QEMU_VIDEO_PRIVATE_DATA *Private,
  799. UINTN Reg,
  800. UINT8 Data
  801. )
  802. {
  803. EFI_STATUS Status;
  804. if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
  805. Status = Private->PciIo->Mem.Write (
  806. Private->PciIo,
  807. EfiPciIoWidthUint8,
  808. PCI_BAR_IDX2,
  809. 0x400 - 0x3c0 + Reg,
  810. 1,
  811. &Data
  812. );
  813. ASSERT_EFI_ERROR (Status);
  814. } else {
  815. outb (Private, Reg, Data);
  816. }
  817. }
  818. VOID
  819. InitializeBochsGraphicsMode (
  820. QEMU_VIDEO_PRIVATE_DATA *Private,
  821. QEMU_VIDEO_BOCHS_MODES *ModeData
  822. )
  823. {
  824. DEBUG ((EFI_D_INFO, "InitializeBochsGraphicsMode: %dx%d @ %d\n",
  825. ModeData->Width, ModeData->Height, ModeData->ColorDepth));
  826. /* unblank */
  827. VgaOutb (Private, ATT_ADDRESS_REGISTER, 0x20);
  828. BochsWrite (Private, VBE_DISPI_INDEX_ENABLE, 0);
  829. BochsWrite (Private, VBE_DISPI_INDEX_BANK, 0);
  830. BochsWrite (Private, VBE_DISPI_INDEX_X_OFFSET, 0);
  831. BochsWrite (Private, VBE_DISPI_INDEX_Y_OFFSET, 0);
  832. BochsWrite (Private, VBE_DISPI_INDEX_BPP, (UINT16) ModeData->ColorDepth);
  833. BochsWrite (Private, VBE_DISPI_INDEX_XRES, (UINT16) ModeData->Width);
  834. BochsWrite (Private, VBE_DISPI_INDEX_VIRT_WIDTH, (UINT16) ModeData->Width);
  835. BochsWrite (Private, VBE_DISPI_INDEX_YRES, (UINT16) ModeData->Height);
  836. BochsWrite (Private, VBE_DISPI_INDEX_VIRT_HEIGHT, (UINT16) ModeData->Height);
  837. BochsWrite (Private, VBE_DISPI_INDEX_ENABLE,
  838. VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
  839. SetDefaultPalette (Private);
  840. ClearScreen (Private);
  841. }
  842. EFI_STATUS
  843. EFIAPI
  844. InitializeQemuVideo (
  845. IN EFI_HANDLE ImageHandle,
  846. IN EFI_SYSTEM_TABLE *SystemTable
  847. )
  848. {
  849. EFI_STATUS Status;
  850. Status = EfiLibInstallDriverBindingComponentName2 (
  851. ImageHandle,
  852. SystemTable,
  853. &gQemuVideoDriverBinding,
  854. ImageHandle,
  855. &gQemuVideoComponentName,
  856. &gQemuVideoComponentName2
  857. );
  858. ASSERT_EFI_ERROR (Status);
  859. //
  860. // Install EFI Driver Supported EFI Version Protocol required for
  861. // EFI drivers that are on PCI and other plug in cards.
  862. //
  863. gQemuVideoDriverSupportedEfiVersion.FirmwareVersion = PcdGet32 (PcdDriverSupportedEfiVersion);
  864. Status = gBS->InstallMultipleProtocolInterfaces (
  865. &ImageHandle,
  866. &gEfiDriverSupportedEfiVersionProtocolGuid,
  867. &gQemuVideoDriverSupportedEfiVersion,
  868. NULL
  869. );
  870. ASSERT_EFI_ERROR (Status);
  871. return Status;
  872. }