1 /*++ @file
2 
3 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
4 Portions copyright (c) 2010 - 2011, Apple Inc. All rights reserved.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 Module Name:
8 
9     EmuGopScreen.c
10 
11 Abstract:
12 
13   This file produces the graphics abstration of UGA. It is called by
14   EmuGopDriver.c file which deals with the EFI 1.1 driver model.
15   This file just does graphics.
16 
17 **/
18 
19 #include "Gop.h"
20 
21 
22 EFI_EVENT               mGopScreenExitBootServicesEvent;
23 
24 GOP_MODE_DATA mGopModeData[] = {
25     { 800,  600, 0, 0 },
26     { 640,  480, 0, 0 },
27     { 720,  400, 0, 0 },
28     {1024,  768, 0, 0 },
29     {1280, 1024, 0, 0 }
30     };
31 
32 
33 /**
34   Returns information for an available graphics mode that the graphics device
35   and the set of active video output devices supports.
36 
37   @param  This                  The EFI_GRAPHICS_OUTPUT_PROTOCOL instance.
38   @param  ModeNumber            The mode number to return information on.
39   @param  SizeOfInfo            A pointer to the size, in bytes, of the Info buffer.
40   @param  Info                  A pointer to callee allocated buffer that returns information about ModeNumber.
41 
42   @retval EFI_SUCCESS           Mode information returned.
43   @retval EFI_BUFFER_TOO_SMALL  The Info buffer was too small.
44   @retval EFI_DEVICE_ERROR      A hardware error occurred trying to retrieve the video mode.
45   @retval EFI_NOT_STARTED       Video display is not initialized. Call SetMode ()
46   @retval EFI_INVALID_PARAMETER One of the input args was NULL.
47 
48 **/
49 EFI_STATUS
50 EFIAPI
EmuGopQuerytMode(IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,IN UINT32 ModeNumber,OUT UINTN * SizeOfInfo,OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION ** Info)51 EmuGopQuerytMode (
52   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL          *This,
53   IN  UINT32                                ModeNumber,
54   OUT UINTN                                 *SizeOfInfo,
55   OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  **Info
56   )
57 {
58   GOP_PRIVATE_DATA  *Private;
59 
60   Private = GOP_PRIVATE_DATA_FROM_THIS (This);
61 
62   if (Info == NULL || SizeOfInfo == NULL || (UINTN) ModeNumber >= This->Mode->MaxMode) {
63     return EFI_INVALID_PARAMETER;
64   }
65 
66   *Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
67   if (*Info == NULL) {
68     return EFI_OUT_OF_RESOURCES;
69   }
70 
71   *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
72 
73   (*Info)->Version = 0;
74   (*Info)->HorizontalResolution = Private->ModeData[ModeNumber].HorizontalResolution;
75   (*Info)->VerticalResolution   = Private->ModeData[ModeNumber].VerticalResolution;
76   (*Info)->PixelFormat = PixelBltOnly;
77   (*Info)->PixelsPerScanLine = (*Info)->HorizontalResolution;
78 
79   return EFI_SUCCESS;
80 }
81 
82 
83 
84 /**
85   Set the video device into the specified mode and clears the visible portions of
86   the output display to black.
87 
88   @param  This              The EFI_GRAPHICS_OUTPUT_PROTOCOL instance.
89   @param  ModeNumber        Abstraction that defines the current video mode.
90 
91   @retval EFI_SUCCESS       The graphics mode specified by ModeNumber was selected.
92   @retval EFI_DEVICE_ERROR  The device had an error and could not complete the request.
93   @retval EFI_UNSUPPORTED   ModeNumber is not supported by this device.
94 
95 **/
96 EFI_STATUS
97 EFIAPI
EmuGopSetMode(IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,IN UINT32 ModeNumber)98 EmuGopSetMode (
99   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL  *This,
100   IN  UINT32                        ModeNumber
101   )
102 {
103   EFI_STATUS                      Status;
104   GOP_PRIVATE_DATA                *Private;
105   GOP_MODE_DATA                   *ModeData;
106   EFI_GRAPHICS_OUTPUT_BLT_PIXEL   Fill;
107 
108   Private = GOP_PRIVATE_DATA_FROM_THIS (This);
109 
110   if (ModeNumber >= This->Mode->MaxMode) {
111     return EFI_UNSUPPORTED;
112   }
113 
114   ModeData = &Private->ModeData[ModeNumber];
115   This->Mode->Mode = ModeNumber;
116   Private->GraphicsOutput.Mode->Info->HorizontalResolution = ModeData->HorizontalResolution;
117   Private->GraphicsOutput.Mode->Info->VerticalResolution = ModeData->VerticalResolution;
118   Private->GraphicsOutput.Mode->Info->PixelsPerScanLine = ModeData->HorizontalResolution;
119 
120   if (Private->HardwareNeedsStarting) {
121     Status = EmuGopStartWindow (
122               Private,
123               ModeData->HorizontalResolution,
124               ModeData->VerticalResolution,
125               ModeData->ColorDepth,
126               ModeData->RefreshRate
127               );
128     if (EFI_ERROR (Status)) {
129       return EFI_DEVICE_ERROR;
130     }
131 
132     Private->HardwareNeedsStarting = FALSE;
133   }
134 
135 
136   Status = Private->EmuGraphicsWindow->Size(
137                             Private->EmuGraphicsWindow,
138                             ModeData->HorizontalResolution,
139                             ModeData->VerticalResolution
140                             );
141 
142 
143   Fill.Red   = 0;
144   Fill.Green = 0;
145   Fill.Blue  = 0;
146   This->Blt (
147           This,
148           &Fill,
149           EfiBltVideoFill,
150           0,
151           0,
152           0,
153           0,
154           ModeData->HorizontalResolution,
155           ModeData->VerticalResolution,
156           ModeData->HorizontalResolution * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
157           );
158   return EFI_SUCCESS;
159 }
160 
161 
162 
163 /**
164   Blt a rectangle of pixels on the graphics screen. Blt stands for BLock Transfer.
165 
166   @param  This         Protocol instance pointer.
167   @param  BltBuffer    Buffer containing data to blit into video buffer. This
168                        buffer has a size of Width*Height*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
169   @param  BltOperation Operation to perform on BlitBuffer and video memory
170   @param  SourceX      X coordinate of source for the BltBuffer.
171   @param  SourceY      Y coordinate of source for the BltBuffer.
172   @param  DestinationX X coordinate of destination for the BltBuffer.
173   @param  DestinationY Y coordinate of destination for the BltBuffer.
174   @param  Width        Width of rectangle in BltBuffer in pixels.
175   @param  Height       Hight of rectangle in BltBuffer in pixels.
176   @param  Delta        OPTIONAL
177 
178   @retval EFI_SUCCESS           The Blt operation completed.
179   @retval EFI_INVALID_PARAMETER BltOperation is not valid.
180   @retval EFI_DEVICE_ERROR      A hardware error occurred writting to the video buffer.
181 
182 **/
183 EFI_STATUS
184 EFIAPI
EmuGopBlt(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 OPTIONAL)185 EmuGopBlt (
186   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL            *This,
187   IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL           *BltBuffer,   OPTIONAL
188   IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION       BltOperation,
189   IN  UINTN                                   SourceX,
190   IN  UINTN                                   SourceY,
191   IN  UINTN                                   DestinationX,
192   IN  UINTN                                   DestinationY,
193   IN  UINTN                                   Width,
194   IN  UINTN                                   Height,
195   IN  UINTN                                   Delta         OPTIONAL
196   )
197 {
198   GOP_PRIVATE_DATA  *Private;
199   EFI_TPL           OriginalTPL;
200   EFI_STATUS        Status;
201   EMU_GRAPHICS_WINDOWS__BLT_ARGS      GopBltArgs;
202 
203   Private = GOP_PRIVATE_DATA_FROM_THIS (This);
204 
205   if ((UINT32)BltOperation >= EfiGraphicsOutputBltOperationMax) {
206     return EFI_INVALID_PARAMETER;
207   }
208 
209   if (Width == 0 || Height == 0) {
210     return EFI_INVALID_PARAMETER;
211   }
212   //
213   // If Delta is zero, then the entire BltBuffer is being used, so Delta
214   // is the number of bytes in each row of BltBuffer.  Since BltBuffer is Width pixels size,
215   // the number of bytes in each row can be computed.
216   //
217   if (Delta == 0) {
218     Delta = Width * sizeof (EFI_UGA_PIXEL);
219   }
220 
221   //
222   // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
223   // We would not want a timer based event (Cursor, ...) to come in while we are
224   // doing this operation.
225   //
226   OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
227 
228   //
229   // Pack UGA Draw protocol parameters to EMU_GRAPHICS_WINDOWS__BLT_ARGS structure to adapt to
230   // GopBlt() API of Unix UGA IO protocol.
231   //
232   GopBltArgs.DestinationX = DestinationX;
233   GopBltArgs.DestinationY = DestinationY;
234   GopBltArgs.Height       = Height;
235   GopBltArgs.Width        = Width;
236   GopBltArgs.SourceX      = SourceX;
237   GopBltArgs.SourceY      = SourceY;
238   GopBltArgs.Delta        = Delta;
239   Status = Private->EmuGraphicsWindow->Blt (
240                             Private->EmuGraphicsWindow,
241                             (EFI_UGA_PIXEL *)BltBuffer,
242                             (EFI_UGA_BLT_OPERATION)BltOperation,
243                             &GopBltArgs
244                             );
245 
246   gBS->RestoreTPL (OriginalTPL);
247 
248   return Status;
249 }
250 
251 
252 //
253 // Construction and Destruction functions
254 //
255 
256 EFI_STATUS
EmuGopSupported(IN EMU_IO_THUNK_PROTOCOL * EmuIoThunk)257 EmuGopSupported (
258   IN  EMU_IO_THUNK_PROTOCOL  *EmuIoThunk
259   )
260 {
261   //
262   // Check to see if the IO abstraction represents a device type we support.
263   //
264   // This would be replaced a check of PCI subsystem ID, etc.
265   //
266   if (!CompareGuid (EmuIoThunk->Protocol, &gEmuGraphicsWindowProtocolGuid)) {
267     return EFI_UNSUPPORTED;
268   }
269 
270   return EFI_SUCCESS;
271 }
272 
273 
274 EFI_STATUS
EmuGopStartWindow(IN GOP_PRIVATE_DATA * Private,IN UINT32 HorizontalResolution,IN UINT32 VerticalResolution,IN UINT32 ColorDepth,IN UINT32 RefreshRate)275 EmuGopStartWindow (
276   IN  GOP_PRIVATE_DATA    *Private,
277   IN  UINT32              HorizontalResolution,
278   IN  UINT32              VerticalResolution,
279   IN  UINT32              ColorDepth,
280   IN  UINT32              RefreshRate
281   )
282 {
283   EFI_STATUS          Status;
284 
285   //
286   // Register to be notified on exit boot services so we can destroy the window.
287   //
288   Status = gBS->CreateEvent (
289                   EVT_SIGNAL_EXIT_BOOT_SERVICES,
290                   TPL_CALLBACK,
291                   ShutdownGopEvent,
292                   Private,
293                   &mGopScreenExitBootServicesEvent
294                   );
295 
296   Status = Private->EmuIoThunk->Open (Private->EmuIoThunk);
297   if (!EFI_ERROR (Status)) {
298     Private->EmuGraphicsWindow = Private->EmuIoThunk->Interface;
299 
300     // Register callback to support RegisterKeyNotify()
301     Status  = Private->EmuGraphicsWindow->RegisterKeyNotify (
302                                             Private->EmuGraphicsWindow,
303                                             GopPrivateMakeCallbackFunction,
304                                             GopPrivateBreakCallbackFunction,
305                                             Private
306                                             );
307     ASSERT_EFI_ERROR (Status);
308   }
309   return Status;
310 }
311 
312 EFI_STATUS
EmuGopConstructor(GOP_PRIVATE_DATA * Private)313 EmuGopConstructor (
314   GOP_PRIVATE_DATA    *Private
315   )
316 {
317   Private->ModeData = mGopModeData;
318 
319   Private->GraphicsOutput.QueryMode      = EmuGopQuerytMode;
320   Private->GraphicsOutput.SetMode        = EmuGopSetMode;
321   Private->GraphicsOutput.Blt            = EmuGopBlt;
322 
323   //
324   // Allocate buffer for Graphics Output Protocol mode information
325   //
326   Private->GraphicsOutput.Mode = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE));
327   if (Private->GraphicsOutput.Mode == NULL) {
328     return EFI_OUT_OF_RESOURCES;
329   }
330   Private->GraphicsOutput.Mode->Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
331   if (Private->GraphicsOutput.Mode->Info == NULL) {
332     return EFI_OUT_OF_RESOURCES;
333   }
334 
335   Private->GraphicsOutput.Mode->MaxMode = sizeof(mGopModeData) / sizeof(GOP_MODE_DATA);
336   //
337   // Till now, we have no idea about the window size.
338   //
339   Private->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
340   Private->GraphicsOutput.Mode->Info->Version = 0;
341   Private->GraphicsOutput.Mode->Info->HorizontalResolution = 0;
342   Private->GraphicsOutput.Mode->Info->VerticalResolution = 0;
343   Private->GraphicsOutput.Mode->Info->PixelFormat = PixelBltOnly;
344   Private->GraphicsOutput.Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
345   Private->GraphicsOutput.Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL;
346   Private->GraphicsOutput.Mode->FrameBufferSize = 0;
347 
348   Private->HardwareNeedsStarting  = TRUE;
349   Private->EmuGraphicsWindow                  = NULL;
350 
351   EmuGopInitializeSimpleTextInForWindow (Private);
352 
353   EmuGopInitializeSimplePointerForWindow (Private);
354 
355   return EFI_SUCCESS;
356 }
357 
358 
359 
360 EFI_STATUS
EmuGopDestructor(GOP_PRIVATE_DATA * Private)361 EmuGopDestructor (
362   GOP_PRIVATE_DATA     *Private
363   )
364 {
365   if (!Private->HardwareNeedsStarting) {
366     Private->EmuIoThunk->Close (Private->EmuIoThunk);
367     Private->EmuGraphicsWindow = NULL;
368   }
369 
370   //
371   // Free graphics output protocol occupied resource
372   //
373   if (Private->GraphicsOutput.Mode != NULL) {
374     if (Private->GraphicsOutput.Mode->Info != NULL) {
375       FreePool (Private->GraphicsOutput.Mode->Info);
376     }
377     FreePool (Private->GraphicsOutput.Mode);
378   }
379 
380   return EFI_SUCCESS;
381 }
382 
383 
384 VOID
385 EFIAPI
ShutdownGopEvent(IN EFI_EVENT Event,IN VOID * Context)386 ShutdownGopEvent (
387   IN EFI_EVENT  Event,
388   IN VOID       *Context
389   )
390 /*++
391 
392 Routine Description:
393 
394   This is the UGA screen's callback notification function for exit-boot-services.
395   All we do here is call EmuGopDestructor().
396 
397 Arguments:
398 
399   Event   - not used
400   Context - pointer to the Private structure.
401 
402 Returns:
403 
404   None.
405 
406 **/
407 {
408   EmuGopDestructor (Context);
409 }
410 
411