Hello Gerd,

Thanks a lot for contributing this code. I am quite pleased that we
finally have a solution for the EFI frame buffer for ARM systems
running under KVM.

One comment below.

On 8 June 2018 at 13:39, Gerd Hoffmann <kra...@redhat.com> wrote:
> Add a driver for the qemu ramfb display device.
>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Gerd Hoffmann <kra...@redhat.com>
> ---
>  OvmfPkg/QemuRamfbDxe/QemuRamfb.c      | 308 
> ++++++++++++++++++++++++++++++++++
>  OvmfPkg/OvmfPkgIa32.dsc               |   1 +
>  OvmfPkg/OvmfPkgIa32.fdf               |   1 +
>  OvmfPkg/OvmfPkgIa32X64.dsc            |   1 +
>  OvmfPkg/OvmfPkgIa32X64.fdf            |   1 +
>  OvmfPkg/OvmfPkgX64.dsc                |   1 +
>  OvmfPkg/OvmfPkgX64.fdf                |   1 +
>  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf |  34 ++++
>  8 files changed, 348 insertions(+)
>  create mode 100644 OvmfPkg/QemuRamfbDxe/QemuRamfb.c
>  create mode 100644 OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
>
> diff --git a/OvmfPkg/QemuRamfbDxe/QemuRamfb.c 
> b/OvmfPkg/QemuRamfbDxe/QemuRamfb.c
> new file mode 100644
> index 0000000000..f04a314c24
> --- /dev/null
> +++ b/OvmfPkg/QemuRamfbDxe/QemuRamfb.c
> @@ -0,0 +1,308 @@
> +#include <Uefi.h>
> +#include <Protocol/GraphicsOutput.h>
> +
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/FrameBufferBltLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/UefiBootManagerLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiDriverEntryPoint.h>
> +#include <Library/UefiLib.h>
> +#include <Library/QemuFwCfgLib.h>
> +
> +#include <Guid/QemuRamfb.h>
> +
> +#define RAMFB_FORMAT  0x34325258 /* DRM_FORMAT_XRGB8888 */
> +#define RAMFB_BPP     4
> +
> +EFI_GUID gQemuRamfbGuid = QEMU_RAMFB_GUID;
> +
> +typedef struct RAMFB_CONFIG {
> +  UINT64 Address;
> +  UINT32 FourCC;
> +  UINT32 Flags;
> +  UINT32 Width;
> +  UINT32 Height;
> +  UINT32 Stride;
> +} RAMFB_CONFIG;
> +
> +EFI_HANDLE                    RamfbHandle;
> +EFI_HANDLE                    GopHandle;
> +FRAME_BUFFER_CONFIGURE        *QemuRamfbFrameBufferBltConfigure;
> +UINTN                         QemuRamfbFrameBufferBltConfigureSize;
> +
> +EFI_GRAPHICS_OUTPUT_MODE_INFORMATION QemuRamfbModeInfo[] = {
> +  {
> +    .HorizontalResolution  = 640,
> +    .VerticalResolution    = 480,
> +  },{
> +    .HorizontalResolution  = 800,
> +    .VerticalResolution    = 600,
> +  },{
> +    .HorizontalResolution  = 1024,
> +    .VerticalResolution    = 768,
> +  }
> +};
> +#define QemuRamfbModeCount 
> (sizeof(QemuRamfbModeInfo)/sizeof(QemuRamfbModeInfo[0]))
> +
> +EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE QemuRamfbMode = {
> +  .MaxMode               = QemuRamfbModeCount,
> +  .Mode                  = 0,
> +  .Info                  = QemuRamfbModeInfo,
> +  .SizeOfInfo            = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION),
> +};
> +
> +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 > 
> QemuRamfbMode.MaxMode) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +  ModeInfo = &QemuRamfbModeInfo[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;
> +}
> +
> +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                         Ret;
> +  FIRMWARE_CONFIG_ITEM                  Item;
> +  UINTN                                 Size;
> +
> +  if (ModeNumber > QemuRamfbMode.MaxMode) {
> +    return EFI_UNSUPPORTED;
> +  }
> +  ModeInfo = &QemuRamfbModeInfo[ModeNumber];
> +
> +  DEBUG ((EFI_D_INFO, "Ramfb: SetMode %d (%dx%d)\n", ModeNumber,
> +          ModeInfo->HorizontalResolution,
> +          ModeInfo->VerticalResolution));
> +
> +  QemuRamfbMode.Mode = ModeNumber;
> +  QemuRamfbMode.Info = ModeInfo;
> +
> +  Config.Address = SwapBytes64( QemuRamfbMode.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 );
> +
> +  QemuFwCfgFindFile("etc/ramfb", &Item, &Size);
> +  QemuFwCfgSelectItem(Item);
> +  QemuFwCfgWriteBytes(sizeof(Config), &Config);
> +
> +  Ret = FrameBufferBltConfigure (
> +    (VOID*)(UINTN)QemuRamfbMode.FrameBufferBase,
> +    ModeInfo,
> +    QemuRamfbFrameBufferBltConfigure,
> +    &QemuRamfbFrameBufferBltConfigureSize);
> +
> +  if (Ret == RETURN_BUFFER_TOO_SMALL) {
> +    if (QemuRamfbFrameBufferBltConfigure != NULL) {
> +      FreePool(QemuRamfbFrameBufferBltConfigure);
> +    }
> +    QemuRamfbFrameBufferBltConfigure =
> +      AllocatePool(QemuRamfbFrameBufferBltConfigureSize);
> +
> +    Ret = FrameBufferBltConfigure (
> +      (VOID*)(UINTN)QemuRamfbMode.FrameBufferBase,
> +      ModeInfo,
> +      QemuRamfbFrameBufferBltConfigure,
> +      &QemuRamfbFrameBufferBltConfigureSize);
> +  }
> +
> +  /* clear screen */
> +  ZeroMem (&Black, sizeof (Black));
> +  Ret = FrameBufferBlt (
> +    QemuRamfbFrameBufferBltConfigure,
> +    &Black,
> +    EfiBltVideoFill,
> +    0, 0,
> +    0, 0,
> +    ModeInfo->HorizontalResolution,
> +    ModeInfo->VerticalResolution,
> +    0
> +    );
> +
> +  return EFI_SUCCESS;
> +}
> +
> +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 (
> +    QemuRamfbFrameBufferBltConfigure,
> +    BltBuffer,
> +    BltOperation,
> +    SourceX,
> +    SourceY,
> +    DestinationX,
> +    DestinationY,
> +    Width,
> +    Height,
> +    Delta);
> +}
> +
> +EFI_GRAPHICS_OUTPUT_PROTOCOL QemuRamfbGraphicsOutput = {
> +  .QueryMode        = QemuRamfbGraphicsOutputQueryMode,
> +  .SetMode          = QemuRamfbGraphicsOutputSetMode,
> +  .Blt              = QemuRamfbGraphicsOutputBlt,
> +  .Mode             = &QemuRamfbMode,
> +};
> +
> +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;
> +  RETURN_STATUS             Ret;
> +  FIRMWARE_CONFIG_ITEM      Item;
> +  EFI_PHYSICAL_ADDRESS      FbBase;
> +  UINTN                     Size, FbSize, MaxFbSize, Pages, Index;
> +
> +  DEBUG ((EFI_D_INFO, "InitializeQemuRamfb\n"));
> +
> +  if (!QemuFwCfgIsAvailable()) {
> +    DEBUG ((EFI_D_INFO, "Ramfb: no FwCfg\n"));
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  Ret = QemuFwCfgFindFile("etc/ramfb", &Item, &Size);
> +  if (Ret != RETURN_SUCCESS) {
> +    DEBUG ((EFI_D_INFO, "Ramfb: no etc/ramfb in FwCfg\n"));
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  MaxFbSize = 0;
> +  for (Index = 0; Index < QemuRamfbModeCount; Index++) {
> +    QemuRamfbModeInfo[Index].PixelsPerScanLine =
> +      QemuRamfbModeInfo[Index].HorizontalResolution;
> +    QemuRamfbModeInfo[Index].PixelFormat =
> +      PixelBlueGreenRedReserved8BitPerColor,
> +    FbSize = RAMFB_BPP *
> +      QemuRamfbModeInfo[Index].HorizontalResolution *
> +      QemuRamfbModeInfo[Index].VerticalResolution;
> +    if (MaxFbSize < FbSize)
> +      MaxFbSize = FbSize;
> +    DEBUG ((EFI_D_INFO, "Ramfb: Mode %d: %dx%d, %d kB\n", Index,
> +            QemuRamfbModeInfo[Index].HorizontalResolution,
> +            QemuRamfbModeInfo[Index].VerticalResolution,
> +            FbSize / 1024));
> +  }
> +
> +  Pages = EFI_SIZE_TO_PAGES(MaxFbSize);
> +  MaxFbSize = EFI_PAGES_TO_SIZE(Pages);
> +  FbBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateRuntimePages(Pages);

EfiRuntimeServicesMemory is special in the sense that it gets added to
the page tables that are installed while UEFI runtime services are
being invoked by the OS. Given that the runtime firmware does not care
about this frame buffer, this is unnecessary, and so I'd rather avoid
it. The proper fix /could/ be to use EfiRuntimeServicesMemory with the
EFI_MEMORY_RUNTIME attribute cleared, but sadly, edk2 does not
implement that at all. So instead, I recommend using
EfiReservedMemoryType here.

(The spec may argue that you should never use it, but it also
recommends that, e.g., SMBIOS tables are put in
EfiRuntimeServicesMemory with the EFI_MEMORY_RUNTIME attribute
cleared, so it is obviously not in sync with reality)

Thanks,
Ard.


> +  if (!FbBase) {
> +    DEBUG ((EFI_D_INFO, "Ramfb: memory allocation failed\n"));
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +  DEBUG ((EFI_D_INFO, "Ramfb: Framebuffer at 0x%lx, %d kB, %d pages\n",
> +          FbBase, MaxFbSize / 1024, Pages));
> +  QemuRamfbMode.FrameBufferSize = MaxFbSize;
> +  QemuRamfbMode.FrameBufferBase = FbBase;
> +
> +  /* 800 x 600 */
> +  QemuRamfbGraphicsOutputSetMode (&QemuRamfbGraphicsOutput, 1);
> +
> +  /* ramfb vendor devpath */
> +  ZeroMem (&VendorDeviceNode, sizeof (VENDOR_DEVICE_PATH));
> +  VendorDeviceNode.Header.Type = HARDWARE_DEVICE_PATH;
> +  VendorDeviceNode.Header.SubType = HW_VENDOR_DP;
> +  VendorDeviceNode.Guid = gQemuRamfbGuid;
> +  SetDevicePathNodeLength (&VendorDeviceNode.Header, sizeof 
> (VENDOR_DEVICE_PATH));
> +
> +  RamfbDevicePath = AppendDevicePathNode (
> +    NULL,
> +    (EFI_DEVICE_PATH_PROTOCOL *) &VendorDeviceNode);
> +
> +  Status = gBS->InstallMultipleProtocolInterfaces (
> +    &RamfbHandle,
> +    &gEfiDevicePathProtocolGuid, RamfbDevicePath,
> +    NULL);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((EFI_D_INFO, "Ramfb: install Ramfb Vendor DevicePath failed\n"));
> +    FreePool((VOID*)(UINTN)QemuRamfbMode.FrameBufferBase);
> +    return Status;
> +  }
> +
> +  /* gop devpath + protocol */
> +  ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));
> +  AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;
> +  AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;
> +  AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0,
> +                                         
> ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL,
> +                                         0, 0);
> +  SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof 
> (ACPI_ADR_DEVICE_PATH));
> +
> +  GopDevicePath = AppendDevicePathNode (
> +    RamfbDevicePath,
> +    (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode);
> +
> +  Status = gBS->InstallMultipleProtocolInterfaces (
> +    &GopHandle,
> +    &gEfiDevicePathProtocolGuid, GopDevicePath,
> +    &gEfiGraphicsOutputProtocolGuid, &QemuRamfbGraphicsOutput,
> +    NULL);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((EFI_D_INFO, "Ramfb: install GOP DevicePath failed\n"));
> +    FreePool((VOID*)(UINTN)QemuRamfbMode.FrameBufferBase);
> +    return Status;
> +  }
> +
> +  gBS->OpenProtocol (
> +    RamfbHandle,
> +    &gEfiDevicePathProtocolGuid,
> +    &DevicePath,
> +    gImageHandle,
> +    GopHandle,
> +    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
> index a2c995b910..7ddda89999 100644
> --- a/OvmfPkg/OvmfPkgIa32.dsc
> +++ b/OvmfPkg/OvmfPkgIa32.dsc
> @@ -745,6 +745,7 @@
>    MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf
>
>    OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
> +  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
>    OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
>
>    #
> diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf
> index b199713925..52b8b1fea1 100644
> --- a/OvmfPkg/OvmfPkgIa32.fdf
> +++ b/OvmfPkg/OvmfPkgIa32.fdf
> @@ -351,6 +351,7 @@ INF  RuleOverride=CSM OvmfPkg/Csm/Csm16/Csm16.inf
>  !endif
>
>  INF  OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
> +INF  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
>  INF  OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
>  INF  OvmfPkg/PlatformDxe/Platform.inf
>  INF  OvmfPkg/IoMmuDxe/IoMmuDxe.inf
> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
> index bc7db229d2..3481cdc36b 100644
> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
> @@ -754,6 +754,7 @@
>    MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf
>
>    OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
> +  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
>    OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
>
>    #
> diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf
> index 4ebf64b2b9..70845d6972 100644
> --- a/OvmfPkg/OvmfPkgIa32X64.fdf
> +++ b/OvmfPkg/OvmfPkgIa32X64.fdf
> @@ -357,6 +357,7 @@ INF  RuleOverride=CSM OvmfPkg/Csm/Csm16/Csm16.inf
>  !endif
>
>  INF  OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
> +INF  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
>  INF  OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
>  INF  OvmfPkg/PlatformDxe/Platform.inf
>  INF  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
> index 0767b34d18..8b0895b0ff 100644
> --- a/OvmfPkg/OvmfPkgX64.dsc
> +++ b/OvmfPkg/OvmfPkgX64.dsc
> @@ -752,6 +752,7 @@
>    MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf
>
>    OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
> +  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
>    OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
>
>    #
> diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
> index 9ca96f9282..1eb46ac9a2 100644
> --- a/OvmfPkg/OvmfPkgX64.fdf
> +++ b/OvmfPkg/OvmfPkgX64.fdf
> @@ -357,6 +357,7 @@ INF  RuleOverride=CSM OvmfPkg/Csm/Csm16/Csm16.inf
>  !endif
>
>  INF  OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
> +INF  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
>  INF  OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
>  INF  OvmfPkg/PlatformDxe/Platform.inf
>  INF  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
> diff --git a/OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf 
> b/OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
> new file mode 100644
> index 0000000000..75a7d86832
> --- /dev/null
> +++ b/OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
> @@ -0,0 +1,34 @@
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = QemuRamfbDxe
> +  FILE_GUID                      = dce1b094-7dc6-45d0-9fdd-d7fc3cc3e4ef
> +  MODULE_TYPE                    = DXE_DRIVER
> +  VERSION_STRING                 = 1.0
> +
> +  ENTRY_POINT                    = InitializeQemuRamfb
> +
> +[Sources.common]
> +  QemuRamfb.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  OvmfPkg/OvmfPkg.dec
> +
> +[LibraryClasses]
> +  BaseMemoryLib
> +  DebugLib
> +  DevicePathLib
> +  FrameBufferBltLib
> +  MemoryAllocationLib
> +  UefiBootManagerLib
> +  UefiBootServicesTableLib
> +  UefiDriverEntryPoint
> +  UefiLib
> +  QemuFwCfgLib
> +
> +[Protocols]
> +  gEfiGraphicsOutputProtocolGuid                # PROTOCOL BY_START
> +
> +[Depex]
> +  TRUE
> --
> 2.9.3
>
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to