MdeModulePkg: load boot logo into BGRT table

This is a shoehorned-in implementation of an ACPI BGRT
table, ported pretty much directly from the version used
under CorebootPayloadPkg.

EDK2 provides a facility to do this already, but it assumes
the ACPI tables already exist as EFI structures, so would need
to write code to populate those using the tables already in RAM
created by coreboot. This seemed like the easier option ATM.

Signed-off-by: Matt DeVillier <matt.devillier@gmail.com>
This commit is contained in:
Matt DeVillier
2020-04-19 18:51:03 -05:00
committed by Tim Crawford
parent 2046be8d5e
commit f8d5dcd99b
6 changed files with 313 additions and 0 deletions

View File

@@ -60,4 +60,14 @@ BootLogoUpdateProgress (
IN UINTN PreviousValue
);
/**
Install Boot Logo into BGRT table
**/
VOID
AddBGRT (
VOID
);
#endif

View File

@@ -0,0 +1,283 @@
#include <IndustryStandard/Acpi.h>
#include <IndustryStandard/Bmp.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/BootLogoLib.h>
#include <Library/DebugLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/FirmwareVolume2.h>
#include <Protocol/SimpleFileSystem.h>
/** RSDP (Root System Description Pointer) */
typedef struct {
CHAR8 signature[8];
UINT8 checksum;
CHAR8 oem_id[6];
UINT8 revision;
UINT32 rsdt_address;
UINT32 length;
UINT64 xsdt_address;
UINT8 extended_checksum;
UINT8 reserved[3];
} ACPI_20_RSDP;
/** SDT (System Description Table) entry header */
typedef struct {
CHAR8 signature[4];
UINT32 length;
UINT8 revision;
UINT8 checksum;
CHAR8 oem_id[6];
CHAR8 oem_table_id[8];
UINT32 oem_revision;
UINT32 asl_compiler_id;
UINT32 asl_compiler_revision;
} ACPI_SDT_HEADER;
/** BGRT structure */
typedef struct {
ACPI_SDT_HEADER header;
UINT16 version;
UINT8 status;
UINT8 image_type;
UINT64 image_address;
UINT32 image_offset_x;
UINT32 image_offset_y;
} ACPI_BGRT;
EFI_STATUS
EFIAPI
LoadBmp(
OUT EFI_PHYSICAL_ADDRESS *BmpAddress,
OUT UINT32 *BmpSize
)
{
EFI_STATUS Status;
UINTN FvProtocolCount;
EFI_HANDLE *FvHandles;
EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
UINTN Index;
UINT32 AuthenticationStatus;
UINT8 *Buffer;
UINTN BmpBufferSize;
Buffer = 0;
FvHandles = NULL;
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiFirmwareVolume2ProtocolGuid,
NULL,
&FvProtocolCount,
&FvHandles
);
if (!EFI_ERROR (Status)) {
for (Index = 0; Index < FvProtocolCount; Index++) {
Status = gBS->HandleProtocol (
FvHandles[Index],
&gEfiFirmwareVolume2ProtocolGuid,
(VOID **) &Fv
);
BmpBufferSize = 0;
Status = Fv->ReadSection (
Fv,
(EFI_GUID *)PcdGetPtr(PcdLogoFile),
EFI_SECTION_RAW,
0,
(void **)&Buffer,
&BmpBufferSize,
&AuthenticationStatus
);
if (!EFI_ERROR (Status)) {
*BmpAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
*BmpSize = (UINT32)BmpBufferSize;
Status = EFI_SUCCESS;
break;
}
}
} else {
Status = EFI_NOT_FOUND;
}
if (FvHandles != NULL) {
gBS->FreePool (FvHandles);
FvHandles = NULL;
}
return Status;
}
UINT8 SumBytes(const UINT8* arr, UINTN size) {
UINT8 sum = 0;
UINTN i;
for (i = 0; i < size; ++i) {
sum += arr[i];
}
return sum;
}
int VerifyAcpiRsdp2Checksums(const void* data) {
const UINT8* arr = data;
UINTN size = *(const UINT32*)&arr[20];
return SumBytes(arr, 20) == 0 && SumBytes(arr, size) == 0;
}
void SetAcpiRsdp2Checksums(void* data) {
UINT8* arr = data;
UINTN size = *(const UINT32*)&arr[20];
arr[9] = 0;
arr[32] = 0;
arr[9] = -SumBytes(arr, 20);
arr[32] = -SumBytes(arr, size);
}
int VerifyAcpiSdtChecksum(const void* data) {
const UINT8* arr = data;
UINTN size = *(const UINT32*)&arr[4];
return SumBytes(arr, size) == 0;
}
void SetAcpiSdtChecksum(void* data) {
UINT8* arr = data;
UINTN size = *(const UINT32*)&arr[4];
arr[9] = 0;
arr[9] = -SumBytes(arr, size);
}
const CHAR16* TmpStr(CHAR8 *src, int length) {
static CHAR16 arr[4][16];
static int j;
CHAR16* dest = arr[j = (j+1) % 4];
int i;
for (i = 0; i < length && i < 16-1 && src[i]; ++i) {
dest[i] = src[i];
}
dest[i] = 0;
return dest;
}
static UINT32 min(UINT32 first, UINT32 second){
if (first < second)
return first;
return second;
}
ACPI_SDT_HEADER* CreateXsdt(ACPI_SDT_HEADER* xsdt0, UINTN entries) {
ACPI_SDT_HEADER* xsdt = 0;
UINT32 xsdt_len = (UINT32)(sizeof(ACPI_SDT_HEADER) + entries * sizeof(UINT64));
gBS->AllocatePool(EfiACPIReclaimMemory, xsdt_len, (void**)&xsdt);
if (!xsdt) {
DEBUG ((EFI_D_INFO, "HackBGRT: Failed to allocate memory for XSDT.\n"));
return 0;
}
ZeroMem(xsdt, xsdt_len);
CopyMem(xsdt, xsdt0, min(xsdt0->length, xsdt_len));
xsdt->length = xsdt_len;
SetAcpiSdtChecksum(xsdt);
return xsdt;
}
static ACPI_BGRT* HandleAcpiTables(ACPI_BGRT* bgrt) {
int i;
for (i = 0; i < gST->NumberOfTableEntries; i++) {
EFI_GUID* vendor_guid = &gST->ConfigurationTable[i].VendorGuid;
ACPI_20_RSDP *rsdp;
ACPI_SDT_HEADER *xsdt;
UINT64 *entry_arr;
UINT32 entry_arr_length;
if (!CompareGuid(vendor_guid, &gEfiAcpiTableGuid) && !CompareGuid(vendor_guid, &gEfiAcpi20TableGuid)) {
continue;
}
rsdp = (ACPI_20_RSDP *) gST->ConfigurationTable[i].VendorTable;
if (CompareMem(rsdp->signature, "RSD PTR ", 8) != 0 || rsdp->revision < 2 || !VerifyAcpiRsdp2Checksums(rsdp)) {
continue;
}
DEBUG ((EFI_D_INFO, "RSDP: revision = %d, OEM ID = %s\n", rsdp->revision, TmpStr(rsdp->oem_id, 6)));
xsdt = (ACPI_SDT_HEADER *) (UINTN) rsdp->xsdt_address;
if (!xsdt || CompareMem(xsdt->signature, "XSDT", 4) != 0 || !VerifyAcpiSdtChecksum(xsdt)) {
DEBUG ((EFI_D_INFO, "* XSDT: missing or invalid\n"));
continue;
}
entry_arr = (UINT64*)&xsdt[1];
entry_arr_length = (xsdt->length - sizeof(*xsdt)) / sizeof(UINT64);
DEBUG ((EFI_D_INFO, "* XSDT: OEM ID = %s, entry count = %d\n", TmpStr(xsdt->oem_id, 6), entry_arr_length));
if (bgrt) {
DEBUG ((EFI_D_INFO, " - Adding missing BGRT.\n"));
xsdt = CreateXsdt(xsdt, entry_arr_length + 1);
entry_arr = (UINT64*)&xsdt[1];
entry_arr[entry_arr_length++] = (UINTN) bgrt;
rsdp->xsdt_address = (UINTN) xsdt;
SetAcpiRsdp2Checksums(rsdp);
}
SetAcpiSdtChecksum(xsdt);
}
return bgrt;
}
VOID
AddBGRT (
VOID
)
{
EFI_STATUS Status;
ACPI_BGRT *bgrt;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
EFI_PHYSICAL_ADDRESS BmpAddress;
UINT32 BmpSize;
BMP_IMAGE_HEADER *BmpHeader;
const char data[0x38] =
"BGRT" "\x38\x00\x00\x00" "\x00" "\xd6" "INTEL " " EDK2"
"\x20\x17\x00\x00" "PTL " "\x02\x00\x00\x00"
"\x01\x00" "\x00" "\x00";
BmpAddress = 0;
DEBUG ((EFI_D_INFO, "HackBGRT Start\n"));
Status = gBS->HandleProtocol (
gST->ConsoleOutHandle,
&gEfiGraphicsOutputProtocolGuid,
(VOID**)&GraphicsOutput
);
// Replace missing = allocate new.
gBS->AllocatePool(EfiACPIReclaimMemory, sizeof(*bgrt), (void**)&bgrt);
if (!bgrt) {
DEBUG ((EFI_D_INFO, "HackBGRT MEM ERR\n"));
return;
}
DEBUG ((EFI_D_INFO, "HackBGRT Load Bmp\n"));
Status = LoadBmp(&BmpAddress, &BmpSize);
if (EFI_ERROR(Status)){
DEBUG ((EFI_D_INFO, "HackBGRT BMP Load ERR\n"));
return;
}
DEBUG ((EFI_D_INFO, "HackBGRT Set Table; BMP Size: %d\n", BmpSize));
// Clear the BGRT.
CopyMem(bgrt, data, sizeof(data));
if (GraphicsOutput != NULL && GraphicsOutput->Mode != NULL && GraphicsOutput->Mode->Info != NULL)
{
BmpHeader = (BMP_IMAGE_HEADER *)BmpAddress;
bgrt->image_address = (UINTN)BmpAddress;
bgrt->image_offset_x = (GraphicsOutput->Mode->Info->HorizontalResolution - BmpHeader->PixelWidth) / 2;
bgrt->image_offset_y = ((GraphicsOutput->Mode->Info->VerticalResolution * 382) / 1000) -
(BmpHeader->PixelHeight / 2);
DEBUG ((EFI_D_INFO, "HackBGRT Set checksum\n"));
SetAcpiSdtChecksum(bgrt);
DEBUG ((EFI_D_INFO, "HackBGRT Add Table\n"));
HandleAcpiTables(bgrt);
} else {
DEBUG ((EFI_D_INFO, "HackBGRT no display connected, skip adding table\n"));
}
}

View File

@@ -24,6 +24,7 @@
#
[Sources]
Bgrt.c
BootLogoLib.c
[Packages]
@@ -48,5 +49,12 @@
gEfiUserManagerProtocolGuid ## CONSUMES
gEdkiiPlatformLogoProtocolGuid ## CONSUMES
[Guids]
gEfiAcpiTableGuid ## CONSUMES ## GUID
gEfiAcpi20TableGuid ## CONSUMES ## GUID
[FeaturePcd]
gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport ## CONSUMES
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdLogoFile ## CONSUMES

View File

@@ -2175,3 +2175,8 @@
[UserExtensions.TianoCore."ExtraFiles"]
MdeModulePkgExtra.uni
[PcdsFixedAtBuild, PcdsPatchableInModule]
## FFS filename to find the default BMP Logo file.
# @Prompt FFS Name of Boot Logo File
gEfiMdeModulePkgTokenSpaceGuid.PcdLogoFile |{ 0x99, 0x8b, 0xB2, 0x7B, 0xBB, 0x61, 0xD5, 0x11, 0x9A, 0x5D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }|VOID*|0x40000003

View File

@@ -272,6 +272,9 @@ PlatformBootManagerAfterConsole (
0,
0
);
// Inject boot logo into BGRT table
AddBGRT();
}
/**

View File

@@ -160,6 +160,10 @@ INF UefiPayloadPkg/BlSupportDxe/BlSupportDxe.inf
INF MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf
INF MdeModulePkg/Logo/LogoDxe.inf
FILE FREEFORM = PCD(gEfiMdeModulePkgTokenSpaceGuid.PcdLogoFile) {
SECTION RAW = MdeModulePkg/Logo/Logo.bmp
}
#
# PCI Support
#