https://bugzilla.tianocore.org/show_bug.cgi?id=1373 Replace BSD 2-Clause License with BSD+Patent License. This change is based on the following emails: https://lists.01.org/pipermail/edk2-devel/2019-February/036260.html https://lists.01.org/pipermail/edk2-devel/2018-October/030385.html RFCs with detailed process for the license change: V3: https://lists.01.org/pipermail/edk2-devel/2019-March/038116.html V2: https://lists.01.org/pipermail/edk2-devel/2019-March/037669.html V1: https://lists.01.org/pipermail/edk2-devel/2019-March/037500.html Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
		
			
				
	
	
		
			394 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			394 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   This driver is a implementation of the Graphics Output Protocol
 | |
|   for the QEMU ramfb device.
 | |
| 
 | |
|   Copyright (c) 2018, Red Hat Inc.
 | |
| 
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include <Protocol/GraphicsOutput.h>
 | |
| 
 | |
| #include <Library/BaseLib.h>
 | |
| #include <Library/BaseMemoryLib.h>
 | |
| #include <Library/DebugLib.h>
 | |
| #include <Library/DevicePathLib.h>
 | |
| #include <Library/FrameBufferBltLib.h>
 | |
| #include <Library/MemoryAllocationLib.h>
 | |
| #include <Library/UefiBootServicesTableLib.h>
 | |
| #include <Library/QemuFwCfgLib.h>
 | |
| 
 | |
| #include <Guid/QemuRamfb.h>
 | |
| 
 | |
| #define RAMFB_FORMAT  0x34325258 /* DRM_FORMAT_XRGB8888 */
 | |
| #define RAMFB_BPP     4
 | |
| 
 | |
| #pragma pack (1)
 | |
| typedef struct RAMFB_CONFIG {
 | |
|   UINT64 Address;
 | |
|   UINT32 FourCC;
 | |
|   UINT32 Flags;
 | |
|   UINT32 Width;
 | |
|   UINT32 Height;
 | |
|   UINT32 Stride;
 | |
| } RAMFB_CONFIG;
 | |
| #pragma pack ()
 | |
| 
 | |
| STATIC EFI_HANDLE                    mRamfbHandle;
 | |
| STATIC EFI_HANDLE                    mGopHandle;
 | |
| STATIC FRAME_BUFFER_CONFIGURE        *mQemuRamfbFrameBufferBltConfigure;
 | |
| STATIC UINTN                         mQemuRamfbFrameBufferBltConfigureSize;
 | |
| STATIC FIRMWARE_CONFIG_ITEM          mRamfbFwCfgItem;
 | |
| 
 | |
| STATIC EFI_GRAPHICS_OUTPUT_MODE_INFORMATION mQemuRamfbModeInfo[] = {
 | |
|   {
 | |
|     0,    // Version
 | |
|     640,  // HorizontalResolution
 | |
|     480,  // VerticalResolution
 | |
|   },{
 | |
|     0,    // Version
 | |
|     800,  // HorizontalResolution
 | |
|     600,  // VerticalResolution
 | |
|   },{
 | |
|     0,    // Version
 | |
|     1024, // HorizontalResolution
 | |
|     768,  // VerticalResolution
 | |
|   }
 | |
| };
 | |
| 
 | |
| STATIC EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE mQemuRamfbMode = {
 | |
|   ARRAY_SIZE (mQemuRamfbModeInfo),                // MaxMode
 | |
|   0,                                              // Mode
 | |
|   mQemuRamfbModeInfo,                             // Info
 | |
|   sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION),  // SizeOfInfo
 | |
| };
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| QemuRamfbGraphicsOutputQueryMode (
 | |
|   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL          *This,
 | |
|   IN  UINT32                                ModeNumber,
 | |
|   OUT UINTN                                 *SizeOfInfo,
 | |
|   OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  **Info
 | |
|   )
 | |
| {
 | |
|   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *ModeInfo;
 | |
| 
 | |
|   if (Info == NULL || SizeOfInfo == NULL ||
 | |
|       ModeNumber >= mQemuRamfbMode.MaxMode) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   ModeInfo = &mQemuRamfbModeInfo[ModeNumber];
 | |
| 
 | |
|   *Info = AllocateCopyPool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION),
 | |
|             ModeInfo);
 | |
|   if (*Info == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| QemuRamfbGraphicsOutputSetMode (
 | |
|   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
 | |
|   IN  UINT32                       ModeNumber
 | |
|   )
 | |
| {
 | |
|   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *ModeInfo;
 | |
|   RAMFB_CONFIG                          Config;
 | |
|   EFI_GRAPHICS_OUTPUT_BLT_PIXEL         Black;
 | |
|   RETURN_STATUS                         Status;
 | |
| 
 | |
|   if (ModeNumber >= mQemuRamfbMode.MaxMode) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
|   ModeInfo = &mQemuRamfbModeInfo[ModeNumber];
 | |
| 
 | |
|   DEBUG ((DEBUG_INFO, "Ramfb: SetMode %u (%ux%u)\n", ModeNumber,
 | |
|     ModeInfo->HorizontalResolution, ModeInfo->VerticalResolution));
 | |
| 
 | |
|   Config.Address = SwapBytes64 (mQemuRamfbMode.FrameBufferBase);
 | |
|   Config.FourCC  = SwapBytes32 (RAMFB_FORMAT);
 | |
|   Config.Flags   = SwapBytes32 (0);
 | |
|   Config.Width   = SwapBytes32 (ModeInfo->HorizontalResolution);
 | |
|   Config.Height  = SwapBytes32 (ModeInfo->VerticalResolution);
 | |
|   Config.Stride  = SwapBytes32 (ModeInfo->HorizontalResolution * RAMFB_BPP);
 | |
| 
 | |
|   Status = FrameBufferBltConfigure (
 | |
|              (VOID*)(UINTN)mQemuRamfbMode.FrameBufferBase,
 | |
|              ModeInfo,
 | |
|              mQemuRamfbFrameBufferBltConfigure,
 | |
|              &mQemuRamfbFrameBufferBltConfigureSize
 | |
|              );
 | |
| 
 | |
|   if (Status == RETURN_BUFFER_TOO_SMALL) {
 | |
|     if (mQemuRamfbFrameBufferBltConfigure != NULL) {
 | |
|       FreePool (mQemuRamfbFrameBufferBltConfigure);
 | |
|     }
 | |
|     mQemuRamfbFrameBufferBltConfigure =
 | |
|       AllocatePool (mQemuRamfbFrameBufferBltConfigureSize);
 | |
|     if (mQemuRamfbFrameBufferBltConfigure == NULL) {
 | |
|       mQemuRamfbFrameBufferBltConfigureSize = 0;
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     Status = FrameBufferBltConfigure (
 | |
|                (VOID*)(UINTN)mQemuRamfbMode.FrameBufferBase,
 | |
|                ModeInfo,
 | |
|                mQemuRamfbFrameBufferBltConfigure,
 | |
|                &mQemuRamfbFrameBufferBltConfigureSize
 | |
|                );
 | |
|   }
 | |
|   if (RETURN_ERROR (Status)) {
 | |
|     ASSERT (Status == RETURN_UNSUPPORTED);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   mQemuRamfbMode.Mode = ModeNumber;
 | |
|   mQemuRamfbMode.Info = ModeInfo;
 | |
| 
 | |
|   QemuFwCfgSelectItem (mRamfbFwCfgItem);
 | |
|   QemuFwCfgWriteBytes (sizeof (Config), &Config);
 | |
| 
 | |
|   //
 | |
|   // clear screen
 | |
|   //
 | |
|   ZeroMem (&Black, sizeof (Black));
 | |
|   Status = FrameBufferBlt (
 | |
|              mQemuRamfbFrameBufferBltConfigure,
 | |
|              &Black,
 | |
|              EfiBltVideoFill,
 | |
|              0,                               // SourceX -- ignored
 | |
|              0,                               // SourceY -- ignored
 | |
|              0,                               // DestinationX
 | |
|              0,                               // DestinationY
 | |
|              ModeInfo->HorizontalResolution,  // Width
 | |
|              ModeInfo->VerticalResolution,    // Height
 | |
|              0                                // Delta -- ignored
 | |
|              );
 | |
|   if (RETURN_ERROR (Status)) {
 | |
|     DEBUG ((DEBUG_WARN, "%a: clearing the screen failed: %r\n",
 | |
|       __FUNCTION__, Status));
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| QemuRamfbGraphicsOutputBlt (
 | |
|   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
 | |
|   )
 | |
| {
 | |
|   return FrameBufferBlt (
 | |
|            mQemuRamfbFrameBufferBltConfigure,
 | |
|            BltBuffer,
 | |
|            BltOperation,
 | |
|            SourceX,
 | |
|            SourceY,
 | |
|            DestinationX,
 | |
|            DestinationY,
 | |
|            Width,
 | |
|            Height,
 | |
|            Delta
 | |
|            );
 | |
| }
 | |
| 
 | |
| STATIC EFI_GRAPHICS_OUTPUT_PROTOCOL mQemuRamfbGraphicsOutput = {
 | |
|   QemuRamfbGraphicsOutputQueryMode,
 | |
|   QemuRamfbGraphicsOutputSetMode,
 | |
|   QemuRamfbGraphicsOutputBlt,
 | |
|   &mQemuRamfbMode,
 | |
| };
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| InitializeQemuRamfb (
 | |
|   IN EFI_HANDLE           ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE     *SystemTable
 | |
|   )
 | |
| {
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *RamfbDevicePath;
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *GopDevicePath;
 | |
|   VOID                      *DevicePath;
 | |
|   VENDOR_DEVICE_PATH        VendorDeviceNode;
 | |
|   ACPI_ADR_DEVICE_PATH      AcpiDeviceNode;
 | |
|   EFI_STATUS                Status;
 | |
|   EFI_PHYSICAL_ADDRESS      FbBase;
 | |
|   UINTN                     FbSize, MaxFbSize, Pages;
 | |
|   UINTN                     FwCfgSize;
 | |
|   UINTN                     Index;
 | |
| 
 | |
|   if (!QemuFwCfgIsAvailable ()) {
 | |
|     DEBUG ((DEBUG_INFO, "Ramfb: no FwCfg\n"));
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   Status = QemuFwCfgFindFile ("etc/ramfb", &mRamfbFwCfgItem, &FwCfgSize);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
|   if (FwCfgSize != sizeof (RAMFB_CONFIG)) {
 | |
|     DEBUG ((DEBUG_ERROR, "Ramfb: FwCfg size mismatch (expected %lu, got %lu)\n",
 | |
|       (UINT64)sizeof (RAMFB_CONFIG), (UINT64)FwCfgSize));
 | |
|     return EFI_PROTOCOL_ERROR;
 | |
|   }
 | |
| 
 | |
|   MaxFbSize = 0;
 | |
|   for (Index = 0; Index < ARRAY_SIZE (mQemuRamfbModeInfo); Index++) {
 | |
|     mQemuRamfbModeInfo[Index].PixelsPerScanLine =
 | |
|       mQemuRamfbModeInfo[Index].HorizontalResolution;
 | |
|     mQemuRamfbModeInfo[Index].PixelFormat =
 | |
|       PixelBlueGreenRedReserved8BitPerColor;
 | |
|     FbSize = RAMFB_BPP *
 | |
|       mQemuRamfbModeInfo[Index].HorizontalResolution *
 | |
|       mQemuRamfbModeInfo[Index].VerticalResolution;
 | |
|     if (MaxFbSize < FbSize) {
 | |
|       MaxFbSize = FbSize;
 | |
|     }
 | |
|     DEBUG ((DEBUG_INFO, "Ramfb: Mode %lu: %ux%u, %lu kB\n", (UINT64)Index,
 | |
|       mQemuRamfbModeInfo[Index].HorizontalResolution,
 | |
|       mQemuRamfbModeInfo[Index].VerticalResolution,
 | |
|       (UINT64)(FbSize / 1024)));
 | |
|   }
 | |
| 
 | |
|   Pages = EFI_SIZE_TO_PAGES (MaxFbSize);
 | |
|   MaxFbSize = EFI_PAGES_TO_SIZE (Pages);
 | |
|   FbBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateReservedPages (Pages);
 | |
|   if (FbBase == 0) {
 | |
|     DEBUG ((DEBUG_ERROR, "Ramfb: memory allocation failed\n"));
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   DEBUG ((DEBUG_INFO, "Ramfb: Framebuffer at 0x%lx, %lu kB, %lu pages\n",
 | |
|     (UINT64)FbBase, (UINT64)(MaxFbSize / 1024), (UINT64)Pages));
 | |
|   mQemuRamfbMode.FrameBufferSize = MaxFbSize;
 | |
|   mQemuRamfbMode.FrameBufferBase = FbBase;
 | |
| 
 | |
|   //
 | |
|   // 800 x 600
 | |
|   //
 | |
|   QemuRamfbGraphicsOutputSetMode (&mQemuRamfbGraphicsOutput, 1);
 | |
| 
 | |
|   //
 | |
|   // ramfb vendor devpath
 | |
|   //
 | |
|   VendorDeviceNode.Header.Type = HARDWARE_DEVICE_PATH;
 | |
|   VendorDeviceNode.Header.SubType = HW_VENDOR_DP;
 | |
|   CopyGuid (&VendorDeviceNode.Guid, &gQemuRamfbGuid);
 | |
|   SetDevicePathNodeLength (&VendorDeviceNode.Header,
 | |
|     sizeof (VENDOR_DEVICE_PATH));
 | |
| 
 | |
|   RamfbDevicePath = AppendDevicePathNode (NULL,
 | |
|     (EFI_DEVICE_PATH_PROTOCOL *) &VendorDeviceNode);
 | |
|   if (RamfbDevicePath == NULL) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto FreeFramebuffer;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                   &mRamfbHandle,
 | |
|                   &gEfiDevicePathProtocolGuid,
 | |
|                   RamfbDevicePath,
 | |
|                   NULL
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((DEBUG_ERROR, "Ramfb: install Ramfb Vendor DevicePath failed: %r\n",
 | |
|       Status));
 | |
|     goto FreeRamfbDevicePath;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // gop devpath + protocol
 | |
|   //
 | |
|   AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;
 | |
|   AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;
 | |
|   AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (
 | |
|     1,                                       // DeviceIdScheme
 | |
|     0,                                       // HeadId
 | |
|     0,                                       // NonVgaOutput
 | |
|     1,                                       // BiosCanDetect
 | |
|     0,                                       // VendorInfo
 | |
|     ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL,  // Type
 | |
|     0,                                       // Port
 | |
|     0                                        // Index
 | |
|     );
 | |
|   SetDevicePathNodeLength (&AcpiDeviceNode.Header,
 | |
|     sizeof (ACPI_ADR_DEVICE_PATH));
 | |
| 
 | |
|   GopDevicePath = AppendDevicePathNode (RamfbDevicePath,
 | |
|     (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode);
 | |
|   if (GopDevicePath == NULL) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto FreeRamfbHandle;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                   &mGopHandle,
 | |
|                   &gEfiDevicePathProtocolGuid,
 | |
|                   GopDevicePath,
 | |
|                   &gEfiGraphicsOutputProtocolGuid,
 | |
|                   &mQemuRamfbGraphicsOutput,
 | |
|                   NULL
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((DEBUG_ERROR, "Ramfb: install GOP DevicePath failed: %r\n",
 | |
|       Status));
 | |
|     goto FreeGopDevicePath;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   mRamfbHandle,
 | |
|                   &gEfiDevicePathProtocolGuid,
 | |
|                   &DevicePath,
 | |
|                   gImageHandle,
 | |
|                   mGopHandle,
 | |
|                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((DEBUG_ERROR, "Ramfb: OpenProtocol failed: %r\n", Status));
 | |
|     goto FreeGopHandle;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| FreeGopHandle:
 | |
|   gBS->UninstallMultipleProtocolInterfaces (
 | |
|          mGopHandle,
 | |
|          &gEfiDevicePathProtocolGuid,
 | |
|          GopDevicePath,
 | |
|          &gEfiGraphicsOutputProtocolGuid,
 | |
|          &mQemuRamfbGraphicsOutput,
 | |
|          NULL
 | |
|          );
 | |
| FreeGopDevicePath:
 | |
|   FreePool (GopDevicePath);
 | |
| FreeRamfbHandle:
 | |
|   gBS->UninstallMultipleProtocolInterfaces (
 | |
|          mRamfbHandle,
 | |
|          &gEfiDevicePathProtocolGuid,
 | |
|          RamfbDevicePath,
 | |
|          NULL
 | |
|          );
 | |
| FreeRamfbDevicePath:
 | |
|   FreePool (RamfbDevicePath);
 | |
| FreeFramebuffer:
 | |
|   FreePages ((VOID*)(UINTN)mQemuRamfbMode.FrameBufferBase, Pages);
 | |
|   return Status;
 | |
| }
 |