From f8d5dcd99b62ed1d5eca6950de329fd95b53f8b3 Mon Sep 17 00:00:00 2001 From: Matt DeVillier Date: Sun, 19 Apr 2020 18:51:03 -0500 Subject: [PATCH] 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 --- MdeModulePkg/Include/Library/BootLogoLib.h | 10 + MdeModulePkg/Library/BootLogoLib/Bgrt.c | 283 ++++++++++++++++++ .../Library/BootLogoLib/BootLogoLib.inf | 8 + MdeModulePkg/MdeModulePkg.dec | 5 + .../PlatformBootManager.c | 3 + UefiPayloadPkg/UefiPayloadPkg.fdf | 4 + 6 files changed, 313 insertions(+) create mode 100644 MdeModulePkg/Library/BootLogoLib/Bgrt.c diff --git a/MdeModulePkg/Include/Library/BootLogoLib.h b/MdeModulePkg/Include/Library/BootLogoLib.h index 2d6209a278..8fe909ffdf 100644 --- a/MdeModulePkg/Include/Library/BootLogoLib.h +++ b/MdeModulePkg/Include/Library/BootLogoLib.h @@ -60,4 +60,14 @@ BootLogoUpdateProgress ( IN UINTN PreviousValue ); +/** + + Install Boot Logo into BGRT table + +**/ +VOID +AddBGRT ( + VOID + ); + #endif diff --git a/MdeModulePkg/Library/BootLogoLib/Bgrt.c b/MdeModulePkg/Library/BootLogoLib/Bgrt.c new file mode 100644 index 0000000000..5b97ce098a --- /dev/null +++ b/MdeModulePkg/Library/BootLogoLib/Bgrt.c @@ -0,0 +1,283 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** 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")); + } +} diff --git a/MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf b/MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf index 7d50f2dfa3..aa4bd7f52f 100644 --- a/MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf +++ b/MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf @@ -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 diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 2bcb9f9453..179721494b 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -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 diff --git a/UefiPayloadPkg/Library/PlatformBootManagerLib/PlatformBootManager.c b/UefiPayloadPkg/Library/PlatformBootManagerLib/PlatformBootManager.c index f590df313e..c835c815aa 100644 --- a/UefiPayloadPkg/Library/PlatformBootManagerLib/PlatformBootManager.c +++ b/UefiPayloadPkg/Library/PlatformBootManagerLib/PlatformBootManager.c @@ -272,6 +272,9 @@ PlatformBootManagerAfterConsole ( 0, 0 ); + + // Inject boot logo into BGRT table + AddBGRT(); } /** diff --git a/UefiPayloadPkg/UefiPayloadPkg.fdf b/UefiPayloadPkg/UefiPayloadPkg.fdf index 2beef7ba10..80f6a2e3ab 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.fdf +++ b/UefiPayloadPkg/UefiPayloadPkg.fdf @@ -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 #