OvmfPkg: add QemuRamfbDxe

Add a driver for the qemu ramfb display device.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
[lersek@redhat.com: fix INF banner typo]
[lersek@redhat.com: make some local variable definitions more idiomatic]
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Tested-by: Laszlo Ersek <lersek@redhat.com>
This commit is contained in:
Gerd Hoffmann 2018-06-13 09:29:34 +02:00 committed by Laszlo Ersek
parent 2c123c14cd
commit 1d25ff51af
8 changed files with 459 additions and 0 deletions

View File

@ -745,6 +745,7 @@
MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf
OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
#

View File

@ -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

View File

@ -754,6 +754,7 @@
MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf
OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
#

View File

@ -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

View File

@ -752,6 +752,7 @@
MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf
OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
#

View File

@ -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

View File

@ -0,0 +1,400 @@
/** @file
This driver is a implementation of the Graphics Output Protocol
for the QEMU ramfb device.
Copyright (c) 2018, Red Hat Inc.
This program and the accompanying materials are licensed and made
available under the terms and conditions of the BSD License which
accompanies this distribution. The full text of the license may be
found at http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
EXPRESS OR IMPLIED.
**/
#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;
}

View File

@ -0,0 +1,53 @@
## @file
# This driver is a implementation of the Graphics Output Protocol
# for the QEMU ramfb device.
#
# Copyright (c) 2018, Red Hat Inc.
#
# This program and the accompanying materials are licensed and made
# available under the terms and conditions of the BSD License which
# accompanies this distribution. The full text of the license may be
# found at http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
# BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
# EXPRESS OR IMPLIED.
#
##
[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]
QemuRamfb.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
OvmfPkg/OvmfPkg.dec
[LibraryClasses]
BaseLib
BaseMemoryLib
DebugLib
DevicePathLib
FrameBufferBltLib
MemoryAllocationLib
UefiBootServicesTableLib
UefiDriverEntryPoint
QemuFwCfgLib
[Protocols]
gEfiGraphicsOutputProtocolGuid ## PRODUCES
[Guids]
gQemuRamfbGuid
[Depex]
TRUE