summaryrefslogtreecommitdiff
path: root/OvmfPkg/Library
diff options
context:
space:
mode:
Diffstat (limited to 'OvmfPkg/Library')
-rw-r--r--OvmfPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.inf2
-rw-r--r--OvmfPkg/Library/AmdSvsmLib/AmdSvsmLib.c47
-rw-r--r--OvmfPkg/Library/CcExitLib/CcExitVcHandler.c4
-rw-r--r--OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.c28
-rw-r--r--OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.inf1
-rw-r--r--OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c8
-rw-r--r--OvmfPkg/Library/HardwareInfoLib/HardwareInfoTypesLib.h14
-rw-r--r--OvmfPkg/Library/MemDebugLogLib/MemDebugLogCommon.c297
-rw-r--r--OvmfPkg/Library/MemDebugLogLib/MemDebugLogDxe.c44
-rw-r--r--OvmfPkg/Library/MemDebugLogLib/MemDebugLogDxeLib.inf37
-rw-r--r--OvmfPkg/Library/MemDebugLogLib/MemDebugLogLibNull.inf31
-rw-r--r--OvmfPkg/Library/MemDebugLogLib/MemDebugLogNull.c40
-rw-r--r--OvmfPkg/Library/MemDebugLogLib/MemDebugLogPei.c89
-rw-r--r--OvmfPkg/Library/MemDebugLogLib/MemDebugLogPeiCore.c58
-rw-r--r--OvmfPkg/Library/MemDebugLogLib/MemDebugLogPeiCoreLib.inf40
-rw-r--r--OvmfPkg/Library/MemDebugLogLib/MemDebugLogPeiLib.inf49
-rw-r--r--OvmfPkg/Library/MemDebugLogLib/MemDebugLogRt.c54
-rw-r--r--OvmfPkg/Library/MemDebugLogLib/MemDebugLogRtLib.inf38
-rw-r--r--OvmfPkg/Library/MemDebugLogLib/MemDebugLogSec.c48
-rw-r--r--OvmfPkg/Library/MemDebugLogLib/MemDebugLogSecLib.inf39
-rw-r--r--OvmfPkg/Library/MemEncryptSevLibNull/MemEncryptSevLibNull.c241
-rw-r--r--OvmfPkg/Library/MemEncryptSevLibNull/MemEncryptSevLibNull.inf32
-rw-r--r--OvmfPkg/Library/MmPlatformHobProducerLibOvmf/MmPlatformHobProducerLibOvmf.c131
-rw-r--r--OvmfPkg/Library/MmPlatformHobProducerLibOvmf/MmPlatformHobProducerLibOvmf.inf51
-rw-r--r--OvmfPkg/Library/PeilessStartupLib/DxeLoad.c8
-rw-r--r--OvmfPkg/Library/PeilessStartupLib/X64/VirtualMemory.c66
-rw-r--r--OvmfPkg/Library/PlatformBmPrintScLib/StatusCodeHandler.c10
-rw-r--r--OvmfPkg/Library/PlatformDebugLibIoPort/DebugLib.c26
-rw-r--r--OvmfPkg/Library/PlatformDebugLibIoPort/PlatformDebugLibIoPort.inf3
-rw-r--r--OvmfPkg/Library/PlatformDebugLibIoPort/PlatformRomDebugLibIoPort.inf1
-rw-r--r--OvmfPkg/Library/PlatformInitLib/IntelTdx.c5
-rw-r--r--OvmfPkg/Library/PlatformInitLib/MemDetect.c14
-rw-r--r--OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf3
-rw-r--r--OvmfPkg/Library/PlatformSecureLib/PlatformSecureLib.inf2
-rw-r--r--OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgMmioPei.c11
-rw-r--r--OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgMmioPeiLib.inf1
-rw-r--r--OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c200
-rw-r--r--OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf1
-rw-r--r--OvmfPkg/Library/SmmCpuFeaturesLib/StandaloneMmCpuFeaturesLib.c75
-rw-r--r--OvmfPkg/Library/SmmCpuFeaturesLib/StandaloneMmCpuFeaturesLib.inf42
-rw-r--r--OvmfPkg/Library/SmmCpuFeaturesLib/TraditionalMmCpuFeaturesLib.c248
-rw-r--r--OvmfPkg/Library/SmmRelocationLib/SmmRelocationLib.c8
-rw-r--r--OvmfPkg/Library/VirtNorFlashDeviceLib/VirtNorFlashDeviceLib.c964
-rw-r--r--OvmfPkg/Library/VirtNorFlashDeviceLib/VirtNorFlashDeviceLib.inf30
-rw-r--r--OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c8
45 files changed, 2831 insertions, 318 deletions
diff --git a/OvmfPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.inf b/OvmfPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.inf
index 9c364be..b0e3478 100644
--- a/OvmfPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.inf
+++ b/OvmfPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.inf
@@ -14,7 +14,7 @@
FILE_GUID = 52DECA02-2EE8-4EAA-8EAD-1AB83F8A5955
MODULE_TYPE = BASE
VERSION_STRING = 1.0
- LIBRARY_CLASS = TimerLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER UEFI_APPLICATION SMM_CORE
+ LIBRARY_CLASS = TimerLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER UEFI_APPLICATION SMM_CORE MM_CORE_STANDALONE MM_STANDALONE
CONSTRUCTOR = AcpiTimerLibConstructor
[Sources]
diff --git a/OvmfPkg/Library/AmdSvsmLib/AmdSvsmLib.c b/OvmfPkg/Library/AmdSvsmLib/AmdSvsmLib.c
index e286ac0..6a92ffc 100644
--- a/OvmfPkg/Library/AmdSvsmLib/AmdSvsmLib.c
+++ b/OvmfPkg/Library/AmdSvsmLib/AmdSvsmLib.c
@@ -593,3 +593,50 @@ AmdSvsmVtpmCmd (
return (Ret == 0) ? TRUE : FALSE;
}
+
+BOOLEAN
+EFIAPI
+AmdSvsmQueryProtocol (
+ IN UINT32 ProtocolId,
+ IN UINT32 ProtocolVersion,
+ OUT UINT32 *ProtocolMin,
+ OUT UINT32 *ProtocolMax
+ )
+{
+ SVSM_CALL_DATA SvsmCallData;
+ SVSM_FUNCTION Function;
+ UINT64 Rcx;
+ UINTN Ret;
+
+ if (!AmdSvsmIsSvsmPresent ()) {
+ return FALSE;
+ }
+
+ Function.Id.Protocol = SVSM_PROTOCOL_CORE;
+ Function.Id.CallId = SVSM_CORE_QUERY_PROTOCOL;
+
+ Rcx = ((UINT64)ProtocolId << 32) | ProtocolVersion;
+
+ SvsmCallData.Caa = (SVSM_CAA *)AmdSvsmSnpGetCaa ();
+ SvsmCallData.RaxIn = Function.Uint64;
+ SvsmCallData.RcxIn = Rcx;
+
+ Ret = SvsmMsrProtocol (&SvsmCallData);
+ if (Ret != 0) {
+ return FALSE;
+ }
+
+ if (SvsmCallData.RcxOut == 0) {
+ return FALSE;
+ }
+
+ if (ProtocolMin) {
+ *ProtocolMin = (UINT32)(SvsmCallData.RcxOut & 0xffffffff);
+ }
+
+ if (ProtocolMax) {
+ *ProtocolMax = (UINT32)(SvsmCallData.RcxOut >> 32);
+ }
+
+ return TRUE;
+}
diff --git a/OvmfPkg/Library/CcExitLib/CcExitVcHandler.c b/OvmfPkg/Library/CcExitLib/CcExitVcHandler.c
index 2031fa9..2c12f78 100644
--- a/OvmfPkg/Library/CcExitLib/CcExitVcHandler.c
+++ b/OvmfPkg/Library/CcExitLib/CcExitVcHandler.c
@@ -701,6 +701,7 @@ MsrExit (
MSR_SVSM_CAA_REGISTER Msr;
UINT64 ExitInfo1;
UINT64 Status;
+ UINT32 EcxIn;
ExitInfo1 = 0;
@@ -708,7 +709,8 @@ MsrExit (
// The SVSM CAA MSR is a software implemented MSR and not supported
// by the hardware, handle it directly.
//
- if (Regs->Rax == MSR_SVSM_CAA) {
+ EcxIn = (UINT32)(UINTN)Regs->Rcx;
+ if (EcxIn == MSR_SVSM_CAA) {
// Writes to the SVSM CAA MSR are ignored
if (*(InstructionData->OpCodes + 1) == 0x30) {
return 0;
diff --git a/OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.c b/OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.c
index f6508e0..a90d626 100644
--- a/OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.c
+++ b/OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.c
@@ -11,8 +11,8 @@
**/
#include <Library/BaseLib.h>
+#include <Library/FdtLib.h>
#include <Library/FdtSerialPortAddressLib.h>
-#include <libfdt.h>
/**
Read the "reg" property of Node in DeviceTree as a UINT64 base address.
@@ -46,12 +46,12 @@ GetBaseAddress (
CONST VOID *RegProp;
INT32 PropSize;
- NodeStatus = fdt_getprop (DeviceTree, Node, "status", NULL);
+ NodeStatus = FdtGetProp (DeviceTree, Node, "status", NULL);
if ((NodeStatus != NULL) && (AsciiStrCmp (NodeStatus, "okay") != 0)) {
return RETURN_DEVICE_ERROR;
}
- RegProp = fdt_getprop (DeviceTree, Node, "reg", &PropSize);
+ RegProp = FdtGetProp (DeviceTree, Node, "reg", &PropSize);
if (RegProp == NULL) {
return RETURN_NOT_FOUND;
}
@@ -60,7 +60,7 @@ GetBaseAddress (
return RETURN_BAD_BUFFER_SIZE;
}
- *BaseAddress = fdt64_to_cpu (ReadUnaligned64 (RegProp));
+ *BaseAddress = Fdt64ToCpu (ReadUnaligned64 (RegProp));
return RETURN_SUCCESS;
}
@@ -99,19 +99,19 @@ FdtSerialGetPorts (
{
INT32 Node;
- if (fdt_check_header (DeviceTree) != 0) {
+ if (FdtCheckHeader (DeviceTree) != 0) {
return RETURN_INVALID_PARAMETER;
}
Ports->NumberOfPorts = 0;
- Node = fdt_next_node (DeviceTree, 0, NULL);
+ Node = FdtNextNode (DeviceTree, 0, NULL);
while ((Node > 0) &&
(Ports->NumberOfPorts < ARRAY_SIZE (Ports->BaseAddress)))
{
CONST CHAR8 *CompatProp;
INT32 PropSize;
- CompatProp = fdt_getprop (DeviceTree, Node, "compatible", &PropSize);
+ CompatProp = FdtGetProp (DeviceTree, Node, "compatible", &PropSize);
if (CompatProp != NULL) {
CONST CHAR8 *CompatItem;
@@ -133,7 +133,7 @@ FdtSerialGetPorts (
}
}
- Node = fdt_next_node (DeviceTree, Node, NULL);
+ Node = FdtNextNode (DeviceTree, Node, NULL);
}
return Ports->NumberOfPorts > 0 ? RETURN_SUCCESS : RETURN_NOT_FOUND;
@@ -178,16 +178,16 @@ FdtSerialGetConsolePort (
INT32 ConsoleNode;
RETURN_STATUS Status;
- if (fdt_check_header (DeviceTree) != 0) {
+ if (FdtCheckHeader (DeviceTree) != 0) {
return RETURN_INVALID_PARAMETER;
}
- ChosenNode = fdt_path_offset (DeviceTree, "/chosen");
+ ChosenNode = FdtPathOffset (DeviceTree, "/chosen");
if (ChosenNode < 0) {
return RETURN_NOT_FOUND;
}
- StdoutPathProp = fdt_getprop (
+ StdoutPathProp = FdtGetProp (
DeviceTree,
ChosenNode,
"stdout-path",
@@ -216,7 +216,7 @@ FdtSerialGetConsolePort (
//
// StdoutPathProp starts with an absolute node path.
//
- ConsoleNode = fdt_path_offset_namelen (
+ ConsoleNode = FdtPathOffsetNameLen (
DeviceTree,
StdoutPathProp,
(INT32)StdoutPathLength
@@ -227,7 +227,7 @@ FdtSerialGetConsolePort (
//
CONST CHAR8 *ResolvedStdoutPath;
- ResolvedStdoutPath = fdt_get_alias_namelen (
+ ResolvedStdoutPath = FdtGetAliasNameLen (
DeviceTree,
StdoutPathProp,
(INT32)StdoutPathLength
@@ -236,7 +236,7 @@ FdtSerialGetConsolePort (
return RETURN_NOT_FOUND;
}
- ConsoleNode = fdt_path_offset (DeviceTree, ResolvedStdoutPath);
+ ConsoleNode = FdtPathOffset (DeviceTree, ResolvedStdoutPath);
}
if (ConsoleNode < 0) {
diff --git a/OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.inf b/OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.inf
index e27742e..b70ca21 100644
--- a/OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.inf
+++ b/OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.inf
@@ -18,7 +18,6 @@
FdtSerialPortAddressLib.c
[Packages]
- EmbeddedPkg/EmbeddedPkg.dec
MdePkg/MdePkg.dec
OvmfPkg/OvmfPkg.dec
diff --git a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
index f46e5bd..608f35e 100644
--- a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
+++ b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
@@ -351,9 +351,9 @@ QemuLoadKernelImage (
if (InitrdSize > 0) {
//
- // Append ' initrd=initrd' in UTF-16.
+ // Prefix ' initrd=initrd' in UTF-16.
//
- KernelLoadedImage->LoadOptionsSize += sizeof (L" initrd=initrd") - 2;
+ KernelLoadedImage->LoadOptionsSize += sizeof (L"initrd=initrd ") - 2;
}
if (Shim) {
@@ -385,8 +385,8 @@ QemuLoadKernelImage (
KernelLoadedImage->LoadOptionsSize,
"%a%a%a",
(Shim == FALSE) ? "" : "kernel ",
- (CommandLineSize == 0) ? "" : CommandLine,
- (InitrdSize == 0) ? "" : " initrd=initrd"
+ (InitrdSize == 0) ? "" : "initrd=initrd ",
+ (CommandLineSize == 0) ? "" : CommandLine
);
DEBUG ((
DEBUG_INFO,
diff --git a/OvmfPkg/Library/HardwareInfoLib/HardwareInfoTypesLib.h b/OvmfPkg/Library/HardwareInfoLib/HardwareInfoTypesLib.h
index bee60bd..40a785e 100644
--- a/OvmfPkg/Library/HardwareInfoLib/HardwareInfoTypesLib.h
+++ b/OvmfPkg/Library/HardwareInfoLib/HardwareInfoTypesLib.h
@@ -20,9 +20,8 @@
typedef enum {
HardwareInfoTypeUndefined = 0,
HardwareInfoTypeHostBridge = 1,
+ HardwareInfoTypeQemuUefiVars = 2,
HardwareInfoTypeSvsmVirtioMmio = 0x1000,
-
- HardwareInfoTypeMax
} HARDWARE_INFO_TYPE;
//
@@ -40,6 +39,16 @@ typedef struct {
#pragma pack()
//
+// used by:
+// - HardwareInfoTypeQemuUefiVars
+//
+#pragma pack(1)
+typedef struct {
+ UINT64 MmioAddress;
+} SIMPLE_INFO;
+#pragma pack()
+
+//
// Generic data structure to access any supported hardware type
// resource definition
//
@@ -50,6 +59,7 @@ typedef struct {
union {
UINT8 *Raw;
HOST_BRIDGE_INFO *PciHostBridge;
+ SIMPLE_INFO *SimpleDevice;
} Data;
} HARDWARE_INFO;
#pragma pack()
diff --git a/OvmfPkg/Library/MemDebugLogLib/MemDebugLogCommon.c b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogCommon.c
new file mode 100644
index 0000000..8c9ce61
--- /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 <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;
+}
diff --git a/OvmfPkg/Library/MemDebugLogLib/MemDebugLogDxe.c b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogDxe.c
new file mode 100644
index 0000000..9655257
--- /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 <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;
+}
diff --git a/OvmfPkg/Library/MemDebugLogLib/MemDebugLogDxeLib.inf b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogDxeLib.inf
new file mode 100644
index 0000000..edb405d
--- /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 0000000..7c2c68f
--- /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 MM_STANDALONE MM_CORE_STANDALONE
+
+
+[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 0000000..59bb7c8
--- /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 <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;
+}
diff --git a/OvmfPkg/Library/MemDebugLogLib/MemDebugLogPei.c b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogPei.c
new file mode 100644
index 0000000..cbdab6c
--- /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 <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;
+}
diff --git a/OvmfPkg/Library/MemDebugLogLib/MemDebugLogPeiCore.c b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogPeiCore.c
new file mode 100644
index 0000000..1e95d65
--- /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 <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;
+}
diff --git a/OvmfPkg/Library/MemDebugLogLib/MemDebugLogPeiCoreLib.inf b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogPeiCoreLib.inf
new file mode 100644
index 0000000..56908ca
--- /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 0000000..18f06e4
--- /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 0000000..456bb70
--- /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 <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;
+}
diff --git a/OvmfPkg/Library/MemDebugLogLib/MemDebugLogRtLib.inf b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogRtLib.inf
new file mode 100644
index 0000000..a2e4729
--- /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 0000000..62905fc
--- /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 <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;
+}
diff --git a/OvmfPkg/Library/MemDebugLogLib/MemDebugLogSecLib.inf b/OvmfPkg/Library/MemDebugLogLib/MemDebugLogSecLib.inf
new file mode 100644
index 0000000..0817e57
--- /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
diff --git a/OvmfPkg/Library/MemEncryptSevLibNull/MemEncryptSevLibNull.c b/OvmfPkg/Library/MemEncryptSevLibNull/MemEncryptSevLibNull.c
new file mode 100644
index 0000000..e22aedc
--- /dev/null
+++ b/OvmfPkg/Library/MemEncryptSevLibNull/MemEncryptSevLibNull.c
@@ -0,0 +1,241 @@
+/** @file
+
+ Secure Encrypted Virtualization (SEV) library helper function
+
+ Copyright (c) 2017 - 2020, AMD Incorporated. All rights reserved.<BR>
+ Copyright (c) Microsoft Corporation.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Library/MemEncryptSevLib.h>
+
+/**
+ Returns a boolean to indicate whether SEV-SNP is enabled.
+
+ @retval TRUE SEV-SNP is enabled
+ @retval FALSE SEV-SNP is not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptSevSnpIsEnabled (
+ VOID
+ )
+{
+ return FALSE;
+}
+
+/**
+ Returns a boolean to indicate whether SEV-ES is enabled.
+
+ @retval TRUE SEV-ES is enabled
+ @retval FALSE SEV-ES is not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptSevEsIsEnabled (
+ VOID
+ )
+{
+ return FALSE;
+}
+
+/**
+ Returns a boolean to indicate whether SEV is enabled.
+
+ @retval TRUE SEV is enabled
+ @retval FALSE SEV is not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptSevIsEnabled (
+ VOID
+ )
+{
+ return FALSE;
+}
+
+/**
+ This function clears memory encryption bit for the memory region specified by
+ BaseAddress and NumPages from the current page table context.
+
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
+ current CR3)
+ @param[in] BaseAddress The physical address that is the start
+ address of a memory region.
+ @param[in] NumPages The number of pages from start memory
+ region.
+
+ @retval RETURN_SUCCESS The attributes were cleared for the
+ memory region.
+ @retval RETURN_INVALID_PARAMETER Number of pages is zero.
+ @retval RETURN_UNSUPPORTED Clearing the memory encryption attribute
+ is not supported
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptSevClearPageEncMask (
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN NumPages
+ )
+{
+ return RETURN_UNSUPPORTED;
+}
+
+/**
+ This function sets memory encryption bit for the memory region specified by
+ BaseAddress and NumPages from the current page table context.
+
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
+ current CR3)
+ @param[in] BaseAddress The physical address that is the start
+ address of a memory region.
+ @param[in] NumPages The number of pages from start memory
+ region.
+
+ @retval RETURN_SUCCESS The attributes were set for the memory
+ region.
+ @retval RETURN_INVALID_PARAMETER Number of pages is zero.
+ @retval RETURN_UNSUPPORTED Setting the memory encryption attribute
+ is not supported
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptSevSetPageEncMask (
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN NumPages
+ )
+{
+ return RETURN_UNSUPPORTED;
+}
+
+/**
+ Locate the page range that covers the initial (pre-SMBASE-relocation) SMRAM
+ Save State Map.
+
+ @param[out] BaseAddress The base address of the lowest-address page that
+ covers the initial SMRAM Save State Map.
+
+ @param[out] NumberOfPages The number of pages in the page range that covers
+ the initial SMRAM Save State Map.
+
+ @retval RETURN_SUCCESS BaseAddress and NumberOfPages have been set on
+ output.
+
+ @retval RETURN_UNSUPPORTED SMM is unavailable.
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptSevLocateInitialSmramSaveStateMapPages (
+ OUT UINTN *BaseAddress,
+ OUT UINTN *NumberOfPages
+ )
+{
+ return RETURN_UNSUPPORTED;
+}
+
+/**
+ Returns the SEV encryption mask.
+
+ @return The SEV pagtable encryption mask
+**/
+UINT64
+EFIAPI
+MemEncryptSevGetEncryptionMask (
+ VOID
+ )
+{
+ return 0;
+}
+
+/**
+ Returns a boolean to indicate whether DebugVirtualization is enabled.
+
+ @retval TRUE DebugVirtualization is enabled
+ @retval FALSE DebugVirtualization is not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptSevEsDebugVirtualizationIsEnabled (
+ VOID
+ )
+{
+ return FALSE;
+}
+
+/**
+ Returns the encryption state of the specified virtual address range.
+
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
+ current CR3)
+ @param[in] BaseAddress Base address to check
+ @param[in] Length Length of virtual address range
+
+ @retval MemEncryptSevAddressRangeUnencrypted Address range is mapped
+ unencrypted
+ @retval MemEncryptSevAddressRangeEncrypted Address range is mapped
+ encrypted
+ @retval MemEncryptSevAddressRangeMixed Address range is mapped mixed
+ @retval MemEncryptSevAddressRangeError Address range is not mapped
+**/
+MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE
+EFIAPI
+MemEncryptSevGetAddressRangeState (
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Length
+ )
+{
+ return MemEncryptSevAddressRangeUnencrypted;
+}
+
+/**
+ This function clears memory encryption bit for the MMIO region specified by
+ BaseAddress and NumPages.
+
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
+ current CR3)
+ @param[in] BaseAddress The physical address that is the start
+ address of a MMIO region.
+ @param[in] NumPages The number of pages from start memory
+ region.
+
+ @retval RETURN_SUCCESS The attributes were cleared for the
+ memory region.
+ @retval RETURN_INVALID_PARAMETER Number of pages is zero.
+ @retval RETURN_UNSUPPORTED Clearing the memory encryption attribute
+ is not supported
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptSevClearMmioPageEncMask (
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN NumPages
+ )
+{
+ return RETURN_UNSUPPORTED;
+}
+
+/**
+ Pre-validate the system RAM when SEV-SNP is enabled in the guest VM.
+
+ @param[in] BaseAddress Base address
+ @param[in] NumPages Number of pages starting from the base address
+
+**/
+VOID
+EFIAPI
+MemEncryptSevSnpPreValidateSystemRam (
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN NumPages
+ )
+{
+ //
+ // Do nothing
+ //
+}
diff --git a/OvmfPkg/Library/MemEncryptSevLibNull/MemEncryptSevLibNull.inf b/OvmfPkg/Library/MemEncryptSevLibNull/MemEncryptSevLibNull.inf
new file mode 100644
index 0000000..a7ed263
--- /dev/null
+++ b/OvmfPkg/Library/MemEncryptSevLibNull/MemEncryptSevLibNull.inf
@@ -0,0 +1,32 @@
+## @file
+# Library provides the helper functions for SEV guest
+#
+# Copyright (c) 2017 - 2024, Advanced Micro Devices. All rights reserved.<BR>
+# Copyright (c) Microsoft Corporation.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = MemEncryptSevLibNull
+ FILE_GUID = 02A5CD1B-05F2-4C7F-B8E9-66A5E66C47C7
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MemEncryptSevLib
+
+#
+# The following information is for reference only and not required by the build
+# tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Packages]
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[Sources]
+ MemEncryptSevLibNull.c
diff --git a/OvmfPkg/Library/MmPlatformHobProducerLibOvmf/MmPlatformHobProducerLibOvmf.c b/OvmfPkg/Library/MmPlatformHobProducerLibOvmf/MmPlatformHobProducerLibOvmf.c
new file mode 100644
index 0000000..16197c3
--- /dev/null
+++ b/OvmfPkg/Library/MmPlatformHobProducerLibOvmf/MmPlatformHobProducerLibOvmf.c
@@ -0,0 +1,131 @@
+/** @file
+ Null instance of MM Platform HOB Producer Library Class.
+
+ CreateMmPlatformHob() function is called by StandaloneMm IPL to create all
+ Platform specific HOBs that required by Standalone MM environment.
+
+ Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <PiPei.h>
+#include <Library/HobLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MmPlatformHobProducerLib.h>
+#include <Library/DebugLib.h>
+
+#define NUMBER_OF_HOB_RESOURCE_DESCRIPTOR 2
+
+/**
+ Create the platform specific HOBs needed by the Standalone MM environment.
+
+ The following HOBs are created by StandaloneMm IPL common logic.
+ Hence they should NOT be created by this function:
+ * Single EFI_HOB_TYPE_FV to describe the Firmware Volume where MM Core resides.
+ * Single GUIDed (gEfiSmmSmramMemoryGuid) HOB to describe the MM regions.
+ * Single EFI_HOB_MEMORY_ALLOCATION_MODULE to describe the MM region used by MM Core.
+ * Multiple EFI_HOB_RESOURCE_DESCRIPTOR to describe the non-MM regions and their access permissions.
+ Note: All accessible non-MM regions should be described by EFI_HOB_RESOURCE_DESCRIPTOR HOBs.
+ * Single GUIDed (gMmCommBufferHobGuid) HOB to identify MM Communication buffer in non-MM region.
+ * Multiple GUIDed (gSmmBaseHobGuid) HOB to describe the SMM base address of each processor.
+ * Multiple GUIDed (gMpInformation2HobGuid) HOB to describe the MP information.
+ * Single GUIDed (gMmCpuSyncConfigHobGuid) HOB to describe how BSP synchronizes with APs in x86 SMM.
+ * Single GUIDed (gMmAcpiS3EnableHobGuid) HOB to describe the ACPI S3 enable status.
+ * Single GUIDed (gEfiAcpiVariableGuid) HOB to identify the S3 data root region in x86.
+ * Single GUIDed (gMmProfileDataHobGuid) HOB to describe the MM profile data region.
+ * Single GUIDed (gMmStatusCodeUseSerialHobGuid) HOB to describe the status code use serial port.
+
+ @param[in] Buffer The free buffer to be used for HOB creation.
+ @param[in, out] BufferSize The buffer size.
+ On return, the expected/used size.
+
+ @retval RETURN_INVALID_PARAMETER BufferSize is NULL.
+ @retval RETURN_INVALID_PARAMETER Buffer is NULL and BufferSize is not 0.
+ @retval RETURN_BUFFER_TOO_SMALL The buffer is too small for HOB creation.
+ BufferSize is updated to indicate the expected buffer size.
+ When the input BufferSize is bigger than the expected buffer size,
+ the BufferSize value will be changed to the used buffer size.
+ @retval RETURN_SUCCESS The HOB list is created successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+CreateMmPlatformHob (
+ IN VOID *Buffer,
+ IN OUT UINTN *BufferSize
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ UINTN Size;
+ EFI_HOB_RESOURCE_DESCRIPTOR Hob;
+ UINTN NumberOfHobResourceDescriptor;
+
+ if (BufferSize == NULL) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ if ((*BufferSize != 0) && (Buffer == NULL)) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ Size = 0;
+
+ // Account for the Platform Info HOB
+ GuidHob = GetFirstGuidHob (&gUefiOvmfPkgPlatformInfoGuid);
+ Size += GET_HOB_LENGTH (GuidHob);
+
+ // Account for resource descriptor HOBs for MM region
+ Size += sizeof (EFI_HOB_RESOURCE_DESCRIPTOR) * NUMBER_OF_HOB_RESOURCE_DESCRIPTOR;
+
+ if (Size > *BufferSize) {
+ *BufferSize = Size;
+ return RETURN_BUFFER_TOO_SMALL;
+ }
+
+ *BufferSize = Size;
+
+ Size = 0;
+ NumberOfHobResourceDescriptor = 0;
+
+ // Duplicate the Platform Info HOB
+ CopyMem (Buffer, GuidHob, GET_HOB_LENGTH (GuidHob));
+ Size += GET_HOB_LENGTH (GuidHob);
+
+ // Create resource descriptor HOBs for MM region
+ // APIC
+ Hob.Header.HobType = EFI_HOB_TYPE_RESOURCE_DESCRIPTOR;
+ Hob.Header.HobLength = (UINT16)sizeof (EFI_HOB_RESOURCE_DESCRIPTOR);
+ Hob.ResourceType = EFI_RESOURCE_MEMORY_MAPPED_IO;
+ Hob.ResourceAttribute = EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_TESTED;
+ Hob.PhysicalStart = PcdGet32 (PcdOvmfFlashNvStorageVariableBase);
+ Hob.ResourceLength = SIZE_1MB;
+ ZeroMem (&(Hob.Owner), sizeof (EFI_GUID));
+ CopyMem ((UINT8 *)Buffer + Size, &Hob, sizeof (EFI_HOB_RESOURCE_DESCRIPTOR));
+ Size += sizeof (EFI_HOB_RESOURCE_DESCRIPTOR);
+ NumberOfHobResourceDescriptor++;
+
+ // Variable Storage
+ Hob.Header.HobType = EFI_HOB_TYPE_RESOURCE_DESCRIPTOR;
+ Hob.Header.HobLength = (UINT16)sizeof (EFI_HOB_RESOURCE_DESCRIPTOR);
+ Hob.ResourceType = EFI_RESOURCE_MEMORY_MAPPED_IO;
+ Hob.ResourceAttribute = EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_TESTED;
+ Hob.PhysicalStart = PcdGet32 (PcdCpuLocalApicBaseAddress);
+ Hob.ResourceLength = PcdGet32 (PcdFlashNvStorageVariableSize);
+ ZeroMem (&(Hob.Owner), sizeof (EFI_GUID));
+ CopyMem ((UINT8 *)Buffer + Size, &Hob, sizeof (EFI_HOB_RESOURCE_DESCRIPTOR));
+ Size += sizeof (EFI_HOB_RESOURCE_DESCRIPTOR);
+ NumberOfHobResourceDescriptor++;
+
+ ASSERT (NumberOfHobResourceDescriptor == NUMBER_OF_HOB_RESOURCE_DESCRIPTOR);
+
+ return EFI_SUCCESS;
+}
diff --git a/OvmfPkg/Library/MmPlatformHobProducerLibOvmf/MmPlatformHobProducerLibOvmf.inf b/OvmfPkg/Library/MmPlatformHobProducerLibOvmf/MmPlatformHobProducerLibOvmf.inf
new file mode 100644
index 0000000..a86010b
--- /dev/null
+++ b/OvmfPkg/Library/MmPlatformHobProducerLibOvmf/MmPlatformHobProducerLibOvmf.inf
@@ -0,0 +1,51 @@
+## @file
+# Null instance of MM Platform HOB Producer Library Class.
+#
+# Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010017
+ BASE_NAME = MmPlatformHobProducerLibOvmf
+ FILE_GUID = 011E97D9-2CA9-453D-9652-50C43AE54A4E
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MmPlatformHobProducerLib
+
+#
+# VALID_ARCHITECTURES = X64
+#
+
+[Sources]
+ MmPlatformHobProducerLibOvmf.c
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ PcdLib
+ MemoryAllocationLib
+ HobLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ StandaloneMmPkg/StandaloneMmPkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[Guids]
+ gUefiOvmfPkgPlatformInfoGuid ## CONSUMES ## SystemTable
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageVariableBase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask
+ gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr
+
+[Depex]
+ gEfiPeiMmAccessPpiGuid
diff --git a/OvmfPkg/Library/PeilessStartupLib/DxeLoad.c b/OvmfPkg/Library/PeilessStartupLib/DxeLoad.c
index d34690e..b7bacae 100644
--- a/OvmfPkg/Library/PeilessStartupLib/DxeLoad.c
+++ b/OvmfPkg/Library/PeilessStartupLib/DxeLoad.c
@@ -43,14 +43,6 @@ HandOffToDxeCore (
UINTN PageTables;
//
- // Clear page 0 and mark it as allocated if NULL pointer detection is enabled.
- //
- if (IsNullDetectionEnabled ()) {
- ClearFirst4KPage (GetHobList ());
- BuildMemoryAllocationHob (0, EFI_PAGES_TO_SIZE (1), EfiBootServicesData);
- }
-
- //
// Allocate 128KB for the Stack
//
BaseOfStack = AllocatePages (EFI_SIZE_TO_PAGES (STACK_SIZE));
diff --git a/OvmfPkg/Library/PeilessStartupLib/X64/VirtualMemory.c b/OvmfPkg/Library/PeilessStartupLib/X64/VirtualMemory.c
index e2c1bac..d824a64 100644
--- a/OvmfPkg/Library/PeilessStartupLib/X64/VirtualMemory.c
+++ b/OvmfPkg/Library/PeilessStartupLib/X64/VirtualMemory.c
@@ -65,72 +65,6 @@ IsSetNxForStack (
}
/**
- Clear legacy memory located at the first 4K-page, if available.
-
- This function traverses the whole HOB list to check if memory from 0 to 4095
- exists and has not been allocated, and then clear it if so.
-
- @param HobStart The start of HobList passed to DxeCore.
-
-**/
-VOID
-ClearFirst4KPage (
- IN VOID *HobStart
- )
-{
- EFI_PEI_HOB_POINTERS RscHob;
- EFI_PEI_HOB_POINTERS MemHob;
- BOOLEAN DoClear;
-
- RscHob.Raw = HobStart;
- MemHob.Raw = HobStart;
- DoClear = FALSE;
-
- //
- // Check if page 0 exists and free
- //
- while ((RscHob.Raw = GetNextHob (
- EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,
- RscHob.Raw
- )) != NULL)
- {
- if ((RscHob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
- (RscHob.ResourceDescriptor->PhysicalStart == 0))
- {
- DoClear = TRUE;
- //
- // Make sure memory at 0-4095 has not been allocated.
- //
- while ((MemHob.Raw = GetNextHob (
- EFI_HOB_TYPE_MEMORY_ALLOCATION,
- MemHob.Raw
- )) != NULL)
- {
- if (MemHob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress
- < EFI_PAGE_SIZE)
- {
- DoClear = FALSE;
- break;
- }
-
- MemHob.Raw = GET_NEXT_HOB (MemHob);
- }
-
- break;
- }
-
- RscHob.Raw = GET_NEXT_HOB (RscHob);
- }
-
- if (DoClear) {
- DEBUG ((DEBUG_INFO, "Clearing first 4K-page!\r\n"));
- SetMem (NULL, EFI_PAGE_SIZE, 0);
- }
-
- return;
-}
-
-/**
Return configure status of NULL pointer detection feature.
@return TRUE NULL pointer detection feature is enabled
diff --git a/OvmfPkg/Library/PlatformBmPrintScLib/StatusCodeHandler.c b/OvmfPkg/Library/PlatformBmPrintScLib/StatusCodeHandler.c
index 1809164..2c2695b 100644
--- a/OvmfPkg/Library/PlatformBmPrintScLib/StatusCodeHandler.c
+++ b/OvmfPkg/Library/PlatformBmPrintScLib/StatusCodeHandler.c
@@ -214,14 +214,20 @@ HandleStatusCode (
DevPathString
);
} else {
+ EFI_STATUS ReturnStatus;
+
+ ReturnStatus = ((EFI_RETURN_STATUS_EXTENDED_DATA *)Data)->ReturnStatus;
Print (
- L"%a: failed to %a %s \"%s\" from %s: %r\n",
+ L"%a: failed to %a %s \"%s\" from %s: %r%a\n",
gEfiCallerBaseName,
Value == mLoadFail ? "load" : "start",
BootOptionName,
BmBootOption.Description,
DevPathString,
- ((EFI_RETURN_STATUS_EXTENDED_DATA *)Data)->ReturnStatus
+ ReturnStatus,
+ ((ReturnStatus == EFI_SECURITY_VIOLATION ||
+ (Value == mLoadFail && ReturnStatus == EFI_ACCESS_DENIED)) ?
+ " -- rejected probably by Secure Boot" : "")
);
}
diff --git a/OvmfPkg/Library/PlatformDebugLibIoPort/DebugLib.c b/OvmfPkg/Library/PlatformDebugLibIoPort/DebugLib.c
index 6895458..f07e994e 100644
--- a/OvmfPkg/Library/PlatformDebugLibIoPort/DebugLib.c
+++ b/OvmfPkg/Library/PlatformDebugLibIoPort/DebugLib.c
@@ -16,6 +16,7 @@
#include <Library/PcdLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugPrintErrorLevelLib.h>
+#include <Library/MemDebugLogLib.h>
#include "DebugLibDetect.h"
//
@@ -93,10 +94,11 @@ DebugPrintMarker (
ASSERT (Format != NULL);
//
- // Check if the global mask disables this message or the device is inactive
+ // If the global mask disables this message OR the debug I/O port is not
+ // present and Memory Debug Logging is disabled, there's nothing to do.
//
if (((ErrorLevel & GetDebugPrintErrorLevel ()) == 0) ||
- !PlatformDebugLibIoPortFound ())
+ (!PlatformDebugLibIoPortFound () && !MemDebugLogEnabled ()))
{
return;
}
@@ -111,9 +113,18 @@ DebugPrintMarker (
}
//
- // Send the print string to the debug I/O port
+ // Send the print string to the debug I/O port, if present
+ //
+ if (PlatformDebugLibIoPortFound ()) {
+ IoWriteFifo8 (PcdGet16 (PcdDebugIoPort), Length, Buffer);
+ }
+
//
- IoWriteFifo8 (PcdGet16 (PcdDebugIoPort), Length, Buffer);
+ // Send string to Memory Debug Log if enabled
+ //
+ if (MemDebugLogEnabled ()) {
+ MemDebugLogWrite (Buffer, Length);
+ }
}
/**
@@ -222,6 +233,13 @@ DebugAssert (
}
//
+ // Send the string to Memory Debug Log
+ //
+ if (MemDebugLogEnabled ()) {
+ MemDebugLogWrite (Buffer, Length);
+ }
+
+ //
// Generate a Breakpoint, DeadLoop, or NOP based on PCD settings
//
if ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED) != 0) {
diff --git a/OvmfPkg/Library/PlatformDebugLibIoPort/PlatformDebugLibIoPort.inf b/OvmfPkg/Library/PlatformDebugLibIoPort/PlatformDebugLibIoPort.inf
index 94ab910..a8febf0 100644
--- a/OvmfPkg/Library/PlatformDebugLibIoPort/PlatformDebugLibIoPort.inf
+++ b/OvmfPkg/Library/PlatformDebugLibIoPort/PlatformDebugLibIoPort.inf
@@ -16,7 +16,7 @@
FILE_GUID = DF934DA3-CD31-49FE-AF50-B3C87C79325F
MODULE_TYPE = BASE
VERSION_STRING = 1.0
- LIBRARY_CLASS = DebugLib|PEI_CORE PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER SMM_CORE DXE_SMM_DRIVER UEFI_DRIVER UEFI_APPLICATION
+ LIBRARY_CLASS = DebugLib|PEI_CORE PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER SMM_CORE DXE_SMM_DRIVER UEFI_DRIVER UEFI_APPLICATION MM_CORE_STANDALONE MM_STANDALONE
CONSTRUCTOR = PlatformDebugLibIoPortConstructor
#
@@ -40,6 +40,7 @@
PrintLib
BaseLib
DebugPrintErrorLevelLib
+ MemDebugLogLib
[Pcd]
gUefiOvmfPkgTokenSpaceGuid.PcdDebugIoPort ## CONSUMES
diff --git a/OvmfPkg/Library/PlatformDebugLibIoPort/PlatformRomDebugLibIoPort.inf b/OvmfPkg/Library/PlatformDebugLibIoPort/PlatformRomDebugLibIoPort.inf
index c89b157..17e970d 100644
--- a/OvmfPkg/Library/PlatformDebugLibIoPort/PlatformRomDebugLibIoPort.inf
+++ b/OvmfPkg/Library/PlatformDebugLibIoPort/PlatformRomDebugLibIoPort.inf
@@ -40,6 +40,7 @@
PrintLib
BaseLib
DebugPrintErrorLevelLib
+ MemDebugLogLib
[Pcd]
gUefiOvmfPkgTokenSpaceGuid.PcdDebugIoPort ## CONSUMES
diff --git a/OvmfPkg/Library/PlatformInitLib/IntelTdx.c b/OvmfPkg/Library/PlatformInitLib/IntelTdx.c
index 12e4501..c3e08d8 100644
--- a/OvmfPkg/Library/PlatformInitLib/IntelTdx.c
+++ b/OvmfPkg/Library/PlatformInitLib/IntelTdx.c
@@ -186,10 +186,13 @@ PlatformTdxPublishRamRegions (
// work area. We ought to prevent DXE from serving allocation requests
// such that they would overlap the work area.
//
+ // Since this memory range will be used by the Reset Vector on Maibox
+ // wakeup again, it must be reserved as ACPI NVS.
+ //
BuildMemoryAllocationHob (
(EFI_PHYSICAL_ADDRESS)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaBase),
(UINT64)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaSize),
- EfiBootServicesData
+ EfiACPIMemoryNVS
);
}
}
diff --git a/OvmfPkg/Library/PlatformInitLib/MemDetect.c b/OvmfPkg/Library/PlatformInitLib/MemDetect.c
index 44b2e0d..17eaff3 100644
--- a/OvmfPkg/Library/PlatformInitLib/MemDetect.c
+++ b/OvmfPkg/Library/PlatformInitLib/MemDetect.c
@@ -1504,6 +1504,20 @@ PlatformQemuInitializeRamForS3 (
);
}
+ if (FixedPcdGet32 (PcdOvmfEarlyMemDebugLogSize) != 0) {
+ //
+ // Reserve the Early Memory Debug Log buffer
+ //
+ // Since this memory range will be used on S3 resume, it must be
+ // reserved as ACPI NVS.
+ //
+ BuildMemoryAllocationHob (
+ (EFI_PHYSICAL_ADDRESS)(UINTN)FixedPcdGet32 (PcdOvmfEarlyMemDebugLogBase),
+ (UINT64)(UINTN)FixedPcdGet32 (PcdOvmfEarlyMemDebugLogSize),
+ PlatformInfoHob->S3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
+ );
+ }
+
#endif
}
}
diff --git a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
index c79b2ee..fe46dc0 100644
--- a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
+++ b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
@@ -107,5 +107,8 @@
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageVariableBase
gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataSize
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfEarlyMemDebugLogBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfEarlyMemDebugLogSize
+
[FeaturePcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode
diff --git a/OvmfPkg/Library/PlatformSecureLib/PlatformSecureLib.inf b/OvmfPkg/Library/PlatformSecureLib/PlatformSecureLib.inf
index db340f6..538a80d 100644
--- a/OvmfPkg/Library/PlatformSecureLib/PlatformSecureLib.inf
+++ b/OvmfPkg/Library/PlatformSecureLib/PlatformSecureLib.inf
@@ -13,7 +13,7 @@
FILE_GUID = 4204D78D-EDBF-4cee-BE80-3881457CF344
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
- LIBRARY_CLASS = PlatformSecureLib|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_DRIVER
+ LIBRARY_CLASS = PlatformSecureLib|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_DRIVER MM_STANDALONE
#
# The following information is for reference only and not required by the build tools.
diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgMmioPei.c b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgMmioPei.c
index 6f35fb4..0c00e7b 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgMmioPei.c
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgMmioPei.c
@@ -14,12 +14,11 @@
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
+#include <Library/FdtLib.h>
#include <Library/IoLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/QemuFwCfgLib.h>
-#include <libfdt.h>
-
#include "QemuFwCfgLibMmioInternal.h"
/**
@@ -120,7 +119,7 @@ QemuFwCfgInitialize (
//
// Make sure we have a valid device tree blob
//
- ASSERT (fdt_check_header (DeviceTreeBase) == 0);
+ ASSERT (FdtCheckHeader (DeviceTreeBase) == 0);
//
// Create resouce memory
@@ -129,7 +128,7 @@ QemuFwCfgInitialize (
ASSERT (FwCfgResource != NULL);
for (Prev = 0; ; Prev = Node) {
- Node = fdt_next_node (DeviceTreeBase, Prev, NULL);
+ Node = FdtNextNode (DeviceTreeBase, Prev, NULL);
if (Node < 0) {
break;
}
@@ -137,7 +136,7 @@ QemuFwCfgInitialize (
//
// Check for memory node
//
- Type = fdt_getprop (DeviceTreeBase, Node, "compatible", &Len);
+ Type = FdtGetProp (DeviceTreeBase, Node, "compatible", &Len);
if ((Type != NULL) &&
(AsciiStrnCmp (Type, "qemu,fw-cfg-mmio", Len) == 0))
{
@@ -145,7 +144,7 @@ QemuFwCfgInitialize (
// Get the 'reg' property of this node. For now, we will assume
// two 8 byte quantities for base and size, respectively.
//
- Reg = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);
+ Reg = FdtGetProp (DeviceTreeBase, Node, "reg", &Len);
if ((Reg != 0) && (Len == (2 * sizeof (UINT64)))) {
FwCfgDataAddress = SwapBytes64 (Reg[0]);
FwCfgDataSize = 8;
diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgMmioPeiLib.inf b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgMmioPeiLib.inf
index b91f106..5d6e45b 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgMmioPeiLib.inf
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgMmioPeiLib.inf
@@ -33,6 +33,7 @@
BaseLib
BaseMemoryLib
DebugLib
+ FdtLib
HobLib
IoLib
MemoryAllocationLib
diff --git a/OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c b/OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c
index 0a6f33c..6efc630 100644
--- a/OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c
+++ b/OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c
@@ -45,9 +45,8 @@ BOOLEAN mSmmCpuFeaturesSmmRelocated;
**/
EFI_STATUS
EFIAPI
-SmmCpuFeaturesLibConstructor (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
+MmCpuFeaturesLibConstructorCommon (
+ VOID
)
{
//
@@ -194,152 +193,6 @@ SmmCpuFeaturesHookReturnFromSmm (
return OriginalInstructionPointer;
}
-STATIC CPU_HOT_EJECT_DATA *mCpuHotEjectData = NULL;
-
-/**
- Initialize mCpuHotEjectData if PcdCpuMaxLogicalProcessorNumber > 1.
-
- Also setup the corresponding PcdCpuHotEjectDataAddress.
-**/
-STATIC
-VOID
-InitCpuHotEjectData (
- VOID
- )
-{
- UINTN Size;
- UINT32 Idx;
- UINT32 MaxNumberOfCpus;
- RETURN_STATUS PcdStatus;
-
- MaxNumberOfCpus = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
- if (MaxNumberOfCpus == 1) {
- return;
- }
-
- //
- // We allocate CPU_HOT_EJECT_DATA and CPU_HOT_EJECT_DATA->QemuSelectorMap[]
- // in a single allocation, and explicitly align the QemuSelectorMap[] (which
- // is a UINT64 array) at its natural boundary.
- // Accordingly, allocate:
- // sizeof(*mCpuHotEjectData) + (MaxNumberOfCpus * sizeof(UINT64))
- // and, add sizeof(UINT64) - 1 to use as padding if needed.
- //
-
- if (RETURN_ERROR (SafeUintnMult (MaxNumberOfCpus, sizeof (UINT64), &Size)) ||
- RETURN_ERROR (SafeUintnAdd (Size, sizeof (*mCpuHotEjectData), &Size)) ||
- RETURN_ERROR (SafeUintnAdd (Size, sizeof (UINT64) - 1, &Size)))
- {
- DEBUG ((DEBUG_ERROR, "%a: invalid CPU_HOT_EJECT_DATA\n", __func__));
- goto Fatal;
- }
-
- mCpuHotEjectData = AllocatePool (Size);
- if (mCpuHotEjectData == NULL) {
- ASSERT (mCpuHotEjectData != NULL);
- goto Fatal;
- }
-
- mCpuHotEjectData->Handler = NULL;
- mCpuHotEjectData->ArrayLength = MaxNumberOfCpus;
-
- mCpuHotEjectData->QemuSelectorMap = ALIGN_POINTER (
- mCpuHotEjectData + 1,
- sizeof (UINT64)
- );
- //
- // We use mCpuHotEjectData->QemuSelectorMap to map
- // ProcessorNum -> QemuSelector. Initialize to invalid values.
- //
- for (Idx = 0; Idx < mCpuHotEjectData->ArrayLength; Idx++) {
- mCpuHotEjectData->QemuSelectorMap[Idx] = CPU_EJECT_QEMU_SELECTOR_INVALID;
- }
-
- //
- // Expose address of CPU Hot eject Data structure
- //
- PcdStatus = PcdSet64S (
- PcdCpuHotEjectDataAddress,
- (UINTN)(VOID *)mCpuHotEjectData
- );
- ASSERT_RETURN_ERROR (PcdStatus);
-
- return;
-
-Fatal:
- CpuDeadLoop ();
-}
-
-/**
- Hook point in normal execution mode that allows the one CPU that was elected
- as monarch during System Management Mode initialization to perform additional
- initialization actions immediately after all of the CPUs have processed their
- first SMI and called SmmCpuFeaturesInitializeProcessor() relocating SMBASE
- into a buffer in SMRAM and called SmmCpuFeaturesHookReturnFromSmm().
-**/
-VOID
-EFIAPI
-SmmCpuFeaturesSmmRelocationComplete (
- VOID
- )
-{
- EFI_STATUS Status;
- UINTN MapPagesBase;
- UINTN MapPagesCount;
-
- InitCpuHotEjectData ();
-
- if (!MemEncryptSevIsEnabled ()) {
- return;
- }
-
- //
- // Now that SMBASE relocation is complete, re-encrypt the original SMRAM save
- // state map's container pages, and release the pages to DXE. (The pages were
- // allocated in PlatformPei.)
- //
- Status = MemEncryptSevLocateInitialSmramSaveStateMapPages (
- &MapPagesBase,
- &MapPagesCount
- );
- ASSERT_EFI_ERROR (Status);
-
- Status = MemEncryptSevSetPageEncMask (
- 0, // Cr3BaseAddress -- use current CR3
- MapPagesBase, // BaseAddress
- MapPagesCount // NumPages
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_ERROR,
- "%a: MemEncryptSevSetPageEncMask(): %r\n",
- __func__,
- Status
- ));
- ASSERT (FALSE);
- CpuDeadLoop ();
- }
-
- ZeroMem ((VOID *)MapPagesBase, EFI_PAGES_TO_SIZE (MapPagesCount));
-
- if (PcdGetBool (PcdQ35SmramAtDefaultSmbase)) {
- //
- // The initial SMRAM Save State Map has been covered as part of a larger
- // reserved memory allocation in PlatformPei's InitializeRamRegions(). That
- // allocation is supposed to survive into OS runtime; we must not release
- // any part of it. Only re-assert the containment here.
- //
- ASSERT (SMM_DEFAULT_SMBASE <= MapPagesBase);
- ASSERT (
- (MapPagesBase + EFI_PAGES_TO_SIZE (MapPagesCount) <=
- SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE)
- );
- } else {
- Status = gBS->FreePages (MapPagesBase, MapPagesCount);
- ASSERT_EFI_ERROR (Status);
- }
-}
-
/**
Return the size, in bytes, of a custom SMI Handler in bytes. If 0 is
returned, then a custom SMI handler is not provided by this library,
@@ -467,55 +320,6 @@ SmmCpuFeaturesRendezvousEntry (
}
/**
- Processor specific hook point each time a CPU exits System Management Mode.
-
- @param[in] CpuIndex The index of the CPU that is exiting SMM. The value
- must be between 0 and the NumberOfCpus field in the
- System Management System Table (SMST).
-**/
-VOID
-EFIAPI
-SmmCpuFeaturesRendezvousExit (
- IN UINTN CpuIndex
- )
-{
- //
- // We only call the Handler if CPU hot-eject is enabled
- // (PcdCpuMaxLogicalProcessorNumber > 1), and hot-eject is needed
- // in this SMI exit (otherwise mCpuHotEjectData->Handler is not armed.)
- //
-
- if (mCpuHotEjectData != NULL) {
- CPU_HOT_EJECT_HANDLER Handler;
-
- //
- // As the comment above mentions, mCpuHotEjectData->Handler might be
- // written to on the BSP as part of handling of the CPU-ejection.
- //
- // We know that any initial assignment to mCpuHotEjectData->Handler
- // (on the BSP, in the CpuHotplugMmi() context) is ordered-before the
- // load below, since it is guaranteed to happen before the
- // control-dependency of the BSP's SMI exit signal -- by way of a store
- // to AllCpusInSync (on the BSP, in BspHandler()) and the corresponding
- // AllCpusInSync loop (on the APs, in SmiRendezvous()) which depends on
- // that store.
- //
- // This guarantees that these pieces of code can never execute
- // simultaneously. In addition, we ensure that the following load is
- // ordered-after the AllCpusInSync loop by using a MemoryFence() with
- // acquire semantics.
- //
- MemoryFence ();
-
- Handler = mCpuHotEjectData->Handler;
-
- if (Handler != NULL) {
- Handler (CpuIndex);
- }
- }
-}
-
-/**
Check to see if an SMM register is supported by a specified CPU.
@param[in] CpuIndex The index of the CPU to check for SMM register support.
diff --git a/OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf b/OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
index 2697a90..13abcf0 100644
--- a/OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
+++ b/OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
@@ -19,6 +19,7 @@
[Sources]
SmmCpuFeaturesLib.c
+ TraditionalMmCpuFeaturesLib.c
[Packages]
MdePkg/MdePkg.dec
diff --git a/OvmfPkg/Library/SmmCpuFeaturesLib/StandaloneMmCpuFeaturesLib.c b/OvmfPkg/Library/SmmCpuFeaturesLib/StandaloneMmCpuFeaturesLib.c
new file mode 100644
index 0000000..9f3b54c
--- /dev/null
+++ b/OvmfPkg/Library/SmmCpuFeaturesLib/StandaloneMmCpuFeaturesLib.c
@@ -0,0 +1,75 @@
+/** @file
+ The CPU specific programming for Standalone MM environment.
+
+ Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) Microsoft Corporation.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <PiMm.h>
+#include <Library/SmmCpuFeaturesLib.h>
+#include <Library/MmServicesTableLib.h>
+
+/**
+ The common constructor function
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+MmCpuFeaturesLibConstructorCommon (
+ VOID
+ );
+
+/**
+ Hook point in normal execution mode that allows the one CPU that was elected
+ as monarch during System Management Mode initialization to perform additional
+ initialization actions immediately after all of the CPUs have processed their
+ first SMI and called SmmCpuFeaturesInitializeProcessor() relocating SMBASE
+ into a buffer in SMRAM and called SmmCpuFeaturesHookReturnFromSmm().
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesSmmRelocationComplete (
+ VOID
+ )
+{
+ // Do nothing for Standalone MM instance.
+}
+
+/**
+ Processor specific hook point each time a CPU exits System Management Mode.
+
+ @param[in] CpuIndex The index of the CPU that is exiting SMM. The value
+ must be between 0 and the NumberOfCpus field in the
+ System Management System Table (SMST).
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesRendezvousExit (
+ IN UINTN CpuIndex
+ )
+{
+ // Do nothing for Standalone MM instance.
+}
+
+/**
+ The constructor function
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+StandalonMmCpuFeaturesLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_MM_SYSTEM_TABLE *SystemTable
+ )
+{
+ return MmCpuFeaturesLibConstructorCommon ();
+}
diff --git a/OvmfPkg/Library/SmmCpuFeaturesLib/StandaloneMmCpuFeaturesLib.inf b/OvmfPkg/Library/SmmCpuFeaturesLib/StandaloneMmCpuFeaturesLib.inf
new file mode 100644
index 0000000..ae7396a
--- /dev/null
+++ b/OvmfPkg/Library/SmmCpuFeaturesLib/StandaloneMmCpuFeaturesLib.inf
@@ -0,0 +1,42 @@
+## @file
+# The CPU specific programming for Standalone MM environment.
+#
+# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) Microsoft Corporation.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = StandaloneMmCpuFeaturesLib
+ MODULE_UNI_FILE = StandaloneMmCpuFeaturesLib.uni
+ FILE_GUID = 74B868F6-7DC6-4CDE-86B1-27E9A7CEBFCC
+ MODULE_TYPE = MM_STANDALONE
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x00010032
+ LIBRARY_CLASS = SmmCpuFeaturesLib
+ CONSTRUCTOR = StandalonMmCpuFeaturesLibConstructor
+
+[Sources]
+ SmmCpuFeaturesLib.c
+ StandaloneMmCpuFeaturesLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemEncryptSevLib
+ PcdLib
+
+[Guids]
+ gSmmBaseHobGuid ## CONSUMES
+
+[Pcd]
+ gUefiOvmfPkgTokenSpaceGuid.PcdQ35SmramAtDefaultSmbase
diff --git a/OvmfPkg/Library/SmmCpuFeaturesLib/TraditionalMmCpuFeaturesLib.c b/OvmfPkg/Library/SmmCpuFeaturesLib/TraditionalMmCpuFeaturesLib.c
new file mode 100644
index 0000000..7552b29
--- /dev/null
+++ b/OvmfPkg/Library/SmmCpuFeaturesLib/TraditionalMmCpuFeaturesLib.c
@@ -0,0 +1,248 @@
+/** @file
+ The CPU specific programming for PiSmmCpuDxeSmm module.
+
+ Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) Microsoft Corporation.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <IndustryStandard/Q35MchIch9.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemEncryptSevLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/SafeIntLib.h>
+#include <Library/SmmCpuFeaturesLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Pcd/CpuHotEjectData.h>
+#include <PiSmm.h>
+
+STATIC CPU_HOT_EJECT_DATA *mCpuHotEjectData = NULL;
+
+/**
+ The common constructor function
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+MmCpuFeaturesLibConstructorCommon (
+ VOID
+ );
+
+/**
+ Initialize mCpuHotEjectData if PcdCpuMaxLogicalProcessorNumber > 1.
+
+ Also setup the corresponding PcdCpuHotEjectDataAddress.
+**/
+STATIC
+VOID
+InitCpuHotEjectData (
+ VOID
+ )
+{
+ UINTN Size;
+ UINT32 Idx;
+ UINT32 MaxNumberOfCpus;
+ RETURN_STATUS PcdStatus;
+
+ MaxNumberOfCpus = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
+ if (MaxNumberOfCpus == 1) {
+ return;
+ }
+
+ //
+ // We allocate CPU_HOT_EJECT_DATA and CPU_HOT_EJECT_DATA->QemuSelectorMap[]
+ // in a single allocation, and explicitly align the QemuSelectorMap[] (which
+ // is a UINT64 array) at its natural boundary.
+ // Accordingly, allocate:
+ // sizeof(*mCpuHotEjectData) + (MaxNumberOfCpus * sizeof(UINT64))
+ // and, add sizeof(UINT64) - 1 to use as padding if needed.
+ //
+
+ if (RETURN_ERROR (SafeUintnMult (MaxNumberOfCpus, sizeof (UINT64), &Size)) ||
+ RETURN_ERROR (SafeUintnAdd (Size, sizeof (*mCpuHotEjectData), &Size)) ||
+ RETURN_ERROR (SafeUintnAdd (Size, sizeof (UINT64) - 1, &Size)))
+ {
+ DEBUG ((DEBUG_ERROR, "%a: invalid CPU_HOT_EJECT_DATA\n", __func__));
+ goto Fatal;
+ }
+
+ mCpuHotEjectData = AllocatePool (Size);
+ if (mCpuHotEjectData == NULL) {
+ ASSERT (mCpuHotEjectData != NULL);
+ goto Fatal;
+ }
+
+ mCpuHotEjectData->Handler = NULL;
+ mCpuHotEjectData->ArrayLength = MaxNumberOfCpus;
+
+ mCpuHotEjectData->QemuSelectorMap = ALIGN_POINTER (
+ mCpuHotEjectData + 1,
+ sizeof (UINT64)
+ );
+ //
+ // We use mCpuHotEjectData->QemuSelectorMap to map
+ // ProcessorNum -> QemuSelector. Initialize to invalid values.
+ //
+ for (Idx = 0; Idx < mCpuHotEjectData->ArrayLength; Idx++) {
+ mCpuHotEjectData->QemuSelectorMap[Idx] = CPU_EJECT_QEMU_SELECTOR_INVALID;
+ }
+
+ //
+ // Expose address of CPU Hot eject Data structure
+ //
+ PcdStatus = PcdSet64S (
+ PcdCpuHotEjectDataAddress,
+ (UINTN)(VOID *)mCpuHotEjectData
+ );
+ ASSERT_RETURN_ERROR (PcdStatus);
+
+ return;
+
+Fatal:
+ CpuDeadLoop ();
+}
+
+/**
+ Hook point in normal execution mode that allows the one CPU that was elected
+ as monarch during System Management Mode initialization to perform additional
+ initialization actions immediately after all of the CPUs have processed their
+ first SMI and called SmmCpuFeaturesInitializeProcessor() relocating SMBASE
+ into a buffer in SMRAM and called SmmCpuFeaturesHookReturnFromSmm().
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesSmmRelocationComplete (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN MapPagesBase;
+ UINTN MapPagesCount;
+
+ InitCpuHotEjectData ();
+
+ if (!MemEncryptSevIsEnabled ()) {
+ return;
+ }
+
+ //
+ // Now that SMBASE relocation is complete, re-encrypt the original SMRAM save
+ // state map's container pages, and release the pages to DXE. (The pages were
+ // allocated in PlatformPei.)
+ //
+ Status = MemEncryptSevLocateInitialSmramSaveStateMapPages (
+ &MapPagesBase,
+ &MapPagesCount
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = MemEncryptSevSetPageEncMask (
+ 0, // Cr3BaseAddress -- use current CR3
+ MapPagesBase, // BaseAddress
+ MapPagesCount // NumPages
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: MemEncryptSevSetPageEncMask(): %r\n",
+ __func__,
+ Status
+ ));
+ ASSERT (FALSE);
+ CpuDeadLoop ();
+ }
+
+ ZeroMem ((VOID *)MapPagesBase, EFI_PAGES_TO_SIZE (MapPagesCount));
+
+ if (PcdGetBool (PcdQ35SmramAtDefaultSmbase)) {
+ //
+ // The initial SMRAM Save State Map has been covered as part of a larger
+ // reserved memory allocation in PlatformPei's InitializeRamRegions(). That
+ // allocation is supposed to survive into OS runtime; we must not release
+ // any part of it. Only re-assert the containment here.
+ //
+ ASSERT (SMM_DEFAULT_SMBASE <= MapPagesBase);
+ ASSERT (
+ (MapPagesBase + EFI_PAGES_TO_SIZE (MapPagesCount) <=
+ SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE)
+ );
+ } else {
+ Status = gBS->FreePages (MapPagesBase, MapPagesCount);
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
+/**
+ Processor specific hook point each time a CPU exits System Management Mode.
+
+ @param[in] CpuIndex The index of the CPU that is exiting SMM. The value
+ must be between 0 and the NumberOfCpus field in the
+ System Management System Table (SMST).
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesRendezvousExit (
+ IN UINTN CpuIndex
+ )
+{
+ //
+ // We only call the Handler if CPU hot-eject is enabled
+ // (PcdCpuMaxLogicalProcessorNumber > 1), and hot-eject is needed
+ // in this SMI exit (otherwise mCpuHotEjectData->Handler is not armed.)
+ //
+
+ if (mCpuHotEjectData != NULL) {
+ CPU_HOT_EJECT_HANDLER Handler;
+
+ //
+ // As the comment above mentions, mCpuHotEjectData->Handler might be
+ // written to on the BSP as part of handling of the CPU-ejection.
+ //
+ // We know that any initial assignment to mCpuHotEjectData->Handler
+ // (on the BSP, in the CpuHotplugMmi() context) is ordered-before the
+ // load below, since it is guaranteed to happen before the
+ // control-dependency of the BSP's SMI exit signal -- by way of a store
+ // to AllCpusInSync (on the BSP, in BspHandler()) and the corresponding
+ // AllCpusInSync loop (on the APs, in SmiRendezvous()) which depends on
+ // that store.
+ //
+ // This guarantees that these pieces of code can never execute
+ // simultaneously. In addition, we ensure that the following load is
+ // ordered-after the AllCpusInSync loop by using a MemoryFence() with
+ // acquire semantics.
+ //
+ MemoryFence ();
+
+ Handler = mCpuHotEjectData->Handler;
+
+ if (Handler != NULL) {
+ Handler (CpuIndex);
+ }
+ }
+}
+
+/**
+ The constructor function
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuFeaturesLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return MmCpuFeaturesLibConstructorCommon ();
+}
diff --git a/OvmfPkg/Library/SmmRelocationLib/SmmRelocationLib.c b/OvmfPkg/Library/SmmRelocationLib/SmmRelocationLib.c
index 7e65bbf..4f6b513 100644
--- a/OvmfPkg/Library/SmmRelocationLib/SmmRelocationLib.c
+++ b/OvmfPkg/Library/SmmRelocationLib/SmmRelocationLib.c
@@ -166,9 +166,9 @@ SmmInitHandler (
**/
VOID
SmmRelocateBases (
- IN EDKII_PEI_MP_SERVICES2_PPI *MpServices2,
- IN EFI_PHYSICAL_ADDRESS SmmRelocationStart,
- IN UINTN TileSize
+ IN EFI_PEI_MP_SERVICES2_PPI *MpServices2,
+ IN EFI_PHYSICAL_ADDRESS SmmRelocationStart,
+ IN UINTN TileSize
)
{
EFI_STATUS Status;
@@ -424,7 +424,7 @@ SplitSmramHobForSmmRelocation (
EFI_STATUS
EFIAPI
SmmRelocationInit (
- IN EDKII_PEI_MP_SERVICES2_PPI *MpServices2
+ IN EFI_PEI_MP_SERVICES2_PPI *MpServices2
)
{
EFI_STATUS Status;
diff --git a/OvmfPkg/Library/VirtNorFlashDeviceLib/VirtNorFlashDeviceLib.c b/OvmfPkg/Library/VirtNorFlashDeviceLib/VirtNorFlashDeviceLib.c
new file mode 100644
index 0000000..731af75
--- /dev/null
+++ b/OvmfPkg/Library/VirtNorFlashDeviceLib/VirtNorFlashDeviceLib.c
@@ -0,0 +1,964 @@
+/** @file VirtNorFlashDeviceLib.c
+
+ Copyright (c) 2011 - 2020, Arm Limited. All rights reserved.<BR>
+ Copyright (c) 2020, Linaro, Ltd. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <PiDxe.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/VirtNorFlashDeviceLib.h>
+
+#define NOR_FLASH_ERASE_RETRY 10
+
+// Device access macros
+// These are necessary because we use 2 x 16bit parts to make up 32bit data
+
+#define HIGH_16_BITS 0xFFFF0000
+#define LOW_16_BITS 0x0000FFFF
+#define LOW_8_BITS 0x000000FF
+
+#define FOLD_32BIT_INTO_16BIT(value) ( ( value >> 16 ) | ( value & LOW_16_BITS ) )
+
+#define GET_LOW_BYTE(value) ( value & LOW_8_BITS )
+#define GET_HIGH_BYTE(value) ( GET_LOW_BYTE( value >> 16 ) )
+
+// Status Register Bits
+#define P30_SR_BIT_WRITE (BIT7 << 16 | BIT7)
+#define P30_SR_BIT_ERASE_SUSPEND (BIT6 << 16 | BIT6)
+#define P30_SR_BIT_ERASE (BIT5 << 16 | BIT5)
+#define P30_SR_BIT_PROGRAM (BIT4 << 16 | BIT4)
+#define P30_SR_BIT_VPP (BIT3 << 16 | BIT3)
+#define P30_SR_BIT_PROGRAM_SUSPEND (BIT2 << 16 | BIT2)
+#define P30_SR_BIT_BLOCK_LOCKED (BIT1 << 16 | BIT1)
+#define P30_SR_BIT_BEFP (BIT0 << 16 | BIT0)
+
+// Device Commands for Intel StrataFlash(R) Embedded Memory (P30) Family
+
+// On chip buffer size for buffered programming operations
+// There are 2 chips, each chip can buffer up to 32 (16-bit)words, and each word is 2 bytes.
+// Therefore the total size of the buffer is 2 x 32 x 2 = 128 bytes
+#define P30_MAX_BUFFER_SIZE_IN_BYTES ((UINTN)128)
+#define P30_MAX_BUFFER_SIZE_IN_WORDS (P30_MAX_BUFFER_SIZE_IN_BYTES/((UINTN)4))
+#define MAX_BUFFERED_PROG_ITERATIONS 10000000
+#define BOUNDARY_OF_32_WORDS ((UINTN)0x7F)
+
+// CFI Addresses
+#define P30_CFI_ADDR_QUERY_UNIQUE_QRY 0x10
+#define P30_CFI_ADDR_VENDOR_ID 0x13
+
+// CFI Data
+#define CFI_QRY 0x00595251
+
+// READ Commands
+#define P30_CMD_READ_DEVICE_ID 0x0090
+#define P30_CMD_READ_STATUS_REGISTER 0x0070
+#define P30_CMD_CLEAR_STATUS_REGISTER 0x0050
+#define P30_CMD_READ_ARRAY 0x00FF
+#define P30_CMD_READ_CFI_QUERY 0x0098
+
+// WRITE Commands
+#define P30_CMD_WORD_PROGRAM_SETUP 0x0040
+#define P30_CMD_ALTERNATE_WORD_PROGRAM_SETUP 0x0010
+#define P30_CMD_BUFFERED_PROGRAM_SETUP 0x00E8
+#define P30_CMD_BUFFERED_PROGRAM_CONFIRM 0x00D0
+#define P30_CMD_BEFP_SETUP 0x0080
+#define P30_CMD_BEFP_CONFIRM 0x00D0
+
+// ERASE Commands
+#define P30_CMD_BLOCK_ERASE_SETUP 0x0020
+#define P30_CMD_BLOCK_ERASE_CONFIRM 0x00D0
+
+// SUSPEND Commands
+#define P30_CMD_PROGRAM_OR_ERASE_SUSPEND 0x00B0
+#define P30_CMD_SUSPEND_RESUME 0x00D0
+
+// BLOCK LOCKING / UNLOCKING Commands
+#define P30_CMD_LOCK_BLOCK_SETUP 0x0060
+#define P30_CMD_LOCK_BLOCK 0x0001
+#define P30_CMD_UNLOCK_BLOCK 0x00D0
+#define P30_CMD_LOCK_DOWN_BLOCK 0x002F
+
+// PROTECTION Commands
+#define P30_CMD_PROGRAM_PROTECTION_REGISTER_SETUP 0x00C0
+
+// CONFIGURATION Commands
+#define P30_CMD_READ_CONFIGURATION_REGISTER_SETUP 0x0060
+#define P30_CMD_READ_CONFIGURATION_REGISTER 0x0003
+
+STATIC
+UINT32
+NorFlashReadStatusRegister (
+ IN UINTN DeviceBaseAddress,
+ IN UINTN SR_Address
+ )
+{
+ // Prepare to read the status register
+ SEND_NOR_COMMAND (DeviceBaseAddress, 0, P30_CMD_READ_STATUS_REGISTER);
+ return MmioRead32 (DeviceBaseAddress);
+}
+
+STATIC
+BOOLEAN
+NorFlashBlockIsLocked (
+ IN UINTN DeviceBaseAddress,
+ IN UINTN BlockAddress
+ )
+{
+ UINT32 LockStatus;
+
+ // Send command for reading device id
+ SEND_NOR_COMMAND (BlockAddress, 2, P30_CMD_READ_DEVICE_ID);
+
+ // Read block lock status
+ LockStatus = MmioRead32 (CREATE_NOR_ADDRESS (BlockAddress, 2));
+
+ // Decode block lock status
+ LockStatus = FOLD_32BIT_INTO_16BIT (LockStatus);
+
+ if ((LockStatus & 0x2) != 0) {
+ DEBUG ((DEBUG_ERROR, "NorFlashBlockIsLocked: WARNING: Block LOCKED DOWN\n"));
+ }
+
+ return ((LockStatus & 0x1) != 0);
+}
+
+STATIC
+EFI_STATUS
+NorFlashUnlockSingleBlock (
+ IN UINTN DeviceBaseAddress,
+ IN UINTN BlockAddress
+ )
+{
+ UINT32 LockStatus;
+
+ // Raise the Task Priority Level to TPL_NOTIFY to serialise all its operations
+ // and to protect shared data structures.
+
+ // Request a lock setup
+ SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_LOCK_BLOCK_SETUP);
+
+ // Request an unlock
+ SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_UNLOCK_BLOCK);
+
+ // Wait until the status register gives us the all clear
+ do {
+ LockStatus = NorFlashReadStatusRegister (DeviceBaseAddress, BlockAddress);
+ } while ((LockStatus & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
+
+ // Put device back into Read Array mode
+ SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_READ_ARRAY);
+
+ DEBUG ((DEBUG_BLKIO, "UnlockSingleBlock: BlockAddress=0x%08x\n", BlockAddress));
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+NorFlashUnlockSingleBlockIfNecessary (
+ IN UINTN DeviceBaseAddress,
+ IN UINTN BlockAddress
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ if (NorFlashBlockIsLocked (DeviceBaseAddress, BlockAddress)) {
+ Status = NorFlashUnlockSingleBlock (DeviceBaseAddress, BlockAddress);
+ }
+
+ return Status;
+}
+
+/**
+ * The following function presumes that the block has already been unlocked.
+ **/
+EFI_STATUS
+EFIAPI
+NorFlashEraseSingleBlock (
+ IN UINTN DeviceBaseAddress,
+ IN UINTN BlockAddress
+ )
+{
+ EFI_STATUS Status;
+ UINT32 StatusRegister;
+
+ Status = EFI_SUCCESS;
+
+ // Request a block erase and then confirm it
+ SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_BLOCK_ERASE_SETUP);
+ SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_BLOCK_ERASE_CONFIRM);
+
+ // Wait until the status register gives us the all clear
+ do {
+ StatusRegister = NorFlashReadStatusRegister (DeviceBaseAddress, BlockAddress);
+ } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
+
+ if (StatusRegister & P30_SR_BIT_VPP) {
+ DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=0x%08x: VPP Range Error\n", BlockAddress));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if ((StatusRegister & (P30_SR_BIT_ERASE | P30_SR_BIT_PROGRAM)) == (P30_SR_BIT_ERASE | P30_SR_BIT_PROGRAM)) {
+ DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=0x%08x: Command Sequence Error\n", BlockAddress));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (StatusRegister & P30_SR_BIT_ERASE) {
+ DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=0x%08x: Block Erase Error StatusRegister:0x%X\n", BlockAddress, StatusRegister));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {
+ // The debug level message has been reduced because a device lock might happen. In this case we just retry it ...
+ DEBUG ((DEBUG_INFO, "EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error\n", BlockAddress));
+ Status = EFI_WRITE_PROTECTED;
+ }
+
+ if (EFI_ERROR (Status)) {
+ // Clear the Status Register
+ SEND_NOR_COMMAND (DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
+ }
+
+ // Put device back into Read Array mode
+ SEND_NOR_COMMAND (DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+NorFlashWriteSingleWord (
+ IN UINTN DeviceBaseAddress,
+ IN UINTN WordAddress,
+ IN UINT32 WriteData
+ )
+{
+ EFI_STATUS Status;
+ UINT32 StatusRegister;
+
+ Status = EFI_SUCCESS;
+
+ // Request a write single word command
+ SEND_NOR_COMMAND (WordAddress, 0, P30_CMD_WORD_PROGRAM_SETUP);
+
+ // Store the word into NOR Flash;
+ MmioWrite32 (WordAddress, WriteData);
+
+ // Wait for the write to complete and then check for any errors; i.e. check the Status Register
+ do {
+ // Prepare to read the status register
+ StatusRegister = NorFlashReadStatusRegister (DeviceBaseAddress, WordAddress);
+ // The chip is busy while the WRITE bit is not asserted
+ } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
+
+ // Perform a full status check:
+ // Mask the relevant bits of Status Register.
+ // Everything should be zero, if not, we have a problem
+
+ if (StatusRegister & P30_SR_BIT_VPP) {
+ DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleWord(WordAddress:0x%X): VPP Range Error\n", WordAddress));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (StatusRegister & P30_SR_BIT_PROGRAM) {
+ DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleWord(WordAddress:0x%X): Program Error\n", WordAddress));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {
+ DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleWord(WordAddress:0x%X): Device Protect Error\n", WordAddress));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ // Clear the Status Register
+ SEND_NOR_COMMAND (DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
+ }
+
+ return Status;
+}
+
+/*
+ * Writes data to the NOR Flash using the Buffered Programming method.
+ *
+ * The maximum size of the on-chip buffer is 32-words, because of hardware restrictions.
+ * Therefore this function will only handle buffers up to 32 words or 128 bytes.
+ * To deal with larger buffers, call this function again.
+ *
+ * This function presumes that both the TargetAddress and the TargetAddress+BufferSize
+ * exist entirely within the NOR Flash. Therefore these conditions will not be checked here.
+ *
+ * In buffered programming, if the target address not at the beginning of a 32-bit word boundary,
+ * then programming time is doubled and power consumption is increased.
+ * Therefore, it is a requirement to align buffer writes to 32-bit word boundaries.
+ * i.e. the last 4 bits of the target start address must be zero: 0x......00
+ */
+EFI_STATUS
+EFIAPI
+NorFlashWriteBuffer (
+ IN UINTN DeviceBaseAddress,
+ IN UINTN TargetAddress,
+ IN UINTN BufferSizeInBytes,
+ IN UINT32 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSizeInWords;
+ UINTN Count;
+ volatile UINT32 *Data;
+ UINTN WaitForBuffer;
+ BOOLEAN BufferAvailable;
+ UINT32 StatusRegister;
+
+ WaitForBuffer = MAX_BUFFERED_PROG_ITERATIONS;
+ BufferAvailable = FALSE;
+
+ // Check that the target address does not cross a 32-word boundary.
+ if ((TargetAddress & BOUNDARY_OF_32_WORDS) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Check there are some data to program
+ if (BufferSizeInBytes == 0) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ // Check that the buffer size does not exceed the maximum hardware buffer size on chip.
+ if (BufferSizeInBytes > P30_MAX_BUFFER_SIZE_IN_BYTES) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ // Check that the buffer size is a multiple of 32-bit words
+ if ((BufferSizeInBytes % 4) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ // Pre-programming conditions checked, now start the algorithm.
+
+ // Prepare the data destination address
+ Data = (UINT32 *)TargetAddress;
+
+ // Check the availability of the buffer
+ do {
+ // Issue the Buffered Program Setup command
+ SEND_NOR_COMMAND (TargetAddress, 0, P30_CMD_BUFFERED_PROGRAM_SETUP);
+
+ // Read back the status register bit#7 from the same address
+ if (((*Data) & P30_SR_BIT_WRITE) == P30_SR_BIT_WRITE) {
+ BufferAvailable = TRUE;
+ }
+
+ // Update the loop counter
+ WaitForBuffer--;
+ } while ((WaitForBuffer > 0) && (BufferAvailable == FALSE));
+
+ // The buffer was not available for writing
+ if (WaitForBuffer == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ // From now on we work in 32-bit words
+ BufferSizeInWords = BufferSizeInBytes / (UINTN)4;
+
+ // Write the word count, which is (buffer_size_in_words - 1),
+ // because word count 0 means one word.
+ SEND_NOR_COMMAND (TargetAddress, 0, (BufferSizeInWords - 1));
+
+ // Write the data to the NOR Flash, advancing each address by 4 bytes
+ for (Count = 0; Count < BufferSizeInWords; Count++, Data++, Buffer++) {
+ MmioWrite32 ((UINTN)Data, *Buffer);
+ }
+
+ // Issue the Buffered Program Confirm command, to start the programming operation
+ SEND_NOR_COMMAND (DeviceBaseAddress, 0, P30_CMD_BUFFERED_PROGRAM_CONFIRM);
+
+ // Wait for the write to complete and then check for any errors; i.e. check the Status Register
+ do {
+ StatusRegister = NorFlashReadStatusRegister (DeviceBaseAddress, TargetAddress);
+ // The chip is busy while the WRITE bit is not asserted
+ } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
+
+ // Perform a full status check:
+ // Mask the relevant bits of Status Register.
+ // Everything should be zero, if not, we have a problem
+
+ Status = EFI_SUCCESS;
+
+ if (StatusRegister & P30_SR_BIT_VPP) {
+ DEBUG ((DEBUG_ERROR, "NorFlashWriteBuffer(TargetAddress:0x%X): VPP Range Error\n", TargetAddress));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (StatusRegister & P30_SR_BIT_PROGRAM) {
+ DEBUG ((DEBUG_ERROR, "NorFlashWriteBuffer(TargetAddress:0x%X): Program Error\n", TargetAddress));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {
+ DEBUG ((DEBUG_ERROR, "NorFlashWriteBuffer(TargetAddress:0x%X): Device Protect Error\n", TargetAddress));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ // Clear the Status Register
+ SEND_NOR_COMMAND (DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
+ }
+
+ return Status;
+}
+
+/**
+ * This function unlock and erase an entire NOR Flash block.
+ **/
+EFI_STATUS
+NorFlashUnlockAndEraseSingleBlock (
+ IN UINTN DeviceBaseAddress,
+ IN UINTN BlockAddress
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+
+ Index = 0;
+ // The block erase might fail a first time (SW bug ?). Retry it ...
+ do {
+ // Unlock the block if we have to
+ Status = NorFlashUnlockSingleBlockIfNecessary (DeviceBaseAddress, BlockAddress);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ Status = NorFlashEraseSingleBlock (DeviceBaseAddress, BlockAddress);
+ Index++;
+ } while ((Index < NOR_FLASH_ERASE_RETRY) && (Status == EFI_WRITE_PROTECTED));
+
+ if (Index == NOR_FLASH_ERASE_RETRY) {
+ DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n", BlockAddress, Index));
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+NorFlashWriteFullBlock (
+ IN UINTN DeviceBaseAddress,
+ IN UINTN RegionBaseAddress,
+ IN EFI_LBA Lba,
+ IN UINT32 *DataBuffer,
+ IN UINT32 BlockSizeInWords
+ )
+{
+ EFI_STATUS Status;
+ UINTN WordAddress;
+ UINT32 WordIndex;
+ UINTN BufferIndex;
+ UINTN BlockAddress;
+ UINTN BuffersInBlock;
+ UINTN RemainingWords;
+ UINTN Cnt;
+
+ Status = EFI_SUCCESS;
+
+ // Get the physical address of the block
+ BlockAddress = GET_NOR_BLOCK_ADDRESS (RegionBaseAddress, Lba, BlockSizeInWords * 4);
+
+ // Start writing from the first address at the start of the block
+ WordAddress = BlockAddress;
+ Status = NorFlashUnlockAndEraseSingleBlock (DeviceBaseAddress, BlockAddress);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n", BlockAddress));
+ goto EXIT;
+ }
+
+ // To speed up the programming operation, NOR Flash is programmed using the Buffered Programming method.
+
+ // Check that the address starts at a 32-word boundary, i.e. last 7 bits must be zero
+ if ((WordAddress & BOUNDARY_OF_32_WORDS) == 0x00) {
+ // First, break the entire block into buffer-sized chunks.
+ BuffersInBlock = (UINTN)(BlockSizeInWords * 4) / P30_MAX_BUFFER_SIZE_IN_BYTES;
+
+ // Then feed each buffer chunk to the NOR Flash
+ // If a buffer does not contain any data, don't write it.
+ for (BufferIndex = 0;
+ BufferIndex < BuffersInBlock;
+ BufferIndex++, WordAddress += P30_MAX_BUFFER_SIZE_IN_BYTES, DataBuffer += P30_MAX_BUFFER_SIZE_IN_WORDS
+ )
+ {
+ // Check the buffer to see if it contains any data (not set all 1s).
+ for (Cnt = 0; Cnt < P30_MAX_BUFFER_SIZE_IN_WORDS; Cnt++) {
+ if (~DataBuffer[Cnt] != 0 ) {
+ // Some data found, write the buffer.
+ Status = NorFlashWriteBuffer (
+ DeviceBaseAddress,
+ WordAddress,
+ P30_MAX_BUFFER_SIZE_IN_BYTES,
+ DataBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ break;
+ }
+ }
+ }
+
+ // Finally, finish off any remaining words that are less than the maximum size of the buffer
+ RemainingWords = BlockSizeInWords % P30_MAX_BUFFER_SIZE_IN_WORDS;
+
+ if (RemainingWords != 0) {
+ Status = NorFlashWriteBuffer (DeviceBaseAddress, WordAddress, (RemainingWords * 4), DataBuffer);
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+ }
+ } else {
+ // For now, use the single word programming algorithm
+ // It is unlikely that the NOR Flash will exist in an address which falls within a 32 word boundary range,
+ // i.e. which ends in the range 0x......01 - 0x......7F.
+ for (WordIndex = 0; WordIndex < BlockSizeInWords; WordIndex++, DataBuffer++, WordAddress = WordAddress + 4) {
+ Status = NorFlashWriteSingleWord (DeviceBaseAddress, WordAddress, *DataBuffer);
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+ }
+ }
+
+EXIT:
+ // Put device back into Read Array mode
+ SEND_NOR_COMMAND (DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = \"%r\".\n", WordAddress, Status));
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+NorFlashWriteBlocks (
+ IN UINTN DeviceBaseAddress,
+ IN UINTN RegionBaseAddress,
+ IN EFI_LBA Lba,
+ IN EFI_LBA LastBlock,
+ IN UINT32 BlockSize,
+ IN UINTN BufferSizeInBytes,
+ IN VOID *Buffer
+ )
+{
+ UINT32 *pWriteBuffer;
+ EFI_STATUS Status;
+ EFI_LBA CurrentBlock;
+ UINT32 BlockSizeInWords;
+ UINT32 NumBlocks;
+ UINT32 BlockCount;
+
+ Status = EFI_SUCCESS;
+
+ // The buffer must be valid
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // We must have some bytes to read
+ DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n", BufferSizeInBytes));
+ if (BufferSizeInBytes == 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ // The size of the buffer must be a multiple of the block size
+ DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n", BlockSize));
+ if ((BufferSizeInBytes % BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ // All blocks must be within the device
+ NumBlocks = ((UINT32)BufferSizeInBytes) / BlockSize;
+
+ DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n", NumBlocks, LastBlock, Lba));
+
+ if ((Lba + NumBlocks) > (LastBlock + 1)) {
+ DEBUG ((DEBUG_ERROR, "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BlockSizeInWords = BlockSize / 4;
+
+ // Because the target *Buffer is a pointer to VOID, we must put all the data into a pointer
+ // to a proper data type, so use *ReadBuffer
+ pWriteBuffer = (UINT32 *)Buffer;
+
+ CurrentBlock = Lba;
+ for (BlockCount = 0; BlockCount < NumBlocks; BlockCount++, CurrentBlock++, pWriteBuffer = pWriteBuffer + BlockSizeInWords) {
+ DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: Writing block #%d\n", (UINTN)CurrentBlock));
+
+ Status = NorFlashWriteFullBlock (
+ DeviceBaseAddress,
+ RegionBaseAddress,
+ CurrentBlock,
+ pWriteBuffer,
+ BlockSizeInWords
+ );
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: Exit Status = \"%r\".\n", Status));
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+NorFlashReadBlocks (
+ IN UINTN DeviceBaseAddress,
+ IN UINTN RegionBaseAddress,
+ IN EFI_LBA Lba,
+ IN EFI_LBA LastBlock,
+ IN UINT32 BlockSize,
+ IN UINTN BufferSizeInBytes,
+ OUT VOID *Buffer
+ )
+{
+ UINT32 NumBlocks;
+ UINTN StartAddress;
+
+ DEBUG ((
+ DEBUG_BLKIO,
+ "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n",
+ BufferSizeInBytes,
+ BlockSize,
+ LastBlock,
+ Lba
+ ));
+
+ // The buffer must be valid
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Return if we have not any byte to read
+ if (BufferSizeInBytes == 0) {
+ return EFI_SUCCESS;
+ }
+
+ // The size of the buffer must be a multiple of the block size
+ if ((BufferSizeInBytes % BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ // All blocks must be within the device
+ NumBlocks = ((UINT32)BufferSizeInBytes) / BlockSize;
+
+ if ((Lba + NumBlocks) > (LastBlock + 1)) {
+ DEBUG ((DEBUG_ERROR, "NorFlashReadBlocks: ERROR - Read will exceed last block\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Get the address to start reading from
+ StartAddress = GET_NOR_BLOCK_ADDRESS (
+ RegionBaseAddress,
+ Lba,
+ BlockSize
+ );
+
+ // Put the device into Read Array mode
+ SEND_NOR_COMMAND (DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
+
+ // Readout the data
+ CopyMem (Buffer, (VOID *)StartAddress, BufferSizeInBytes);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+NorFlashRead (
+ IN UINTN DeviceBaseAddress,
+ IN UINTN RegionBaseAddress,
+ IN EFI_LBA Lba,
+ IN UINT32 BlockSize,
+ IN UINTN Size,
+ IN UINTN Offset,
+ IN UINTN BufferSizeInBytes,
+ OUT VOID *Buffer
+ )
+{
+ UINTN StartAddress;
+
+ // The buffer must be valid
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Return if we have not any byte to read
+ if (BufferSizeInBytes == 0) {
+ return EFI_SUCCESS;
+ }
+
+ if (((Lba * BlockSize) + Offset + BufferSizeInBytes) > Size) {
+ DEBUG ((DEBUG_ERROR, "NorFlashRead: ERROR - Read will exceed device size.\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Get the address to start reading from
+ StartAddress = GET_NOR_BLOCK_ADDRESS (
+ RegionBaseAddress,
+ Lba,
+ BlockSize
+ );
+
+ // Put the device into Read Array mode
+ SEND_NOR_COMMAND (DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
+
+ // Readout the data
+ CopyMem (Buffer, (VOID *)(StartAddress + Offset), BufferSizeInBytes);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+NorFlashWriteSingleBlockWithErase (
+ IN UINTN DeviceBaseAddress,
+ IN UINTN RegionBaseAddress,
+ IN EFI_LBA Lba,
+ IN UINT32 LastBlock,
+ IN UINT32 BlockSize,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer,
+ IN VOID *ShadowBuffer
+ )
+{
+ EFI_STATUS Status;
+
+ // Read NOR Flash data into shadow buffer
+ Status = NorFlashReadBlocks (
+ DeviceBaseAddress,
+ RegionBaseAddress,
+ Lba,
+ LastBlock,
+ BlockSize,
+ BlockSize,
+ ShadowBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ // Return one of the pre-approved error statuses
+ return EFI_DEVICE_ERROR;
+ }
+
+ // Put the data at the appropriate location inside the buffer area
+ CopyMem ((VOID *)((UINTN)ShadowBuffer + Offset), Buffer, *NumBytes);
+
+ // Write the modified buffer back to the NorFlash
+ Status = NorFlashWriteBlocks (
+ DeviceBaseAddress,
+ RegionBaseAddress,
+ Lba,
+ LastBlock,
+ BlockSize,
+ BlockSize,
+ ShadowBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ // Return one of the pre-approved error statuses
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/*
+ Write a full or portion of a block. It must not span block boundaries; that is,
+ Offset + *NumBytes <= Instance->BlockSize.
+*/
+EFI_STATUS
+EFIAPI
+NorFlashWriteSingleBlock (
+ IN UINTN DeviceBaseAddress,
+ IN UINTN RegionBaseAddress,
+ IN EFI_LBA Lba,
+ IN UINT32 LastBlock,
+ IN UINT32 BlockSize,
+ IN UINTN Size,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer,
+ IN VOID *ShadowBuffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN CurOffset;
+ UINTN BlockAddress;
+ UINT8 *OrigData;
+ UINTN Start, End;
+ UINT32 Index, Count;
+
+ DEBUG ((DEBUG_BLKIO, "NorFlashWriteSingleBlock(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", Lba, Offset, *NumBytes, Buffer));
+
+ // Check we did get some memory. Buffer is BlockSize.
+ if (ShadowBuffer == NULL) {
+ DEBUG ((DEBUG_ERROR, "FvbWrite: ERROR - Buffer not ready\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ // The write must not span block boundaries.
+ // We need to check each variable individually because adding two large values together overflows.
+ if ((Offset >= BlockSize) ||
+ (*NumBytes > BlockSize) ||
+ ((Offset + *NumBytes) > BlockSize))
+ {
+ DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize));
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ // We must have some bytes to write
+ if (*NumBytes == 0) {
+ DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize));
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ // Pick 4 * P30_MAX_BUFFER_SIZE_IN_BYTES (== 512 bytes) as a good
+ // start for word operations as opposed to erasing the block and
+ // writing the data regardless if an erase is really needed.
+ //
+ // Many NV variable updates are small enough for a a single
+ // P30_MAX_BUFFER_SIZE_IN_BYTES block write. In case the update is
+ // larger than a single block, or the update crosses a
+ // P30_MAX_BUFFER_SIZE_IN_BYTES boundary (as shown in the diagram
+ // below), or both, we might have to write two or more blocks.
+ //
+ // 0 128 256
+ // [----------------|----------------]
+ // ^ ^ ^ ^
+ // | | | |
+ // | | | End, the next "word" boundary beyond
+ // | | | the (logical) update
+ // | | |
+ // | | (Offset & BOUNDARY_OF_32_WORDS) + NumBytes;
+ // | | i.e., the relative offset inside (or just past)
+ // | | the *double-word* such that it is the
+ // | | *exclusive* end of the (logical) update.
+ // | |
+ // | Offset & BOUNDARY_OF_32_WORDS; i.e., Offset within the "word";
+ // | this is where the (logical) update is supposed to start
+ // |
+ // Start = Offset & ~BOUNDARY_OF_32_WORDS; i.e., Offset truncated to "word" boundary
+
+ Start = Offset & ~BOUNDARY_OF_32_WORDS;
+ End = ALIGN_VALUE (Offset + *NumBytes, P30_MAX_BUFFER_SIZE_IN_BYTES);
+
+ if ((End - Start) <= (4 * P30_MAX_BUFFER_SIZE_IN_BYTES)) {
+ // Check to see if we need to erase before programming the data into NOR.
+ // If the destination bits are only changing from 1s to 0s we can just write.
+ // After a block is erased all bits in the block is set to 1.
+ // If any byte requires us to erase we just give up and rewrite all of it.
+
+ // Read the old version of the data into the shadow buffer
+ Status = NorFlashRead (
+ DeviceBaseAddress,
+ RegionBaseAddress,
+ Lba,
+ BlockSize,
+ Size,
+ Start,
+ End - Start,
+ ShadowBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ // Make OrigData point to the start of the old version of the data inside
+ // the word aligned buffer
+ OrigData = ShadowBuffer + (Offset & BOUNDARY_OF_32_WORDS);
+
+ // Update the buffer containing the old version of the data with the new
+ // contents, while checking whether the old version had any bits cleared
+ // that we want to set. In that case, we will need to erase the block first.
+ for (CurOffset = 0; CurOffset < *NumBytes; CurOffset++) {
+ if (~(UINT32)OrigData[CurOffset] & (UINT32)Buffer[CurOffset]) {
+ Status = NorFlashWriteSingleBlockWithErase (
+ DeviceBaseAddress,
+ RegionBaseAddress,
+ Lba,
+ LastBlock,
+ BlockSize,
+ Offset,
+ NumBytes,
+ Buffer,
+ ShadowBuffer
+ );
+ return Status;
+ }
+
+ OrigData[CurOffset] = Buffer[CurOffset];
+ }
+
+ //
+ // Write the updated buffer to NOR.
+ //
+ BlockAddress = GET_NOR_BLOCK_ADDRESS (RegionBaseAddress, Lba, BlockSize);
+
+ // Unlock the block if we have to
+ Status = NorFlashUnlockSingleBlockIfNecessary (DeviceBaseAddress, BlockAddress);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Count = (End - Start) / P30_MAX_BUFFER_SIZE_IN_BYTES;
+ for (Index = 0; Index < Count; Index++) {
+ Status = NorFlashWriteBuffer (
+ DeviceBaseAddress,
+ BlockAddress + Start + Index * P30_MAX_BUFFER_SIZE_IN_BYTES,
+ P30_MAX_BUFFER_SIZE_IN_BYTES,
+ ShadowBuffer + Index * P30_MAX_BUFFER_SIZE_IN_BYTES
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ }
+ } else {
+ Status = NorFlashWriteSingleBlockWithErase (
+ DeviceBaseAddress,
+ RegionBaseAddress,
+ Lba,
+ LastBlock,
+ BlockSize,
+ Offset,
+ NumBytes,
+ Buffer,
+ ShadowBuffer
+ );
+ return Status;
+ }
+
+Exit:
+ // Put device back into Read Array mode
+ SEND_NOR_COMMAND (DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+NorFlashReset (
+ IN UINTN DeviceBaseAddress
+ )
+{
+ // As there is no specific RESET to perform, ensure that the devices is in the default Read Array mode
+ SEND_NOR_COMMAND (DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
+ return EFI_SUCCESS;
+}
diff --git a/OvmfPkg/Library/VirtNorFlashDeviceLib/VirtNorFlashDeviceLib.inf b/OvmfPkg/Library/VirtNorFlashDeviceLib/VirtNorFlashDeviceLib.inf
new file mode 100644
index 0000000..befa570
--- /dev/null
+++ b/OvmfPkg/Library/VirtNorFlashDeviceLib/VirtNorFlashDeviceLib.inf
@@ -0,0 +1,30 @@
+#/** @file
+#
+# This library enables low-level access to Virt Flash devices
+#
+# Copyright (c) 2011 - 2021, Arm Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+[Defines]
+ INF_VERSION = 1.29
+ BASE_NAME = VirtNorFlashDeviceLib
+ FILE_GUID = 3f8c8c4b-5b92-4e71-ae73-9f7d2f1e33d4
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = VirtNorFlashDeviceLib
+
+[Sources.common]
+ VirtNorFlashDeviceLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ IoLib
diff --git a/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c b/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c
index 2d610f6..85faae6 100644
--- a/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c
+++ b/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c
@@ -538,9 +538,9 @@ QemuLoadKernelImage (
if (InitrdSize > 0) {
//
- // Append ' initrd=initrd' in UTF-16.
+ // Prefix ' initrd=initrd' in UTF-16.
//
- KernelLoadedImage->LoadOptionsSize += sizeof (L" initrd=initrd") - 2;
+ KernelLoadedImage->LoadOptionsSize += sizeof (L"initrd=initrd ") - 2;
}
if (Shim) {
@@ -572,8 +572,8 @@ QemuLoadKernelImage (
KernelLoadedImage->LoadOptionsSize,
"%a%a%a",
(Shim == FALSE) ? "" : "kernel ",
- (CommandLineSize == 0) ? "" : CommandLine,
- (InitrdSize == 0) ? "" : " initrd=initrd"
+ (InitrdSize == 0) ? "" : "initrd=initrd ",
+ (CommandLineSize == 0) ? "" : CommandLine
);
DEBUG ((
DEBUG_INFO,