Driver.c 28 KB

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