]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/QemuVideoDxe/Initialize.c
OvmfPkg/Gop: clear the screen to black in SetMode()
[mirror_edk2.git] / OvmfPkg / QemuVideoDxe / Initialize.c
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 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include <IndustryStandard/VmwareSvga.h>
17 #include "Qemu.h"
18
19
20 ///
21 /// Generic Attribute Controller Register Settings
22 ///
23 UINT8 AttributeController[21] = {
24 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
25 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
26 0x41, 0x00, 0x0F, 0x00, 0x00
27 };
28
29 ///
30 /// Generic Graphics Controller Register Settings
31 ///
32 UINT8 GraphicsController[9] = {
33 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0xFF
34 };
35
36 //
37 // 640 x 480 x 256 color @ 60 Hertz
38 //
39 UINT8 Crtc_640_480_256_60[28] = {
40 0x5d, 0x4f, 0x50, 0x82, 0x53, 0x9f, 0x00, 0x3e,
41 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
42 0xe1, 0x83, 0xdf, 0x50, 0x00, 0xe7, 0x04, 0xe3,
43 0xff, 0x00, 0x00, 0x22
44 };
45
46 UINT8 Crtc_640_480_32bpp_60[28] = {
47 0x5d, 0x4f, 0x50, 0x82, 0x53, 0x9f, 0x00, 0x3e,
48 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 0xe1, 0x83, 0xdf, 0x40, 0x00, 0xe7, 0x04, 0xe3,
50 0xff, 0x00, 0x00, 0x32
51 };
52
53 UINT16 Seq_640_480_256_60[15] = {
54 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b,
55 0x5b0c, 0x450d, 0x7e0e, 0x2b1b, 0x2f1c, 0x301d, 0x331e
56 };
57
58 UINT16 Seq_640_480_32bpp_60[15] = {
59 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b,
60 0x5b0c, 0x450d, 0x7e0e, 0x2b1b, 0x2f1c, 0x301d, 0x331e
61 };
62
63 //
64 // 800 x 600 x 256 color @ 60 Hertz
65 //
66 UINT8 Crtc_800_600_256_60[28] = {
67 0x7F, 0x63, 0x64, 0x80, 0x6B, 0x1B, 0x72, 0xF0,
68 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69 0x58, 0x8C, 0x57, 0x64, 0x00, 0x5F, 0x91, 0xE3,
70 0xFF, 0x00, 0x00, 0x22
71 };
72
73 UINT8 Crtc_800_600_32bpp_60[28] = {
74 0x7F, 0x63, 0x64, 0x80, 0x6B, 0x1B, 0x72, 0xF0,
75 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
76 0x58, 0x8C, 0x57, 0x90, 0x00, 0x5F, 0x91, 0xE3,
77 0xFF, 0x00, 0x00, 0x32
78 };
79
80 UINT16 Seq_800_600_256_60[15] = {
81 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b,
82 0x5b0c, 0x450d, 0x510e, 0x2b1b, 0x2f1c, 0x301d, 0x3a1e
83 };
84
85 UINT16 Seq_800_600_32bpp_60[15] = {
86 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b,
87 0x5b0c, 0x450d, 0x510e, 0x2b1b, 0x2f1c, 0x301d, 0x3a1e
88 };
89
90 UINT8 Crtc_960_720_32bpp_60[28] = {
91 0xA3, 0x77, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD,
92 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
93 0x02, 0x88, 0xCF, 0xe0, 0x00, 0x00, 0x64, 0xE3,
94 0xFF, 0x4A, 0x00, 0x32
95 };
96
97 UINT16 Seq_960_720_32bpp_60[15] = {
98 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b,
99 0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e
100 };
101
102 //
103 // 1024 x 768 x 256 color @ 60 Hertz
104 //
105 UINT8 Crtc_1024_768_256_60[28] = {
106 0xA3, 0x7F, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD,
107 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
108 0x02, 0x88, 0xFF, 0x80, 0x00, 0x00, 0x24, 0xE3,
109 0xFF, 0x4A, 0x00, 0x22
110 };
111
112 UINT16 Seq_1024_768_256_60[15] = {
113 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b,
114 0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e
115 };
116
117 //
118 // 1024 x 768 x 24-bit color @ 60 Hertz
119 //
120 UINT8 Crtc_1024_768_24bpp_60[28] = {
121 0xA3, 0x7F, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD,
122 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
123 0x02, 0x88, 0xFF, 0x80, 0x00, 0x00, 0x24, 0xE3,
124 0xFF, 0x4A, 0x00, 0x32
125 };
126
127 UINT16 Seq_1024_768_24bpp_60[15] = {
128 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1507, 0x0008, 0x4a0b,
129 0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e
130 };
131
132 UINT8 Crtc_1024_768_32bpp_60[28] = {
133 0xA3, 0x7F, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD,
134 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135 0x02, 0x88, 0xFF, 0xe0, 0x00, 0x00, 0x64, 0xE3,
136 0xFF, 0x4A, 0x00, 0x32
137 };
138
139 UINT16 Seq_1024_768_32bpp_60[15] = {
140 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b,
141 0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e
142 };
143
144 ///
145 /// Table of supported video modes
146 ///
147 QEMU_VIDEO_CIRRUS_MODES QemuVideoCirrusModes[] = {
148 // { 640, 480, 8, Crtc_640_480_256_60, Seq_640_480_256_60, 0xe3 },
149 // { 800, 600, 8, Crtc_800_600_256_60, Seq_800_600_256_60, 0xef },
150 { 640, 480, 32, Crtc_640_480_32bpp_60, Seq_640_480_32bpp_60, 0xef },
151 { 800, 600, 32, Crtc_800_600_32bpp_60, Seq_800_600_32bpp_60, 0xef },
152 // { 1024, 768, 8, Crtc_1024_768_256_60, Seq_1024_768_256_60, 0xef }
153 { 1024, 768, 24, Crtc_1024_768_24bpp_60, Seq_1024_768_24bpp_60, 0xef }
154 // { 1024, 768, 32, Crtc_1024_768_32bpp_60, Seq_1024_768_32bpp_60, 0xef }
155 // { 960, 720, 32, Crtc_960_720_32bpp_60, Seq_1024_768_32bpp_60, 0xef }
156 };
157
158 #define QEMU_VIDEO_CIRRUS_MODE_COUNT \
159 (ARRAY_SIZE (QemuVideoCirrusModes))
160
161 /**
162 Construct the valid video modes for QemuVideo.
163
164 **/
165 EFI_STATUS
166 QemuVideoCirrusModeSetup (
167 QEMU_VIDEO_PRIVATE_DATA *Private
168 )
169 {
170 UINT32 Index;
171 QEMU_VIDEO_MODE_DATA *ModeData;
172 QEMU_VIDEO_CIRRUS_MODES *VideoMode;
173
174 //
175 // Setup Video Modes
176 //
177 Private->ModeData = AllocatePool (
178 sizeof (Private->ModeData[0]) * QEMU_VIDEO_CIRRUS_MODE_COUNT
179 );
180 if (Private->ModeData == NULL) {
181 return EFI_OUT_OF_RESOURCES;
182 }
183 ModeData = Private->ModeData;
184 VideoMode = &QemuVideoCirrusModes[0];
185 for (Index = 0; Index < QEMU_VIDEO_CIRRUS_MODE_COUNT; Index ++) {
186 ModeData->InternalModeIndex = Index;
187 ModeData->HorizontalResolution = VideoMode->Width;
188 ModeData->VerticalResolution = VideoMode->Height;
189 ModeData->ColorDepth = VideoMode->ColorDepth;
190 DEBUG ((EFI_D_INFO,
191 "Adding Mode %d as Cirrus Internal Mode %d: %dx%d, %d-bit\n",
192 (INT32) (ModeData - Private->ModeData),
193 ModeData->InternalModeIndex,
194 ModeData->HorizontalResolution,
195 ModeData->VerticalResolution,
196 ModeData->ColorDepth
197 ));
198
199 ModeData ++ ;
200 VideoMode ++;
201 }
202 Private->MaxMode = ModeData - Private->ModeData;
203
204 return EFI_SUCCESS;
205 }
206
207 ///
208 /// Table of supported video modes
209 ///
210 QEMU_VIDEO_BOCHS_MODES QemuVideoBochsModes[] = {
211 { 640, 480, 32 },
212 { 800, 480, 32 },
213 { 800, 600, 32 },
214 { 832, 624, 32 },
215 { 960, 640, 32 },
216 { 1024, 600, 32 },
217 { 1024, 768, 32 },
218 { 1152, 864, 32 },
219 { 1152, 870, 32 },
220 { 1280, 720, 32 },
221 { 1280, 760, 32 },
222 { 1280, 768, 32 },
223 { 1280, 800, 32 },
224 { 1280, 960, 32 },
225 { 1280, 1024, 32 },
226 { 1360, 768, 32 },
227 { 1366, 768, 32 },
228 { 1400, 1050, 32 },
229 { 1440, 900, 32 },
230 { 1600, 900, 32 },
231 { 1600, 1200, 32 },
232 { 1680, 1050, 32 },
233 { 1920, 1080, 32 },
234 { 1920, 1200, 32 },
235 { 1920, 1440, 32 },
236 { 2000, 2000, 32 },
237 { 2048, 1536, 32 },
238 { 2048, 2048, 32 },
239 { 2560, 1440, 32 },
240 { 2560, 1600, 32 },
241 { 2560, 2048, 32 },
242 { 2800, 2100, 32 },
243 { 3200, 2400, 32 },
244 { 3840, 2160, 32 },
245 { 4096, 2160, 32 },
246 { 7680, 4320, 32 },
247 { 8192, 4320, 32 }
248 };
249
250 #define QEMU_VIDEO_BOCHS_MODE_COUNT \
251 (ARRAY_SIZE (QemuVideoBochsModes))
252
253 EFI_STATUS
254 QemuVideoBochsModeSetup (
255 QEMU_VIDEO_PRIVATE_DATA *Private,
256 BOOLEAN IsQxl
257 )
258 {
259 UINT32 AvailableFbSize;
260 UINT32 Index;
261 QEMU_VIDEO_MODE_DATA *ModeData;
262 QEMU_VIDEO_BOCHS_MODES *VideoMode;
263
264 //
265 // Fetch the available framebuffer size.
266 //
267 // VBE_DISPI_INDEX_VIDEO_MEMORY_64K is expected to return the size of the
268 // drawable framebuffer. Up to and including qemu-2.1 however it used to
269 // return the size of PCI BAR 0 (ie. the full video RAM size).
270 //
271 // On stdvga the two concepts coincide with each other; the full memory size
272 // is usable for drawing.
273 //
274 // On QXL however, only a leading segment, "surface 0", can be used for
275 // drawing; the rest of the video memory is used for the QXL guest-host
276 // protocol. VBE_DISPI_INDEX_VIDEO_MEMORY_64K should report the size of
277 // "surface 0", but since it doesn't (up to and including qemu-2.1), we
278 // retrieve the size of the drawable portion from a field in the QXL ROM BAR,
279 // where it is also available.
280 //
281 if (IsQxl) {
282 UINT32 Signature;
283 UINT32 DrawStart;
284
285 Signature = 0;
286 DrawStart = 0xFFFFFFFF;
287 AvailableFbSize = 0;
288 if (EFI_ERROR (
289 Private->PciIo->Mem.Read (Private->PciIo, EfiPciIoWidthUint32,
290 PCI_BAR_IDX2, 0, 1, &Signature)) ||
291 Signature != SIGNATURE_32 ('Q', 'X', 'R', 'O') ||
292 EFI_ERROR (
293 Private->PciIo->Mem.Read (Private->PciIo, EfiPciIoWidthUint32,
294 PCI_BAR_IDX2, 36, 1, &DrawStart)) ||
295 DrawStart != 0 ||
296 EFI_ERROR (
297 Private->PciIo->Mem.Read (Private->PciIo, EfiPciIoWidthUint32,
298 PCI_BAR_IDX2, 40, 1, &AvailableFbSize))) {
299 DEBUG ((EFI_D_ERROR, "%a: can't read size of drawable buffer from QXL "
300 "ROM\n", __FUNCTION__));
301 return EFI_NOT_FOUND;
302 }
303 } else {
304 AvailableFbSize = BochsRead (Private, VBE_DISPI_INDEX_VIDEO_MEMORY_64K);
305 AvailableFbSize *= SIZE_64KB;
306 }
307 DEBUG ((EFI_D_INFO, "%a: AvailableFbSize=0x%x\n", __FUNCTION__,
308 AvailableFbSize));
309
310 //
311 // Setup Video Modes
312 //
313 Private->ModeData = AllocatePool (
314 sizeof (Private->ModeData[0]) * QEMU_VIDEO_BOCHS_MODE_COUNT
315 );
316 if (Private->ModeData == NULL) {
317 return EFI_OUT_OF_RESOURCES;
318 }
319 ModeData = Private->ModeData;
320 VideoMode = &QemuVideoBochsModes[0];
321 for (Index = 0; Index < QEMU_VIDEO_BOCHS_MODE_COUNT; Index ++) {
322 UINTN RequiredFbSize;
323
324 ASSERT (VideoMode->ColorDepth % 8 == 0);
325 RequiredFbSize = (UINTN) VideoMode->Width * VideoMode->Height *
326 (VideoMode->ColorDepth / 8);
327 if (RequiredFbSize <= AvailableFbSize) {
328 ModeData->InternalModeIndex = Index;
329 ModeData->HorizontalResolution = VideoMode->Width;
330 ModeData->VerticalResolution = VideoMode->Height;
331 ModeData->ColorDepth = VideoMode->ColorDepth;
332 DEBUG ((EFI_D_INFO,
333 "Adding Mode %d as Bochs Internal Mode %d: %dx%d, %d-bit\n",
334 (INT32) (ModeData - Private->ModeData),
335 ModeData->InternalModeIndex,
336 ModeData->HorizontalResolution,
337 ModeData->VerticalResolution,
338 ModeData->ColorDepth
339 ));
340
341 ModeData ++ ;
342 }
343 VideoMode ++;
344 }
345 Private->MaxMode = ModeData - Private->ModeData;
346
347 return EFI_SUCCESS;
348 }
349
350 EFI_STATUS
351 QemuVideoVmwareSvgaModeSetup (
352 QEMU_VIDEO_PRIVATE_DATA *Private
353 )
354 {
355 EFI_STATUS Status;
356 UINT32 FbSize;
357 UINT32 MaxWidth, MaxHeight;
358 UINT32 Capabilities;
359 UINT32 BitsPerPixel;
360 UINT32 Index;
361 QEMU_VIDEO_MODE_DATA *ModeData;
362 QEMU_VIDEO_BOCHS_MODES *VideoMode;
363 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *ModeInfo;
364
365 VmwareSvgaWrite (Private, VmwareSvgaRegEnable, 0);
366
367 Private->ModeData =
368 AllocatePool (sizeof (Private->ModeData[0]) * QEMU_VIDEO_BOCHS_MODE_COUNT);
369 if (Private->ModeData == NULL) {
370 Status = EFI_OUT_OF_RESOURCES;
371 goto ModeDataAllocError;
372 }
373
374 Private->VmwareSvgaModeInfo =
375 AllocatePool (
376 sizeof (Private->VmwareSvgaModeInfo[0]) * QEMU_VIDEO_BOCHS_MODE_COUNT
377 );
378 if (Private->VmwareSvgaModeInfo == NULL) {
379 Status = EFI_OUT_OF_RESOURCES;
380 goto ModeInfoAllocError;
381 }
382
383 FbSize = VmwareSvgaRead (Private, VmwareSvgaRegFbSize);
384 MaxWidth = VmwareSvgaRead (Private, VmwareSvgaRegMaxWidth);
385 MaxHeight = VmwareSvgaRead (Private, VmwareSvgaRegMaxHeight);
386 Capabilities = VmwareSvgaRead (Private, VmwareSvgaRegCapabilities);
387 if ((Capabilities & VMWARE_SVGA_CAP_8BIT_EMULATION) != 0) {
388 BitsPerPixel = VmwareSvgaRead (
389 Private,
390 VmwareSvgaRegHostBitsPerPixel
391 );
392 VmwareSvgaWrite (
393 Private,
394 VmwareSvgaRegBitsPerPixel,
395 BitsPerPixel
396 );
397 } else {
398 BitsPerPixel = VmwareSvgaRead (
399 Private,
400 VmwareSvgaRegBitsPerPixel
401 );
402 }
403
404 if (FbSize == 0 ||
405 MaxWidth == 0 ||
406 MaxHeight == 0 ||
407 BitsPerPixel == 0 ||
408 BitsPerPixel % 8 != 0) {
409 Status = EFI_DEVICE_ERROR;
410 goto Rollback;
411 }
412
413 ModeData = Private->ModeData;
414 ModeInfo = Private->VmwareSvgaModeInfo;
415 VideoMode = &QemuVideoBochsModes[0];
416 for (Index = 0; Index < QEMU_VIDEO_BOCHS_MODE_COUNT; Index++) {
417 UINTN RequiredFbSize;
418
419 RequiredFbSize = (UINTN) VideoMode->Width * VideoMode->Height *
420 (BitsPerPixel / 8);
421 if (RequiredFbSize <= FbSize &&
422 VideoMode->Width <= MaxWidth &&
423 VideoMode->Height <= MaxHeight) {
424 UINT32 BytesPerLine;
425 UINT32 RedMask, GreenMask, BlueMask, PixelMask;
426
427 VmwareSvgaWrite (
428 Private,
429 VmwareSvgaRegWidth,
430 VideoMode->Width
431 );
432 VmwareSvgaWrite (
433 Private,
434 VmwareSvgaRegHeight,
435 VideoMode->Height
436 );
437
438 ModeData->InternalModeIndex = Index;
439 ModeData->HorizontalResolution = VideoMode->Width;
440 ModeData->VerticalResolution = VideoMode->Height;
441 ModeData->ColorDepth = BitsPerPixel;
442
443 //
444 // Setting VmwareSvgaRegWidth/VmwareSvgaRegHeight actually changes
445 // the device's display mode, so we save all properties of each mode up
446 // front to avoid inadvertent mode changes later.
447 //
448 ModeInfo->Version = 0;
449 ModeInfo->HorizontalResolution = ModeData->HorizontalResolution;
450 ModeInfo->VerticalResolution = ModeData->VerticalResolution;
451
452 ModeInfo->PixelFormat = PixelBitMask;
453
454 RedMask = VmwareSvgaRead (Private, VmwareSvgaRegRedMask);
455 ModeInfo->PixelInformation.RedMask = RedMask;
456
457 GreenMask = VmwareSvgaRead (Private, VmwareSvgaRegGreenMask);
458 ModeInfo->PixelInformation.GreenMask = GreenMask;
459
460 BlueMask = VmwareSvgaRead (Private, VmwareSvgaRegBlueMask);
461 ModeInfo->PixelInformation.BlueMask = BlueMask;
462
463 //
464 // Reserved mask is whatever bits in the pixel not containing RGB data,
465 // so start with binary 1s for every bit in the pixel, then mask off
466 // bits already used for RGB. Special case 32 to avoid undefined
467 // behaviour in the shift.
468 //
469 if (BitsPerPixel == 32) {
470 if (BlueMask == 0xff && GreenMask == 0xff00 && RedMask == 0xff0000) {
471 ModeInfo->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
472 } else if (BlueMask == 0xff0000 &&
473 GreenMask == 0xff00 &&
474 RedMask == 0xff) {
475 ModeInfo->PixelFormat = PixelRedGreenBlueReserved8BitPerColor;
476 }
477 PixelMask = MAX_UINT32;
478 } else {
479 PixelMask = (1u << BitsPerPixel) - 1;
480 }
481 ModeInfo->PixelInformation.ReservedMask =
482 PixelMask & ~(RedMask | GreenMask | BlueMask);
483
484 BytesPerLine = VmwareSvgaRead (Private, VmwareSvgaRegBytesPerLine);
485 ModeInfo->PixelsPerScanLine = BytesPerLine / (BitsPerPixel / 8);
486
487 ModeData++;
488 ModeInfo++;
489 }
490 VideoMode++;
491 }
492 Private->MaxMode = ModeData - Private->ModeData;
493 return EFI_SUCCESS;
494
495 Rollback:
496 FreePool (Private->VmwareSvgaModeInfo);
497 Private->VmwareSvgaModeInfo = NULL;
498
499 ModeInfoAllocError:
500 FreePool (Private->ModeData);
501 Private->ModeData = NULL;
502
503 ModeDataAllocError:
504 return Status;
505 }