512fd27acbda08a4ed7ee9ddacd0b3a1a6875b83
[mirror_edk2.git] / OvmfPkg / QemuVideoDxe / Gop.c
1 /** @file
2 Graphics Output Protocol functions for the QEMU video controller.
3
4 Copyright (c) 2007 - 2017, 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
203 Private = QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);
204
205 if (ModeNumber >= This->Mode->MaxMode) {
206 return EFI_UNSUPPORTED;
207 }
208
209 ModeData = &Private->ModeData[ModeNumber];
210
211 switch (Private->Variant) {
212 case QEMU_VIDEO_CIRRUS_5430:
213 case QEMU_VIDEO_CIRRUS_5446:
214 InitializeCirrusGraphicsMode (Private, &QemuVideoCirrusModes[ModeData->InternalModeIndex]);
215 break;
216 case QEMU_VIDEO_BOCHS_MMIO:
217 case QEMU_VIDEO_BOCHS:
218 InitializeBochsGraphicsMode (Private, &QemuVideoBochsModes[ModeData->InternalModeIndex]);
219 break;
220 case QEMU_VIDEO_VMWARE_SVGA:
221 InitializeVmwareSvgaGraphicsMode (
222 Private,
223 &QemuVideoBochsModes[ModeData->InternalModeIndex]
224 );
225 break;
226 default:
227 ASSERT (FALSE);
228 return EFI_DEVICE_ERROR;
229 }
230
231 This->Mode->Mode = ModeNumber;
232 This->Mode->Info->HorizontalResolution = ModeData->HorizontalResolution;
233 This->Mode->Info->VerticalResolution = ModeData->VerticalResolution;
234 This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
235
236 if (Private->Variant == QEMU_VIDEO_VMWARE_SVGA) {
237 QemuVideoVmwareSvgaCompleteModeData (Private, This->Mode);
238 } else {
239 QemuVideoCompleteModeData (Private, This->Mode);
240 }
241
242 //
243 // Re-initialize the frame buffer configure when mode changes.
244 //
245 Status = FrameBufferBltConfigure (
246 (VOID*) (UINTN) This->Mode->FrameBufferBase,
247 This->Mode->Info,
248 Private->FrameBufferBltConfigure,
249 &Private->FrameBufferBltConfigureSize
250 );
251 if (Status == RETURN_BUFFER_TOO_SMALL) {
252 //
253 // Frame buffer configure may be larger in new mode.
254 //
255 if (Private->FrameBufferBltConfigure != NULL) {
256 FreePool (Private->FrameBufferBltConfigure);
257 }
258 Private->FrameBufferBltConfigure =
259 AllocatePool (Private->FrameBufferBltConfigureSize);
260 ASSERT (Private->FrameBufferBltConfigure != NULL);
261
262 //
263 // Create the configuration for FrameBufferBltLib
264 //
265 Status = FrameBufferBltConfigure (
266 (VOID*) (UINTN) This->Mode->FrameBufferBase,
267 This->Mode->Info,
268 Private->FrameBufferBltConfigure,
269 &Private->FrameBufferBltConfigureSize
270 );
271 }
272 ASSERT (Status == RETURN_SUCCESS);
273
274 return EFI_SUCCESS;
275 }
276
277 EFI_STATUS
278 EFIAPI
279 QemuVideoGraphicsOutputBlt (
280 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
281 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
282 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
283 IN UINTN SourceX,
284 IN UINTN SourceY,
285 IN UINTN DestinationX,
286 IN UINTN DestinationY,
287 IN UINTN Width,
288 IN UINTN Height,
289 IN UINTN Delta
290 )
291 /*++
292
293 Routine Description:
294
295 Graphics Output protocol instance to block transfer for CirrusLogic device
296
297 Arguments:
298
299 This - Pointer to Graphics Output protocol instance
300 BltBuffer - The data to transfer to screen
301 BltOperation - The operation to perform
302 SourceX - The X coordinate of the source for BltOperation
303 SourceY - The Y coordinate of the source for BltOperation
304 DestinationX - The X coordinate of the destination for BltOperation
305 DestinationY - The Y coordinate of the destination for BltOperation
306 Width - The width of a rectangle in the blt rectangle in pixels
307 Height - The height of a rectangle in the blt rectangle in pixels
308 Delta - Not used for EfiBltVideoFill and EfiBltVideoToVideo operation.
309 If a Delta of 0 is used, the entire BltBuffer will be operated on.
310 If a subrectangle of the BltBuffer is used, then Delta represents
311 the number of bytes in a row of the BltBuffer.
312
313 Returns:
314
315 EFI_INVALID_PARAMETER - Invalid parameter passed in
316 EFI_SUCCESS - Blt operation success
317
318 --*/
319 {
320 EFI_STATUS Status;
321 EFI_TPL OriginalTPL;
322 QEMU_VIDEO_PRIVATE_DATA *Private;
323
324 Private = QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);
325 //
326 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
327 // We would not want a timer based event (Cursor, ...) to come in while we are
328 // doing this operation.
329 //
330 OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
331
332 switch (BltOperation) {
333 case EfiBltVideoToBltBuffer:
334 case EfiBltBufferToVideo:
335 case EfiBltVideoFill:
336 case EfiBltVideoToVideo:
337 Status = FrameBufferBlt (
338 Private->FrameBufferBltConfigure,
339 BltBuffer,
340 BltOperation,
341 SourceX,
342 SourceY,
343 DestinationX,
344 DestinationY,
345 Width,
346 Height,
347 Delta
348 );
349 break;
350
351 default:
352 Status = EFI_INVALID_PARAMETER;
353 ASSERT (FALSE);
354 }
355
356 gBS->RestoreTPL (OriginalTPL);
357
358 return Status;
359 }
360
361 EFI_STATUS
362 QemuVideoGraphicsOutputConstructor (
363 QEMU_VIDEO_PRIVATE_DATA *Private
364 )
365 {
366 EFI_STATUS Status;
367 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
368
369
370 GraphicsOutput = &Private->GraphicsOutput;
371 GraphicsOutput->QueryMode = QemuVideoGraphicsOutputQueryMode;
372 GraphicsOutput->SetMode = QemuVideoGraphicsOutputSetMode;
373 GraphicsOutput->Blt = QemuVideoGraphicsOutputBlt;
374
375 //
376 // Initialize the private data
377 //
378 Status = gBS->AllocatePool (
379 EfiBootServicesData,
380 sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE),
381 (VOID **) &Private->GraphicsOutput.Mode
382 );
383 if (EFI_ERROR (Status)) {
384 return Status;
385 }
386
387 Status = gBS->AllocatePool (
388 EfiBootServicesData,
389 sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION),
390 (VOID **) &Private->GraphicsOutput.Mode->Info
391 );
392 if (EFI_ERROR (Status)) {
393 goto FreeMode;
394 }
395 Private->GraphicsOutput.Mode->MaxMode = (UINT32) Private->MaxMode;
396 Private->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
397 Private->FrameBufferBltConfigure = NULL;
398 Private->FrameBufferBltConfigureSize = 0;
399
400 //
401 // Initialize the hardware
402 //
403 Status = GraphicsOutput->SetMode (GraphicsOutput, 0);
404 if (EFI_ERROR (Status)) {
405 goto FreeInfo;
406 }
407
408 DrawLogo (
409 Private,
410 Private->ModeData[Private->GraphicsOutput.Mode->Mode].HorizontalResolution,
411 Private->ModeData[Private->GraphicsOutput.Mode->Mode].VerticalResolution
412 );
413
414 return EFI_SUCCESS;
415
416 FreeInfo:
417 FreePool (Private->GraphicsOutput.Mode->Info);
418
419 FreeMode:
420 FreePool (Private->GraphicsOutput.Mode);
421 Private->GraphicsOutput.Mode = NULL;
422
423 return Status;
424 }
425
426 EFI_STATUS
427 QemuVideoGraphicsOutputDestructor (
428 QEMU_VIDEO_PRIVATE_DATA *Private
429 )
430 /*++
431
432 Routine Description:
433
434 Arguments:
435
436 Returns:
437
438 None
439
440 --*/
441 {
442 if (Private->FrameBufferBltConfigure != NULL) {
443 FreePool (Private->FrameBufferBltConfigure);
444 }
445
446 if (Private->GraphicsOutput.Mode != NULL) {
447 if (Private->GraphicsOutput.Mode->Info != NULL) {
448 gBS->FreePool (Private->GraphicsOutput.Mode->Info);
449 }
450 gBS->FreePool (Private->GraphicsOutput.Mode);
451 }
452
453 return EFI_SUCCESS;
454 }
455
456