From ba05ea83b7383ea126fbeac812503a9a027f506a Mon Sep 17 00:00:00 2001 From: Aaron Young Date: Mon, 28 Apr 2025 09:18:31 -0700 Subject: [PATCH] OvmfPkg: Add OVMF Memory Debug Logging MemDebugLogLib library Add the Memory Debug Logging feature MemDebugLogLib library which provides the key MemDebugLogWrite() function. Several versions (i.e. SEC, PEIM, DXE, runtime) of the function are included to provide the proper method to write the debug messages to the memory debug log buffer. The library also provides the core functions to maintain the circular memory debug log buffer. Cc: Gerd Hoffmann Cc: Ard Biesheuvel Cc: Jiewen Yao Signed-off-by: Aaron Young --- OvmfPkg/Include/Library/MemDebugLogLib.h | 214 +++++++++++++ .../MemDebugLogLib/MemDebugLogCommon.c | 297 ++++++++++++++++++ .../Library/MemDebugLogLib/MemDebugLogDxe.c | 44 +++ .../MemDebugLogLib/MemDebugLogDxeLib.inf | 37 +++ .../MemDebugLogLib/MemDebugLogLibNull.inf | 31 ++ .../Library/MemDebugLogLib/MemDebugLogNull.c | 40 +++ .../Library/MemDebugLogLib/MemDebugLogPei.c | 89 ++++++ .../MemDebugLogLib/MemDebugLogPeiCore.c | 58 ++++ .../MemDebugLogLib/MemDebugLogPeiCoreLib.inf | 40 +++ .../MemDebugLogLib/MemDebugLogPeiLib.inf | 49 +++ .../Library/MemDebugLogLib/MemDebugLogRt.c | 54 ++++ .../MemDebugLogLib/MemDebugLogRtLib.inf | 38 +++ .../Library/MemDebugLogLib/MemDebugLogSec.c | 48 +++ .../MemDebugLogLib/MemDebugLogSecLib.inf | 39 +++ 14 files changed, 1078 insertions(+) create mode 100644 OvmfPkg/Include/Library/MemDebugLogLib.h create mode 100644 OvmfPkg/Library/MemDebugLogLib/MemDebugLogCommon.c create mode 100644 OvmfPkg/Library/MemDebugLogLib/MemDebugLogDxe.c create mode 100644 OvmfPkg/Library/MemDebugLogLib/MemDebugLogDxeLib.inf create mode 100644 OvmfPkg/Library/MemDebugLogLib/MemDebugLogLibNull.inf create mode 100644 OvmfPkg/Library/MemDebugLogLib/MemDebugLogNull.c create mode 100644 OvmfPkg/Library/MemDebugLogLib/MemDebugLogPei.c create mode 100644 OvmfPkg/Library/MemDebugLogLib/MemDebugLogPeiCore.c create mode 100644 OvmfPkg/Library/MemDebugLogLib/MemDebugLogPeiCoreLib.inf create mode 100644 OvmfPkg/Library/MemDebugLogLib/MemDebugLogPeiLib.inf create mode 100644 OvmfPkg/Library/MemDebugLogLib/MemDebugLogRt.c create mode 100644 OvmfPkg/Library/MemDebugLogLib/MemDebugLogRtLib.inf create mode 100644 OvmfPkg/Library/MemDebugLogLib/MemDebugLogSec.c create mode 100644 OvmfPkg/Library/MemDebugLogLib/MemDebugLogSecLib.inf diff --git a/OvmfPkg/Include/Library/MemDebugLogLib.h b/OvmfPkg/Include/Library/MemDebugLogLib.h new file mode 100644 index 0000000000..6dde585574 --- /dev/null +++ b/OvmfPkg/Include/Library/MemDebugLogLib.h @@ -0,0 +1,214 @@ +/** @file + Interface functions for the Memory Debug Log Library. + + Copyright (C) 2025, Oracle and/or its affiliates. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _MEM_DEBUG_LOG_LIB_H_ +#define _MEM_DEBUG_LOG_LIB_H_ + +#include +#include + +// +// Cap max buffer at 2MB (0x200 4K pages) +// +#define MAX_MEM_DEBUG_LOG_PAGES 0x200 + +#define MEM_DEBUG_LOG_MAGIC1 0x3167646d666d766f // "ovmfmdg1" +#define MEM_DEBUG_LOG_MAGIC2 0x3267646d666d766f // "ovmfmdg2" + +#pragma pack(1) +// +// Mem Debug Log buffer header. +// The Log buffer is circular. Only the most +// recent messages are retained. Older messages +// will be discarded if the buffer overflows. +// The Debug Log starts just after the header. +// +typedef struct { + // + // Magic values + // These fields are used by tools to locate the buffer in + // memory. These MUST be the first two fields of the structure. + // Use a 128 bit Magic to vastly reduce the possibility of + // a collision with random data in memory. + UINT64 Magic1; + UINT64 Magic2; + // + // Header Size + // This MUST be the third field of the structure + // + UINT64 HeaderSize; + // + // Debug log size (minus header) + // + UINT64 DebugLogSize; + // + // Protect the log from potential MP access (by APs during + // vCPU init) to maintain integrity of the Head/Tail Offsets. + // NOTE: MemDebugLogLock is used as a SPIN_LOCK (which is type + // UINTN). Thus, we declared it as a UINT64 to ensure a + // consistent structure size. + // + volatile UINT64 MemDebugLogLock; + // + // Debug log head offset + // + UINT64 DebugLogHeadOffset; + // + // Debug log tail offset + // + UINT64 DebugLogTailOffset; + // + // Flag to indicate if the buffer wrapped and was thus truncated. + // + UINT64 Truncated; + // + // Firmware Build Version (PcdFirmwareVersionString) + // + CHAR8 FirmwareVersion[128]; +} MEM_DEBUG_LOG_HDR; + +// +// HOB used to pass the mem debug log buffer addr from PEI to DXE +// +typedef struct { + EFI_PHYSICAL_ADDRESS MemDebugLogBufAddr; +} MEM_DEBUG_LOG_HOB_DATA; + +#pragma pack() + +/** + Write a CHAR8 string to the memory debug log. + This is the interface function used by DebugLib. + There are several versions for each boot + phase (i.e. SEC, PEI, DXE, Runtime). + Each version will obtain the proper memory debug log + buffer address and call MemDebugLogWriteBuffer(). + + @param[in] Buffer The buffer containing the string of CHAR8s + + @param[in] Length The buffer length (number of CHAR8s) + not including the NULL terminator byte. + + @retval RETURN_SUCCESS String succcessfully written to the memory log buffer. + + @retval RETURN_NOT_FOUND Memory log buffer is not properly initialized. + + @retval EFI_INVALID_PARAMETER Invalid input parameters. +**/ +EFI_STATUS +EFIAPI +MemDebugLogWrite ( + IN CHAR8 *Buffer, + IN UINTN Length + ); + +/** + Return the memory debug log buffer size (in pages). + This function is implemented by PEIM version of + MemDebugLogLib only. + + @retval UINT32 Buffer size in pages +**/ +UINT32 +EFIAPI +MemDebugLogPages ( + VOID + ); + +/** + Write a CHAR8 string to a memory debug log circular + buffer located at the given address. + + @param MemDebugLogBufAddr Address of the memory debug log buffer. + + @param Buffer Pointer to a CHAR8 string to write to the + debug log buffer. + + @param Length Length of the CHAR8 string to write to the + debug log buffer. Not including NULL terminator + byte. + + @retval RETURN_SUCCESS String succcessfully written to the memory log buffer. + + @retval RETURN_NOT_FOUND Memory log buffer is not properly initialized. + + @retval EFI_INVALID_PARAMETER Invalid input parameters. +**/ +EFI_STATUS +EFIAPI +MemDebugLogWriteBuffer ( + IN EFI_PHYSICAL_ADDRESS MemDebugLogBufAddr, + IN CHAR8 *Buffer, + IN UINTN Length + ); + +/** + Initialize the memory debug log buffer header + + @param MemDebugLogBufAddr Address of the memory debug log buffer. + + @param MemDebugLogBufSize Size of the memory debug log buffer. + + @retval RETURN_SUCCESS Log buffer successfully initialized. + + @retval EFI_INVALID_PARAMETER Invalid input parameters. +**/ +EFI_STATUS +EFIAPI +MemDebugLogInit ( + IN EFI_PHYSICAL_ADDRESS MemDebugLogBufAddr, + UINT32 MemDebugLogBufSize + ); + +/** + Copy the memory debug log buffer + + @param MemDebugLogBufDestAddr Address of destination memory debug log buffer. + + @param MemDebugLogBufSrcAddr Address of source memory debug log buffer. + + @retval RETURN_SUCCESS Log buffer successfuly copied. + + @retval EFI_INVALID_PARAMETER Invalid input parameters. +**/ +EFI_STATUS +EFIAPI +MemDebugLogCopy ( + IN EFI_PHYSICAL_ADDRESS MemDebugLogBufDestAddr, + IN EFI_PHYSICAL_ADDRESS MemDebugLogBufSrcAddr + ); + +/** + Obtain the Memory Debug Log Buffer Addr from the HOB + + @param MemDebugLogBufAddr Address of memory debug log buffer. + + @retval RETURN_SUCCESS Log buffer address successfuly obtained. + + @retval EFI_NOT_FOUND HOB not found. +**/ +EFI_STATUS +EFIAPI +MemDebugLogAddrFromHOB ( + EFI_PHYSICAL_ADDRESS *MemDebugLogBufAddr + ); + +/** + Return whether the Memory Debug Logging feature is enabled + + @retval TRUE Feature is enabled + + @retval FALSE Feature is not enabled +**/ +BOOLEAN +EFIAPI +MemDebugLogEnabled ( + VOID + ); + +#endif // _MEM_DEBUG_LOG_LIB_H_ diff --git a/OvmfPkg/Library/MemDebugLogLib/MemDebugLogCommon.c b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogCommon.c new file mode 100644 index 0000000000..8c9ce61cb6 --- /dev/null +++ b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogCommon.c @@ -0,0 +1,297 @@ +/** @file + Memory Debug Log common defs/funcs to access the memory buffer. + + Copyright (C) 2025, Oracle and/or its affiliates. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MEMDEBUGLOG_COPYSIZE 0x200 + +STATIC +VOID +MemDebugLogLockInit ( + IN volatile UINT64 *MemDebugLogLock + ) +{ + InitializeSpinLock ((SPIN_LOCK *)MemDebugLogLock); +} + +STATIC +VOID +MemDebugLogLockAcquire ( + IN volatile UINT64 *MemDebugLogLock + ) +{ + AcquireSpinLock ((SPIN_LOCK *)MemDebugLogLock); +} + +STATIC +VOID +MemDebugLogLockRelease ( + IN volatile UINT64 *MemDebugLogLock + ) +{ + ReleaseSpinLock ((SPIN_LOCK *)MemDebugLogLock); +} + +EFI_STATUS +EFIAPI +MemDebugLogWriteBuffer ( + IN EFI_PHYSICAL_ADDRESS MemDebugLogBufAddr, + IN CHAR8 *Buffer, + IN UINTN Length + ) +{ + volatile UINT64 *MemDebugLogLock; + MEM_DEBUG_LOG_HDR *MemDebugLogHdr; + UINTN BufSpaceLeft; + CHAR8 *BufStart; + CHAR8 *BufHead; + CHAR8 *BufTail; + CHAR8 *BufEnd; + + // + // NOTE: we cannot call DEBUG or ASSERT from this function. + // + + if (!MemDebugLogBufAddr || !Buffer) { + return EFI_INVALID_PARAMETER; + } + + if (Length == 0) { + return EFI_SUCCESS; + } + + MemDebugLogHdr = (MEM_DEBUG_LOG_HDR *)(UINTN)MemDebugLogBufAddr; + MemDebugLogLock = &(MemDebugLogHdr->MemDebugLogLock); + + // + // Validate the header magic before proceeding + // + if ((MemDebugLogHdr->Magic1 != MEM_DEBUG_LOG_MAGIC1) || + (MemDebugLogHdr->Magic2 != MEM_DEBUG_LOG_MAGIC2)) + { + return EFI_NOT_FOUND; + } + + if (Length >= MemDebugLogHdr->DebugLogSize) { + return EFI_INVALID_PARAMETER; + } + + MemDebugLogLockAcquire (MemDebugLogLock); + + BufStart = (CHAR8 *)(UINTN)(MemDebugLogBufAddr + MemDebugLogHdr->HeaderSize); + BufEnd = (CHAR8 *)(UINTN)(MemDebugLogBufAddr + MemDebugLogHdr->HeaderSize + MemDebugLogHdr->DebugLogSize) - 1; + BufHead = BufStart + MemDebugLogHdr->DebugLogHeadOffset; + BufTail = BufStart + MemDebugLogHdr->DebugLogTailOffset; + + // + // Maintain a circular (wrap around) log buffer + // NOTES: + // tail always points to next available slot to populate + // Algorithm to process/display strings from buffer in time order: + // 1. head==tail indicates empty buffer + // 2. if (head < tail), process from head (tail-head) bytes + // 3. if (head > tail), process from head (bufend-head) bytes + // process from bufstart (tail-bufstart) bytes + // + + if ((BufTail + Length) <= BufEnd) { + // + // There's enough room from tail to end of the buffer + // + CopyMem (BufTail, Buffer, Length); + // + // If we have previously wrapped around, need to keep Head updated + // + if (BufHead == (BufTail + 1)) { + BufHead += Length; + // + // Check if we need to wrap Head + // + if (BufHead > BufEnd) { + BufHead = BufStart; + } + } + + BufTail += Length; + } else { + // + // We need to wrap around. + // + // Fill remaining buffer space with initial part of the string + // + BufSpaceLeft = (UINTN)(BufEnd - BufTail + 1); + CopyMem (BufTail, Buffer, BufSpaceLeft); + + // + // Wrap to start of the buffer for the rest of the string + // + BufTail = BufStart; + CopyMem (BufTail, (Buffer + BufSpaceLeft), (Length - BufSpaceLeft)); + BufTail += (Length - BufSpaceLeft); + BufHead = (BufTail + 1); + + MemDebugLogHdr->Truncated = 1; + } + + // + // Write the new buffer offsets back to the header + // + MemDebugLogHdr->DebugLogHeadOffset = BufHead - BufStart; + MemDebugLogHdr->DebugLogTailOffset = BufTail - BufStart; + + MemDebugLogLockRelease (MemDebugLogLock); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +MemDebugLogInit ( + IN EFI_PHYSICAL_ADDRESS MemDebugLogBufAddr, + UINT32 MemDebugLogBufSize + ) +{ + MEM_DEBUG_LOG_HDR *MemDebugLogHdr; + + if (MemDebugLogBufAddr == 0) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem ((VOID *)(UINTN)MemDebugLogBufAddr, MemDebugLogBufSize); + + MemDebugLogHdr = (MEM_DEBUG_LOG_HDR *)(UINTN)MemDebugLogBufAddr; + MemDebugLogHdr->Magic1 = MEM_DEBUG_LOG_MAGIC1; + MemDebugLogHdr->Magic2 = MEM_DEBUG_LOG_MAGIC2; + MemDebugLogHdr->HeaderSize = sizeof (MEM_DEBUG_LOG_HDR); + MemDebugLogHdr->DebugLogSize = (MemDebugLogBufSize - MemDebugLogHdr->HeaderSize); + MemDebugLogHdr->DebugLogHeadOffset = 0; + MemDebugLogHdr->DebugLogTailOffset = 0; + MemDebugLogLockInit (&(MemDebugLogHdr->MemDebugLogLock)); + MemDebugLogHdr->Truncated = 0; + AsciiSPrint (MemDebugLogHdr->FirmwareVersion, 128, "%s", (CHAR16 *)PcdGetPtr (PcdFirmwareVersionString)); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +MemDebugLogCopy ( + IN EFI_PHYSICAL_ADDRESS MemDebugLogBufDestAddr, + IN EFI_PHYSICAL_ADDRESS MemDebugLogBufSrcAddr + ) +{ + MEM_DEBUG_LOG_HDR *MemDebugLogSrcHdr; + MEM_DEBUG_LOG_HDR *MemDebugLogDestHdr; + CHAR8 *BufStart; + CHAR8 *BufHead; + CHAR8 *BufTail; + CHAR8 *BufEnd; + CHAR8 *BufPtr; + + if ((MemDebugLogBufSrcAddr == 0) || (MemDebugLogBufDestAddr == 0)) { + return EFI_INVALID_PARAMETER; + } + + MemDebugLogSrcHdr = (MEM_DEBUG_LOG_HDR *)(UINTN)MemDebugLogBufSrcAddr; + MemDebugLogDestHdr = (MEM_DEBUG_LOG_HDR *)(UINTN)MemDebugLogBufDestAddr; + + BufStart = (CHAR8 *)(UINTN)(MemDebugLogBufSrcAddr + MemDebugLogSrcHdr->HeaderSize); + BufEnd = (CHAR8 *)(UINTN)(MemDebugLogBufSrcAddr + MemDebugLogSrcHdr->HeaderSize + MemDebugLogSrcHdr->DebugLogSize); + BufHead = BufStart + MemDebugLogSrcHdr->DebugLogHeadOffset; + BufTail = BufStart + MemDebugLogSrcHdr->DebugLogTailOffset; + + MemDebugLogDestHdr->Truncated = MemDebugLogSrcHdr->Truncated; + + if (BufHead == BufTail) { + // + // Source Debug Log empty + // + return EFI_SUCCESS; + } else if (BufHead < BufTail) { + // + // Source buffer didn't wrap, so copy debug messages + // from Source buffer (head to tail) to the Dest buffer + // NOTE: we limit each copy to MEMDEBUGLOG_COPYSIZE + // to ensure to not copy too much at a time and ensure + // the dest buffer head/tail pointers are created properly. + // + for (BufPtr = BufHead; (BufTail - BufPtr) > MEMDEBUGLOG_COPYSIZE; BufPtr += MEMDEBUGLOG_COPYSIZE) { + MemDebugLogWriteBuffer (MemDebugLogBufDestAddr, BufPtr, MEMDEBUGLOG_COPYSIZE); + } + + // + // write remaining bytes + // + MemDebugLogWriteBuffer (MemDebugLogBufDestAddr, BufPtr, (BufTail - BufPtr)); + } else { + // + // Source buffer wrapped. + // First copy (bufend - head) chars from head to Dest buffer + // + for (BufPtr = BufHead; (BufEnd - BufPtr) > MEMDEBUGLOG_COPYSIZE; BufPtr += MEMDEBUGLOG_COPYSIZE) { + MemDebugLogWriteBuffer (MemDebugLogBufDestAddr, BufPtr, MEMDEBUGLOG_COPYSIZE); + } + + // + // write remaining bytes + // + MemDebugLogWriteBuffer (MemDebugLogBufDestAddr, BufPtr, (BufEnd - BufPtr)); + + // + // Next, copy (bufend - head) chars from start to Dest buffer + // + for (BufPtr = BufStart; (BufTail - BufPtr) > MEMDEBUGLOG_COPYSIZE; BufPtr += MEMDEBUGLOG_COPYSIZE) { + MemDebugLogWriteBuffer (MemDebugLogBufDestAddr, BufPtr, MEMDEBUGLOG_COPYSIZE); + } + + // + // write remaining bytes + // + MemDebugLogWriteBuffer (MemDebugLogBufDestAddr, BufPtr, (BufTail - BufPtr)); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +MemDebugLogAddrFromHOB ( + EFI_PHYSICAL_ADDRESS *MemDebugLogBufAddr + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + MEM_DEBUG_LOG_HOB_DATA *HobData; + + GuidHob = GetFirstGuidHob (&gMemDebugLogHobGuid); + if (GuidHob == NULL) { + return EFI_NOT_FOUND; + } else { + HobData = (MEM_DEBUG_LOG_HOB_DATA *)GET_GUID_HOB_DATA (GuidHob); + *MemDebugLogBufAddr = HobData->MemDebugLogBufAddr; + } + + return EFI_SUCCESS; +} + +BOOLEAN +EFIAPI +MemDebugLogEnabled ( + VOID + ) +{ + return TRUE; +} diff --git a/OvmfPkg/Library/MemDebugLogLib/MemDebugLogDxe.c b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogDxe.c new file mode 100644 index 0000000000..9655257315 --- /dev/null +++ b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogDxe.c @@ -0,0 +1,44 @@ +/** @file + * + Memory Debug Log Library - DXE/Smm + + Copyright (C) 2025, Oracle and/or its affiliates. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include + +EFI_PHYSICAL_ADDRESS mMemDebugLogBufAddr; +BOOLEAN mMemDebugLogBufAddrInit; + +EFI_STATUS +EFIAPI +MemDebugLogWrite ( + IN CHAR8 *Buffer, + IN UINTN Length + ) +{ + EFI_STATUS Status; + + if (!mMemDebugLogBufAddrInit) { + // + // Obtain the Memory Debug Log buffer addr from HOB + // + Status = MemDebugLogAddrFromHOB (&mMemDebugLogBufAddr); + if (EFI_ERROR (Status)) { + mMemDebugLogBufAddr = 0; + } + + mMemDebugLogBufAddrInit = TRUE; + } + + if (mMemDebugLogBufAddr) { + Status = MemDebugLogWriteBuffer (mMemDebugLogBufAddr, Buffer, Length); + } else { + Status = EFI_NOT_FOUND; + } + + return Status; +} diff --git a/OvmfPkg/Library/MemDebugLogLib/MemDebugLogDxeLib.inf b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogDxeLib.inf new file mode 100644 index 0000000000..edb405dac1 --- /dev/null +++ b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogDxeLib.inf @@ -0,0 +1,37 @@ +## @file +# Instance of MemDebugLog Library for DXE/Smm +# +# Copyright (C) 2025, Oracle and/or its affiliates. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MemDebugLogLib + FILE_GUID = 4988621E-8EE8-4D27-862F-EB98BD8F17E6 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = MemDebugLogLib|DXE_CORE DXE_DRIVER UEFI_DRIVER UEFI_APPLICATION SMM_CORE DXE_SMM_DRIVER + + +[Sources] + MemDebugLogDxe.c + MemDebugLogCommon.c + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + OvmfPkg/OvmfPkg.dec + +[LibraryClasses] + HobLib + SynchronizationLib + +[Guids] + gMemDebugLogHobGuid ## CONSUMES + +[FixedPcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString ## CONSUMES diff --git a/OvmfPkg/Library/MemDebugLogLib/MemDebugLogLibNull.inf b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogLibNull.inf new file mode 100644 index 0000000000..33f8dfee9c --- /dev/null +++ b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogLibNull.inf @@ -0,0 +1,31 @@ +## @file +# Null Instance of MemDebugLog Library +# +# Copyright (C) 2025, Oracle and/or its affiliates. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MemDebugLogLibNull + FILE_GUID = 11b4523c-2c30-44f7-9dee-e6d59eef3d04 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = MemDebugLogLib|SEC PEI_CORE PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER SMM_CORE DXE_SMM_DRIVER + + +[Sources] + MemDebugLogNull.c + +[Packages] + MdePkg/MdePkg.dec + OvmfPkg/OvmfPkg.dec + +[LibraryClasses] + +[FixedPcd] + +[Guids] diff --git a/OvmfPkg/Library/MemDebugLogLib/MemDebugLogNull.c b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogNull.c new file mode 100644 index 0000000000..59bb7c87a0 --- /dev/null +++ b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogNull.c @@ -0,0 +1,40 @@ +/** @file + * + Memory Debug Log Library - Null. + + Copyright (C) 2025, Oracle and/or its affiliates. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +EFI_STATUS +EFIAPI +MemDebugLogWrite ( + IN CHAR8 *Buffer, + IN UINTN Length + ) +{ + // Null Instance - NOP + return EFI_SUCCESS; +} + +UINT32 +EFIAPI +MemDebugLogPages ( + VOID + ) +{ + return 0; +} + +BOOLEAN +EFIAPI +MemDebugLogEnabled ( + VOID + ) +{ + return FALSE; +} diff --git a/OvmfPkg/Library/MemDebugLogLib/MemDebugLogPei.c b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogPei.c new file mode 100644 index 0000000000..cbdab6c22f --- /dev/null +++ b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogPei.c @@ -0,0 +1,89 @@ +/** @file + * + Memory Debug Log Library - PEI Phase + + Copyright (C) 2025, Oracle and/or its affiliates. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include + +EFI_PHYSICAL_ADDRESS mMemDebugLogBufAddr; +BOOLEAN mMemDebugLogBufAddrInit; + +EFI_STATUS +EFIAPI +MemDebugLogWrite ( + IN CHAR8 *Buffer, + IN UINTN Length + ) +{ + EFI_STATUS Status; + + if (!mMemDebugLogBufAddrInit) { + // + // Obtain the Memory Debug Log buffer addr from HOB + // NOTE: This is expected to fail until the HOB is created. + // + Status = MemDebugLogAddrFromHOB (&mMemDebugLogBufAddr); + if (EFI_ERROR (Status)) { + mMemDebugLogBufAddr = 0; + } else { + mMemDebugLogBufAddrInit = TRUE; + } + } + + if (mMemDebugLogBufAddr) { + Status = MemDebugLogWriteBuffer (mMemDebugLogBufAddr, Buffer, Length); + } else { + // + // HOB has not yet been created, so + // write to the early debug log buffer. + // + if (FixedPcdGet32 (PcdOvmfEarlyMemDebugLogBase) != 0x0) { + Status = MemDebugLogWriteBuffer ( + (EFI_PHYSICAL_ADDRESS)(UINTN)FixedPcdGet32 (PcdOvmfEarlyMemDebugLogBase), + Buffer, + Length + ); + } else { + Status = EFI_NOT_FOUND; + } + } + + return Status; +} + +UINT32 +EFIAPI +MemDebugLogPages ( + VOID + ) +{ + UINT32 FwCfg_MemDebugLogPages; + UINT32 MemDebugLogBufPages; + EFI_STATUS Status; + + // + // Allow FwCfg value to override Pcd. + // + Status = QemuFwCfgParseUint32 ("opt/ovmf/MemDebugLogPages", TRUE, &FwCfg_MemDebugLogPages); + if (Status == EFI_SUCCESS) { + MemDebugLogBufPages = FwCfg_MemDebugLogPages; + } else { + MemDebugLogBufPages = FixedPcdGet32 (PcdMemDebugLogPages); + } + + // + // Cap max memory debug log size at MAX_MEM_DEBUG_LOG_PAGES + // + if (MemDebugLogBufPages > MAX_MEM_DEBUG_LOG_PAGES) { + MemDebugLogBufPages = MAX_MEM_DEBUG_LOG_PAGES; + } + + return MemDebugLogBufPages; +} diff --git a/OvmfPkg/Library/MemDebugLogLib/MemDebugLogPeiCore.c b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogPeiCore.c new file mode 100644 index 0000000000..1e95d65aaa --- /dev/null +++ b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogPeiCore.c @@ -0,0 +1,58 @@ +/** @file + * + Memory Debug Log Library - PEI Core + + Copyright (C) 2025, Oracle and/or its affiliates. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include + +EFI_PHYSICAL_ADDRESS mMemDebugLogBufAddr; +BOOLEAN mMemDebugLogBufAddrInit; + +EFI_STATUS +EFIAPI +MemDebugLogWrite ( + IN CHAR8 *Buffer, + IN UINTN Length + ) +{ + EFI_STATUS Status; + + if (!mMemDebugLogBufAddrInit) { + // + // Obtain the Memory Debug Log buffer addr from HOB + // NOTE: This is expected to fail until the HOB is created. + // + Status = MemDebugLogAddrFromHOB (&mMemDebugLogBufAddr); + if (EFI_ERROR (Status)) { + mMemDebugLogBufAddr = 0; + } else { + mMemDebugLogBufAddrInit = TRUE; + } + } + + if (mMemDebugLogBufAddr) { + Status = MemDebugLogWriteBuffer (mMemDebugLogBufAddr, Buffer, Length); + } else { + // + // HOB has not yet been created, so + // write to the early debug log buffer. + // + if (FixedPcdGet32 (PcdOvmfEarlyMemDebugLogBase) != 0x0) { + Status = MemDebugLogWriteBuffer ( + (EFI_PHYSICAL_ADDRESS)(UINTN)FixedPcdGet32 (PcdOvmfEarlyMemDebugLogBase), + Buffer, + Length + ); + } else { + Status = EFI_NOT_FOUND; + } + } + + return Status; +} diff --git a/OvmfPkg/Library/MemDebugLogLib/MemDebugLogPeiCoreLib.inf b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogPeiCoreLib.inf new file mode 100644 index 0000000000..56908caa5a --- /dev/null +++ b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogPeiCoreLib.inf @@ -0,0 +1,40 @@ +## @file +# Instance of MemDebugLog Library for PEI phase +# +# Copyright (C) 2025, Oracle and/or its affiliates. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MemDebugLogLib + FILE_GUID = EEAF8A01-167A-4222-A647-80EB16AEEC69 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = MemDebugLogLib|PEI_CORE + + +[Sources] + MemDebugLogPeiCore.c + MemDebugLogCommon.c + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + OvmfPkg/OvmfPkg.dec + +[LibraryClasses] + SynchronizationLib + +[Guids] + gMemDebugLogHobGuid + +[Ppis] + +[FixedPcd] + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfEarlyMemDebugLogBase + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfEarlyMemDebugLogSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString ## CONSUMES diff --git a/OvmfPkg/Library/MemDebugLogLib/MemDebugLogPeiLib.inf b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogPeiLib.inf new file mode 100644 index 0000000000..18f06e45b3 --- /dev/null +++ b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogPeiLib.inf @@ -0,0 +1,49 @@ +## @file +# Instance of MemDebugLog Library for PEI phase +# +# Copyright (C) 2025, Oracle and/or its affiliates. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MemDebugLogLib + FILE_GUID = D473DE36-0D8A-4F6B-9FA0-126185F36D9D + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = MemDebugLogLib|PEIM + + +[Sources] + MemDebugLogPei.c + MemDebugLogCommon.c + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + OvmfPkg/OvmfPkg.dec + +[LibraryClasses] + SynchronizationLib + PcdLib + +[LibraryClasses.Ia32] + QemuFwCfgSimpleParserLib + +[LibraryClasses.X64] + QemuFwCfgSimpleParserLib + +[Guids] + gMemDebugLogHobGuid + +[Ppis] + +[FixedPcd] + gUefiOvmfPkgTokenSpaceGuid.PcdMemDebugLogPages + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfEarlyMemDebugLogBase + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfEarlyMemDebugLogSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString ## CONSUMES + diff --git a/OvmfPkg/Library/MemDebugLogLib/MemDebugLogRt.c b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogRt.c new file mode 100644 index 0000000000..456bb70a85 --- /dev/null +++ b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogRt.c @@ -0,0 +1,54 @@ +/** @file + * + Memory Debug Log Library - Runtime + + Copyright (C) 2025, Oracle and/or its affiliates. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include + +EFI_PHYSICAL_ADDRESS mMemDebugLogBufAddr; +BOOLEAN mMemDebugLogBufAddrInit; + +EFI_STATUS +EFIAPI +MemDebugLogWrite ( + IN CHAR8 *Buffer, + IN UINTN Length + ) +{ + EFI_STATUS Status; + + // + // Stop logging after we have switched to virtual mode + // to avoid potential problems (such as crashes accessing + // physical pointers). + // + if (EfiGoneVirtual ()) { + return EFI_SUCCESS; + } + + if (!mMemDebugLogBufAddrInit) { + // + // Obtain the Memory Debug Log buffer addr from HOB + // + Status = MemDebugLogAddrFromHOB (&mMemDebugLogBufAddr); + if (EFI_ERROR (Status)) { + mMemDebugLogBufAddr = 0; + } + + mMemDebugLogBufAddrInit = TRUE; + } + + if (mMemDebugLogBufAddr) { + Status = MemDebugLogWriteBuffer (mMemDebugLogBufAddr, Buffer, Length); + } else { + Status = EFI_NOT_FOUND; + } + + return Status; +} diff --git a/OvmfPkg/Library/MemDebugLogLib/MemDebugLogRtLib.inf b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogRtLib.inf new file mode 100644 index 0000000000..a2e4729555 --- /dev/null +++ b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogRtLib.inf @@ -0,0 +1,38 @@ +## @file +# Instance of MemDebugLog Library for Runtime +# +# Copyright (C) 2025, Oracle and/or its affiliates. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MemDebugLogLib + FILE_GUID = BE0D0FFD-206C-48F3-9910-C32467567C44 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = MemDebugLogLib|DXE_RUNTIME_DRIVER + + +[Sources] + MemDebugLogRt.c + MemDebugLogCommon.c + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + OvmfPkg/OvmfPkg.dec + +[LibraryClasses] + HobLib + UefiRuntimeLib + SynchronizationLib + +[Guids] + gMemDebugLogHobGuid ## CONSUMES + +[FixedPcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString ## CONSUMES diff --git a/OvmfPkg/Library/MemDebugLogLib/MemDebugLogSec.c b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogSec.c new file mode 100644 index 0000000000..62905fc177 --- /dev/null +++ b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogSec.c @@ -0,0 +1,48 @@ +/** @file + * + Memory Debug Log Library - SEC Phase + + Copyright (C) 2025, Oracle and/or its affiliates. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include + +EFI_STATUS +EFIAPI +MemDebugLogWrite ( + IN CHAR8 *Buffer, + IN UINTN Length + ) +{ + EFI_STATUS Status; + + if (FixedPcdGet32 (PcdOvmfEarlyMemDebugLogBase) != 0x0) { + Status = MemDebugLogWriteBuffer ( + (EFI_PHYSICAL_ADDRESS)(UINTN)FixedPcdGet32 (PcdOvmfEarlyMemDebugLogBase), + Buffer, + Length + ); + } else { + Status = EFI_NOT_FOUND; + } + + return Status; +} + +RETURN_STATUS +EFIAPI +MemDebugLogLibConstructor ( + VOID + ) +{ + if (FixedPcdGet32 (PcdOvmfEarlyMemDebugLogSize) != 0) { + MemDebugLogInit ( + (EFI_PHYSICAL_ADDRESS)(UINTN)FixedPcdGet32 (PcdOvmfEarlyMemDebugLogBase), + (UINT32)FixedPcdGet32 (PcdOvmfEarlyMemDebugLogSize) + ); + } + + return RETURN_SUCCESS; +} diff --git a/OvmfPkg/Library/MemDebugLogLib/MemDebugLogSecLib.inf b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogSecLib.inf new file mode 100644 index 0000000000..0817e570c5 --- /dev/null +++ b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogSecLib.inf @@ -0,0 +1,39 @@ +## @file +# Instance of MemDebugLog Library for SEC phase +# +# Copyright (C) 2025, Oracle and/or its affiliates. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MemDebugLogLib + FILE_GUID = 9B3A8F82-CBCE-4E3A-A3E0-DBD7172E9506 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = MemDebugLogLib|SEC + CONSTRUCTOR = MemDebugLogLibConstructor + + +[Sources] + MemDebugLogSec.c + MemDebugLogCommon.c + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + OvmfPkg/OvmfPkg.dec + +[LibraryClasses] + SynchronizationLib + +[Guids] + gMemDebugLogHobGuid + +[FixedPcd] + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfEarlyMemDebugLogBase + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfEarlyMemDebugLogSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString ## CONSUMES