This patch adds the main bootlog infrastructure to dynamically create the bootlog configuration table and edk2 bootlog at DXE phase. It attempts to do all this dynamically: The bootlog configuration table may first get created by a UEFI application.
This code also collects all PEI phase log entries and assembles them into the final bootlog. Signed-off-by: Alexander Graf <g...@amazon.com> --- .../BaseDebugBootlog/BaseDebugBootlogLib.inf | 61 +++ .../BaseDebugBootlog/DebugBootlogDxe.c | 349 ++++++++++++++++++ 2 files changed, 410 insertions(+) create mode 100644 MdePkg/Library/BaseDebugBootlog/BaseDebugBootlogLib.inf create mode 100644 MdePkg/Library/BaseDebugBootlog/DebugBootlogDxe.c diff --git a/MdePkg/Library/BaseDebugBootlog/BaseDebugBootlogLib.inf b/MdePkg/Library/BaseDebugBootlog/BaseDebugBootlogLib.inf new file mode 100644 index 0000000000..49cdd3f9ad --- /dev/null +++ b/MdePkg/Library/BaseDebugBootlog/BaseDebugBootlogLib.inf @@ -0,0 +1,61 @@ +## @file +# Base Debug library instance for a RAM based boot log +# It provides functions to store debug messages in RAM and make them available as +# Bootlog Configuration Table. +# +# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2012, Red Hat, Inc.<BR> +# Copyright (c) 2022, Amazon Development Center Germany GmbH. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BaseDebugBootlog + FILE_GUID = DF934DA3-CD31-49FE-AF50-B3C87C79325C + MODULE_TYPE = DXE_CORE + VERSION_STRING = 1.0 + LIBRARY_CLASS = DebugBootlogLib|DXE_CORE DXE_DRIVER UEFI_DRIVER UEFI_APPLICATION + CONSTRUCTOR = BaseDebugBootlogLibConstructor + +[Sources] + DebugBootlog.c + DebugBootlogDxe.c + +[Sources.IA32, Sources.X64] + DebugBootlogX86.c + +[Sources.ARM, Sources.AARCH64] + DebugBootlogArm.c + +[Sources.EBC, Sources.RISCV64] + DebugBootlogNotime.c + +[Packages] + MdePkg/MdePkg.dec + +[Packages.AARCH64] + ArmPkg/ArmPkg.dec + +[LibraryClasses] + BaseMemoryLib + PcdLib + PrintLib + BaseLib + DebugPrintErrorLevelLib + +[LibraryClasses.AARCH64] + ArmGenericTimerCounterLib + +[LibraryClasses.ARM] + ArmGenericTimerCounterLib + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdDebugBootlogErrorLevel ## CONSUMES + +[Guids] + gBootlogConfigTableGuid ## CONSUMES + gEfiHobListGuid ## CONSUMES diff --git a/MdePkg/Library/BaseDebugBootlog/DebugBootlogDxe.c b/MdePkg/Library/BaseDebugBootlog/DebugBootlogDxe.c new file mode 100644 index 0000000000..b95cb969f1 --- /dev/null +++ b/MdePkg/Library/BaseDebugBootlog/DebugBootlogDxe.c @@ -0,0 +1,349 @@ +/** @file + Base Debug library instance for a RAM based boot log + It provides functions to store debug messages in RAM and make them available as + Bootlog Configuration Table. + + Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2012, Red Hat, Inc.<BR> + Copyright (c) 2022, Amazon Development Center Germany GmbH.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "BaseDebugBootlog.h" + +// +// Cached pointer to the current bootlog structure +// +BOOTLOG_HEADER *gBootlog; + +// +// We can not link against UefiBootServicesTableLib as that itself references +// DebugLib, so instead we save our own copies of the System Table and Boot +// Services structs. +// +static EFI_SYSTEM_TABLE *mDebugST; + +/** + We can not link against UefiBootServicesTableLib as that itself references + DebugLib, so instead we save our own copies of the System Table and Boot + Services structs. + + @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS. + +**/ +EFI_STATUS +EFIAPI +BaseDebugBootlogLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + mDebugST = SystemTable; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +BaseDebugBootlogAppendInternal ( + IN CONST CHAR8 *String, + IN UINTN Length, + IN UINTN ErrorLevel, + IN UINT64 Ticks + ); + +static +EFI_STATUS +EFIAPI +UpdateEdk2Bootlog ( + IN BOOTLOG_CONFIG_TABLE *Table, + IN BOOTLOG_HEADER *OldBootlog, + IN BOOTLOG_HEADER *NewBootlog + ) +{ + UINTN Index; + + for (Index = 0; Index < Table->NrLogs; Index++) { + if (Table->LogAddress[Index] == (EFI_PHYSICAL_ADDRESS) OldBootlog) { + Table->LogAddress[Index] = (EFI_PHYSICAL_ADDRESS) NewBootlog; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +static +EFI_STATUS +EFIAPI +FindEdk2Bootlog ( + IN BOOTLOG_CONFIG_TABLE *Table, + OUT BOOTLOG_HEADER **Bootlog + ) +{ + UINTN Index; + BOOTLOG_HEADER *Cur; + + for (Index = 0; Index < Table->NrLogs; Index++) { + Cur = (BOOTLOG_HEADER *)Table->LogAddress[Index]; + if (Cur->Signature == SIG_BOOTLOG_HEADER && + CompareMem(Cur->Producer, BOOTLOG_PRODUCER, sizeof(Cur->Producer)) == 0 && + Cur->ExtraHeaderType == BOOTLOG_EXTRA_HEADER_EDK2) { + *Bootlog = Cur; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +static +EFI_STATUS +EFIAPI +FindConfigTable ( + IN EFI_GUID *TableGuid, + OUT VOID *Table + ) +{ + EFI_SYSTEM_TABLE *SystemTable; + VOID **_Table = Table; + UINTN Index; + + if (TableGuid == NULL || Table == NULL) { + return EFI_NOT_FOUND; + } + + SystemTable = mDebugST; + *_Table = NULL; + for (Index = 0; Index < SystemTable->NumberOfTableEntries; Index++) { + if (CompareGuid (TableGuid, &(SystemTable->ConfigurationTable[Index].VendorGuid))) { + *_Table = SystemTable->ConfigurationTable[Index].VendorTable; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +static +EFI_STATUS +EFIAPI +AllocateTable ( + IN EFI_BOOT_SERVICES *BS, + IN BOOTLOG_CONFIG_TABLE **pTable + ) +{ + EFI_STATUS Status; + UINTN TableLength = sizeof(BOOTLOG_CONFIG_TABLE) + MAX_LOGS * sizeof(UINT64); + + Status = BS->AllocatePool ( + EfiBootServicesData, + TableLength, + (VOID **)pTable + ); + if (Status != EFI_SUCCESS) + return Status; + + ZeroMem (*pTable, TableLength); + (*pTable)->Signature = SIG_BOOTLOG_CONFIG_TABLE; + (*pTable)->MaxLogs = MAX_LOGS; + + return Status; +} + +static +EFI_STATUS +EFIAPI +AllocateBootlog ( + IN EFI_BOOT_SERVICES *BS, + IN BOOTLOG_HEADER **NewBootlog, + IN UINTN Size + ) +{ + EFI_STATUS Status; + + Status = BS->AllocatePages ( + AllocateAnyPages, + EfiBootServicesData, + EFI_SIZE_TO_PAGES (Size), + (EFI_PHYSICAL_ADDRESS *)NewBootlog + ); + if (Status != EFI_SUCCESS) + return Status; + + ZeroMem (*NewBootlog, Size); + + return Status; +} + +static +VOID +EFIAPI +BaseDebugLibBootlogInitialize ( + IN BOOTLOG_HEADER *Bootlog, + IN UINT64 Size + ) +{ + Bootlog->Signature = SIG_BOOTLOG_HEADER; + CopyMem(Bootlog->Producer, BOOTLOG_PRODUCER, sizeof(Bootlog->Producer)); + Bootlog->ExtraHeaderType = BOOTLOG_EXTRA_HEADER_EDK2; + Bootlog->ExtraHeaderSize = sizeof(Bootlog->ExtraHeader); + Bootlog->MsgExtraHeaderSize = sizeof(BOOTLOG_ENTRY_EDK2) - sizeof(BOOTLOG_ENTRY); + Bootlog->LastByte = OFFSET_OF(BOOTLOG_HEADER, Data); + Bootlog->TicksPerSecond = BaseDebugLibBootlogTicksPerSecond(); + Bootlog->ExtraHeader.AllocatedSize = Size; +} + +static +EFI_STATUS +EFIAPI +BaseDebugLibFindAndExpandBootlog ( + IN BOOTLOG_HEADER **pBootlog, + IN UINTN AppendDataLength + ) +{ + EFI_BOOT_SERVICES *BS; + BOOTLOG_HEADER *Bootlog; + BOOTLOG_HEADER *NewBootlog; + BOOTLOG_CONFIG_TABLE *Table; + EFI_STATUS Status = EFI_SUCCESS; + UINTN NewSize; + EFI_PEI_HOB_POINTERS Hob; + + if (!mDebugST || !mDebugST->BootServices) + return EFI_NOT_FOUND; + + BS = mDebugST->BootServices; + + if (!gBootlog) { + /* Allocate a new Bootlog Configuration Table if not present */ + if (FindConfigTable (&gBootlogConfigTableGuid, &Table) != EFI_SUCCESS) { + Status = AllocateTable (BS, &Table); + if (Status != EFI_SUCCESS) { + return Status; + } + + Status = BS->InstallConfigurationTable ( + &gBootlogConfigTableGuid, + Table + ); + if (Status != EFI_SUCCESS) { + return Status; + } + } + + /* Allocate a Bootlog structure if none is in the table */ + if (FindEdk2Bootlog (Table, &Bootlog) != EFI_SUCCESS) { + /* + * There is a tiny phase right after DXE entry where gEfiHobListGuid is + * not populated yet. But we need the HobList to carry PEI logs over. + * Let's just drop any line that we get in that period. + */ + Status = FindConfigTable (&gEfiHobListGuid, &Hob.Raw); + if (Status != EFI_SUCCESS) { + return Status; + } + + Status = AllocateBootlog (BS, &Bootlog, BOOTLOG_MIN_SIZE); + if (Status != EFI_SUCCESS) { + return Status; + } + BaseDebugLibBootlogInitialize(Bootlog, BOOTLOG_MIN_SIZE); + + if (Table->NrLogs >= Table->MaxLogs) { + return EFI_NOT_FOUND; + } + Table->LogAddress[Table->NrLogs++] = (EFI_PHYSICAL_ADDRESS) Bootlog; + + gBootlog = Bootlog; + + /* + * This is the first time we go from PEI -> DXE. Copy all PEI log entries + * into our full fledged boot log structure + */ + if (Status == EFI_SUCCESS) { + while (!END_OF_HOB_LIST (Hob)) { + if (Hob.Header->HobType == EFI_HOB_TYPE_GUID_EXTENSION && + CompareGuid (&gBootlogConfigTableGuid, &Hob.Guid->Name) && + GET_HOB_LENGTH (Hob) > sizeof (BOOTLOG_ENTRY_EDK2)) { + BOOTLOG_ENTRY_EDK2 *Entry = GET_GUID_HOB_DATA (Hob); + BaseDebugBootlogAppendInternal ( + Entry->Log.String, + AsciiStrLen (Entry->Log.String), + Entry->ErrorLevel, + Entry->Log.Ticks + ); + } + + Hob.Raw = GET_NEXT_HOB (Hob); + } + } + } + + gBootlog = Bootlog; + } else { + Bootlog = gBootlog; + } + + /* Resize if the new string would not fit */ + if ((Bootlog->LastByte + AppendDataLength) > Bootlog->ExtraHeader.AllocatedSize) { + NewSize = ALIGN_VALUE (Bootlog->LastByte + AppendDataLength + EFI_PAGE_SIZE * 16, + EFI_PAGE_SIZE); + Status = AllocateBootlog (BS, &NewBootlog, NewSize); + if (Status != EFI_SUCCESS) { + return Status; + } + + CopyMem (NewBootlog, Bootlog, Bootlog->LastByte); + NewBootlog->ExtraHeader.AllocatedSize = NewSize; + UpdateEdk2Bootlog (Table, Bootlog, NewBootlog); + BS->FreePages ((EFI_PHYSICAL_ADDRESS) Bootlog, + EFI_SIZE_TO_PAGES (Bootlog->ExtraHeader.AllocatedSize)); + Bootlog = gBootlog = NewBootlog; + } + + *pBootlog = Bootlog; + + return Status; +} + +EFI_STATUS +EFIAPI +BaseDebugBootlogAppendInternal ( + IN CONST CHAR8 *String, + IN UINTN Length, + IN UINTN ErrorLevel, + IN UINT64 Ticks + ) +{ + BOOTLOG_HEADER *Bootlog; + BOOTLOG_ENTRY_EDK2 Hdr; + + if (BaseDebugLibFindAndExpandBootlog (&Bootlog, Length + sizeof(Hdr)) != EFI_SUCCESS) + return EFI_SUCCESS; + + Hdr.ErrorLevel = ErrorLevel; + Hdr.Log.Ticks = Ticks; + + CopyMem (((VOID *)Bootlog) + Bootlog->LastByte, &Hdr, sizeof(Hdr)); + Bootlog->LastByte += sizeof(Hdr); + CopyMem (((VOID *)Bootlog) + Bootlog->LastByte, String, Length); + Bootlog->LastByte += Length; + *((CHAR8 *)Bootlog + Bootlog->LastByte) = '\0'; + Bootlog->LastByte += 1; + + return EFI_SUCCESS; +} + +RETURN_STATUS +EFIAPI +DebugBootlogAppend ( + IN CONST CHAR8 *String, + IN UINTN Length, + IN UINTN ErrorLevel + ) +{ + return BaseDebugBootlogAppendInternal(String, Length, ErrorLevel, + BaseDebugLibBootlogTicks ()); +} -- 2.28.0.394.ge197136389 Amazon Development Center Germany GmbH Krausenstr. 38 10117 Berlin Geschaeftsfuehrung: Christian Schlaeger, Jonathan Weiss Eingetragen am Amtsgericht Charlottenburg unter HRB 149173 B Sitz: Berlin Ust-ID: DE 289 237 879 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#90073): https://edk2.groups.io/g/devel/message/90073 Mute This Topic: https://groups.io/mt/91368913/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-