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