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