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 <kraxel@redhat.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Signed-off-by: Aaron Young <aaron.young@oracle.com>
This commit is contained in:
Aaron Young
2025-04-28 09:18:31 -07:00
committed by mergify[bot]
parent 26b37a1670
commit ba05ea83b7
14 changed files with 1078 additions and 0 deletions

View File

@@ -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 <Uefi/UefiBaseType.h>
#include <Base.h>
//
// 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_

View File

@@ -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 <PiPei.h>
#include <PiDxe.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/HobLib.h>
#include <Library/PrintLib.h>
#include <Library/SynchronizationLib.h>
#include <Library/MemDebugLogLib.h>
#include <Library/PcdLib.h>
#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;
}

View File

@@ -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 <PiDxe.h>
#include <Library/MemDebugLogLib.h>
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;
}

View File

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

View File

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

View File

@@ -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 <Library/MemDebugLogLib.h>
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;
}

View File

@@ -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 <PiPei.h>
#include <Library/PeiServicesLib.h>
#include <Library/QemuFwCfgSimpleParserLib.h>
#include <Library/MemDebugLogLib.h>
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;
}

View File

@@ -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 <PiPei.h>
#include <Library/PeiServicesLib.h>
#include <Library/MemDebugLogLib.h>
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;
}

View File

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

View File

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

View File

@@ -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 <PiDxe.h>
#include <Library/MemDebugLogLib.h>
#include <Library/UefiRuntimeLib.h>
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;
}

View File

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

View File

@@ -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 <Library/MemDebugLogLib.h>
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;
}

View File

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