1 /** @file
2   ConsoleOut Routines that speak VGA.
3 
4 Copyright (c) 2007 - 2013, 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
8 of the BSD License which accompanies this distribution.  The
9 full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11 
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 
17 #include "FbGop.h"
18 
19 EFI_PIXEL_BITMASK  mPixelBitMask = {0x0000FF, 0x00FF00, 0xFF0000, 0x000000};
20 
21 //
22 // Save controller attributes during first start
23 //
24 UINT64                         mOriginalPciAttributes;
25 BOOLEAN                        mPciAttributesSaved = FALSE;
26 
27 
28 //
29 // EFI Driver Binding Protocol Instance
30 //
31 EFI_DRIVER_BINDING_PROTOCOL gFbGopDriverBinding = {
32   FbGopDriverBindingSupported,
33   FbGopDriverBindingStart,
34   FbGopDriverBindingStop,
35   0x3,
36   NULL,
37   NULL
38 };
39 
40 //
41 // Native resolution in EDID DetailedTiming[0]
42 //
43 UINT32    mNativeModeHorizontal;
44 UINT32    mNativeModeVertical;
45 
46 /**
47   Supported.
48 
49   @param  This                   Pointer to driver binding protocol
50   @param  Controller             Controller handle to connect
51   @param  RemainingDevicePath    A pointer to the remaining portion of a device
52                                  path
53 
54   @retval EFI_STATUS             EFI_SUCCESS:This controller can be managed by this
55                                  driver, Otherwise, this controller cannot be
56                                  managed by this driver
57 
58 **/
59 EFI_STATUS
60 EFIAPI
FbGopDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)61 FbGopDriverBindingSupported (
62   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
63   IN EFI_HANDLE                   Controller,
64   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
65   )
66 {
67   EFI_STATUS                Status;
68   EFI_PCI_IO_PROTOCOL       *PciIo;
69   PCI_TYPE00                Pci;
70   EFI_DEV_PATH              *Node;
71 
72   //
73   // Open the IO Abstraction(s) needed to perform the supported test
74   //
75   Status = gBS->OpenProtocol (
76                   Controller,
77                   &gEfiPciIoProtocolGuid,
78                   (VOID **) &PciIo,
79                   This->DriverBindingHandle,
80                   Controller,
81                   EFI_OPEN_PROTOCOL_BY_DRIVER
82                   );
83   if (EFI_ERROR (Status)) {
84     return Status;
85   }
86 
87   //
88   // See if this is a PCI Graphics Controller by looking at the Command register and
89   // Class Code Register
90   //
91   Status = PciIo->Pci.Read (
92                         PciIo,
93                         EfiPciIoWidthUint32,
94                         0,
95                         sizeof (Pci) / sizeof (UINT32),
96                         &Pci
97                         );
98   if (EFI_ERROR (Status)) {
99     Status = EFI_UNSUPPORTED;
100     goto Done;
101   }
102 
103   Status = EFI_UNSUPPORTED;
104   if (Pci.Hdr.ClassCode[2] == 0x03 || (Pci.Hdr.ClassCode[2] == 0x00 && Pci.Hdr.ClassCode[1] == 0x01)) {
105 
106     Status = EFI_SUCCESS;
107     //
108     // If this is a graphics controller,
109     // go further check RemainingDevicePath validation
110     //
111     if (RemainingDevicePath != NULL) {
112       Node = (EFI_DEV_PATH *) RemainingDevicePath;
113       //
114       // Check if RemainingDevicePath is the End of Device Path Node,
115       // if yes, return EFI_SUCCESS
116       //
117       if (!IsDevicePathEnd (Node)) {
118         //
119         // If RemainingDevicePath isn't the End of Device Path Node,
120         // check its validation
121         //
122         if (Node->DevPath.Type != ACPI_DEVICE_PATH ||
123             Node->DevPath.SubType != ACPI_ADR_DP ||
124             DevicePathNodeLength(&Node->DevPath) < sizeof(ACPI_ADR_DEVICE_PATH)) {
125           Status = EFI_UNSUPPORTED;
126         }
127       }
128     }
129   }
130 
131 Done:
132   gBS->CloseProtocol (
133          Controller,
134          &gEfiPciIoProtocolGuid,
135          This->DriverBindingHandle,
136          Controller
137          );
138 
139   return Status;
140 }
141 
142 
143 /**
144   Install Graphics Output Protocol onto VGA device handles.
145 
146   @param  This                   Pointer to driver binding protocol
147   @param  Controller             Controller handle to connect
148   @param  RemainingDevicePath    A pointer to the remaining portion of a device
149                                  path
150 
151   @return EFI_STATUS
152 
153 **/
154 EFI_STATUS
155 EFIAPI
FbGopDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)156 FbGopDriverBindingStart (
157   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
158   IN EFI_HANDLE                   Controller,
159   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
160   )
161 {
162   EFI_STATUS                Status;
163   EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
164   EFI_PCI_IO_PROTOCOL       *PciIo;
165   UINT64                    Supports;
166 
167   DEBUG ((EFI_D_INFO, "GOP START\n"));
168 
169   //
170   // Initialize local variables
171   //
172   PciIo            = NULL;
173   ParentDevicePath = NULL;
174 
175   //
176   // Prepare for status code
177   //
178   Status = gBS->HandleProtocol (
179                   Controller,
180                   &gEfiDevicePathProtocolGuid,
181                   (VOID **) &ParentDevicePath
182                   );
183   if (EFI_ERROR (Status)) {
184     return Status;
185   }
186 
187   //
188   // Open the IO Abstraction(s) needed
189   //
190   Status = gBS->OpenProtocol (
191                   Controller,
192                   &gEfiPciIoProtocolGuid,
193                   (VOID **) &PciIo,
194                   This->DriverBindingHandle,
195                   Controller,
196                   EFI_OPEN_PROTOCOL_BY_DRIVER
197                   );
198   if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
199     return Status;
200   }
201 
202   //
203   // Save original PCI attributes
204   //
205   if (!mPciAttributesSaved) {
206     Status = PciIo->Attributes (
207                       PciIo,
208                       EfiPciIoAttributeOperationGet,
209                       0,
210                       &mOriginalPciAttributes
211                       );
212 
213     if (EFI_ERROR (Status)) {
214       goto Done;
215     }
216     mPciAttributesSaved = TRUE;
217   }
218 
219   //
220   // Get supported PCI attributes
221   //
222   Status = PciIo->Attributes (
223                     PciIo,
224                     EfiPciIoAttributeOperationSupported,
225                     0,
226                     &Supports
227                     );
228   if (EFI_ERROR (Status)) {
229     goto Done;
230   }
231 
232   Supports &= (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);
233   if (Supports == 0 || Supports == (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) {
234     Status = EFI_UNSUPPORTED;
235     goto Done;
236   }
237 
238   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
239     EFI_PROGRESS_CODE,
240     EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_ENABLE,
241     ParentDevicePath
242     );
243   //
244   // Enable the device and make sure VGA cycles are being forwarded to this VGA device
245   //
246   Status = PciIo->Attributes (
247              PciIo,
248              EfiPciIoAttributeOperationEnable,
249              EFI_PCI_DEVICE_ENABLE,
250              NULL
251              );
252   if (EFI_ERROR (Status)) {
253     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
254       EFI_ERROR_CODE | EFI_ERROR_MINOR,
255       EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_RESOURCE_CONFLICT,
256       ParentDevicePath
257       );
258     goto Done;
259   }
260 
261   if (RemainingDevicePath != NULL) {
262     if (IsDevicePathEnd (RemainingDevicePath)) {
263       //
264       // If RemainingDevicePath is the End of Device Path Node,
265       // don't create any child device and return EFI_SUCESS
266       Status = EFI_SUCCESS;
267       goto Done;
268     }
269   }
270 
271   //
272   // Create child handle and install GraphicsOutputProtocol on it
273   //
274   Status = FbGopChildHandleInstall (
275              This,
276              Controller,
277              PciIo,
278              NULL,
279              ParentDevicePath,
280              RemainingDevicePath
281              );
282 
283 Done:
284   if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {
285 
286     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
287       EFI_PROGRESS_CODE,
288       EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_DISABLE,
289       ParentDevicePath
290       );
291 
292     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
293       EFI_PROGRESS_CODE,
294       EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_NOT_DETECTED,
295       ParentDevicePath
296       );
297     if (!HasChildHandle (Controller)) {
298       if (mPciAttributesSaved) {
299         //
300         // Restore original PCI attributes
301         //
302         PciIo->Attributes (
303                         PciIo,
304                         EfiPciIoAttributeOperationSet,
305                         mOriginalPciAttributes,
306                         NULL
307                         );
308       }
309     }
310     //
311     // Release PCI I/O Protocols on the controller handle.
312     //
313     gBS->CloseProtocol (
314            Controller,
315            &gEfiPciIoProtocolGuid,
316            This->DriverBindingHandle,
317            Controller
318            );
319   }
320 
321   return Status;
322 }
323 
324 
325 /**
326   Stop.
327 
328   @param  This                   Pointer to driver binding protocol
329   @param  Controller             Controller handle to connect
330   @param  NumberOfChildren       Number of children handle created by this driver
331   @param  ChildHandleBuffer      Buffer containing child handle created
332 
333   @retval EFI_SUCCESS            Driver disconnected successfully from controller
334   @retval EFI_UNSUPPORTED        Cannot find FB_VIDEO_DEV structure
335 
336 **/
337 EFI_STATUS
338 EFIAPI
FbGopDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)339 FbGopDriverBindingStop (
340   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
341   IN  EFI_HANDLE                      Controller,
342   IN  UINTN                           NumberOfChildren,
343   IN  EFI_HANDLE                      *ChildHandleBuffer
344   )
345 {
346   EFI_STATUS                   Status;
347   BOOLEAN                      AllChildrenStopped;
348   UINTN                        Index;
349   EFI_PCI_IO_PROTOCOL          *PciIo;
350 
351   AllChildrenStopped = TRUE;
352 
353   if (NumberOfChildren == 0) {
354     //
355     // Close PCI I/O protocol on the controller handle
356     //
357     gBS->CloseProtocol (
358            Controller,
359            &gEfiPciIoProtocolGuid,
360            This->DriverBindingHandle,
361            Controller
362            );
363 
364     return EFI_SUCCESS;
365   }
366 
367   for (Index = 0; Index < NumberOfChildren; Index++) {
368 
369     Status = EFI_SUCCESS;
370 
371     FbGopChildHandleUninstall (This, Controller, ChildHandleBuffer[Index]);
372 
373     if (EFI_ERROR (Status)) {
374       AllChildrenStopped = FALSE;
375     }
376   }
377 
378   if (!AllChildrenStopped) {
379     return EFI_DEVICE_ERROR;
380   }
381 
382   if (!HasChildHandle (Controller)) {
383     if (mPciAttributesSaved) {
384       Status = gBS->HandleProtocol (
385                       Controller,
386                       &gEfiPciIoProtocolGuid,
387                       (VOID **) &PciIo
388                       );
389       ASSERT_EFI_ERROR (Status);
390 
391       //
392       // Restore original PCI attributes
393       //
394       Status = PciIo->Attributes (
395                         PciIo,
396                         EfiPciIoAttributeOperationSet,
397                         mOriginalPciAttributes,
398                         NULL
399                         );
400       ASSERT_EFI_ERROR (Status);
401     }
402   }
403 
404 
405   return EFI_SUCCESS;
406 }
407 
408 
409 /**
410   Install child handles if the Handle supports MBR format.
411 
412   @param  This                   Calling context.
413   @param  ParentHandle           Parent Handle
414   @param  ParentPciIo            Parent PciIo interface
415   @param  ParentLegacyBios       Parent LegacyBios interface
416   @param  ParentDevicePath       Parent Device Path
417   @param  RemainingDevicePath    Remaining Device Path
418 
419   @retval EFI_SUCCESS            If a child handle was added
420   @retval other                  A child handle was not added
421 
422 **/
423 EFI_STATUS
FbGopChildHandleInstall(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ParentHandle,IN EFI_PCI_IO_PROTOCOL * ParentPciIo,IN VOID * ParentLegacyBios,IN EFI_DEVICE_PATH_PROTOCOL * ParentDevicePath,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)424 FbGopChildHandleInstall (
425   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
426   IN  EFI_HANDLE                   ParentHandle,
427   IN  EFI_PCI_IO_PROTOCOL          *ParentPciIo,
428   IN  VOID                         *ParentLegacyBios,
429   IN  EFI_DEVICE_PATH_PROTOCOL     *ParentDevicePath,
430   IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
431   )
432 {
433   EFI_STATUS               Status;
434   FB_VIDEO_DEV            *FbGopPrivate;
435   PCI_TYPE00               Pci;
436   ACPI_ADR_DEVICE_PATH     AcpiDeviceNode;
437   BOOLEAN                  ProtocolInstalled;
438 
439   //
440   // Allocate the private device structure for video device
441   //
442   FbGopPrivate = (FB_VIDEO_DEV *) AllocateZeroPool (
443 																					sizeof (FB_VIDEO_DEV)
444 																					);
445   if (NULL == FbGopPrivate) {
446 		Status = EFI_OUT_OF_RESOURCES;
447     goto Done;
448   }
449 
450   //
451   // See if this is a VGA compatible controller or not
452   //
453   Status = ParentPciIo->Pci.Read (
454                           ParentPciIo,
455                           EfiPciIoWidthUint32,
456                           0,
457                           sizeof (Pci) / sizeof (UINT32),
458                           &Pci
459                           );
460   if (EFI_ERROR (Status)) {
461     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
462       EFI_ERROR_CODE | EFI_ERROR_MINOR,
463       EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR,
464       ParentDevicePath
465       );
466     goto Done;
467   }
468 
469   //
470   // Initialize the child private structure
471   //
472   FbGopPrivate->Signature = FB_VIDEO_DEV_SIGNATURE;
473 
474   //
475   // Fill in Graphics Output specific mode structures
476   //
477   FbGopPrivate->ModeData              = NULL;
478 
479   FbGopPrivate->VbeFrameBuffer        = NULL;
480 
481   FbGopPrivate->EdidDiscovered.SizeOfEdid  = 0;
482   FbGopPrivate->EdidDiscovered.Edid        = NULL;
483   FbGopPrivate->EdidActive.SizeOfEdid      = 0;
484   FbGopPrivate->EdidActive.Edid            = NULL;
485 
486   //
487   // Fill in the Graphics Output Protocol
488   //
489   FbGopPrivate->GraphicsOutput.QueryMode = FbGopGraphicsOutputQueryMode;
490   FbGopPrivate->GraphicsOutput.SetMode   = FbGopGraphicsOutputSetMode;
491 
492 
493   //
494   // Allocate buffer for Graphics Output Protocol mode information
495   //
496   FbGopPrivate->GraphicsOutput.Mode = (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *) AllocatePool (
497                                              sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE)
498                                              );
499   if (NULL == FbGopPrivate->GraphicsOutput.Mode) {
500     Status = EFI_OUT_OF_RESOURCES;
501     goto Done;
502   }
503 
504   FbGopPrivate->GraphicsOutput.Mode->Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) AllocatePool (
505                                              sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)
506                                              );
507   if (NULL ==  FbGopPrivate->GraphicsOutput.Mode->Info) {
508     Status = EFI_OUT_OF_RESOURCES;
509     goto Done;
510   }
511 
512   //
513   // Set Gop Device Path, here RemainingDevicePath will not be one End of Device Path Node.
514   //
515   if ((RemainingDevicePath == NULL) || (!IsDevicePathEnd (RemainingDevicePath))) {
516     if (RemainingDevicePath == NULL) {
517       ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));
518       AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;
519       AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;
520       AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);
521       SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));
522 
523       FbGopPrivate->GopDevicePath = AppendDevicePathNode (
524                                           ParentDevicePath,
525                                           (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode
526                                           );
527     } else {
528       FbGopPrivate->GopDevicePath = AppendDevicePathNode (ParentDevicePath, RemainingDevicePath);
529     }
530 
531     //
532     // Creat child handle and device path protocol firstly
533     //
534     FbGopPrivate->Handle = NULL;
535     Status = gBS->InstallMultipleProtocolInterfaces (
536                     &FbGopPrivate->Handle,
537                     &gEfiDevicePathProtocolGuid,
538                     FbGopPrivate->GopDevicePath,
539                     NULL
540                     );
541     if (EFI_ERROR (Status)) {
542       goto Done;
543     }
544   }
545 
546   //
547   // When check for VBE, PCI I/O protocol is needed, so use parent's protocol interface temporally
548   //
549   FbGopPrivate->PciIo                 = ParentPciIo;
550 
551   //
552   // Check for VESA BIOS Extensions for modes that are compatible with Graphics Output
553   //
554   Status = FbGopCheckForVbe (FbGopPrivate);
555   DEBUG ((EFI_D_INFO, "FbGopCheckForVbe - %r\n", Status));
556 
557   if (EFI_ERROR (Status)) {
558     Status = EFI_UNSUPPORTED;
559     //goto Done;
560   }
561 
562   ProtocolInstalled = FALSE;
563 
564   //
565   // Creat child handle and install Graphics Output Protocol,EDID Discovered/Active Protocol
566   //
567   Status = gBS->InstallMultipleProtocolInterfaces (
568                   &FbGopPrivate->Handle,
569                   &gEfiGraphicsOutputProtocolGuid,
570                   &FbGopPrivate->GraphicsOutput,
571                   &gEfiEdidDiscoveredProtocolGuid,
572                   &FbGopPrivate->EdidDiscovered,
573                   &gEfiEdidActiveProtocolGuid,
574                   &FbGopPrivate->EdidActive,
575                   NULL
576                   );
577 
578   if (!EFI_ERROR (Status)) {
579     //
580     // Open the Parent Handle for the child
581     //
582     Status = gBS->OpenProtocol (
583                     ParentHandle,
584                     &gEfiPciIoProtocolGuid,
585                     (VOID **) &FbGopPrivate->PciIo,
586                     This->DriverBindingHandle,
587                     FbGopPrivate->Handle,
588                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
589                     );
590     if (EFI_ERROR (Status)) {
591       goto Done;
592     }
593     ProtocolInstalled = TRUE;
594   }
595 
596 Done:
597   if (EFI_ERROR (Status)) {
598     //
599     // Free private data structure
600     //
601     FbGopDeviceReleaseResource (FbGopPrivate);
602   }
603 
604   return Status;
605 }
606 
607 
608 /**
609   Deregister an video child handle and free resources.
610 
611   @param  This                   Protocol instance pointer.
612   @param  Controller             Video controller handle
613   @param  Handle                 Video child handle
614 
615   @return EFI_STATUS
616 
617 **/
618 EFI_STATUS
FbGopChildHandleUninstall(EFI_DRIVER_BINDING_PROTOCOL * This,EFI_HANDLE Controller,EFI_HANDLE Handle)619 FbGopChildHandleUninstall (
620   EFI_DRIVER_BINDING_PROTOCOL    *This,
621   EFI_HANDLE                     Controller,
622   EFI_HANDLE                     Handle
623   )
624 {
625   EFI_STATUS                    Status;
626   EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
627   FB_VIDEO_DEV                 *FbGopPrivate;
628   EFI_PCI_IO_PROTOCOL          *PciIo;
629 
630   FbGopPrivate     = NULL;
631   GraphicsOutput   = NULL;
632   PciIo            = NULL;
633   Status           = EFI_UNSUPPORTED;
634 
635   Status = gBS->OpenProtocol (
636                   Handle,
637                   &gEfiGraphicsOutputProtocolGuid,
638                   (VOID **) &GraphicsOutput,
639                   This->DriverBindingHandle,
640                   Handle,
641                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
642                   );
643   if (!EFI_ERROR (Status)) {
644       FbGopPrivate = FB_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput);
645   }
646 
647   if (FbGopPrivate == NULL) {
648     return EFI_UNSUPPORTED;
649   }
650 
651   //
652   // Close PCI I/O protocol that opened by child handle
653   //
654   Status = gBS->CloseProtocol (
655                   Controller,
656                   &gEfiPciIoProtocolGuid,
657                   This->DriverBindingHandle,
658                   Handle
659                   );
660 
661   //
662   // Uninstall protocols on child handle
663   //
664   Status = gBS->UninstallMultipleProtocolInterfaces (
665                     FbGopPrivate->Handle,
666                     &gEfiDevicePathProtocolGuid,
667                     FbGopPrivate->GopDevicePath,
668                     &gEfiGraphicsOutputProtocolGuid,
669                     &FbGopPrivate->GraphicsOutput,
670                     NULL
671                     );
672 
673   if (EFI_ERROR (Status)) {
674     gBS->OpenProtocol (
675            Controller,
676            &gEfiPciIoProtocolGuid,
677            (VOID **) &PciIo,
678            This->DriverBindingHandle,
679            Handle,
680            EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
681            );
682     return Status;
683   }
684 
685   //
686   // Release all allocated resources
687   //
688   FbGopDeviceReleaseResource (FbGopPrivate);
689 
690   return EFI_SUCCESS;
691 }
692 
693 
694 /**
695   Release resource for biso video instance.
696 
697   @param  FbGopPrivate       Video child device private data structure
698 
699 **/
700 VOID
FbGopDeviceReleaseResource(FB_VIDEO_DEV * FbGopPrivate)701 FbGopDeviceReleaseResource (
702   FB_VIDEO_DEV  *FbGopPrivate
703   )
704 {
705   if (FbGopPrivate == NULL) {
706     return ;
707   }
708 
709   //
710   // Release all the resourses occupied by the FB_VIDEO_DEV
711   //
712 
713   //
714   // Free VBE Frame Buffer
715   //
716   if (FbGopPrivate->VbeFrameBuffer != NULL) {
717     FreePool (FbGopPrivate->VbeFrameBuffer);
718   }
719 
720   //
721   // Free mode data
722   //
723   if (FbGopPrivate->ModeData != NULL) {
724     FreePool (FbGopPrivate->ModeData);
725   }
726 
727   //
728   // Free graphics output protocol occupied resource
729   //
730   if (FbGopPrivate->GraphicsOutput.Mode != NULL) {
731     if (FbGopPrivate->GraphicsOutput.Mode->Info != NULL) {
732         FreePool (FbGopPrivate->GraphicsOutput.Mode->Info);
733         FbGopPrivate->GraphicsOutput.Mode->Info = NULL;
734     }
735     FreePool (FbGopPrivate->GraphicsOutput.Mode);
736     FbGopPrivate->GraphicsOutput.Mode = NULL;
737   }
738 
739   if (FbGopPrivate->GopDevicePath!= NULL) {
740     FreePool (FbGopPrivate->GopDevicePath);
741   }
742 
743   FreePool (FbGopPrivate);
744 
745   return ;
746 }
747 
748 
749 
750 /**
751   Check if all video child handles have been uninstalled.
752 
753   @param  Controller             Video controller handle
754 
755   @return TRUE                   Child handles exist.
756   @return FALSE                  All video child handles have been uninstalled.
757 
758 **/
759 BOOLEAN
HasChildHandle(IN EFI_HANDLE Controller)760 HasChildHandle (
761   IN EFI_HANDLE  Controller
762   )
763 {
764   UINTN                                Index;
765   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY  *OpenInfoBuffer;
766   UINTN                                EntryCount;
767   BOOLEAN                              HasChild;
768   EFI_STATUS                           Status;
769 
770   EntryCount = 0;
771   HasChild   = FALSE;
772   Status = gBS->OpenProtocolInformation (
773                   Controller,
774                   &gEfiPciIoProtocolGuid,
775                   &OpenInfoBuffer,
776                   &EntryCount
777                   );
778   for (Index = 0; Index < EntryCount; Index++) {
779     if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
780       HasChild = TRUE;
781     }
782   }
783 
784   return HasChild;
785 }
786 
787 /**
788   Check for VBE device.
789 
790   @param  FbGopPrivate       Pointer to FB_VIDEO_DEV structure
791 
792   @retval EFI_SUCCESS            VBE device found
793 
794 **/
795 EFI_STATUS
FbGopCheckForVbe(IN OUT FB_VIDEO_DEV * FbGopPrivate)796 FbGopCheckForVbe (
797   IN OUT FB_VIDEO_DEV  *FbGopPrivate
798   )
799 {
800   EFI_STATUS                             Status;
801   FB_VIDEO_MODE_DATA                     *ModeBuffer;
802   FB_VIDEO_MODE_DATA                     *CurrentModeData;
803   UINTN                                  ModeNumber;
804   UINTN                                  BitsPerPixel;
805   UINTN                                  BytesPerScanLine;
806   UINT32                                 HorizontalResolution;
807   UINT32                                 VerticalResolution;
808   EFI_GRAPHICS_OUTPUT_BLT_PIXEL          *VbeFrameBuffer;
809   EFI_HOB_GUID_TYPE                      *GuidHob;
810   FRAME_BUFFER_INFO                      *pFbInfo;
811 
812   Status = EFI_SUCCESS;
813   //
814   // Find the frame buffer information guid hob
815   //
816   GuidHob = GetFirstGuidHob (&gUefiFrameBufferInfoGuid);
817   ASSERT (GuidHob != NULL);
818   pFbInfo = (FRAME_BUFFER_INFO *)GET_GUID_HOB_DATA (GuidHob);
819 
820   //
821   // Add mode to the list of available modes
822   //
823   VbeFrameBuffer = NULL;
824   ModeBuffer     = NULL;
825 
826   ModeNumber           = 1;
827   BitsPerPixel         = pFbInfo->BitsPerPixel;
828   HorizontalResolution = pFbInfo->HorizontalResolution;
829   VerticalResolution   = pFbInfo->VerticalResolution;
830   BytesPerScanLine     = HorizontalResolution * (BitsPerPixel / 8);
831 
832   ModeBuffer = (FB_VIDEO_MODE_DATA *) AllocatePool (
833 																						ModeNumber * sizeof (FB_VIDEO_MODE_DATA)
834 																			);
835   if (NULL == ModeBuffer) {
836 	  Status = EFI_OUT_OF_RESOURCES;
837     goto Done;
838   }
839 
840   VbeFrameBuffer =
841 			(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) AllocatePool (
842 																					BytesPerScanLine * VerticalResolution
843 																				  );
844   if (NULL == VbeFrameBuffer) {
845 	  Status = EFI_OUT_OF_RESOURCES;
846     goto Done;
847   }
848 
849   if (FbGopPrivate->ModeData != NULL) {
850     FreePool (FbGopPrivate->ModeData);
851   }
852 
853   if (FbGopPrivate->VbeFrameBuffer != NULL) {
854     FreePool (FbGopPrivate->VbeFrameBuffer);
855   }
856 
857   CurrentModeData = &ModeBuffer[ModeNumber - 1];
858   CurrentModeData->BytesPerScanLine = (UINT16)BytesPerScanLine;
859 
860   CurrentModeData->Red      = *(FB_VIDEO_COLOR_PLACEMENT *)&(pFbInfo->Red);
861   CurrentModeData->Blue     = *(FB_VIDEO_COLOR_PLACEMENT *)&(pFbInfo->Blue);
862   CurrentModeData->Green    = *(FB_VIDEO_COLOR_PLACEMENT *)&(pFbInfo->Green);
863   CurrentModeData->Reserved = *(FB_VIDEO_COLOR_PLACEMENT *)&(pFbInfo->Reserved);
864 
865   CurrentModeData->BitsPerPixel    = (UINT32)BitsPerPixel;
866   CurrentModeData->HorizontalResolution = HorizontalResolution;
867   CurrentModeData->VerticalResolution   = VerticalResolution;
868   CurrentModeData->FrameBufferSize = CurrentModeData->BytesPerScanLine * CurrentModeData->VerticalResolution;
869   CurrentModeData->LinearFrameBuffer = (VOID *) (UINTN) pFbInfo->LinearFrameBuffer;
870   CurrentModeData->VbeModeNumber        = 0;
871   CurrentModeData->ColorDepth           = 32;
872   CurrentModeData->RefreshRate          = 60;
873 
874   CurrentModeData->PixelFormat = PixelBitMask;
875   if ((CurrentModeData->BitsPerPixel == 32) &&
876       (CurrentModeData->Red.Mask == 0xff) && (CurrentModeData->Green.Mask == 0xff) && (CurrentModeData->Blue.Mask == 0xff)) {
877     if ((CurrentModeData->Red.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Blue.Position == 16)) {
878       CurrentModeData->PixelFormat = PixelRedGreenBlueReserved8BitPerColor;
879     } else if ((CurrentModeData->Blue.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Red.Position == 16)) {
880       CurrentModeData->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
881     }
882   }
883 
884   CopyMem (&(CurrentModeData->PixelBitMask), &mPixelBitMask, sizeof (EFI_PIXEL_BITMASK));
885 
886   FbGopPrivate->ModeData       = ModeBuffer;
887   FbGopPrivate->VbeFrameBuffer = VbeFrameBuffer;
888 
889   //
890   // Assign Gop's Blt function
891   //
892   FbGopPrivate->GraphicsOutput.Blt     = FbGopGraphicsOutputVbeBlt;
893 
894   FbGopPrivate->GraphicsOutput.Mode->MaxMode = 1;
895   FbGopPrivate->GraphicsOutput.Mode->Mode    = 0;
896   FbGopPrivate->GraphicsOutput.Mode->Info->Version = 0;
897   FbGopPrivate->GraphicsOutput.Mode->Info->HorizontalResolution = HorizontalResolution;
898   FbGopPrivate->GraphicsOutput.Mode->Info->VerticalResolution   = VerticalResolution;
899   FbGopPrivate->GraphicsOutput.Mode->Info->PixelFormat = CurrentModeData->PixelFormat;
900   CopyMem (&(FbGopPrivate->GraphicsOutput.Mode->Info->PixelInformation), &mPixelBitMask, sizeof (EFI_PIXEL_BITMASK));
901   FbGopPrivate->GraphicsOutput.Mode->Info->PixelsPerScanLine = HorizontalResolution;
902   FbGopPrivate->GraphicsOutput.Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
903   FbGopPrivate->GraphicsOutput.Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) CurrentModeData->LinearFrameBuffer;
904   FbGopPrivate->GraphicsOutput.Mode->FrameBufferSize =  CurrentModeData->FrameBufferSize;
905 
906   //
907   // Find the best mode to initialize
908   //
909 
910 Done:
911   //
912   // If there was an error, then free the mode structure
913   //
914   if (EFI_ERROR (Status)) {
915 
916     if (VbeFrameBuffer != NULL) {
917       FreePool (VbeFrameBuffer);
918     }
919 
920     if (ModeBuffer != NULL) {
921       FreePool (ModeBuffer);
922     }
923   }
924 
925   return Status;
926 }
927 
928 
929 //
930 // Graphics Output Protocol Member Functions for VESA BIOS Extensions
931 //
932 
933 /**
934   Graphics Output protocol interface to get video mode.
935 
936   @param  This                   Protocol instance pointer.
937   @param  ModeNumber             The mode number to return information on.
938   @param  SizeOfInfo             A pointer to the size, in bytes, of the Info
939                                  buffer.
940   @param  Info                   Caller allocated buffer that returns information
941                                  about ModeNumber.
942 
943   @retval EFI_SUCCESS            Mode information returned.
944   @retval EFI_DEVICE_ERROR       A hardware error occurred trying to retrieve the
945                                  video mode.
946   @retval EFI_NOT_STARTED        Video display is not initialized. Call SetMode ()
947   @retval EFI_INVALID_PARAMETER  One of the input args was NULL.
948 
949 **/
950 EFI_STATUS
951 EFIAPI
FbGopGraphicsOutputQueryMode(IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,IN UINT32 ModeNumber,OUT UINTN * SizeOfInfo,OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION ** Info)952 FbGopGraphicsOutputQueryMode (
953   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL          *This,
954   IN  UINT32                                ModeNumber,
955   OUT UINTN                                 *SizeOfInfo,
956   OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  **Info
957   )
958 {
959   FB_VIDEO_DEV        *FbGopPrivate;
960   FB_VIDEO_MODE_DATA  *ModeData;
961 
962   FbGopPrivate = FB_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
963 
964   if (This == NULL || Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {
965     return EFI_INVALID_PARAMETER;
966   }
967 
968   *Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) AllocatePool (
969 																										sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)
970 																										);
971   if (NULL == *Info) {
972     return EFI_OUT_OF_RESOURCES;
973   }
974 
975   *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
976 
977   ModeData = &FbGopPrivate->ModeData[ModeNumber];
978   (*Info)->Version = 0;
979   (*Info)->HorizontalResolution = ModeData->HorizontalResolution;
980   (*Info)->VerticalResolution   = ModeData->VerticalResolution;
981   (*Info)->PixelFormat = ModeData->PixelFormat;
982   CopyMem (&((*Info)->PixelInformation), &(ModeData->PixelBitMask), sizeof(ModeData->PixelBitMask));
983 
984   (*Info)->PixelsPerScanLine =  (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel;
985 
986   return EFI_SUCCESS;
987 }
988 
989 /**
990   Graphics Output protocol interface to set video mode.
991 
992   @param  This                   Protocol instance pointer.
993   @param  ModeNumber             The mode number to be set.
994 
995   @retval EFI_SUCCESS            Graphics mode was changed.
996   @retval EFI_DEVICE_ERROR       The device had an error and could not complete the
997                                  request.
998   @retval EFI_UNSUPPORTED        ModeNumber is not supported by this device.
999 
1000 **/
1001 EFI_STATUS
1002 EFIAPI
FbGopGraphicsOutputSetMode(IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,IN UINT32 ModeNumber)1003 FbGopGraphicsOutputSetMode (
1004   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL * This,
1005   IN  UINT32                       ModeNumber
1006   )
1007 {
1008   FB_VIDEO_DEV          *FbGopPrivate;
1009   FB_VIDEO_MODE_DATA    *ModeData;
1010   EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
1011 
1012   if (This == NULL) {
1013     return EFI_INVALID_PARAMETER;
1014   }
1015 
1016   FbGopPrivate = FB_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
1017 
1018   ModeData = &FbGopPrivate->ModeData[ModeNumber];
1019 
1020   if (ModeNumber >= This->Mode->MaxMode) {
1021     return EFI_UNSUPPORTED;
1022   }
1023 
1024   if (ModeNumber == This->Mode->Mode) {
1025     //
1026     // Clear screen to black
1027     //
1028     ZeroMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
1029     FbGopGraphicsOutputVbeBlt (
1030                         This,
1031                         &Background,
1032                         EfiBltVideoFill,
1033                         0,
1034                         0,
1035                         0,
1036                         0,
1037                         ModeData->HorizontalResolution,
1038                         ModeData->VerticalResolution,
1039                         0
1040     );
1041     return EFI_SUCCESS;
1042   } else {
1043     return EFI_UNSUPPORTED;
1044   }
1045 
1046 }
1047 
1048 /**
1049   Update physical frame buffer, copy 4 bytes block, then copy remaining bytes.
1050 
1051   @param   PciIo              The pointer of EFI_PCI_IO_PROTOCOL
1052   @param   VbeBuffer          The data to transfer to screen
1053   @param   MemAddress         Physical frame buffer base address
1054   @param   DestinationX       The X coordinate of the destination for BltOperation
1055   @param   DestinationY       The Y coordinate of the destination for BltOperation
1056   @param   TotalBytes         The total bytes of copy
1057   @param   VbePixelWidth      Bytes per pixel
1058   @param   BytesPerScanLine   Bytes per scan line
1059 
1060 **/
1061 VOID
CopyVideoBuffer(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT8 * VbeBuffer,IN VOID * MemAddress,IN UINTN DestinationX,IN UINTN DestinationY,IN UINTN TotalBytes,IN UINT32 VbePixelWidth,IN UINTN BytesPerScanLine)1062 CopyVideoBuffer (
1063   IN  EFI_PCI_IO_PROTOCOL   *PciIo,
1064   IN  UINT8                 *VbeBuffer,
1065   IN  VOID                  *MemAddress,
1066   IN  UINTN                 DestinationX,
1067   IN  UINTN                 DestinationY,
1068   IN  UINTN                 TotalBytes,
1069   IN  UINT32                VbePixelWidth,
1070   IN  UINTN                 BytesPerScanLine
1071   )
1072 {
1073   UINTN                 FrameBufferAddr;
1074   UINTN                 CopyBlockNum;
1075   UINTN                 RemainingBytes;
1076   UINTN                 UnalignedBytes;
1077   EFI_STATUS            Status;
1078 
1079   FrameBufferAddr = (UINTN) MemAddress + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth;
1080 
1081   //
1082   // If TotalBytes is less than 4 bytes, only start byte copy.
1083   //
1084   if (TotalBytes < 4) {
1085     Status = PciIo->Mem.Write (
1086                      PciIo,
1087                      EfiPciIoWidthUint8,
1088                      EFI_PCI_IO_PASS_THROUGH_BAR,
1089                      (UINT64) FrameBufferAddr,
1090                      TotalBytes,
1091                      VbeBuffer
1092                      );
1093     ASSERT_EFI_ERROR (Status);
1094     return;
1095   }
1096 
1097   //
1098   // If VbeBuffer is not 4-byte aligned, start byte copy.
1099   //
1100   UnalignedBytes  = (4 - ((UINTN) VbeBuffer & 0x3)) & 0x3;
1101 
1102   if (UnalignedBytes != 0) {
1103     Status = PciIo->Mem.Write (
1104                      PciIo,
1105                      EfiPciIoWidthUint8,
1106                      EFI_PCI_IO_PASS_THROUGH_BAR,
1107                      (UINT64) FrameBufferAddr,
1108                      UnalignedBytes,
1109                      VbeBuffer
1110                      );
1111     ASSERT_EFI_ERROR (Status);
1112     FrameBufferAddr += UnalignedBytes;
1113     VbeBuffer       += UnalignedBytes;
1114   }
1115 
1116   //
1117   // Calculate 4-byte block count and remaining bytes.
1118   //
1119   CopyBlockNum   = (TotalBytes - UnalignedBytes) >> 2;
1120   RemainingBytes = (TotalBytes - UnalignedBytes) &  3;
1121 
1122   //
1123   // Copy 4-byte block and remaining bytes to physical frame buffer.
1124   //
1125   if (CopyBlockNum != 0) {
1126     Status = PciIo->Mem.Write (
1127                     PciIo,
1128                     EfiPciIoWidthUint32,
1129                     EFI_PCI_IO_PASS_THROUGH_BAR,
1130                     (UINT64) FrameBufferAddr,
1131                     CopyBlockNum,
1132                     VbeBuffer
1133                     );
1134     ASSERT_EFI_ERROR (Status);
1135   }
1136 
1137   if (RemainingBytes != 0) {
1138     FrameBufferAddr += (CopyBlockNum << 2);
1139     VbeBuffer       += (CopyBlockNum << 2);
1140     Status = PciIo->Mem.Write (
1141                     PciIo,
1142                     EfiPciIoWidthUint8,
1143                     EFI_PCI_IO_PASS_THROUGH_BAR,
1144                     (UINT64) FrameBufferAddr,
1145                     RemainingBytes,
1146                     VbeBuffer
1147                     );
1148     ASSERT_EFI_ERROR (Status);
1149   }
1150 }
1151 
1152 /**
1153   Worker function to block transfer for VBE device.
1154 
1155   @param  FbGopPrivate       Instance of FB_VIDEO_DEV
1156   @param  BltBuffer              The data to transfer to screen
1157   @param  BltOperation           The operation to perform
1158   @param  SourceX                The X coordinate of the source for BltOperation
1159   @param  SourceY                The Y coordinate of the source for BltOperation
1160   @param  DestinationX           The X coordinate of the destination for
1161                                  BltOperation
1162   @param  DestinationY           The Y coordinate of the destination for
1163                                  BltOperation
1164   @param  Width                  The width of a rectangle in the blt rectangle in
1165                                  pixels
1166   @param  Height                 The height of a rectangle in the blt rectangle in
1167                                  pixels
1168   @param  Delta                  Not used for EfiBltVideoFill and
1169                                  EfiBltVideoToVideo operation. If a Delta of 0 is
1170                                  used, the entire BltBuffer will be operated on. If
1171                                  a subrectangle of the BltBuffer is used, then
1172                                  Delta represents the number of bytes in a row of
1173                                  the BltBuffer.
1174   @param  Mode                   Mode data.
1175 
1176   @retval EFI_INVALID_PARAMETER  Invalid parameter passed in
1177   @retval EFI_SUCCESS            Blt operation success
1178 
1179 **/
1180 EFI_STATUS
FbGopVbeBltWorker(IN FB_VIDEO_DEV * FbGopPrivate,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,IN FB_VIDEO_MODE_DATA * Mode)1181 FbGopVbeBltWorker (
1182   IN  FB_VIDEO_DEV                       *FbGopPrivate,
1183   IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL      *BltBuffer, OPTIONAL
1184   IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION  BltOperation,
1185   IN  UINTN                              SourceX,
1186   IN  UINTN                              SourceY,
1187   IN  UINTN                              DestinationX,
1188   IN  UINTN                              DestinationY,
1189   IN  UINTN                              Width,
1190   IN  UINTN                              Height,
1191   IN  UINTN                              Delta,
1192   IN  FB_VIDEO_MODE_DATA               *Mode
1193   )
1194 {
1195   EFI_PCI_IO_PROTOCOL            *PciIo;
1196   EFI_TPL                        OriginalTPL;
1197   UINTN                          DstY;
1198   UINTN                          SrcY;
1199   UINTN                          DstX;
1200   EFI_GRAPHICS_OUTPUT_BLT_PIXEL  *Blt;
1201   VOID                           *MemAddress;
1202   EFI_GRAPHICS_OUTPUT_BLT_PIXEL  *VbeFrameBuffer;
1203   UINTN                          BytesPerScanLine;
1204   UINTN                          Index;
1205   UINT8                          *VbeBuffer;
1206   UINT8                          *VbeBuffer1;
1207   UINT8                          *BltUint8;
1208   UINT32                         VbePixelWidth;
1209   UINT32                         Pixel;
1210   UINTN                          TotalBytes;
1211 
1212   PciIo             = FbGopPrivate->PciIo;
1213 
1214   VbeFrameBuffer    = FbGopPrivate->VbeFrameBuffer;
1215   MemAddress        = Mode->LinearFrameBuffer;
1216   BytesPerScanLine  = Mode->BytesPerScanLine;
1217   VbePixelWidth     = Mode->BitsPerPixel / 8;
1218   BltUint8          = (UINT8 *) BltBuffer;
1219   TotalBytes        = Width * VbePixelWidth;
1220 
1221   if (((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) {
1222     return EFI_INVALID_PARAMETER;
1223   }
1224 
1225   if (Width == 0 || Height == 0) {
1226     return EFI_INVALID_PARAMETER;
1227   }
1228   //
1229   // We need to fill the Virtual Screen buffer with the blt data.
1230   // The virtual screen is upside down, as the first row is the bootom row of
1231   // the image.
1232   //
1233   if (BltOperation == EfiBltVideoToBltBuffer) {
1234     //
1235     // Video to BltBuffer: Source is Video, destination is BltBuffer
1236     //
1237     if (SourceY + Height > Mode->VerticalResolution) {
1238       return EFI_INVALID_PARAMETER;
1239     }
1240 
1241     if (SourceX + Width > Mode->HorizontalResolution) {
1242       return EFI_INVALID_PARAMETER;
1243     }
1244   } else {
1245     //
1246     // BltBuffer to Video: Source is BltBuffer, destination is Video
1247     //
1248     if (DestinationY + Height > Mode->VerticalResolution) {
1249       return EFI_INVALID_PARAMETER;
1250     }
1251 
1252     if (DestinationX + Width > Mode->HorizontalResolution) {
1253       return EFI_INVALID_PARAMETER;
1254     }
1255   }
1256   //
1257   // If Delta is zero, then the entire BltBuffer is being used, so Delta
1258   // is the number of bytes in each row of BltBuffer.  Since BltBuffer is Width pixels size,
1259   // the number of bytes in each row can be computed.
1260   //
1261   if (Delta == 0) {
1262     Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
1263   }
1264   //
1265   // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
1266   // We would not want a timer based event (Cursor, ...) to come in while we are
1267   // doing this operation.
1268   //
1269   OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
1270 
1271   switch (BltOperation) {
1272   case EfiBltVideoToBltBuffer:
1273     for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {
1274       Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + DstY * Delta + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
1275       //
1276       // Shuffle the packed bytes in the hardware buffer to match EFI_GRAPHICS_OUTPUT_BLT_PIXEL
1277       //
1278       VbeBuffer = ((UINT8 *) VbeFrameBuffer + (SrcY * BytesPerScanLine + SourceX * VbePixelWidth));
1279       for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
1280         Pixel         = VbeBuffer[0] | VbeBuffer[1] << 8 | VbeBuffer[2] << 16 | VbeBuffer[3] << 24;
1281         Blt->Red      = (UINT8) ((Pixel >> Mode->Red.Position) & Mode->Red.Mask);
1282         Blt->Blue     = (UINT8) ((Pixel >> Mode->Blue.Position) & Mode->Blue.Mask);
1283         Blt->Green    = (UINT8) ((Pixel >> Mode->Green.Position) & Mode->Green.Mask);
1284         Blt->Reserved = 0;
1285         Blt++;
1286         VbeBuffer += VbePixelWidth;
1287       }
1288 
1289     }
1290     break;
1291 
1292   case EfiBltVideoToVideo:
1293     for (Index = 0; Index < Height; Index++) {
1294       if (DestinationY <= SourceY) {
1295         SrcY  = SourceY + Index;
1296         DstY  = DestinationY + Index;
1297       } else {
1298         SrcY  = SourceY + Height - Index - 1;
1299         DstY  = DestinationY + Height - Index - 1;
1300       }
1301 
1302       VbeBuffer   = ((UINT8 *) VbeFrameBuffer + DstY * BytesPerScanLine + DestinationX * VbePixelWidth);
1303       VbeBuffer1  = ((UINT8 *) VbeFrameBuffer + SrcY * BytesPerScanLine + SourceX * VbePixelWidth);
1304 
1305       gBS->CopyMem (
1306             VbeBuffer,
1307             VbeBuffer1,
1308             TotalBytes
1309             );
1310 
1311       //
1312       // Update physical frame buffer.
1313       //
1314       CopyVideoBuffer (
1315         PciIo,
1316         VbeBuffer,
1317         MemAddress,
1318         DestinationX,
1319         DstY,
1320         TotalBytes,
1321         VbePixelWidth,
1322         BytesPerScanLine
1323         );
1324     }
1325     break;
1326 
1327   case EfiBltVideoFill:
1328     VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);
1329     Blt       = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) BltUint8;
1330     //
1331     // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
1332     //
1333     Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |
1334       (
1335         (Blt->Green & Mode->Green.Mask) <<
1336         Mode->Green.Position
1337       ) |
1338           ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);
1339 
1340     for (Index = 0; Index < Width; Index++) {
1341       gBS->CopyMem (
1342             VbeBuffer,
1343             &Pixel,
1344             VbePixelWidth
1345             );
1346       VbeBuffer += VbePixelWidth;
1347     }
1348 
1349     VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);
1350     for (DstY = DestinationY + 1; DstY < (Height + DestinationY); DstY++) {
1351       gBS->CopyMem (
1352             (VOID *) ((UINTN) VbeFrameBuffer + (DstY * BytesPerScanLine) + DestinationX * VbePixelWidth),
1353             VbeBuffer,
1354             TotalBytes
1355             );
1356     }
1357 
1358     for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {
1359       //
1360       // Update physical frame buffer.
1361       //
1362       CopyVideoBuffer (
1363         PciIo,
1364         VbeBuffer,
1365         MemAddress,
1366         DestinationX,
1367         DstY,
1368         TotalBytes,
1369         VbePixelWidth,
1370         BytesPerScanLine
1371         );
1372     }
1373     break;
1374 
1375   case EfiBltBufferToVideo:
1376     for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
1377       Blt       = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + (SrcY * Delta) + (SourceX) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
1378       VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));
1379       for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
1380         //
1381         // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
1382         //
1383         Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |
1384           ((Blt->Green & Mode->Green.Mask) << Mode->Green.Position) |
1385             ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);
1386         gBS->CopyMem (
1387               VbeBuffer,
1388               &Pixel,
1389               VbePixelWidth
1390               );
1391         Blt++;
1392         VbeBuffer += VbePixelWidth;
1393       }
1394 
1395       VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));
1396 
1397       //
1398       // Update physical frame buffer.
1399       //
1400       CopyVideoBuffer (
1401         PciIo,
1402         VbeBuffer,
1403         MemAddress,
1404         DestinationX,
1405         DstY,
1406         TotalBytes,
1407         VbePixelWidth,
1408         BytesPerScanLine
1409         );
1410     }
1411     break;
1412 
1413     default: ;
1414   }
1415 
1416   gBS->RestoreTPL (OriginalTPL);
1417 
1418   return EFI_SUCCESS;
1419 }
1420 
1421 /**
1422   Graphics Output protocol instance to block transfer for VBE device.
1423 
1424   @param  This                   Pointer to Graphics Output protocol instance
1425   @param  BltBuffer              The data to transfer to screen
1426   @param  BltOperation           The operation to perform
1427   @param  SourceX                The X coordinate of the source for BltOperation
1428   @param  SourceY                The Y coordinate of the source for BltOperation
1429   @param  DestinationX           The X coordinate of the destination for
1430                                  BltOperation
1431   @param  DestinationY           The Y coordinate of the destination for
1432                                  BltOperation
1433   @param  Width                  The width of a rectangle in the blt rectangle in
1434                                  pixels
1435   @param  Height                 The height of a rectangle in the blt rectangle in
1436                                  pixels
1437   @param  Delta                  Not used for EfiBltVideoFill and
1438                                  EfiBltVideoToVideo operation. If a Delta of 0 is
1439                                  used, the entire BltBuffer will be operated on. If
1440                                  a subrectangle of the BltBuffer is used, then
1441                                  Delta represents the number of bytes in a row of
1442                                  the BltBuffer.
1443 
1444   @retval EFI_INVALID_PARAMETER  Invalid parameter passed in
1445   @retval EFI_SUCCESS            Blt operation success
1446 
1447 **/
1448 EFI_STATUS
1449 EFIAPI
FbGopGraphicsOutputVbeBlt(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)1450 FbGopGraphicsOutputVbeBlt (
1451   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL       *This,
1452   IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL      *BltBuffer, OPTIONAL
1453   IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION  BltOperation,
1454   IN  UINTN                              SourceX,
1455   IN  UINTN                              SourceY,
1456   IN  UINTN                              DestinationX,
1457   IN  UINTN                              DestinationY,
1458   IN  UINTN                              Width,
1459   IN  UINTN                              Height,
1460   IN  UINTN                              Delta
1461   )
1462 {
1463   FB_VIDEO_DEV                 *FbGopPrivate;
1464   FB_VIDEO_MODE_DATA           *Mode;
1465 
1466   if (This == NULL) {
1467     return EFI_INVALID_PARAMETER;
1468   }
1469 
1470   FbGopPrivate  = FB_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
1471   Mode          = &FbGopPrivate->ModeData[This->Mode->Mode];
1472 
1473   return FbGopVbeBltWorker (
1474            FbGopPrivate,
1475            BltBuffer,
1476            BltOperation,
1477            SourceX,
1478            SourceY,
1479            DestinationX,
1480            DestinationY,
1481            Width,
1482            Height,
1483            Delta,
1484            Mode
1485            );
1486 }
1487 
1488 
1489 /**
1490   The user Entry Point for module UefiFbGop. The user code starts with this function.
1491 
1492   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
1493   @param[in] SystemTable    A pointer to the EFI System Table.
1494 
1495   @retval EFI_SUCCESS       The entry point is executed successfully.
1496   @retval other             Some error occurs when executing this entry point.
1497 
1498 **/
1499 EFI_STATUS
1500 EFIAPI
FbGopEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1501 FbGopEntryPoint(
1502   IN EFI_HANDLE           ImageHandle,
1503   IN EFI_SYSTEM_TABLE     *SystemTable
1504   )
1505 {
1506   EFI_STATUS  Status;
1507   EFI_HOB_GUID_TYPE  *GuidHob;
1508 
1509   //
1510   // Find the frame buffer information guid hob
1511   //
1512   GuidHob = GetFirstGuidHob (&gUefiFrameBufferInfoGuid);
1513   if (GuidHob != NULL) {
1514     //
1515     // Install driver model protocol(s).
1516     //
1517     Status = EfiLibInstallDriverBindingComponentName2 (
1518                ImageHandle,
1519                SystemTable,
1520                &gFbGopDriverBinding,
1521                ImageHandle,
1522                &gFbGopComponentName,
1523                &gFbGopComponentName2
1524                );
1525     ASSERT_EFI_ERROR (Status);
1526   } else {
1527     DEBUG ((EFI_D_ERROR, "No FrameBuffer information from coreboot.  NO GOP driver !!!\n"));
1528     Status = EFI_ABORTED;
1529   }
1530   return Status;
1531 }
1532 
1533