Initialize.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. /** @file
  2. Graphics Output Protocol functions for the QEMU video controller.
  3. Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "Qemu.h"
  7. ///
  8. /// Generic Attribute Controller Register Settings
  9. ///
  10. UINT8 AttributeController[21] = {
  11. 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
  12. 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
  13. 0x41, 0x00, 0x0F, 0x00, 0x00
  14. };
  15. ///
  16. /// Generic Graphics Controller Register Settings
  17. ///
  18. UINT8 GraphicsController[9] = {
  19. 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0xFF
  20. };
  21. //
  22. // 640 x 480 x 256 color @ 60 Hertz
  23. //
  24. UINT8 Crtc_640_480_256_60[28] = {
  25. 0x5d, 0x4f, 0x50, 0x82, 0x53, 0x9f, 0x00, 0x3e,
  26. 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  27. 0xe1, 0x83, 0xdf, 0x50, 0x00, 0xe7, 0x04, 0xe3,
  28. 0xff, 0x00, 0x00, 0x22
  29. };
  30. UINT8 Crtc_640_480_32bpp_60[28] = {
  31. 0x5d, 0x4f, 0x50, 0x82, 0x53, 0x9f, 0x00, 0x3e,
  32. 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  33. 0xe1, 0x83, 0xdf, 0x40, 0x00, 0xe7, 0x04, 0xe3,
  34. 0xff, 0x00, 0x00, 0x32
  35. };
  36. UINT16 Seq_640_480_256_60[15] = {
  37. 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b,
  38. 0x5b0c, 0x450d, 0x7e0e, 0x2b1b, 0x2f1c, 0x301d, 0x331e
  39. };
  40. UINT16 Seq_640_480_32bpp_60[15] = {
  41. 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b,
  42. 0x5b0c, 0x450d, 0x7e0e, 0x2b1b, 0x2f1c, 0x301d, 0x331e
  43. };
  44. //
  45. // 800 x 600 x 256 color @ 60 Hertz
  46. //
  47. UINT8 Crtc_800_600_256_60[28] = {
  48. 0x7F, 0x63, 0x64, 0x80, 0x6B, 0x1B, 0x72, 0xF0,
  49. 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  50. 0x58, 0x8C, 0x57, 0x64, 0x00, 0x5F, 0x91, 0xE3,
  51. 0xFF, 0x00, 0x00, 0x22
  52. };
  53. UINT8 Crtc_800_600_32bpp_60[28] = {
  54. 0x7F, 0x63, 0x64, 0x80, 0x6B, 0x1B, 0x72, 0xF0,
  55. 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  56. 0x58, 0x8C, 0x57, 0x90, 0x00, 0x5F, 0x91, 0xE3,
  57. 0xFF, 0x00, 0x00, 0x32
  58. };
  59. UINT16 Seq_800_600_256_60[15] = {
  60. 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b,
  61. 0x5b0c, 0x450d, 0x510e, 0x2b1b, 0x2f1c, 0x301d, 0x3a1e
  62. };
  63. UINT16 Seq_800_600_32bpp_60[15] = {
  64. 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b,
  65. 0x5b0c, 0x450d, 0x510e, 0x2b1b, 0x2f1c, 0x301d, 0x3a1e
  66. };
  67. UINT8 Crtc_960_720_32bpp_60[28] = {
  68. 0xA3, 0x77, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD,
  69. 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  70. 0x02, 0x88, 0xCF, 0xe0, 0x00, 0x00, 0x64, 0xE3,
  71. 0xFF, 0x4A, 0x00, 0x32
  72. };
  73. UINT16 Seq_960_720_32bpp_60[15] = {
  74. 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b,
  75. 0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e
  76. };
  77. //
  78. // 1024 x 768 x 256 color @ 60 Hertz
  79. //
  80. UINT8 Crtc_1024_768_256_60[28] = {
  81. 0xA3, 0x7F, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD,
  82. 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  83. 0x02, 0x88, 0xFF, 0x80, 0x00, 0x00, 0x24, 0xE3,
  84. 0xFF, 0x4A, 0x00, 0x22
  85. };
  86. UINT16 Seq_1024_768_256_60[15] = {
  87. 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b,
  88. 0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e
  89. };
  90. //
  91. // 1024 x 768 x 24-bit color @ 60 Hertz
  92. //
  93. UINT8 Crtc_1024_768_24bpp_60[28] = {
  94. 0xA3, 0x7F, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD,
  95. 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  96. 0x02, 0x88, 0xFF, 0x80, 0x00, 0x00, 0x24, 0xE3,
  97. 0xFF, 0x4A, 0x00, 0x32
  98. };
  99. UINT16 Seq_1024_768_24bpp_60[15] = {
  100. 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1507, 0x0008, 0x4a0b,
  101. 0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e
  102. };
  103. UINT8 Crtc_1024_768_32bpp_60[28] = {
  104. 0xA3, 0x7F, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD,
  105. 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  106. 0x02, 0x88, 0xFF, 0xe0, 0x00, 0x00, 0x64, 0xE3,
  107. 0xFF, 0x4A, 0x00, 0x32
  108. };
  109. UINT16 Seq_1024_768_32bpp_60[15] = {
  110. 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b,
  111. 0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e
  112. };
  113. ///
  114. /// Table of supported video modes
  115. ///
  116. QEMU_VIDEO_CIRRUS_MODES QemuVideoCirrusModes[] = {
  117. // { 640, 480, 8, Crtc_640_480_256_60, Seq_640_480_256_60, 0xe3 },
  118. // { 800, 600, 8, Crtc_800_600_256_60, Seq_800_600_256_60, 0xef },
  119. { 640, 480, 32, Crtc_640_480_32bpp_60, Seq_640_480_32bpp_60, 0xef },
  120. { 800, 600, 32, Crtc_800_600_32bpp_60, Seq_800_600_32bpp_60, 0xef },
  121. // { 1024, 768, 8, Crtc_1024_768_256_60, Seq_1024_768_256_60, 0xef }
  122. { 1024, 768, 24, Crtc_1024_768_24bpp_60, Seq_1024_768_24bpp_60, 0xef }
  123. // { 1024, 768, 32, Crtc_1024_768_32bpp_60, Seq_1024_768_32bpp_60, 0xef }
  124. // { 960, 720, 32, Crtc_960_720_32bpp_60, Seq_1024_768_32bpp_60, 0xef }
  125. };
  126. #define QEMU_VIDEO_CIRRUS_MODE_COUNT \
  127. (ARRAY_SIZE (QemuVideoCirrusModes))
  128. /**
  129. Construct the valid video modes for QemuVideo.
  130. **/
  131. EFI_STATUS
  132. QemuVideoCirrusModeSetup (
  133. QEMU_VIDEO_PRIVATE_DATA *Private
  134. )
  135. {
  136. UINT32 Index;
  137. QEMU_VIDEO_MODE_DATA *ModeData;
  138. QEMU_VIDEO_CIRRUS_MODES *VideoMode;
  139. //
  140. // Setup Video Modes
  141. //
  142. Private->ModeData = AllocatePool (
  143. sizeof (Private->ModeData[0]) * QEMU_VIDEO_CIRRUS_MODE_COUNT
  144. );
  145. if (Private->ModeData == NULL) {
  146. return EFI_OUT_OF_RESOURCES;
  147. }
  148. ModeData = Private->ModeData;
  149. VideoMode = &QemuVideoCirrusModes[0];
  150. for (Index = 0; Index < QEMU_VIDEO_CIRRUS_MODE_COUNT; Index++) {
  151. ModeData->InternalModeIndex = Index;
  152. ModeData->HorizontalResolution = VideoMode->Width;
  153. ModeData->VerticalResolution = VideoMode->Height;
  154. ModeData->ColorDepth = VideoMode->ColorDepth;
  155. DEBUG ((
  156. DEBUG_INFO,
  157. "Adding Mode %d as Cirrus Internal Mode %d: %dx%d, %d-bit\n",
  158. (INT32)(ModeData - Private->ModeData),
  159. ModeData->InternalModeIndex,
  160. ModeData->HorizontalResolution,
  161. ModeData->VerticalResolution,
  162. ModeData->ColorDepth
  163. ));
  164. ModeData++;
  165. VideoMode++;
  166. }
  167. Private->MaxMode = ModeData - Private->ModeData;
  168. return EFI_SUCCESS;
  169. }
  170. ///
  171. /// Table of supported video modes
  172. ///
  173. STATIC QEMU_VIDEO_BOCHS_MODES QemuVideoBochsModes[] = {
  174. { 640, 480 },
  175. { 800, 480 },
  176. { 800, 600 },
  177. { 832, 624 },
  178. { 960, 640 },
  179. { 1024, 600 },
  180. { 1024, 768 },
  181. { 1152, 864 },
  182. { 1152, 870 },
  183. { 1280, 720 },
  184. { 1280, 760 },
  185. { 1280, 768 },
  186. { 1280, 800 },
  187. { 1280, 960 },
  188. { 1280, 1024 },
  189. { 1360, 768 },
  190. { 1366, 768 },
  191. { 1400, 1050 },
  192. { 1440, 900 },
  193. { 1600, 900 },
  194. { 1600, 1200 },
  195. { 1680, 1050 },
  196. { 1920, 1080 },
  197. { 1920, 1200 },
  198. { 1920, 1440 },
  199. { 2000, 2000 },
  200. { 2048, 1536 },
  201. { 2048, 2048 },
  202. { 2560, 1440 },
  203. { 2560, 1600 },
  204. { 2560, 2048 },
  205. { 2800, 2100 },
  206. { 3200, 2400 },
  207. { 3840, 2160 },
  208. { 4096, 2160 },
  209. { 7680, 4320 },
  210. { 8192, 4320 }
  211. };
  212. #define QEMU_VIDEO_BOCHS_MODE_COUNT \
  213. (ARRAY_SIZE (QemuVideoBochsModes))
  214. STATIC
  215. VOID
  216. QemuVideoBochsAddMode (
  217. QEMU_VIDEO_PRIVATE_DATA *Private,
  218. UINT32 AvailableFbSize,
  219. UINT32 Width,
  220. UINT32 Height
  221. )
  222. {
  223. QEMU_VIDEO_MODE_DATA *ModeData = Private->ModeData + Private->MaxMode;
  224. UINTN RequiredFbSize;
  225. RequiredFbSize = (UINTN)Width * Height * 4;
  226. if (RequiredFbSize > AvailableFbSize) {
  227. DEBUG ((
  228. DEBUG_INFO,
  229. "Skipping Bochs Mode %dx%d, 32-bit (not enough vram)\n",
  230. Width,
  231. Height
  232. ));
  233. return;
  234. }
  235. ModeData->InternalModeIndex = (UINT32)Private->MaxMode;
  236. ModeData->HorizontalResolution = Width;
  237. ModeData->VerticalResolution = Height;
  238. ModeData->ColorDepth = 32;
  239. DEBUG ((
  240. DEBUG_INFO,
  241. "Adding Bochs Internal Mode %d: %dx%d, %d-bit\n",
  242. ModeData->InternalModeIndex,
  243. ModeData->HorizontalResolution,
  244. ModeData->VerticalResolution,
  245. ModeData->ColorDepth
  246. ));
  247. Private->MaxMode++;
  248. }
  249. STATIC
  250. VOID
  251. QemuVideoBochsEdid (
  252. QEMU_VIDEO_PRIVATE_DATA *Private,
  253. UINT32 *XRes,
  254. UINT32 *YRes
  255. )
  256. {
  257. EFI_STATUS Status;
  258. if (Private->Variant != QEMU_VIDEO_BOCHS_MMIO) {
  259. return;
  260. }
  261. Status = Private->PciIo->Mem.Read (
  262. Private->PciIo,
  263. EfiPciIoWidthUint8,
  264. PCI_BAR_IDX2,
  265. 0,
  266. sizeof (Private->Edid),
  267. Private->Edid
  268. );
  269. if (Status != EFI_SUCCESS) {
  270. DEBUG ((
  271. DEBUG_INFO,
  272. "%a: mmio read failed\n",
  273. __FUNCTION__
  274. ));
  275. return;
  276. }
  277. if ((Private->Edid[0] != 0x00) ||
  278. (Private->Edid[1] != 0xff))
  279. {
  280. DEBUG ((
  281. DEBUG_INFO,
  282. "%a: magic check failed\n",
  283. __FUNCTION__
  284. ));
  285. return;
  286. }
  287. DEBUG ((
  288. DEBUG_INFO,
  289. "%a: blob found (extensions: %d)\n",
  290. __FUNCTION__,
  291. Private->Edid[126]
  292. ));
  293. if ((Private->Edid[54] == 0x00) &&
  294. (Private->Edid[55] == 0x00))
  295. {
  296. DEBUG ((
  297. DEBUG_INFO,
  298. "%a: no detailed timing descriptor\n",
  299. __FUNCTION__
  300. ));
  301. return;
  302. }
  303. *XRes = Private->Edid[56] | ((Private->Edid[58] & 0xf0) << 4);
  304. *YRes = Private->Edid[59] | ((Private->Edid[61] & 0xf0) << 4);
  305. DEBUG ((
  306. DEBUG_INFO,
  307. "%a: default resolution: %dx%d\n",
  308. __FUNCTION__,
  309. *XRes,
  310. *YRes
  311. ));
  312. if (PcdGet8 (PcdVideoResolutionSource) == 0) {
  313. Status = PcdSet32S (PcdVideoHorizontalResolution, *XRes);
  314. ASSERT_RETURN_ERROR (Status);
  315. Status = PcdSet32S (PcdVideoVerticalResolution, *YRes);
  316. ASSERT_RETURN_ERROR (Status);
  317. Status = PcdSet8S (PcdVideoResolutionSource, 2);
  318. ASSERT_RETURN_ERROR (Status);
  319. }
  320. // TODO: register edid as gEfiEdidDiscoveredProtocolGuid ?
  321. }
  322. EFI_STATUS
  323. QemuVideoBochsModeSetup (
  324. QEMU_VIDEO_PRIVATE_DATA *Private,
  325. BOOLEAN IsQxl
  326. )
  327. {
  328. UINT32 AvailableFbSize;
  329. UINT32 Index, XRes = 0, YRes = 0;
  330. //
  331. // Fetch the available framebuffer size.
  332. //
  333. // VBE_DISPI_INDEX_VIDEO_MEMORY_64K is expected to return the size of the
  334. // drawable framebuffer. Up to and including qemu-2.1 however it used to
  335. // return the size of PCI BAR 0 (ie. the full video RAM size).
  336. //
  337. // On stdvga the two concepts coincide with each other; the full memory size
  338. // is usable for drawing.
  339. //
  340. // On QXL however, only a leading segment, "surface 0", can be used for
  341. // drawing; the rest of the video memory is used for the QXL guest-host
  342. // protocol. VBE_DISPI_INDEX_VIDEO_MEMORY_64K should report the size of
  343. // "surface 0", but since it doesn't (up to and including qemu-2.1), we
  344. // retrieve the size of the drawable portion from a field in the QXL ROM BAR,
  345. // where it is also available.
  346. //
  347. if (IsQxl) {
  348. UINT32 Signature;
  349. UINT32 DrawStart;
  350. Signature = 0;
  351. DrawStart = 0xFFFFFFFF;
  352. AvailableFbSize = 0;
  353. if (EFI_ERROR (
  354. Private->PciIo->Mem.Read (
  355. Private->PciIo,
  356. EfiPciIoWidthUint32,
  357. PCI_BAR_IDX2,
  358. 0,
  359. 1,
  360. &Signature
  361. )
  362. ) ||
  363. (Signature != SIGNATURE_32 ('Q', 'X', 'R', 'O')) ||
  364. EFI_ERROR (
  365. Private->PciIo->Mem.Read (
  366. Private->PciIo,
  367. EfiPciIoWidthUint32,
  368. PCI_BAR_IDX2,
  369. 36,
  370. 1,
  371. &DrawStart
  372. )
  373. ) ||
  374. (DrawStart != 0) ||
  375. EFI_ERROR (
  376. Private->PciIo->Mem.Read (
  377. Private->PciIo,
  378. EfiPciIoWidthUint32,
  379. PCI_BAR_IDX2,
  380. 40,
  381. 1,
  382. &AvailableFbSize
  383. )
  384. ))
  385. {
  386. DEBUG ((
  387. DEBUG_ERROR,
  388. "%a: can't read size of drawable buffer from QXL "
  389. "ROM\n",
  390. __FUNCTION__
  391. ));
  392. return EFI_NOT_FOUND;
  393. }
  394. } else {
  395. AvailableFbSize = BochsRead (Private, VBE_DISPI_INDEX_VIDEO_MEMORY_64K);
  396. AvailableFbSize *= SIZE_64KB;
  397. }
  398. DEBUG ((
  399. DEBUG_INFO,
  400. "%a: AvailableFbSize=0x%x\n",
  401. __FUNCTION__,
  402. AvailableFbSize
  403. ));
  404. //
  405. // Setup Video Modes
  406. //
  407. Private->ModeData = AllocatePool (
  408. sizeof (Private->ModeData[0]) * (QEMU_VIDEO_BOCHS_MODE_COUNT+1)
  409. );
  410. if (Private->ModeData == NULL) {
  411. return EFI_OUT_OF_RESOURCES;
  412. }
  413. QemuVideoBochsEdid (Private, &XRes, &YRes);
  414. if (XRes && YRes) {
  415. QemuVideoBochsAddMode (
  416. Private,
  417. AvailableFbSize,
  418. XRes,
  419. YRes
  420. );
  421. }
  422. for (Index = 0; Index < QEMU_VIDEO_BOCHS_MODE_COUNT; Index++) {
  423. if ((QemuVideoBochsModes[Index].Width == XRes) &&
  424. (QemuVideoBochsModes[Index].Height == YRes))
  425. {
  426. continue; // duplicate with edid resolution
  427. }
  428. QemuVideoBochsAddMode (
  429. Private,
  430. AvailableFbSize,
  431. QemuVideoBochsModes[Index].Width,
  432. QemuVideoBochsModes[Index].Height
  433. );
  434. }
  435. return EFI_SUCCESS;
  436. }