VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/OvmfPkg/QemuVideoDxe/Initialize.c

Last change on this file was 108794, checked in by vboxsync, 4 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette