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