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