]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/QemuVideoDxe/Initialize.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "Qemu.h"
11
12 ///
13 /// Generic Attribute Controller Register Settings
14 ///
15 UINT8 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 ///
24 UINT8 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 //
31 UINT8 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
38 UINT8 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
45 UINT16 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
50 UINT16 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 //
58 UINT8 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
65 UINT8 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
72 UINT16 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
77 UINT16 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
82 UINT8 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
89 UINT16 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 //
97 UINT8 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
104 UINT16 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 //
112 UINT8 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
119 UINT16 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
124 UINT8 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
131 UINT16 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 ///
139 QEMU_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 **/
157 EFI_STATUS
158 QemuVideoCirrusModeSetup (
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 ///
205 STATIC 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
248 STATIC
249 VOID
250 QemuVideoBochsAddMode (
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
287 STATIC
288 VOID
289 QemuVideoBochsEdid (
290 QEMU_VIDEO_PRIVATE_DATA *Private,
291 UINT32 *XRes,
292 UINT32 *YRes
293 )
294 {
295 EFI_STATUS Status;
296
297 if (Private->Variant != QEMU_VIDEO_BOCHS_MMIO) {
298 return;
299 }
300
301 Status = Private->PciIo->Mem.Read (
302 Private->PciIo,
303 EfiPciIoWidthUint8,
304 PCI_BAR_IDX2,
305 0,
306 sizeof (Private->Edid),
307 Private->Edid
308 );
309 if (Status != EFI_SUCCESS) {
310 DEBUG ((
311 DEBUG_INFO,
312 "%a: mmio read failed\n",
313 __FUNCTION__
314 ));
315 return;
316 }
317
318 if ((Private->Edid[0] != 0x00) ||
319 (Private->Edid[1] != 0xff))
320 {
321 DEBUG ((
322 DEBUG_INFO,
323 "%a: magic check failed\n",
324 __FUNCTION__
325 ));
326 return;
327 }
328
329 DEBUG ((
330 DEBUG_INFO,
331 "%a: blob found (extensions: %d)\n",
332 __FUNCTION__,
333 Private->Edid[126]
334 ));
335
336 if ((Private->Edid[54] == 0x00) &&
337 (Private->Edid[55] == 0x00))
338 {
339 DEBUG ((
340 DEBUG_INFO,
341 "%a: no detailed timing descriptor\n",
342 __FUNCTION__
343 ));
344 return;
345 }
346
347 *XRes = Private->Edid[56] | ((Private->Edid[58] & 0xf0) << 4);
348 *YRes = Private->Edid[59] | ((Private->Edid[61] & 0xf0) << 4);
349 DEBUG ((
350 DEBUG_INFO,
351 "%a: default resolution: %dx%d\n",
352 __FUNCTION__,
353 *XRes,
354 *YRes
355 ));
356
357 if (PcdGet8 (PcdVideoResolutionSource) == 0) {
358 Status = PcdSet32S (PcdVideoHorizontalResolution, *XRes);
359 ASSERT_RETURN_ERROR (Status);
360 Status = PcdSet32S (PcdVideoVerticalResolution, *YRes);
361 ASSERT_RETURN_ERROR (Status);
362 Status = PcdSet8S (PcdVideoResolutionSource, 2);
363 ASSERT_RETURN_ERROR (Status);
364 }
365
366 // TODO: register edid as gEfiEdidDiscoveredProtocolGuid ?
367 }
368
369 EFI_STATUS
370 QemuVideoBochsModeSetup (
371 QEMU_VIDEO_PRIVATE_DATA *Private,
372 BOOLEAN IsQxl
373 )
374 {
375 UINT32 AvailableFbSize;
376 UINT32 Index, XRes = 0, YRes = 0;
377
378 //
379 // Fetch the available framebuffer size.
380 //
381 // VBE_DISPI_INDEX_VIDEO_MEMORY_64K is expected to return the size of the
382 // drawable framebuffer. Up to and including qemu-2.1 however it used to
383 // return the size of PCI BAR 0 (ie. the full video RAM size).
384 //
385 // On stdvga the two concepts coincide with each other; the full memory size
386 // is usable for drawing.
387 //
388 // On QXL however, only a leading segment, "surface 0", can be used for
389 // drawing; the rest of the video memory is used for the QXL guest-host
390 // protocol. VBE_DISPI_INDEX_VIDEO_MEMORY_64K should report the size of
391 // "surface 0", but since it doesn't (up to and including qemu-2.1), we
392 // retrieve the size of the drawable portion from a field in the QXL ROM BAR,
393 // where it is also available.
394 //
395 if (IsQxl) {
396 UINT32 Signature;
397 UINT32 DrawStart;
398
399 Signature = 0;
400 DrawStart = 0xFFFFFFFF;
401 AvailableFbSize = 0;
402 if (EFI_ERROR (
403 Private->PciIo->Mem.Read (
404 Private->PciIo,
405 EfiPciIoWidthUint32,
406 PCI_BAR_IDX2,
407 0,
408 1,
409 &Signature
410 )
411 ) ||
412 (Signature != SIGNATURE_32 ('Q', 'X', 'R', 'O')) ||
413 EFI_ERROR (
414 Private->PciIo->Mem.Read (
415 Private->PciIo,
416 EfiPciIoWidthUint32,
417 PCI_BAR_IDX2,
418 36,
419 1,
420 &DrawStart
421 )
422 ) ||
423 (DrawStart != 0) ||
424 EFI_ERROR (
425 Private->PciIo->Mem.Read (
426 Private->PciIo,
427 EfiPciIoWidthUint32,
428 PCI_BAR_IDX2,
429 40,
430 1,
431 &AvailableFbSize
432 )
433 ))
434 {
435 DEBUG ((
436 DEBUG_ERROR,
437 "%a: can't read size of drawable buffer from QXL "
438 "ROM\n",
439 __FUNCTION__
440 ));
441 return EFI_NOT_FOUND;
442 }
443 } else {
444 AvailableFbSize = BochsRead (Private, VBE_DISPI_INDEX_VIDEO_MEMORY_64K);
445 AvailableFbSize *= SIZE_64KB;
446 }
447
448 DEBUG ((
449 DEBUG_INFO,
450 "%a: AvailableFbSize=0x%x\n",
451 __FUNCTION__,
452 AvailableFbSize
453 ));
454
455 //
456 // Setup Video Modes
457 //
458 Private->ModeData = AllocatePool (
459 sizeof (Private->ModeData[0]) * (QEMU_VIDEO_BOCHS_MODE_COUNT+1)
460 );
461 if (Private->ModeData == NULL) {
462 return EFI_OUT_OF_RESOURCES;
463 }
464
465 QemuVideoBochsEdid (Private, &XRes, &YRes);
466 if (XRes && YRes) {
467 QemuVideoBochsAddMode (
468 Private,
469 AvailableFbSize,
470 XRes,
471 YRes
472 );
473 }
474
475 for (Index = 0; Index < QEMU_VIDEO_BOCHS_MODE_COUNT; Index++) {
476 if ((QemuVideoBochsModes[Index].Width == XRes) &&
477 (QemuVideoBochsModes[Index].Height == YRes))
478 {
479 continue; // duplicate with edid resolution
480 }
481
482 QemuVideoBochsAddMode (
483 Private,
484 AvailableFbSize,
485 QemuVideoBochsModes[Index].Width,
486 QemuVideoBochsModes[Index].Height
487 );
488 }
489
490 return EFI_SUCCESS;
491 }