2 Graphics Output Protocol functions for the QEMU video controller.
4 Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
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
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.
16 #include <IndustryStandard/VmwareSvga.h>
21 /// Generic Attribute Controller Register Settings
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
30 /// Generic Graphics Controller Register Settings
32 UINT8 GraphicsController
[9] = {
33 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0xFF
37 // 640 x 480 x 256 color @ 60 Hertz
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
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
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
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
64 // 800 x 600 x 256 color @ 60 Hertz
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
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
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
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
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
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
103 // 1024 x 768 x 256 color @ 60 Hertz
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
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
118 // 1024 x 768 x 24-bit color @ 60 Hertz
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
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
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
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
145 /// Table of supported video modes
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 }
158 #define QEMU_VIDEO_CIRRUS_MODE_COUNT \
159 (ARRAY_SIZE (QemuVideoCirrusModes))
162 Construct the valid video modes for QemuVideo.
166 QemuVideoCirrusModeSetup (
167 QEMU_VIDEO_PRIVATE_DATA
*Private
171 QEMU_VIDEO_MODE_DATA
*ModeData
;
172 QEMU_VIDEO_CIRRUS_MODES
*VideoMode
;
177 Private
->ModeData
= AllocatePool (
178 sizeof (Private
->ModeData
[0]) * QEMU_VIDEO_CIRRUS_MODE_COUNT
180 if (Private
->ModeData
== NULL
) {
181 return EFI_OUT_OF_RESOURCES
;
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
;
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
,
202 Private
->MaxMode
= ModeData
- Private
->ModeData
;
208 /// Table of supported video modes
210 QEMU_VIDEO_BOCHS_MODES QemuVideoBochsModes
[] = {
250 #define QEMU_VIDEO_BOCHS_MODE_COUNT \
251 (ARRAY_SIZE (QemuVideoBochsModes))
254 QemuVideoBochsModeSetup (
255 QEMU_VIDEO_PRIVATE_DATA
*Private
,
259 UINT32 AvailableFbSize
;
261 QEMU_VIDEO_MODE_DATA
*ModeData
;
262 QEMU_VIDEO_BOCHS_MODES
*VideoMode
;
265 // Fetch the available framebuffer size.
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).
271 // On stdvga the two concepts coincide with each other; the full memory size
272 // is usable for drawing.
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.
286 DrawStart
= 0xFFFFFFFF;
289 Private
->PciIo
->Mem
.Read (Private
->PciIo
, EfiPciIoWidthUint32
,
290 PCI_BAR_IDX2
, 0, 1, &Signature
)) ||
291 Signature
!= SIGNATURE_32 ('Q', 'X', 'R', 'O') ||
293 Private
->PciIo
->Mem
.Read (Private
->PciIo
, EfiPciIoWidthUint32
,
294 PCI_BAR_IDX2
, 36, 1, &DrawStart
)) ||
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
;
304 AvailableFbSize
= BochsRead (Private
, VBE_DISPI_INDEX_VIDEO_MEMORY_64K
);
305 AvailableFbSize
*= SIZE_64KB
;
307 DEBUG ((EFI_D_INFO
, "%a: AvailableFbSize=0x%x\n", __FUNCTION__
,
313 Private
->ModeData
= AllocatePool (
314 sizeof (Private
->ModeData
[0]) * QEMU_VIDEO_BOCHS_MODE_COUNT
316 if (Private
->ModeData
== NULL
) {
317 return EFI_OUT_OF_RESOURCES
;
319 ModeData
= Private
->ModeData
;
320 VideoMode
= &QemuVideoBochsModes
[0];
321 for (Index
= 0; Index
< QEMU_VIDEO_BOCHS_MODE_COUNT
; Index
++) {
322 UINTN RequiredFbSize
;
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
;
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
,
345 Private
->MaxMode
= ModeData
- Private
->ModeData
;
351 QemuVideoVmwareSvgaModeSetup (
352 QEMU_VIDEO_PRIVATE_DATA
*Private
357 UINT32 MaxWidth
, MaxHeight
;
361 QEMU_VIDEO_MODE_DATA
*ModeData
;
362 QEMU_VIDEO_BOCHS_MODES
*VideoMode
;
363 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
*ModeInfo
;
365 VmwareSvgaWrite (Private
, VmwareSvgaRegEnable
, 0);
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
;
374 Private
->VmwareSvgaModeInfo
=
376 sizeof (Private
->VmwareSvgaModeInfo
[0]) * QEMU_VIDEO_BOCHS_MODE_COUNT
378 if (Private
->VmwareSvgaModeInfo
== NULL
) {
379 Status
= EFI_OUT_OF_RESOURCES
;
380 goto ModeInfoAllocError
;
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 (
390 VmwareSvgaRegHostBitsPerPixel
394 VmwareSvgaRegBitsPerPixel
,
398 BitsPerPixel
= VmwareSvgaRead (
400 VmwareSvgaRegBitsPerPixel
408 BitsPerPixel
% 8 != 0) {
409 Status
= EFI_DEVICE_ERROR
;
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
;
419 RequiredFbSize
= (UINTN
) VideoMode
->Width
* VideoMode
->Height
*
421 if (RequiredFbSize
<= FbSize
&&
422 VideoMode
->Width
<= MaxWidth
&&
423 VideoMode
->Height
<= MaxHeight
) {
425 UINT32 RedMask
, GreenMask
, BlueMask
, PixelMask
;
438 ModeData
->InternalModeIndex
= Index
;
439 ModeData
->HorizontalResolution
= VideoMode
->Width
;
440 ModeData
->VerticalResolution
= VideoMode
->Height
;
441 ModeData
->ColorDepth
= BitsPerPixel
;
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.
448 ModeInfo
->Version
= 0;
449 ModeInfo
->HorizontalResolution
= ModeData
->HorizontalResolution
;
450 ModeInfo
->VerticalResolution
= ModeData
->VerticalResolution
;
452 ModeInfo
->PixelFormat
= PixelBitMask
;
454 RedMask
= VmwareSvgaRead (Private
, VmwareSvgaRegRedMask
);
455 ModeInfo
->PixelInformation
.RedMask
= RedMask
;
457 GreenMask
= VmwareSvgaRead (Private
, VmwareSvgaRegGreenMask
);
458 ModeInfo
->PixelInformation
.GreenMask
= GreenMask
;
460 BlueMask
= VmwareSvgaRead (Private
, VmwareSvgaRegBlueMask
);
461 ModeInfo
->PixelInformation
.BlueMask
= BlueMask
;
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.
469 if (BitsPerPixel
== 32) {
470 if (BlueMask
== 0xff && GreenMask
== 0xff00 && RedMask
== 0xff0000) {
471 ModeInfo
->PixelFormat
= PixelBlueGreenRedReserved8BitPerColor
;
472 } else if (BlueMask
== 0xff0000 &&
473 GreenMask
== 0xff00 &&
475 ModeInfo
->PixelFormat
= PixelRedGreenBlueReserved8BitPerColor
;
477 PixelMask
= MAX_UINT32
;
479 PixelMask
= (1u << BitsPerPixel
) - 1;
481 ModeInfo
->PixelInformation
.ReservedMask
=
482 PixelMask
& ~(RedMask
| GreenMask
| BlueMask
);
484 BytesPerLine
= VmwareSvgaRead (Private
, VmwareSvgaRegBytesPerLine
);
485 ModeInfo
->PixelsPerScanLine
= BytesPerLine
/ (BitsPerPixel
/ 8);
492 Private
->MaxMode
= ModeData
- Private
->ModeData
;
496 FreePool (Private
->VmwareSvgaModeInfo
);
497 Private
->VmwareSvgaModeInfo
= NULL
;
500 FreePool (Private
->ModeData
);
501 Private
->ModeData
= NULL
;