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
18STATIC
19VOID
20QemuVideoCompleteModeInfo (
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
46STATIC
47EFI_STATUS
48QemuVideoCompleteModeData (
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//
82EFI_STATUS
83EFIAPI
84QemuVideoGraphicsOutputQueryMode (
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
92Routine 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
135EFI_STATUS
136EFIAPI
137QemuVideoGraphicsOutputSetMode (
138  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
139  IN  UINT32                       ModeNumber
140  )
141/*++
142
143Routine 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
221EFI_STATUS
222EFIAPI
223QemuVideoGraphicsOutputBlt (
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
237Routine Description:
238
239  Graphics Output protocol instance to block transfer for CirrusLogic device
240
241Arguments:
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
257Returns:
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
305EFI_STATUS
306QemuVideoGraphicsOutputConstructor (
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
360FreeInfo:
361  FreePool (Private->GraphicsOutput.Mode->Info);
362
363FreeMode:
364  FreePool (Private->GraphicsOutput.Mode);
365  Private->GraphicsOutput.Mode = NULL;
366
367  return Status;
368}
369
370EFI_STATUS
371QemuVideoGraphicsOutputDestructor (
372  QEMU_VIDEO_PRIVATE_DATA  *Private
373  )
374/*++
375
376Routine Description:
377
378Arguments:
379
380Returns:
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