]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/QemuVideoDxe/Gop.c
c9941ef138bd01caf819af8566cc221445218282
[mirror_edk2.git] / OvmfPkg / QemuVideoDxe / Gop.c
1 /** @file
2 Graphics Output Protocol functions for the QEMU video controller.
3
4 Copyright (c) 2007 - 2018, 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 STATIC
20 VOID
21 QemuVideoCompleteModeInfo (
22 IN QEMU_VIDEO_MODE_DATA *ModeData,
23 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info
24 )
25 {
26 Info->Version = 0;
27 if (ModeData->ColorDepth == 8) {
28 Info->PixelFormat = PixelBitMask;
29 Info->PixelInformation.RedMask = PIXEL_RED_MASK;
30 Info->PixelInformation.GreenMask = PIXEL_GREEN_MASK;
31 Info->PixelInformation.BlueMask = PIXEL_BLUE_MASK;
32 Info->PixelInformation.ReservedMask = 0;
33 } else if (ModeData->ColorDepth == 24) {
34 Info->PixelFormat = PixelBitMask;
35 Info->PixelInformation.RedMask = PIXEL24_RED_MASK;
36 Info->PixelInformation.GreenMask = PIXEL24_GREEN_MASK;
37 Info->PixelInformation.BlueMask = PIXEL24_BLUE_MASK;
38 Info->PixelInformation.ReservedMask = 0;
39 } else if (ModeData->ColorDepth == 32) {
40 DEBUG ((EFI_D_INFO, "PixelBlueGreenRedReserved8BitPerColor\n"));
41 Info->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
42 }
43 Info->PixelsPerScanLine = Info->HorizontalResolution;
44 }
45
46
47 STATIC
48 EFI_STATUS
49 QemuVideoCompleteModeData (
50 IN QEMU_VIDEO_PRIVATE_DATA *Private,
51 OUT EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode
52 )
53 {
54 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
55 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *FrameBufDesc;
56 QEMU_VIDEO_MODE_DATA *ModeData;
57
58 ModeData = &Private->ModeData[Mode->Mode];
59 Info = Mode->Info;
60 QemuVideoCompleteModeInfo (ModeData, Info);
61
62 Private->PciIo->GetBarAttributes (
63 Private->PciIo,
64 0,
65 NULL,
66 (VOID**) &FrameBufDesc
67 );
68
69 Mode->FrameBufferBase = FrameBufDesc->AddrRangeMin;
70 Mode->FrameBufferSize = Info->HorizontalResolution * Info->VerticalResolution;
71 Mode->FrameBufferSize = Mode->FrameBufferSize * ((ModeData->ColorDepth + 7) / 8);
72 Mode->FrameBufferSize = EFI_PAGES_TO_SIZE (
73 EFI_SIZE_TO_PAGES (Mode->FrameBufferSize)
74 );
75 DEBUG ((EFI_D_INFO, "FrameBufferBase: 0x%Lx, FrameBufferSize: 0x%Lx\n",
76 Mode->FrameBufferBase, (UINT64)Mode->FrameBufferSize));
77
78 FreePool (FrameBufDesc);
79 return EFI_SUCCESS;
80 }
81
82 STATIC
83 EFI_STATUS
84 QemuVideoVmwareSvgaCompleteModeData (
85 IN QEMU_VIDEO_PRIVATE_DATA *Private,
86 OUT EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode
87 )
88 {
89 EFI_STATUS Status;
90 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
91 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *FrameBufDesc;
92 UINT32 BytesPerLine, FbOffset, BytesPerPixel;
93
94 Info = Mode->Info;
95 CopyMem (Info, &Private->VmwareSvgaModeInfo[Mode->Mode], sizeof (*Info));
96 BytesPerPixel = Private->ModeData[Mode->Mode].ColorDepth / 8;
97 BytesPerLine = Info->PixelsPerScanLine * BytesPerPixel;
98
99 FbOffset = VmwareSvgaRead (Private, VmwareSvgaRegFbOffset);
100
101 Status = Private->PciIo->GetBarAttributes (
102 Private->PciIo,
103 PCI_BAR_IDX1,
104 NULL,
105 (VOID**) &FrameBufDesc
106 );
107 if (EFI_ERROR (Status)) {
108 return EFI_DEVICE_ERROR;
109 }
110
111 Mode->FrameBufferBase = FrameBufDesc->AddrRangeMin + FbOffset;
112 Mode->FrameBufferSize = BytesPerLine * Info->VerticalResolution;
113 Mode->FrameBufferSize = EFI_PAGES_TO_SIZE (
114 EFI_SIZE_TO_PAGES (Mode->FrameBufferSize)
115 );
116
117 FreePool (FrameBufDesc);
118 return Status;
119 }
120
121
122 //
123 // Graphics Output Protocol Member Functions
124 //
125 EFI_STATUS
126 EFIAPI
127 QemuVideoGraphicsOutputQueryMode (
128 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
129 IN UINT32 ModeNumber,
130 OUT UINTN *SizeOfInfo,
131 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
132 )
133 /*++
134
135 Routine Description:
136
137 Graphics Output protocol interface to query video mode
138
139 Arguments:
140 This - Protocol instance pointer.
141 ModeNumber - The mode number to return information on.
142 Info - Caller allocated buffer that returns information about ModeNumber.
143 SizeOfInfo - A pointer to the size, in bytes, of the Info buffer.
144
145 Returns:
146 EFI_SUCCESS - Mode information returned.
147 EFI_BUFFER_TOO_SMALL - The Info buffer was too small.
148 EFI_DEVICE_ERROR - A hardware error occurred trying to retrieve the video mode.
149 EFI_NOT_STARTED - Video display is not initialized. Call SetMode ()
150 EFI_INVALID_PARAMETER - One of the input args was NULL.
151
152 --*/
153 {
154 QEMU_VIDEO_PRIVATE_DATA *Private;
155 QEMU_VIDEO_MODE_DATA *ModeData;
156
157 Private = QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);
158
159 if (Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {
160 return EFI_INVALID_PARAMETER;
161 }
162
163 *Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
164 if (*Info == NULL) {
165 return EFI_OUT_OF_RESOURCES;
166 }
167
168 *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
169
170 if (Private->Variant == QEMU_VIDEO_VMWARE_SVGA) {
171 CopyMem (*Info, &Private->VmwareSvgaModeInfo[ModeNumber], sizeof (**Info));
172 } else {
173 ModeData = &Private->ModeData[ModeNumber];
174 (*Info)->HorizontalResolution = ModeData->HorizontalResolution;
175 (*Info)->VerticalResolution = ModeData->VerticalResolution;
176 QemuVideoCompleteModeInfo (ModeData, *Info);
177 }
178
179 return EFI_SUCCESS;
180 }
181
182 EFI_STATUS
183 EFIAPI
184 QemuVideoGraphicsOutputSetMode (
185 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
186 IN UINT32 ModeNumber
187 )
188 /*++
189
190 Routine Description:
191
192 Graphics Output protocol interface to set video mode
193
194 Arguments:
195 This - Protocol instance pointer.
196 ModeNumber - The mode number to be set.
197
198 Returns:
199 EFI_SUCCESS - Graphics mode was changed.
200 EFI_DEVICE_ERROR - The device had an error and could not complete the request.
201 EFI_UNSUPPORTED - ModeNumber is not supported by this device.
202
203 --*/
204 {
205 QEMU_VIDEO_PRIVATE_DATA *Private;
206 QEMU_VIDEO_MODE_DATA *ModeData;
207 RETURN_STATUS Status;
208 EFI_GRAPHICS_OUTPUT_BLT_PIXEL Black;
209
210 Private = QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);
211
212 if (ModeNumber >= This->Mode->MaxMode) {
213 return EFI_UNSUPPORTED;
214 }
215
216 ModeData = &Private->ModeData[ModeNumber];
217
218 switch (Private->Variant) {
219 case QEMU_VIDEO_CIRRUS_5430:
220 case QEMU_VIDEO_CIRRUS_5446:
221 InitializeCirrusGraphicsMode (Private, &QemuVideoCirrusModes[ModeData->InternalModeIndex]);
222 break;
223 case QEMU_VIDEO_BOCHS_MMIO:
224 case QEMU_VIDEO_BOCHS:
225 InitializeBochsGraphicsMode (Private, &QemuVideoBochsModes[ModeData->InternalModeIndex]);
226 break;
227 case QEMU_VIDEO_VMWARE_SVGA:
228 InitializeVmwareSvgaGraphicsMode (
229 Private,
230 &QemuVideoBochsModes[ModeData->InternalModeIndex]
231 );
232 break;
233 default:
234 ASSERT (FALSE);
235 return EFI_DEVICE_ERROR;
236 }
237
238 This->Mode->Mode = ModeNumber;
239 This->Mode->Info->HorizontalResolution = ModeData->HorizontalResolution;
240 This->Mode->Info->VerticalResolution = ModeData->VerticalResolution;
241 This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
242
243 if (Private->Variant == QEMU_VIDEO_VMWARE_SVGA) {
244 QemuVideoVmwareSvgaCompleteModeData (Private, This->Mode);
245 } else {
246 QemuVideoCompleteModeData (Private, This->Mode);
247 }
248
249 //
250 // Re-initialize the frame buffer configure when mode changes.
251 //
252 Status = FrameBufferBltConfigure (
253 (VOID*) (UINTN) This->Mode->FrameBufferBase,
254 This->Mode->Info,
255 Private->FrameBufferBltConfigure,
256 &Private->FrameBufferBltConfigureSize
257 );
258 if (Status == RETURN_BUFFER_TOO_SMALL) {
259 //
260 // Frame buffer configure may be larger in new mode.
261 //
262 if (Private->FrameBufferBltConfigure != NULL) {
263 FreePool (Private->FrameBufferBltConfigure);
264 }
265 Private->FrameBufferBltConfigure =
266 AllocatePool (Private->FrameBufferBltConfigureSize);
267 ASSERT (Private->FrameBufferBltConfigure != NULL);
268
269 //
270 // Create the configuration for FrameBufferBltLib
271 //
272 Status = FrameBufferBltConfigure (
273 (VOID*) (UINTN) This->Mode->FrameBufferBase,
274 This->Mode->Info,
275 Private->FrameBufferBltConfigure,
276 &Private->FrameBufferBltConfigureSize
277 );
278 }
279 ASSERT (Status == RETURN_SUCCESS);
280
281 //
282 // Per UEFI Spec, need to clear the visible portions of the output display to black.
283 //
284 ZeroMem (&Black, sizeof (Black));
285 Status = FrameBufferBlt (
286 Private->FrameBufferBltConfigure,
287 &Black,
288 EfiBltVideoFill,
289 0, 0,
290 0, 0,
291 This->Mode->Info->HorizontalResolution, This->Mode->Info->VerticalResolution,
292 0
293 );
294 ASSERT_RETURN_ERROR (Status);
295
296 return EFI_SUCCESS;
297 }
298
299 EFI_STATUS
300 EFIAPI
301 QemuVideoGraphicsOutputBlt (
302 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
303 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
304 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
305 IN UINTN SourceX,
306 IN UINTN SourceY,
307 IN UINTN DestinationX,
308 IN UINTN DestinationY,
309 IN UINTN Width,
310 IN UINTN Height,
311 IN UINTN Delta
312 )
313 /*++
314
315 Routine Description:
316
317 Graphics Output protocol instance to block transfer for CirrusLogic device
318
319 Arguments:
320
321 This - Pointer to Graphics Output protocol instance
322 BltBuffer - The data to transfer to screen
323 BltOperation - The operation to perform
324 SourceX - The X coordinate of the source for BltOperation
325 SourceY - The Y coordinate of the source for BltOperation
326 DestinationX - The X coordinate of the destination for BltOperation
327 DestinationY - The Y coordinate of the destination for BltOperation
328 Width - The width of a rectangle in the blt rectangle in pixels
329 Height - The height of a rectangle in the blt rectangle in pixels
330 Delta - Not used for EfiBltVideoFill and EfiBltVideoToVideo operation.
331 If a Delta of 0 is used, the entire BltBuffer will be operated on.
332 If a subrectangle of the BltBuffer is used, then Delta represents
333 the number of bytes in a row of the BltBuffer.
334
335 Returns:
336
337 EFI_INVALID_PARAMETER - Invalid parameter passed in
338 EFI_SUCCESS - Blt operation success
339
340 --*/
341 {
342 EFI_STATUS Status;
343 EFI_TPL OriginalTPL;
344 QEMU_VIDEO_PRIVATE_DATA *Private;
345
346 Private = QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);
347 //
348 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
349 // We would not want a timer based event (Cursor, ...) to come in while we are
350 // doing this operation.
351 //
352 OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
353
354 switch (BltOperation) {
355 case EfiBltVideoToBltBuffer:
356 case EfiBltBufferToVideo:
357 case EfiBltVideoFill:
358 case EfiBltVideoToVideo:
359 Status = FrameBufferBlt (
360 Private->FrameBufferBltConfigure,
361 BltBuffer,
362 BltOperation,
363 SourceX,
364 SourceY,
365 DestinationX,
366 DestinationY,
367 Width,
368 Height,
369 Delta
370 );
371 break;
372
373 default:
374 Status = EFI_INVALID_PARAMETER;
375 break;
376 }
377
378 gBS->RestoreTPL (OriginalTPL);
379
380 return Status;
381 }
382
383 EFI_STATUS
384 QemuVideoGraphicsOutputConstructor (
385 QEMU_VIDEO_PRIVATE_DATA *Private
386 )
387 {
388 EFI_STATUS Status;
389 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
390
391
392 GraphicsOutput = &Private->GraphicsOutput;
393 GraphicsOutput->QueryMode = QemuVideoGraphicsOutputQueryMode;
394 GraphicsOutput->SetMode = QemuVideoGraphicsOutputSetMode;
395 GraphicsOutput->Blt = QemuVideoGraphicsOutputBlt;
396
397 //
398 // Initialize the private data
399 //
400 Status = gBS->AllocatePool (
401 EfiBootServicesData,
402 sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE),
403 (VOID **) &Private->GraphicsOutput.Mode
404 );
405 if (EFI_ERROR (Status)) {
406 return Status;
407 }
408
409 Status = gBS->AllocatePool (
410 EfiBootServicesData,
411 sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION),
412 (VOID **) &Private->GraphicsOutput.Mode->Info
413 );
414 if (EFI_ERROR (Status)) {
415 goto FreeMode;
416 }
417 Private->GraphicsOutput.Mode->MaxMode = (UINT32) Private->MaxMode;
418 Private->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
419 Private->FrameBufferBltConfigure = NULL;
420 Private->FrameBufferBltConfigureSize = 0;
421
422 //
423 // Initialize the hardware
424 //
425 Status = GraphicsOutput->SetMode (GraphicsOutput, 0);
426 if (EFI_ERROR (Status)) {
427 goto FreeInfo;
428 }
429
430 DrawLogo (
431 Private,
432 Private->ModeData[Private->GraphicsOutput.Mode->Mode].HorizontalResolution,
433 Private->ModeData[Private->GraphicsOutput.Mode->Mode].VerticalResolution
434 );
435
436 return EFI_SUCCESS;
437
438 FreeInfo:
439 FreePool (Private->GraphicsOutput.Mode->Info);
440
441 FreeMode:
442 FreePool (Private->GraphicsOutput.Mode);
443 Private->GraphicsOutput.Mode = NULL;
444
445 return Status;
446 }
447
448 EFI_STATUS
449 QemuVideoGraphicsOutputDestructor (
450 QEMU_VIDEO_PRIVATE_DATA *Private
451 )
452 /*++
453
454 Routine Description:
455
456 Arguments:
457
458 Returns:
459
460 None
461
462 --*/
463 {
464 if (Private->FrameBufferBltConfigure != NULL) {
465 FreePool (Private->FrameBufferBltConfigure);
466 }
467
468 if (Private->GraphicsOutput.Mode != NULL) {
469 if (Private->GraphicsOutput.Mode->Info != NULL) {
470 gBS->FreePool (Private->GraphicsOutput.Mode->Info);
471 }
472 gBS->FreePool (Private->GraphicsOutput.Mode);
473 }
474
475 return EFI_SUCCESS;
476 }
477
478