summaryrefslogtreecommitdiff
path: root/MdeModulePkg
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg')
-rw-r--r--MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.c2
-rw-r--r--MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c34
-rw-r--r--MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c27
-rw-r--r--MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.h38
-rw-r--r--MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf10
-rw-r--r--MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.c10
-rw-r--r--MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressMediaSanitize.c582
-rw-r--r--MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressMediaSanitize.h191
-rw-r--r--MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c2
-rw-r--r--MdeModulePkg/Bus/Pci/NvmExpressDxe/UnitTest/MediaSanitizeUnitTest.c1128
-rw-r--r--MdeModulePkg/Bus/Pci/NvmExpressDxe/UnitTest/MediaSanitizeUnitTestHost.inf37
-rw-r--r--MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c7
-rw-r--r--MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c2
-rw-r--r--MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c51
-rw-r--r--MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.c57
-rw-r--r--MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.h22
-rw-r--r--MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.inf5
-rw-r--r--MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.c28
-rw-r--r--MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c5
-rw-r--r--MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h6
-rw-r--r--MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruDxe.inf4
-rw-r--r--MdeModulePkg/Core/Dxe/DxeMain.h12
-rw-r--r--MdeModulePkg/Core/Dxe/DxeMain.inf1
-rw-r--r--MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c6
-rw-r--r--MdeModulePkg/Core/Dxe/Gcd/Gcd.c23
-rw-r--r--MdeModulePkg/Core/Dxe/Hand/Handle.c89
-rw-r--r--MdeModulePkg/Core/Dxe/Image/Image.c4
-rw-r--r--MdeModulePkg/Core/Dxe/Mem/HeapGuard.c51
-rw-r--r--MdeModulePkg/Core/Dxe/Mem/Imem.h16
-rw-r--r--MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c31
-rw-r--r--MdeModulePkg/Core/DxeIplPeim/DxeLoad.c13
-rw-r--r--MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c37
-rw-r--r--MdeModulePkg/Core/Pei/FwVol/FwVol.c12
-rw-r--r--MdeModulePkg/Core/Pei/Memory/MemoryServices.c2
-rw-r--r--MdeModulePkg/Core/Pei/PeiMain/PeiMain.c16
-rw-r--r--MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c17
-rw-r--r--MdeModulePkg/Include/Guid/MigratedFvInfo.h3
-rw-r--r--MdeModulePkg/Include/Guid/MmCommBuffer.h63
-rw-r--r--MdeModulePkg/Include/Guid/NVMeEventGroup.h16
-rw-r--r--MdeModulePkg/Include/Protocol/MediaSanitize.h173
-rw-r--r--MdeModulePkg/Library/RuntimeResetSystemLib/RuntimeResetSystemLib.c4
-rw-r--r--MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c6
-rw-r--r--MdeModulePkg/Library/VarCheckHiiLib/VarCheckHii.h10
-rw-r--r--MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.c9
-rw-r--r--MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.h4
-rw-r--r--MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromHii.c251
-rw-r--r--MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.c57
-rw-r--r--MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf8
-rw-r--r--MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibCommon.c349
-rw-r--r--MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibCommon.h43
-rw-r--r--MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibMmDependency.c138
-rw-r--r--MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibMmDependency.inf53
-rw-r--r--MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibNullClass.c630
-rw-r--r--MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibStandaloneMm.c152
-rw-r--r--MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibStandaloneMm.inf47
-rw-r--r--MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibStandaloneMm.uni15
-rw-r--r--MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c4
-rw-r--r--MdeModulePkg/MdeModulePkg.ci.yaml1
-rw-r--r--MdeModulePkg/MdeModulePkg.dec26
-rw-r--r--MdeModulePkg/MdeModulePkg.dsc6
-rw-r--r--MdeModulePkg/Test/MdeModulePkgHostTest.dsc5
-rw-r--r--MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.h6
-rw-r--r--MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf1
-rw-r--r--MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c119
-rw-r--r--MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatform.c21
-rw-r--r--MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c10
-rw-r--r--MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.c9
-rw-r--r--MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c8
-rw-r--r--MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferDxe.c23
-rw-r--r--MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferDxe.inf1
-rw-r--r--MdeModulePkg/Universal/Variable/Pei/Variable.c1
-rw-r--r--MdeModulePkg/Universal/Variable/RuntimeDxe/PrivilegePolymorphic.h14
-rw-r--r--MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockSmm.c2
-rw-r--r--MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.c29
-rw-r--r--MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf1
-rw-r--r--MdeModulePkg/Universal/Variable/RuntimeDxe/VariableTraditionalMm.c6
76 files changed, 4095 insertions, 807 deletions
diff --git a/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.c b/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.c
index 69baf1c..68c2e35 100644
--- a/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.c
+++ b/MdeModulePkg/Application/SmiHandlerProfileInfo/SmiHandlerProfileInfo.c
@@ -667,7 +667,7 @@ SmiHandlerProfileInfoEntrypoint (
//
// Dump all image
//
- Print (L"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
+ Print (L"<?xml version=\"1.0\" encoding=\"utf-16\"?>\n");
Print (L"<SmiHandlerProfile>\n");
Print (L"<ImageDatabase>\n");
Print (L" <!-- SMM image loaded -->\n");
diff --git a/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c b/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c
index e31c38d..4daf517 100644
--- a/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c
+++ b/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c
@@ -1111,6 +1111,8 @@ NonCoherentPciIoAllocateBuffer (
NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION *Alloc;
VOID *AllocAddress;
+ MemType = EFI_MEMORY_XP;
+
if (HostAddress == NULL) {
return EFI_INVALID_PARAMETER;
}
@@ -1152,9 +1154,9 @@ NonCoherentPciIoAllocateBuffer (
// Use write combining if it was requested, or if it is the only
// type supported by the region.
//
- MemType = EFI_MEMORY_WC;
+ MemType |= EFI_MEMORY_WC;
} else {
- MemType = EFI_MEMORY_UC;
+ MemType |= EFI_MEMORY_UC;
}
Alloc = AllocatePool (sizeof *Alloc);
@@ -1172,6 +1174,34 @@ NonCoherentPciIoAllocateBuffer (
//
InsertHeadList (&Dev->UncachedAllocationList, &Alloc->List);
+ //
+ // Ensure that EFI_MEMORY_XP is in the capability set
+ //
+ if ((GcdDescriptor.Capabilities & EFI_MEMORY_XP) != EFI_MEMORY_XP) {
+ Status = gDS->SetMemorySpaceCapabilities (
+ (PHYSICAL_ADDRESS)(UINTN)AllocAddress,
+ EFI_PAGES_TO_SIZE (Pages),
+ GcdDescriptor.Capabilities | EFI_MEMORY_XP
+ );
+
+ // if we were to fail setting the capability, this would indicate an internal failure of the GCD code. We should
+ // assert here to let a platform know something went crazy, but for a release build we can let the allocation occur
+ // without the EFI_MEMORY_XP bit set, as that was the existing behavior
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a failed to set EFI_MEMORY_XP capability on 0x%llx for length 0x%llx. Attempting to allocate without XP set.\n",
+ __func__,
+ AllocAddress,
+ EFI_PAGES_TO_SIZE (Pages)
+ ));
+
+ ASSERT_EFI_ERROR (Status);
+
+ MemType &= ~EFI_MEMORY_XP;
+ }
+ }
+
Status = gDS->SetMemorySpaceAttributes (
(EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,
EFI_PAGES_TO_SIZE (Pages),
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c
index 069da12..c8d8be3 100644
--- a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c
+++ b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c
@@ -3,6 +3,7 @@
NVM Express specification.
Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) Microsoft Corporation.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -182,6 +183,26 @@ EnumerateNvmeDevNamespace (
InitializeListHead (&Device->AsyncQueue);
//
+ // Create Media Sanitize Protocol instance
+ //
+ Device->MediaSanitize.Revision = MEDIA_SANITIZE_PROTOCOL_REVISION;
+ Device->MediaSanitize.Media = &Device->Media;
+ Device->MediaSanitize.MediaClear = NvmExpressMediaClear;
+ Device->MediaSanitize.MediaPurge = NvmExpressMediaPurge;
+ Device->MediaSanitize.MediaFormat = NvmExpressMediaFormat;
+
+ ASSERT (
+ sizeof (Device->MediaSanitize.SanitizeCapabilities) ==
+ sizeof (Device->Controller->ControllerData->Sanicap)
+ );
+
+ CopyMem (
+ &(Device->MediaSanitize.SanitizeCapabilities),
+ &(Device->Controller->ControllerData->Sanicap),
+ sizeof (Device->MediaSanitize.SanitizeCapabilities)
+ );
+
+ //
// Create StorageSecurityProtocol Instance
//
Device->StorageSecurity.ReceiveData = NvmeStorageSecurityReceiveData;
@@ -241,6 +262,8 @@ EnumerateNvmeDevNamespace (
&Device->BlockIo2,
&gEfiDiskInfoProtocolGuid,
&Device->DiskInfo,
+ &gMediaSanitizeProtocolGuid,
+ &Device->MediaSanitize,
NULL
);
@@ -269,6 +292,8 @@ EnumerateNvmeDevNamespace (
&Device->BlockIo2,
&gEfiDiskInfoProtocolGuid,
&Device->DiskInfo,
+ &gMediaSanitizeProtocolGuid,
+ &Device->MediaSanitize,
NULL
);
goto Exit;
@@ -468,6 +493,8 @@ UnregisterNvmeNamespace (
&Device->BlockIo2,
&gEfiDiskInfoProtocolGuid,
&Device->DiskInfo,
+ &gMediaSanitizeProtocolGuid,
+ &Device->MediaSanitize,
NULL
);
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.h b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.h
index 4c26b2e..11207af 100644
--- a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.h
+++ b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.h
@@ -4,6 +4,7 @@
(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) Microsoft Corporation.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -29,6 +30,7 @@
#include <Protocol/DriverSupportedEfiVersion.h>
#include <Protocol/StorageSecurityCommand.h>
#include <Protocol/ResetNotification.h>
+#include <Protocol/MediaSanitize.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
@@ -41,12 +43,15 @@
#include <Library/UefiDriverEntryPoint.h>
#include <Library/ReportStatusCodeLib.h>
+#include <Guid/NVMeEventGroup.h>
+
typedef struct _NVME_CONTROLLER_PRIVATE_DATA NVME_CONTROLLER_PRIVATE_DATA;
typedef struct _NVME_DEVICE_PRIVATE_DATA NVME_DEVICE_PRIVATE_DATA;
#include "NvmExpressBlockIo.h"
#include "NvmExpressDiskInfo.h"
#include "NvmExpressHci.h"
+#include "NvmExpressMediaSanitize.h"
extern EFI_DRIVER_BINDING_PROTOCOL gNvmExpressDriverBinding;
extern EFI_COMPONENT_NAME_PROTOCOL gNvmExpressComponentName;
@@ -75,6 +80,30 @@ extern EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL gNvmExpressDriverSupportedEfiV
#define NVME_MAX_QUEUES 3 // Number of queues supported by the driver
+//
+// FormatNVM Admin Command LBA Format (LBAF) Mask
+//
+#define NVME_LBA_FORMATNVM_LBAF_MASK 0xF
+
+//
+// NVMe Completion Queue Entry Bits, Fields, Masks
+//
+#define NVME_CQE_STATUS_FIELD_MASK 0xFFFF0000
+#define NVME_CQE_STATUS_FIELD_OFFSET 16
+#define NVME_CQE_STATUS_FIELD_SCT_MASK 0x0E00
+#define NVME_CQE_STATUS_FIELD_SCT_OFFSET 0x9
+#define NVME_CQE_STATUS_FIELD_SC_MASK 0x1FE
+#define NVME_CQE_STATUS_FIELD_SC_OFFSET 0x01
+#define NVME_CQE_SCT_GENERIC_CMD_STATUS 0x0
+#define NVME_CQE_SCT_CMD_SPECIFIC_STATUS 0x1
+#define NVME_CQE_SCT_MEDIA_DATA_INTEGRITY_ERRORS_STATUS 0x2
+#define NVME_CQE_SCT_PATH_RELATED_STATUS 0x3
+#define NVME_CQE_SC_SUCCESSFUL_COMPLETION 0x00
+#define NVME_CQE_SC_INVALID_CMD_OPCODE 0x01
+#define NVME_CQE_SC_INVALID_FIELD_IN_CMD 0x02
+
+#define NVME_ALL_NAMESPACES 0xFFFFFFFF
+
#define NVME_CONTROLLER_ID 0
//
@@ -200,6 +229,8 @@ struct _NVME_DEVICE_PRIVATE_DATA {
EFI_DISK_INFO_PROTOCOL DiskInfo;
EFI_STORAGE_SECURITY_COMMAND_PROTOCOL StorageSecurity;
+ MEDIA_SANITIZE_PROTOCOL MediaSanitize;
+
LIST_ENTRY AsyncQueue;
EFI_LBA NumBlocks;
@@ -241,6 +272,13 @@ struct _NVME_DEVICE_PRIVATE_DATA {
NVME_DEVICE_PRIVATE_DATA_SIGNATURE \
)
+#define NVME_DEVICE_PRIVATE_DATA_FROM_MEDIA_SANITIZE(a) \
+ CR (a, \
+ NVME_DEVICE_PRIVATE_DATA, \
+ MediaSanitize, \
+ NVME_DEVICE_PRIVATE_DATA_SIGNATURE \
+ )
+
//
// Nvme block I/O 2 request.
//
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf
index dc1990c..5fd0e46 100644
--- a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf
+++ b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf
@@ -5,7 +5,7 @@
# NVM Express specification.
#
# Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
-#
+# Copyright (c) Microsoft Corporation.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
@@ -40,9 +40,16 @@
NvmExpressHci.c
NvmExpressHci.h
NvmExpressPassthru.c
+ NvmExpressMediaSanitize.c
+ NvmExpressMediaSanitize.h
+
+[Guids]
+ gNVMeEnableStartEventGroupGuid
+ gNVMeEnableCompleteEventGroupGuid
[Packages]
MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
BaseMemoryLib
@@ -67,6 +74,7 @@
gEfiDiskInfoProtocolGuid ## BY_START
gEfiStorageSecurityCommandProtocolGuid ## BY_START
gEfiDriverSupportedEfiVersionProtocolGuid ## PRODUCES
+ gMediaSanitizeProtocolGuid ## PRODUCES
gEfiResetNotificationProtocolGuid ## CONSUMES
# [Event]
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.c b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.c
index b90c487..e1b0ee6 100644
--- a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.c
+++ b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.c
@@ -8,6 +8,7 @@
**/
#include "NvmExpress.h"
+#include <Guid/NVMeEventGroup.h>
#define NVME_SHUTDOWN_PROCESS_TIMEOUT 45
@@ -399,6 +400,8 @@ NvmeEnableController (
UINT32 Index;
UINT8 Timeout;
+ EfiEventGroupSignal (&gNVMeEnableStartEventGroupGuid);
+
//
// Enable the controller.
// CC.AMS, CC.MPS and CC.CSS are all set to 0.
@@ -410,7 +413,7 @@ NvmeEnableController (
Status = WriteNvmeControllerConfiguration (Private, &Cc);
if (EFI_ERROR (Status)) {
- return Status;
+ goto Cleanup;
}
//
@@ -432,7 +435,7 @@ NvmeEnableController (
Status = ReadNvmeControllerStatus (Private, &Csts);
if (EFI_ERROR (Status)) {
- return Status;
+ goto Cleanup;
}
if (Csts.Rdy) {
@@ -449,6 +452,9 @@ NvmeEnableController (
}
DEBUG ((DEBUG_INFO, "NVMe controller is enabled with status [%r].\n", Status));
+
+Cleanup:
+ EfiEventGroupSignal (&gNVMeEnableCompleteEventGroupGuid);
return Status;
}
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressMediaSanitize.c b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressMediaSanitize.c
new file mode 100644
index 0000000..8632924
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressMediaSanitize.c
@@ -0,0 +1,582 @@
+/** @file -- NvmExpressMediaSanitize.c
+ This driver will implement sanitize operations on all NVMe mass storage devices
+ based on NIST purge and clear operations. These operations will then be mapped to
+ one of two NVMe admin commands:
+
+ -Format NVM
+ -Sanitize
+
+ Implementation based off NVMe spec revision 1.4c.
+
+ Copyright (c) Microsoft Corporation.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "NvmExpress.h"
+
+/**
+ Send NVM Express FormatNVM Admin Command
+
+ The Format NVM command is used to low level format the NVM media. This command is used by
+ the host to change the LBA data size and/or metadata size.
+
+ A low level format may destroy all data and metadata associated with all namespaces or only
+ the specific namespace associated with the command (refer to the Format NVM Attributes field
+ in the Identify Controller data structure).
+
+ After the Format NVM command successfully completes, the controller shall not return any user
+ data that was previously contained in an affected namespace.
+
+ @param[in] This Indicates a pointer to the calling context (Block IO Protocol)
+ @param[in] NamespaceId The NVM Express namespace ID for which a device path node is to be
+ allocated and built. Caller must set the NamespaceId to zero if the
+ device path node will contain a valid UUID.
+ @param[in] Ses Secure Erase Setting (SES) value
+ - 000b: No secure erase operation requested
+ - 001b: User Data Erase
+ - 010b: Cryptographic Erase
+ - 011b to 111b: Reserved
+ @param[in] Flbas New LBA size (in terms of LBA Format size Index (bits 3:0) in NamespaceData).
+ If this param is 0 (NULL), then use existing LBA size.
+
+ @retval EFI_SUCCESS The device formatted correctly.
+ @retval EFI_WRITE_PROTECTED The device can not be formatted due to write protection.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the format.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_INVALID_PARAMETER The format request contains parameters that are not valid.
+
+ **/
+EFI_STATUS
+NvmExpressFormatNvm (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 NamespaceId,
+ IN UINT32 Ses,
+ IN UINT32 Flbas
+ )
+{
+ NVME_DEVICE_PRIVATE_DATA *Device;
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND Command;
+ EFI_NVM_EXPRESS_COMPLETION Completion;
+ NVME_ADMIN_FORMAT_NVM FormatNvmCdw10;
+ NVME_ADMIN_NAMESPACE_DATA *NewNamespaceData;
+ UINT32 Lbads;
+ UINT32 NewFlbas;
+ UINT32 LbaFmtIdx;
+ EFI_STATUS Status;
+ UINT32 LbaFormat;
+ UINT16 StatusField;
+ UINT16 Sct;
+ UINT16 Sc;
+
+ Status = EFI_NOT_STARTED;
+ LbaFormat = 0;
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);
+
+ ZeroMem (&CommandPacket, sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof (EFI_NVM_EXPRESS_COMMAND));
+ ZeroMem (&Completion, sizeof (EFI_NVM_EXPRESS_COMPLETION));
+ ZeroMem (&FormatNvmCdw10, sizeof (NVME_ADMIN_FORMAT_NVM));
+
+ NewNamespaceData = NULL;
+ Lbads = 0;
+ NewFlbas = 0;
+ LbaFmtIdx = 0;
+ StatusField = 0;
+ Sct = 0;
+ Sc = 0;
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeCompletion = &Completion;
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueType = NVME_ADMIN_QUEUE;
+ Command.Cdw0.Opcode = NVME_ADMIN_FORMAT_NVM_CMD;
+ Command.Nsid = NamespaceId;
+
+ //
+ // SES (Secure Erase Settings)
+ //
+ FormatNvmCdw10.Ses = Ses;
+
+ //
+ // Change LBA size/format if LbaFormat param != NULL, otherwise keep same LBA format.
+ // Current supported LBA format size in Identify Namespace LBA Format Table, indexed by
+ // FLBAS (bits 3:0).
+ //
+ LbaFormat = (Flbas == 0 ? Device->NamespaceData.Flbas : Flbas);
+ FormatNvmCdw10.Lbaf = LbaFormat & NVME_LBA_FORMATNVM_LBAF_MASK;
+ CopyMem (&CommandPacket.NvmeCmd->Cdw10, &FormatNvmCdw10, sizeof (NVME_ADMIN_FORMAT_NVM));
+
+ //
+ // Send Format NVM command via passthru and wait for completion
+ //
+ // If LBA size changed successfully, then update private data structures and Block IO
+ // and Media protocols to reflect new LBA size.
+ //
+ Status = Device->Controller->Passthru.PassThru (
+ &(Device->Controller->Passthru),
+ NamespaceId,
+ &CommandPacket,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ StatusField = (UINT16)((CommandPacket.NvmeCompletion->DW3 & NVME_CQE_STATUS_FIELD_MASK) >>
+ NVME_CQE_STATUS_FIELD_OFFSET);
+
+ Sc = (StatusField & NVME_CQE_STATUS_FIELD_SC_MASK) >> NVME_CQE_STATUS_FIELD_SC_OFFSET;
+ Sct = (StatusField & NVME_CQE_STATUS_FIELD_SCT_MASK) >> NVME_CQE_STATUS_FIELD_SCT_OFFSET;
+
+ DEBUG ((DEBUG_ERROR, "%a: NVMe FormatNVM admin command failed SCT = 0x%x, SC = 0x%x\n", __func__, Sct, Sc));
+ } else {
+ //
+ // Update Block IO and Media Protocols only if Flbas parameter was not NULL.
+ // Call Identify Namespace again and update all protocols fields and local
+ // cached copies of fields related to block size.
+ //
+ if (Flbas != 0) {
+ NewNamespaceData = AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA));
+ if (NewNamespaceData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ Status = NvmeIdentifyNamespace (
+ Device->Controller,
+ NamespaceId,
+ (VOID *)NewNamespaceData
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Update all fields related to LBA size, allocation, and alignment
+ //
+ NewFlbas = NewNamespaceData->Flbas;
+ LbaFmtIdx = NewFlbas & NVME_LBA_FORMATNVM_LBAF_MASK;
+ Lbads = NewNamespaceData->LbaFormat[LbaFmtIdx].Lbads;
+ Device->Media.BlockSize = (UINT32)1 << Lbads;
+ Device->Media.LastBlock = NewNamespaceData->Nsze - 1;
+
+ CopyMem (&Device->NamespaceData, NewNamespaceData, sizeof (NVME_ADMIN_NAMESPACE_DATA));
+ }
+ }
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Send NVM Express Sanitize Admin Command
+
+ The Sanitize command is used to start a sanitize operation or to recover from a previously
+ failed sanitize operation. The sanitize operation types that may be supported are Block
+ Erase, Crypto Erase, and Overwrite.
+
+ All sanitize operations are processed in the background (i.e., completion of the Sanitize
+ command does not indicate completion of the sanitize operation).
+
+ @param[in] This Indicates a pointer to the calling context (Block IO Protocol)
+ @param[in] NamespaceId The NVM Express namespace ID for which a device path node is to be
+ allocated and built. Caller must set the NamespaceId to zero if the
+ device path node will contain a valid UUID.
+ @param[in] SanitizeAction Sanitize action
+ @param[in] NoDeallocAfterSanitize No deallocate after sanitize option
+ @param[in] OverwritePattern Pattern to overwrite old user data
+
+ @retval EFI_SUCCESS The media was sanitized successfully on the device.
+ @retval EFI_WRITE_PROTECTED The device can not be sanitized due to write protection.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the sanitize.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not match the current device.
+ @retval EFI_INVALID_PARAMETER The sanitize request contains parameters that are not valid.
+
+ **/
+EFI_STATUS
+NvmExpressSanitize (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 NamespaceId,
+ IN UINT32 SanitizeAction,
+ IN UINT32 NoDeallocAfterSanitize,
+ IN UINT32 OverwritePattern
+ )
+{
+ NVME_DEVICE_PRIVATE_DATA *Device;
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND Command;
+ EFI_NVM_EXPRESS_COMPLETION Completion;
+ NVME_ADMIN_SANITIZE SanitizeCdw10Cdw11;
+ EFI_STATUS Status;
+ UINT16 StatusField;
+ UINT16 Sct;
+ UINT16 Sc;
+ UINT32 FnvmSes;
+
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);
+
+ ZeroMem (&CommandPacket, sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof (EFI_NVM_EXPRESS_COMMAND));
+ ZeroMem (&Completion, sizeof (EFI_NVM_EXPRESS_COMPLETION));
+ ZeroMem (&SanitizeCdw10Cdw11, sizeof (NVME_ADMIN_SANITIZE));
+
+ StatusField = 0;
+ Sct = 0;
+ Sc = 0;
+ FnvmSes = 0;
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeCompletion = &Completion;
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueType = NVME_ADMIN_QUEUE;
+ Command.Cdw0.Opcode = NVME_ADMIN_SANITIZE_CMD;
+ Command.Nsid = NamespaceId;
+
+ SanitizeCdw10Cdw11.Nodas = NoDeallocAfterSanitize;
+ SanitizeCdw10Cdw11.Sanact = SanitizeAction;
+ SanitizeCdw10Cdw11.Ovrpat = OverwritePattern;
+ CopyMem (&CommandPacket.NvmeCmd->Cdw10, &SanitizeCdw10Cdw11, sizeof (NVME_ADMIN_SANITIZE));
+
+ //
+ // Send Format NVM command via passthru and wait for completion
+ //
+ Status = Device->Controller->Passthru.PassThru (
+ &(Device->Controller->Passthru),
+ NamespaceId,
+ &CommandPacket,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ StatusField = (UINT16)((CommandPacket.NvmeCompletion->DW3 & NVME_CQE_STATUS_FIELD_MASK) >>
+ NVME_CQE_STATUS_FIELD_OFFSET);
+
+ Sc = (StatusField & NVME_CQE_STATUS_FIELD_SC_MASK) >> NVME_CQE_STATUS_FIELD_SC_OFFSET;
+ Sct = (StatusField & NVME_CQE_STATUS_FIELD_SCT_MASK) >> NVME_CQE_STATUS_FIELD_SCT_OFFSET;
+
+ DEBUG ((DEBUG_ERROR, "%a: NVMe Sanitize admin command failed SCT = 0x%x, SC = 0x%x\n", __func__, Sct, Sc));
+
+ //
+ // Check for an error status code of "Invalid Command Opcode" in case
+ // the NVM Express controller does not support Sanitize. If the NVM
+ // Exress Controller does not support Sanitize, then send a Format NVM
+ // admin command instead to perform the Purge operation.
+ //
+ if ((Sct == NVME_CQE_SCT_GENERIC_CMD_STATUS) &&
+ (Sc == NVME_CQE_SC_INVALID_CMD_OPCODE))
+ {
+ switch (SanitizeCdw10Cdw11.Sanact) {
+ case SANITIZE_ACTION_BLOCK_ERASE:
+ FnvmSes = SES_USER_DATA_ERASE; // User Data Erase (LBAs indeterminate after)
+ break;
+ case SANITIZE_ACTION_CRYPTO_ERASE:
+ FnvmSes = SES_CRYPTO_ERASE; // Crypto Erase
+ break;
+ case SANITIZE_ACTION_OVERWRITE:
+ case SANITIZE_ACTION_EXIT_FAILURE_MODE:
+ default:
+ //
+ // Cannot perform an equivalent FormatNVM action/operation
+ //
+ FnvmSes = SES_NO_SECURE_ERASE;
+ break;
+ }
+
+ if ((FnvmSes == SES_USER_DATA_ERASE) || (FnvmSes == SES_CRYPTO_ERASE)) {
+ Status = NvmExpressFormatNvm (
+ This,
+ NVME_ALL_NAMESPACES,
+ FnvmSes,
+ 0 // Pass in NULL so existing LBA size is used in Format NVM
+ );
+ }
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Clear Media utilizes transport native WRITE commands to write a fixed pattern
+ of non-sensitive data to the media.
+
+ NOTE: The caller shall send buffer of one sector/LBA size with overwrite data.
+ NOTE: This operation is a blocking call.
+ NOTE: This function must be called from TPL_APPLICATION or TPL_CALLBACK.
+
+ Functions are defined to erase and purge data at a block level from mass
+ storage devices as well as to manage such devices in the EFI boot services
+ environment.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] PassCount The number of passes to write over media.
+ @param[in] SectorOwBuffer A pointer to the overwrite buffer.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressMediaClear (
+ IN MEDIA_SANITIZE_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT32 PassCount,
+ IN VOID *SectorOwBuffer
+ )
+{
+ NVME_DEVICE_PRIVATE_DATA *Device;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_LBA SectorOffset;
+ UINT32 TotalPassCount;
+ EFI_STATUS Status;
+
+ //
+ // Check parameters.
+ //
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_MEDIA_SANITIZE (This);
+ Media = &Device->Media;
+ SectorOffset = 0;
+
+ if ((MediaId != Media->MediaId) || (!Media->MediaPresent)) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ //
+ // If an invalid buffer or buffer size is sent, the Media Clear operation
+ // cannot be performed as it requires a native WRITE command. The overwrite
+ // buffer must have granularity of a namespace block size.
+ //
+ if (SectorOwBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Per NIST 800-88r1, one or more pass of writes may be alteratively used.
+ //
+ for (TotalPassCount = 0; TotalPassCount < PassCount; TotalPassCount++) {
+ for (SectorOffset = 0; SectorOffset < Media->LastBlock; SectorOffset++ ) {
+ Status = Device->BlockIo.WriteBlocks (
+ &Device->BlockIo,
+ MediaId,
+ SectorOffset, // Sector/LBA offset (increment each pass)
+ 1, // Write one sector per write
+ SectorOwBuffer // overwrite buffer
+ );
+ }
+
+ //
+ // Reset SectorOffset back to zero if another pass on namespace is needed
+ //
+ SectorOffset = 0;
+ }
+
+ return Status;
+}
+
+/**
+ Purge Media utilizes transport native Sanitize operations. Sanitize specific
+ purge actions include: overwrite, block erase, or crypto erase.
+
+ Functions are defined to erase and purge data at a block level from mass
+ storage devices as well as to manage such devices in the EFI boot services
+ environment. Sanitization refers to a process that renders access to target
+ data on the media infeasible for a given level of effort.
+
+ NOTE: This operation is a blocking call.
+ NOTE: This function must be called from TPL_APPLICATION or TPL_CALLBACK.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] PurgeAction The purage action (overwrite, crypto erase, block erase).
+ @param[in] OverwritePattern 32-bit pattern to overwrite on media (for overwrite).
+
+ @retval EFI_SUCCESS The media was purged successfully on the device.
+ @retval EFI_WRITE_PROTECTED The device can not be purged due to write protection.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the purge.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not match the current device.
+ @retval EFI_INVALID_PARAMETER The purge request contains parameters that are not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressMediaPurge (
+ IN MEDIA_SANITIZE_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT32 PurgeAction,
+ IN UINT32 OverwritePattern
+ )
+{
+ NVME_DEVICE_PRIVATE_DATA *Device;
+ EFI_BLOCK_IO_MEDIA *Media;
+ NVME_SANICAP SaniCap;
+ UINT32 SanitizeAction;
+ UINT32 NoDeallocate;
+ UINT32 NamespaceId;
+ EFI_STATUS Status;
+
+ //
+ // Check parameters.
+ //
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_MEDIA_SANITIZE (This);
+ NamespaceId = Device->NamespaceId;
+ Media = &Device->Media;
+ SaniCap = Device->Controller->ControllerData->Sanicap;
+ NoDeallocate = 0;
+
+ if ((MediaId != Media->MediaId) || (!Media->MediaPresent)) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ //
+ // Purge action will directly map to sanitize action. If no valid purge
+ // action is selected, then default to no action and let the NVMe SSD handle
+ // the no-op sanitize action (as there may be other contingencies).
+ //
+ if (((PurgeAction & PURGE_ACTION_OVERWRITE) == PURGE_ACTION_OVERWRITE) && (SaniCap.Ows)) {
+ SanitizeAction = SANITIZE_ACTION_OVERWRITE;
+ } else if (((PurgeAction & PURGE_ACTION_BLOCK_ERASE) == PURGE_ACTION_BLOCK_ERASE) && (SaniCap.Bes)) {
+ SanitizeAction = SANITIZE_ACTION_BLOCK_ERASE;
+ } else if (((PurgeAction & PURGE_ACTION_CRYPTO_ERASE) == PURGE_ACTION_CRYPTO_ERASE) && (SaniCap.Ces)) {
+ SanitizeAction = SANITIZE_ACTION_CRYPTO_ERASE;
+ } else {
+ SanitizeAction = SANITIZE_ACTION_NO_ACTION;
+ }
+
+ if ((PurgeAction & PURGE_ACTION_NO_DEALLOCATE) == PURGE_ACTION_NO_DEALLOCATE) {
+ NoDeallocate = NVME_NO_DEALLOCATE_AFTER_SANITZE;
+ }
+
+ //
+ // Call NVM Express Admin command Sanitize (blocking call).
+ //
+ Status = NvmExpressSanitize (
+ &Device->BlockIo,
+ NamespaceId,
+ SanitizeAction,
+ NoDeallocate,
+ OverwritePattern
+ );
+
+ return Status;
+}
+
+/**
+ Format Media utilizes native format operations to modify sector/LBA size.
+ Secure erase actions are used to define how latent user data is erased.
+
+ NOTE: This function must be called from TPL_APPLICATION or TPL_CALLBACK.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the clear request is for.
+ @param[in] LbaSize Size of LBA (in terms of power of two: 2^n).
+ @param[in] SecureEraseAction Secure erase action, if any, to apply to format.
+ - 000b: No secure erase operation requested
+ - 001b: User Data Erase
+ - 010b: Cryptographic Erase
+ - 011b to 111b: Reserved
+
+ @retval EFI_SUCCESS The media format request comopleted successfully on the device.
+ @retval EFI_WRITE_PROTECTED The device can't be formatted due to write protection.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the format operation.
+ @retval EFI_INVALID_PARAMETER The format request contains parameters that are not valid.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+
+ **/
+EFI_STATUS
+EFIAPI
+NvmExpressMediaFormat (
+ IN MEDIA_SANITIZE_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT32 LbaSize,
+ IN UINT32 SecureEraseAction
+ )
+{
+ NVME_DEVICE_PRIVATE_DATA *Device;
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINT32 NamespaceId;
+ UINT32 SecureEraseSettings;
+ UINT32 FlbaIndex;
+ BOOLEAN LbaSizeIsSupported;
+ EFI_STATUS Status;
+
+ //
+ // Check parameters.
+ //
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_MEDIA_SANITIZE (This);
+ NamespaceId = Device->NamespaceId;
+ Media = &Device->Media;
+ SecureEraseSettings = FORMAT_SES_NO_SECURE_ERASE_REQUESTED;
+ FlbaIndex = 0;
+
+ if ((MediaId != Media->MediaId) || (!Media->MediaPresent)) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ //
+ // Convert secure erase action to NVMe secure erase setting
+ //
+ switch (SecureEraseAction) {
+ case FORMAT_SES_USER_DATA_ERASE:
+ SecureEraseSettings = SES_USER_DATA_ERASE;
+ break;
+ case FORMAT_SES_CRYPTOGRAPHIC_ERASE:
+ SecureEraseSettings = SES_CRYPTO_ERASE;
+ break;
+ case FORMAT_SES_NO_SECURE_ERASE_REQUESTED:
+ default:
+ //
+ // Cannot perform an equivalent FormatNVM action/operation
+ //
+ SecureEraseSettings = SES_NO_SECURE_ERASE;
+ break;
+ }
+
+ //
+ // The requested LBA size must be supported by the NVMe SSD as defined in Identify
+ // Namespace structure.
+ //
+ // Current supported LBA format sizes is in Identify Namespace LBA Format Table,
+ // indexed by FLBAS (bits 3:0). Loop through all supported LBADF sizes and check
+ // to see if requested LBA size is supported. If yes, send FormatNVM command.
+ //
+ LbaSizeIsSupported = FALSE;
+ for (FlbaIndex = 0; FlbaIndex < Device->NamespaceData.Nlbaf; FlbaIndex++) {
+ if (Device->NamespaceData.LbaFormat[FlbaIndex].Lbads == LbaSize) {
+ LbaSizeIsSupported = TRUE;
+ break;
+ }
+ }
+
+ if (LbaSizeIsSupported) {
+ Status = NvmExpressFormatNvm (
+ &Device->BlockIo,
+ NamespaceId,
+ SecureEraseSettings,
+ FlbaIndex
+ );
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ return Status;
+}
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressMediaSanitize.h b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressMediaSanitize.h
new file mode 100644
index 0000000..197b923
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressMediaSanitize.h
@@ -0,0 +1,191 @@
+/** @file
+ Header file for MEDIA_SANITIZE_PROTOCOL interface.
+
+ Copyright (c) Microsoft Corporation.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef NVME_MEDIA_SANITIZE_H_
+#define NVME_MEDIA_SANITIZE_H_
+
+#define NVME_NO_DEALLOCATE_AFTER_SANITZE 0x1
+
+/**
+ Send NVM Express FormatNVM Admin Command
+
+ The Format NVM command is used to low level format the NVM media. This command is used by
+ the host to change the LBA data size and/or metadata size.
+
+ A low level format may destroy all data and metadata associated with all namespaces or only
+ the specific namespace associated with the command (refer to the Format NVM Attributes field
+ in the Identify Controller data structure).
+
+ After the Format NVM command successfully completes, the controller shall not return any user
+ data that was previously contained in an affected namespace.
+
+ @param[in] This Indicates a pointer to the calling context (Block IO Protocol)
+ @param[in] NamespaceId The NVM Express namespace ID for which a device path node is to be
+ allocated and built. Caller must set the NamespaceId to zero if the
+ device path node will contain a valid UUID.
+ @param[in] Ses Secure Erase Setting (SES) value
+ - 000b: No secure erase operation requested
+ - 001b: User Data Erase
+ - 010b: Cryptographic Erase
+ - 011b to 111b: Reserved
+ @param[in] Flbas New LBA size (in terms of LBA Format size Index (bits 3:0) in NamespaceData).
+ If this param is 0 (NULL), then use existing LBA size.
+
+ @retval EFI_SUCCESS The device formatted correctly.
+ @retval EFI_WRITE_PROTECTED The device can not be formatted due to write protection.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the format.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_INVALID_PARAMETER The format request contains parameters that are not valid.
+
+**/
+EFI_STATUS
+NvmExpressFormatNvm (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 NamespaceId,
+ IN UINT32 Ses,
+ IN UINT32 Flbas
+ );
+
+/**
+ Send NVM Express Sanitize Admin Command
+
+ The Sanitize command is used to start a sanitize operation or to recover from a previously
+ failed sanitize operation. The sanitize operation types that may be supported are Block
+ Erase, Crypto Erase, and Overwrite.
+
+ All sanitize operations are processed in the background (i.e., completion of the Sanitize
+ command does not indicate completion of the sanitize operation).
+
+ @param[in] This Indicates a pointer to the calling context (Block IO Protocol)
+ @param[in] NamespaceId The NVM Express namespace ID for which a device path node is to be
+ allocated and built. Caller must set the NamespaceId to zero if the
+ device path node will contain a valid UUID.
+ @param[in] SanitizeAction Sanitize action
+ @param[in] NoDeallocAfterSanitize No deallocate after sanitize option
+ @param[in] OverwritePattern Pattern to overwrite old user data
+
+ @retval EFI_SUCCESS The media was sanitized successfully on the device.
+ @retval EFI_WRITE_PROTECTED The device can not be sanitized due to write protection.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the sanitize.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not match the current device.
+ @retval EFI_INVALID_PARAMETER The sanitize request contains parameters that are not valid.
+
+**/
+EFI_STATUS
+NvmExpressSanitize (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 NamespaceId,
+ IN UINT32 SanitizeAction,
+ IN UINT32 NoDeallocAfterSanitize,
+ IN UINT32 OverwritePattern
+ );
+
+/**
+ Clear Media utilizes transport native WRITE commands to write a fixed pattern
+ of non-sensitive data to the media.
+
+ NOTE: The caller shall send buffer of one sector/LBA size with overwrite data.
+ NOTE: This operation is a blocking call.
+ NOTE: This function must be called from TPL_APPLICATION or TPL_CALLBACK.
+
+ Functions are defined to erase and purge data at a block level from mass
+ storage devices as well as to manage such devices in the EFI boot services
+ environment.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] PassCount The number of passes to write over media.
+ @param[in] SectorOwBuffer A pointer to the overwrite buffer.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressMediaClear (
+ IN MEDIA_SANITIZE_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT32 PassCount,
+ IN VOID *SectorOwBuffer
+ );
+
+/**
+ Purge Media utilizes transport native Sanitize operations. Sanitize specific
+ purge actions include: overwrite, block erase, or crypto erase.
+
+ Functions are defined to erase and purge data at a block level from mass
+ storage devices as well as to manage such devices in the EFI boot services
+ environment. Sanitization refers to a process that renders access to target
+ data on the media infeasible for a given level of effort.
+
+ NOTE: This operation is a blocking call.
+ NOTE: This function must be called from TPL_APPLICATION or TPL_CALLBACK.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] PurgeAction The purage action (overwrite, crypto erase, block erase).
+ @param[in] OverwritePattern 32-bit pattern to overwrite on media (for overwrite).
+
+ @retval EFI_SUCCESS The media was purged successfully on the device.
+ @retval EFI_WRITE_PROTECTED The device can not be purged due to write protection.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the purge.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not match the current device.
+ @retval EFI_INVALID_PARAMETER The purge request contains parameters that are not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressMediaPurge (
+ IN MEDIA_SANITIZE_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT32 PurgeAction,
+ IN UINT32 OverwritePattern
+ );
+
+/**
+ Format Media utilizes native format operations to modify sector/LBA size.
+ Secure erase actions are used to define how latent user data is erased.
+
+ NOTE: This function must be called from TPL_APPLICATION or TPL_CALLBACK.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the clear request is for.
+ @param[in] LbaSize Size of LBA (in terms of power of two: 2^n).
+ @param[in] SecureEraseAction Secure erase action, if any, to apply to format.
+ - 000b: No secure erase operation requested
+ - 001b: User Data Erase
+ - 010b: Cryptographic Erase
+ - 011b to 111b: Reserved
+
+ @retval EFI_SUCCESS The media format request completed successfully on the device.
+ @retval EFI_WRITE_PROTECTED The device can't be formatted due to write protection.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the format operation.
+ @retval EFI_INVALID_PARAMETER The format request contains parameters that are not valid.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+
+ **/
+EFI_STATUS
+EFIAPI
+NvmExpressMediaFormat (
+ IN MEDIA_SANITIZE_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT32 LbaSize,
+ IN UINT32 SecureEraseAction
+ );
+
+#endif
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c
index 2ff2cb0..f818e48 100644
--- a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c
+++ b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c
@@ -824,6 +824,8 @@ NvmExpressPassThru (
//
CopyMem (Packet->NvmeCompletion, (VOID *)Cq, sizeof (EFI_NVM_EXPRESS_COMPLETION));
} else {
+ ReportStatusCode ((EFI_ERROR_MAJOR | EFI_ERROR_CODE), (EFI_IO_BUS_SCSI | EFI_IOB_EC_INTERFACE_ERROR));
+
//
// Timeout occurs for an NVMe command. Reset the controller to abort the
// outstanding commands.
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/UnitTest/MediaSanitizeUnitTest.c b/MdeModulePkg/Bus/Pci/NvmExpressDxe/UnitTest/MediaSanitizeUnitTest.c
new file mode 100644
index 0000000..b872858
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/NvmExpressDxe/UnitTest/MediaSanitizeUnitTest.c
@@ -0,0 +1,1128 @@
+/** @file -- MediaSanitizeUnitTest.c
+ Placeholder/framework for developing a Media Sanitize unit test package.
+
+ Copyright (c) Microsoft Corporation.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UnitTestLib.h>
+#include <Library/UefiApplicationEntryPoint.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/NvmExpressPassthru.h>
+#include <Protocol/MediaSanitize.h>
+
+#include "../NvmExpress.h"
+#include "../NvmExpressBlockIo.h"
+#include "../NvmExpressMediaSanitize.h"
+#include "../NvmExpressHci.h"
+
+/**
+ Helper function for Nvme pass thru.
+
+ @param[in] This Private Data.
+ @param[in] NamespaceId Name Space Id.
+ @param[in,out] Packet Transfer Buffer.
+ @param[in] Event Event handle.
+
+ **/
+EFI_STATUS
+EFIAPI
+NvmeDeviceUnitTestPassthru (
+ IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This,
+ IN UINT32 NamespaceId,
+ IN OUT EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet,
+ IN EFI_EVENT Event OPTIONAL
+ )
+{
+ //
+ // Parse command packet for unit testing
+ //
+ EFI_NVM_EXPRESS_COMMAND *Command;
+ EFI_NVM_EXPRESS_COMPLETION *Completion;
+ NVME_CQ *Cqe;
+ NVME_ADMIN_FORMAT_NVM FormatNvmCdw10;
+ NVME_ADMIN_SANITIZE SanitizeCdw1011;
+
+ ASSERT (This);
+ ASSERT (Packet);
+
+ Command = Packet->NvmeCmd;
+ Completion = Packet->NvmeCompletion;
+ Cqe = (NVME_CQ *)Completion;
+
+ ZeroMem (&FormatNvmCdw10, sizeof (NVME_ADMIN_FORMAT_NVM));
+ ZeroMem (&SanitizeCdw1011, sizeof (NVME_ADMIN_SANITIZE));
+
+ switch (Command->Cdw0.Opcode) {
+ case NVME_ADMIN_FORMAT_NVM_CMD:
+ UT_LOG_VERBOSE ("%a: Opcode = NVME_ADMIN_FORMAT_NVM_CMD\n", __func__);
+
+ CopyMem (&FormatNvmCdw10, &Command->Cdw10, sizeof (NVME_ADMIN_FORMAT_NVM));
+
+ //
+ // FormatNVM Check 1: Validate SES parameter
+ //
+ if (FormatNvmCdw10.Ses > 0x2) {
+ Cqe->Sct = NVME_CQE_SCT_GENERIC_CMD_STATUS;
+ Cqe->Sc = NVME_CQE_SC_INVALID_FIELD_IN_CMD;
+
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // FormatNVM Check 2: Validate LbaIndex parameter
+ //
+ if (FormatNvmCdw10.Lbaf > 0x1) {
+ Cqe->Sct = NVME_CQE_SCT_GENERIC_CMD_STATUS;
+ Cqe->Sc = NVME_CQE_SC_INVALID_FIELD_IN_CMD;
+
+ return EFI_INVALID_PARAMETER;
+ }
+
+ break;
+ case NVME_ADMIN_SANITIZE_CMD:
+ UT_LOG_VERBOSE ("%a: Opcode = NVME_ADMIN_SANITIZE_CMD\n", __func__);
+
+ CopyMem (&SanitizeCdw1011, &Command->Cdw10, sizeof (NVME_ADMIN_SANITIZE));
+
+ //
+ // Sanitize Check 1: Validate Sanitize Action parameter
+ //
+ if (SanitizeCdw1011.Sanact > 0x4) {
+ Cqe->Sct = NVME_CQE_SCT_GENERIC_CMD_STATUS;
+ Cqe->Sc = NVME_CQE_SC_INVALID_FIELD_IN_CMD;
+
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Sanitize Check 2: Validate overwrite action with non-NULL overwrite pattern
+ //
+ if (((SanitizeCdw1011.Sanact == SANITIZE_ACTION_OVERWRITE) && (SanitizeCdw1011.Ovrpat != 0xDEADBEEF)) ||
+ ((SanitizeCdw1011.Sanact != SANITIZE_ACTION_OVERWRITE) && (SanitizeCdw1011.Ovrpat != 0)))
+ {
+ Cqe->Sct = NVME_CQE_SCT_GENERIC_CMD_STATUS;
+ Cqe->Sc = NVME_CQE_SC_INVALID_FIELD_IN_CMD;
+
+ return EFI_INVALID_PARAMETER;
+ }
+
+ break;
+ default:
+ UT_LOG_VERBOSE ("%a: Invalid Opcode = 0x%x!!!\n", __func__, Command->Cdw0.Opcode);
+ break;
+ }
+
+ //
+ // Populate CQE (completion queue entry based on opcode and parameters
+ //
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Helper function to simulate read.
+
+ @param[in] Private Private Data.
+ @param[in] NamespaceId Name Space Id.
+ @param[in] Buffer Transfer Buffer.
+
+ **/
+EFI_STATUS
+NvmeIdentifyNamespace (
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINT32 NamespaceId,
+ IN VOID *Buffer
+ )
+{
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND Command;
+ EFI_NVM_EXPRESS_COMPLETION Completion;
+
+ ZeroMem (&CommandPacket, sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof (EFI_NVM_EXPRESS_COMMAND));
+ ZeroMem (&Completion, sizeof (EFI_NVM_EXPRESS_COMPLETION));
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeCompletion = &Completion;
+ Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD;
+ Command.Nsid = NamespaceId;
+ CommandPacket.TransferBuffer = Buffer;
+ CommandPacket.TransferLength = sizeof (NVME_ADMIN_NAMESPACE_DATA);
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueType = NVME_ADMIN_QUEUE;
+
+ //
+ // Set bit 0 (Cns bit) to 1 to identify a namespace
+ //
+ CommandPacket.NvmeCmd->Cdw10 = 0;
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Helper function to simulate read.
+
+ @param[in] Device Private Data.
+ @param[out] Buffer Buffer to read into.
+ @param[in] Lba Logical Block Addess to read from.
+ @param[in] Blocks Number of blocks.
+
+ **/
+EFI_STATUS
+NvmeUnitTestRead (
+ IN NVME_DEVICE_PRIVATE_DATA *Device,
+ OUT VOID *Buffer,
+ IN UINT64 Lba,
+ IN UINTN Blocks
+ )
+{
+ UT_ASSERT_NOT_NULL (Device);
+ Buffer = NULL;
+ Lba = 0;
+ Blocks = 0;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Helper function to simulate write.
+
+ @param[in] Device Private Data.
+ @param[in] Buffer Buffer to write.
+ @param[in] Lba Logical Block Addess to write.
+ @param[in] Blocks Number of blocks.
+
+ **/
+EFI_STATUS
+NvmeUnitTestWrite (
+ IN NVME_DEVICE_PRIVATE_DATA *Device,
+ IN VOID *Buffer,
+ IN UINT64 Lba,
+ IN UINTN Blocks
+ )
+{
+ UT_ASSERT_NOT_NULL (Device);
+ Buffer = NULL;
+ Lba = 0;
+ Blocks = 0;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Simulated BlockIo read block function.
+
+ @param[in] This BlockIo Protocol.
+ @param[in] MediaId Id of the media.
+ @param[in] Lba Logical Block Address.
+ @param[in] BufferSize Size of Buffer.
+ @param[out] Buffer Actual buffer to use to read.
+
+ **/
+EFI_STATUS
+EFIAPI
+NvmeBlockIoReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ NVME_DEVICE_PRIVATE_DATA *Device;
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ UINTN IoAlign;
+
+ //
+ // Check parameters.
+ //
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Media = This->Media;
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ BlockSize = Media->BlockSize;
+ if ((BufferSize % BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ NumberOfBlocks = BufferSize / BlockSize;
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IoAlign = Media->IoAlign;
+ if ((IoAlign > 0) && (((UINTN)Buffer & (IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);
+ Status = NvmeUnitTestRead (Device, Buffer, Lba, NumberOfBlocks);
+
+ return Status;
+}
+
+/**
+ Simulated BlockIo write block function.
+
+ @param[in] This BlockIo Protocol.
+ @param[in] MediaId Id of the media.
+ @param[in] Lba Logical Block Address.
+ @param[in] BufferSize Size of Buffer.
+ @param[in] Buffer Actual buffer to use to write.
+
+ **/
+EFI_STATUS
+EFIAPI
+NvmeBlockIoWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ NVME_DEVICE_PRIVATE_DATA *Device;
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ UINTN IoAlign;
+
+ //
+ // Check parameters.
+ //
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Media = This->Media;
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ BlockSize = Media->BlockSize;
+ if ((BufferSize % BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ NumberOfBlocks = BufferSize / BlockSize;
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IoAlign = Media->IoAlign;
+ if ((IoAlign > 0) && (((UINTN)Buffer & (IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);
+ Status = NvmeUnitTestWrite (Device, Buffer, Lba, NumberOfBlocks);
+
+ return Status;
+}
+
+/**
+ Simulated BlockIo read block ex function.
+
+ @param[in] This BlockIo2 Protocol.
+ @param[in] MediaId Id of the media.
+ @param[in] Lba Logical Block Address.
+ @param[in,out] Token Block Io2 token.
+
+ @param[in] BufferSize Size of Buffer.
+ @param[out] Buffer Actual buffer to use to read.
+
+ **/
+EFI_STATUS
+EFIAPI
+NvmeBlockIoReadBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ NVME_DEVICE_PRIVATE_DATA *Device;
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ UINTN IoAlign;
+ EFI_STATUS Status;
+
+ //
+ // Check parameters.
+ //
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Media = This->Media;
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BlockSize = Media->BlockSize;
+ if ((BufferSize % BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ NumberOfBlocks = BufferSize / BlockSize;
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IoAlign = Media->IoAlign;
+ if ((IoAlign > 0) && (((UINTN)Buffer & (IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO2 (This);
+ Status = NvmeUnitTestRead (Device, Buffer, Lba, NumberOfBlocks);
+
+ return Status;
+}
+
+/**
+ Simulated BlockIo write block ex function.
+
+ @param[in] This BlockIo2 Protocol.
+ @param[in] MediaId Id of the media.
+ @param[in] Lba Logical Block Address.
+ @param[in,out] Token Block Io2 token.
+ @param[in] BufferSize Size of Buffer.
+
+ @param[in] Buffer Actual buffer to use to write.
+
+ **/
+EFI_STATUS
+EFIAPI
+NvmeBlockIoWriteBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ NVME_DEVICE_PRIVATE_DATA *Device;
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ UINTN IoAlign;
+ EFI_STATUS Status;
+
+ //
+ // Check parameters.
+ //
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Media = This->Media;
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BlockSize = Media->BlockSize;
+ if ((BufferSize % BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ NumberOfBlocks = BufferSize / BlockSize;
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IoAlign = Media->IoAlign;
+ if ((IoAlign > 0) && (((UINTN)Buffer & (IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO2 (This);
+ Status = NvmeUnitTestWrite (Device, Buffer, Lba, NumberOfBlocks);
+
+ return Status;
+}
+
+/**
+ MediaSanitizePurgeUnitTest to initialize a Private Namespace instance.
+
+ @param[in] ppDevice Nvme Private Data structure to destory and free.
+ **/
+UNIT_TEST_STATUS
+EFIAPI
+NvmeDestroyDeviceInstance (
+ NVME_DEVICE_PRIVATE_DATA **ppDevice
+ )
+{
+ //
+ // Free in following order to to avoid dangling pointers:
+ //
+ // 1 - NVME_ADMIN_CONTROLLER_DATA
+ // 2 - NVME_CONTROLLER_PRIVATE_DATA
+ // 3 - NVME_DEVICE_PRIVATE_DATA
+ //
+ FreePool ((*ppDevice)->Controller->ControllerData);
+ (*ppDevice)->Controller->ControllerData = NULL;
+
+ FreePool ((*ppDevice)->Controller);
+ (*ppDevice)->Controller = NULL;
+
+ FreePool ((*ppDevice));
+ *ppDevice = NULL;
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ MediaSanitizePurgeUnitTest to initialize a Private Namespace instance.
+
+ @param[in] ppDevice Nvme Private Data structure to initialize.
+ **/
+UNIT_TEST_STATUS
+EFIAPI
+NvmeCreateDeviceInstance (
+ NVME_DEVICE_PRIVATE_DATA **ppDevice
+ )
+{
+ NVME_ADMIN_NAMESPACE_DATA *NamespaceData;
+ NVME_CONTROLLER_PRIVATE_DATA *Private;
+ NVME_DEVICE_PRIVATE_DATA *Device;
+
+ Private = AllocateZeroPool (sizeof (NVME_CONTROLLER_PRIVATE_DATA));
+
+ Private->Signature = NVME_CONTROLLER_PRIVATE_DATA_SIGNATURE;
+ Private->Cid[0] = 0;
+ Private->Cid[1] = 0;
+ Private->Cid[2] = 0;
+ Private->Pt[0] = 0;
+ Private->Pt[1] = 0;
+ Private->Pt[2] = 0;
+ Private->SqTdbl[0].Sqt = 0;
+ Private->SqTdbl[1].Sqt = 0;
+ Private->SqTdbl[2].Sqt = 0;
+ Private->CqHdbl[0].Cqh = 0;
+ Private->CqHdbl[1].Cqh = 0;
+ Private->CqHdbl[2].Cqh = 0;
+ Private->AsyncSqHead = 0;
+
+ Private->ControllerData = (NVME_ADMIN_CONTROLLER_DATA *)AllocateZeroPool (sizeof (NVME_ADMIN_CONTROLLER_DATA));
+
+ UT_LOG_VERBOSE ("%a: Allocated and Initialized NVME_CONTROLLER_PRIVATE_DATA\n", __func__);
+ UT_LOG_VERBOSE ("%a: Allocated and Initialized NVME_ADMIN_CONTROLLER_DATA\n", __func__);
+
+ Private->ControllerData->Nn = 1; // One namespace
+ Private->ControllerData->Sanicap.Bes = 1; // Block Erase Supported
+ Private->ControllerData->Sanicap.Ces = 1; // Crypto Erase Supported
+ Private->ControllerData->Sanicap.Ows = 1; // Overwrite Supported
+
+ NamespaceData = AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA));
+ UT_LOG_VERBOSE ("%a: Allocated and Initialized NVME_ADMIN_NAMESPACE_DATA\n", __func__);
+
+ Device = (NVME_DEVICE_PRIVATE_DATA *)(AllocateZeroPool (sizeof (NVME_DEVICE_PRIVATE_DATA)));
+
+ //
+ // Initialize SSD namespace instance data
+ //
+ Device->Signature = NVME_DEVICE_PRIVATE_DATA_SIGNATURE;
+ Device->NamespaceId = 0;
+ Device->NamespaceUuid = 1;
+
+ Device->Controller = Private;
+
+ //
+ // Build BlockIo media structure
+ //
+ Device->Media.MediaId = 0;
+ Device->Media.RemovableMedia = FALSE;
+ Device->Media.MediaPresent = TRUE;
+ Device->Media.LogicalPartition = FALSE;
+ Device->Media.ReadOnly = FALSE;
+ Device->Media.WriteCaching = FALSE;
+ Device->Media.BlockSize = (UINT32)(1 << 9); // 512 byte sector size
+
+ Device->Media.LastBlock = 0x4000; // NamespaceData=>Nsze
+ Device->Media.LogicalBlocksPerPhysicalBlock = 1;
+ Device->Media.LowestAlignedLba = 1;
+
+ Device->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2;
+ Device->BlockIo.Media = &Device->Media;
+ Device->BlockIo.ReadBlocks = NvmeBlockIoReadBlocks;
+ Device->BlockIo.WriteBlocks = NvmeBlockIoWriteBlocks;
+
+ Device->BlockIo2.Media = &Device->Media;
+ Device->BlockIo2.ReadBlocksEx = NvmeBlockIoReadBlocksEx;
+ Device->BlockIo2.WriteBlocksEx = NvmeBlockIoWriteBlocksEx;
+
+ Device->MediaSanitize.Revision = MEDIA_SANITIZE_PROTOCOL_REVISION;
+ Device->MediaSanitize.Media = &Device->Media;
+ Device->MediaSanitize.MediaClear = NvmExpressMediaClear;
+ Device->MediaSanitize.MediaPurge = NvmExpressMediaPurge;
+ Device->MediaSanitize.MediaFormat = NvmExpressMediaFormat;
+
+ Device->Controller->Passthru.Mode = 0;
+ Device->Controller->Passthru.PassThru = NvmeDeviceUnitTestPassthru;
+ Device->Controller->Passthru.BuildDevicePath = NULL;
+ Device->Controller->Passthru.GetNamespace = NULL;
+ Device->Controller->Passthru.GetNextNamespace = NULL;
+
+ CopyMem (&Device->NamespaceData, NamespaceData, sizeof (NVME_ADMIN_NAMESPACE_DATA));
+ *ppDevice = Device;
+
+ UT_LOG_VERBOSE ("%a: Allocated and Initialized NVME_DEVICE_PRIVATE_DATA\n", __func__);
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ MediaSanitizePurgeUnitTest to Test calls to NvmExpressMediaPurge.
+
+ @param[in] Context Unit test case context
+ **/
+UNIT_TEST_STATUS
+EFIAPI
+MediaSanitizePurgeUnitTest (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ UINT32 PurgeAction;
+ UINT32 OverwritePattern;
+ UNIT_TEST_STATUS UnitTestStatus;
+ NVME_DEVICE_PRIVATE_DATA *NvmeDevice;
+ EFI_STATUS Status;
+
+ UnitTestStatus = UNIT_TEST_PASSED;
+ NvmeDevice = NULL;
+ Status = EFI_SUCCESS;
+
+ UnitTestStatus = NvmeCreateDeviceInstance (&NvmeDevice);
+
+ UT_ASSERT_STATUS_EQUAL (UnitTestStatus, UNIT_TEST_PASSED);
+ UT_ASSERT_NOT_NULL (NvmeDevice);
+
+ UT_LOG_VERBOSE ("%a: Create Device Instance Status = 0x%x\n", __func__, UnitTestStatus);
+ UT_LOG_VERBOSE ("%a: Device = 0x%x\n", __func__, NvmeDevice);
+ UT_LOG_VERBOSE ("%a: Device->BlockIo = 0x%x\n", __func__, NvmeDevice->BlockIo);
+ UT_LOG_VERBOSE ("%a: Device->Signature = 0x%x\n", __func__, NvmeDevice->Signature);
+
+ //
+ // Case 1: Block Erase
+ //
+ PurgeAction = SANITIZE_ACTION_BLOCK_ERASE;
+ OverwritePattern = 0;
+
+ Status = NvmExpressMediaPurge (
+ &NvmeDevice->MediaSanitize,
+ NvmeDevice->Media.MediaId,
+ PurgeAction,
+ OverwritePattern
+ );
+
+ UT_ASSERT_NOT_EFI_ERROR (Status);
+
+ UnitTestStatus = NvmeDestroyDeviceInstance (&NvmeDevice);
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ NvmeSanitizeUnitTest to Test calls to NvmExpressSanitize.
+
+ @param[in] Context Unit test case context
+ **/
+UNIT_TEST_STATUS
+EFIAPI
+NvmeSanitizeUnitTest (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ UINT32 NamespaceId;
+ UINT32 SanitizeAction;
+ UINT32 NoDeallocateAfterSanitize;
+ UINT32 OverwritePattern;
+ UNIT_TEST_STATUS UnitTestStatus;
+ NVME_DEVICE_PRIVATE_DATA *NvmeDevice;
+ EFI_STATUS Status;
+
+ NamespaceId = 0;
+ UnitTestStatus = UNIT_TEST_PASSED;
+ NvmeDevice = NULL;
+ Status = EFI_SUCCESS;
+ SanitizeAction = SANITIZE_ACTION_BLOCK_ERASE;
+ NoDeallocateAfterSanitize = 0;
+ OverwritePattern = 0;
+
+ UnitTestStatus = NvmeCreateDeviceInstance (&NvmeDevice);
+
+ UT_ASSERT_STATUS_EQUAL (UnitTestStatus, UNIT_TEST_PASSED);
+ UT_ASSERT_NOT_NULL (NvmeDevice);
+
+ UT_LOG_VERBOSE ("%a: Create Device Instance Status = 0x%x\n", __func__, UnitTestStatus);
+ UT_LOG_VERBOSE ("%a: Device = 0x%x\n", __func__, NvmeDevice);
+ UT_LOG_VERBOSE ("%a: Device->BlockIo = 0x%x\n", __func__, NvmeDevice->BlockIo);
+ UT_LOG_VERBOSE ("%a: Device->Signature = 0x%x\n", __func__, NvmeDevice->Signature);
+
+ //
+ // Case 1: Block Erase
+ //
+ SanitizeAction = SANITIZE_ACTION_BLOCK_ERASE;
+ NoDeallocateAfterSanitize = 0;
+ OverwritePattern = 0;
+
+ Status = NvmExpressSanitize (
+ &NvmeDevice->BlockIo,
+ NamespaceId,
+ SanitizeAction,
+ NoDeallocateAfterSanitize,
+ OverwritePattern
+ );
+
+ UT_ASSERT_NOT_EFI_ERROR (Status);
+
+ //
+ // Case 2: Crypto Erase
+ //
+ SanitizeAction = SANITIZE_ACTION_CRYPTO_ERASE;
+ NoDeallocateAfterSanitize = 0;
+ OverwritePattern = 0;
+
+ Status = NvmExpressSanitize (
+ &NvmeDevice->BlockIo,
+ NamespaceId,
+ SanitizeAction,
+ NoDeallocateAfterSanitize,
+ OverwritePattern
+ );
+
+ UT_ASSERT_NOT_EFI_ERROR (Status);
+
+ //
+ // Case 3: Overwrite
+ //
+ SanitizeAction = SANITIZE_ACTION_OVERWRITE;
+ NoDeallocateAfterSanitize = 0;
+ OverwritePattern = 0xDEADBEEF;
+
+ Status = NvmExpressSanitize (
+ &NvmeDevice->BlockIo,
+ NamespaceId,
+ SanitizeAction,
+ NoDeallocateAfterSanitize,
+ OverwritePattern
+ );
+
+ UT_ASSERT_NOT_EFI_ERROR (Status);
+
+ //
+ // Case 4: Block Erase (invalid overwrite pattern)
+ //
+ SanitizeAction = SANITIZE_ACTION_BLOCK_ERASE;
+ NoDeallocateAfterSanitize = 0;
+ OverwritePattern = 0xDEADBEEF;
+
+ Status = NvmExpressSanitize (
+ &NvmeDevice->BlockIo,
+ NamespaceId,
+ SanitizeAction,
+ NoDeallocateAfterSanitize,
+ OverwritePattern
+ );
+
+ UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER);
+
+ //
+ // Case 5: Overwrite (invalid overwrite pattern)
+ //
+ SanitizeAction = SANITIZE_ACTION_OVERWRITE;
+ NoDeallocateAfterSanitize = 0;
+ OverwritePattern = 0;
+
+ Status = NvmExpressSanitize (
+ &NvmeDevice->BlockIo,
+ NamespaceId,
+ SanitizeAction,
+ NoDeallocateAfterSanitize,
+ OverwritePattern
+ );
+
+ UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER);
+
+ UnitTestStatus = NvmeDestroyDeviceInstance (&NvmeDevice);
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ NvmeFormatNvmUnitTest to Test calls to NvmExpressFormatNvm.
+
+ @param[in] Context Unit test case context
+ **/
+UNIT_TEST_STATUS
+EFIAPI
+NvmeFormatNvmUnitTest (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ UINT32 NamespaceId;
+ UINT32 Ses;
+ UINT32 Flbas;
+ NVME_DEVICE_PRIVATE_DATA *NvmeDevice;
+ UNIT_TEST_STATUS UnitTestStatus;
+ EFI_STATUS Status;
+
+ NamespaceId = 0;
+ NvmeDevice = NULL;
+ UnitTestStatus = UNIT_TEST_PASSED;
+ Status = EFI_SUCCESS;
+
+ UnitTestStatus = NvmeCreateDeviceInstance (&NvmeDevice);
+
+ UT_ASSERT_STATUS_EQUAL (UnitTestStatus, UNIT_TEST_PASSED);
+ UT_ASSERT_NOT_NULL (NvmeDevice);
+
+ UT_LOG_VERBOSE ("%a: Create Device Instance Status = 0x%x\n", __func__, UnitTestStatus);
+ UT_LOG_VERBOSE ("%a: Device = 0x%x\n", __func__, NvmeDevice);
+ UT_LOG_VERBOSE ("%a: Device->BlockIo = 0x%x\n", __func__, NvmeDevice->BlockIo);
+ UT_LOG_VERBOSE ("%a: Device->Signature = 0x%x\n", __func__, NvmeDevice->Signature);
+
+ //
+ // Case 1: User Data Erase (Flbas = 0)
+ //
+ Ses = SES_USER_DATA_ERASE;
+ Flbas = 0;
+ Status = NvmExpressFormatNvm (
+ &NvmeDevice->BlockIo,
+ NamespaceId,
+ Ses,
+ Flbas
+ );
+
+ UT_ASSERT_NOT_EFI_ERROR (Status);
+
+ //
+ // Case 2: Crypto Erase (Flbas = 0)
+ //
+ Ses = SES_CRYPTO_ERASE;
+ Flbas = 0;
+ Status = NvmExpressFormatNvm (
+ &NvmeDevice->BlockIo,
+ NamespaceId,
+ Ses,
+ Flbas
+ );
+
+ UT_ASSERT_NOT_EFI_ERROR (Status);
+
+ //
+ // Case 3: User Data Erase (Invalid Flbas = 3)
+ //
+ Ses = SES_USER_DATA_ERASE;
+ Flbas = 3;
+ Status = NvmExpressFormatNvm (
+ &NvmeDevice->BlockIo,
+ NamespaceId,
+ Ses,
+ Flbas
+ );
+
+ UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER);
+
+ //
+ // Case 4: Invalid SES (Flba = 0)
+ //
+ Ses = 0xFF;
+ Flbas = 0;
+ Status = NvmExpressFormatNvm (
+ &NvmeDevice->BlockIo,
+ NamespaceId,
+ Ses,
+ Flbas
+ );
+
+ UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER);
+
+ UnitTestStatus = NvmeDestroyDeviceInstance (&NvmeDevice);
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Baseline Unit Test.
+
+ @param[in] Context Unit test case context
+ **/
+UNIT_TEST_STATUS
+EFIAPI
+UnitTestBaseline (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ UINT32 A;
+ UINT32 B;
+ UINT32 C;
+
+ A = 1;
+ B = 1;
+ C = A + B;
+
+ UT_ASSERT_EQUAL (C, 2);
+ UT_ASSERT_NOT_EQUAL (0, 1);
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Test Case that locks a variable using the Variable Policy Protocol with a
+ policy other than LOCK_NOW then attempts to lock the same variable using the
+ Variable Lock Protocol. The call to Variable Policy is expected to succeed
+ and the call to Variable Lock is expected to fail.
+
+ @retval EFI_SUCCES Success
+ @retval Other Error
+ **/
+EFI_STATUS
+EFIAPI
+MediaSanitizeUnitTestEntry (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UNIT_TEST_FRAMEWORK_HANDLE Framework;
+ UNIT_TEST_SUITE_HANDLE NvmeFormatNvmTestSuite;
+ UNIT_TEST_SUITE_HANDLE NvmeSanitizeTestSuite;
+ UNIT_TEST_SUITE_HANDLE MediaSanitizeProtocolTestSuite;
+
+ Framework = NULL;
+
+ #define UNIT_TEST_NAME "Media Sanitize Protocol Unit Test"
+ #define UNIT_TEST_VERSION "1.0"
+
+ DEBUG ((DEBUG_INFO, "%a v%a\n", UNIT_TEST_NAME, UNIT_TEST_VERSION));
+
+ //
+ // Start setting up the test framework for running the tests.
+ //
+ Status = InitUnitTestFramework (
+ &Framework,
+ UNIT_TEST_NAME,
+ gEfiCallerBaseName,
+ UNIT_TEST_VERSION
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status = %r\n", Status));
+ goto EXIT;
+ }
+
+ //
+ // Populate the NVM Express Format NVM Unit Test Suite.
+ //
+ Status = CreateUnitTestSuite (
+ &NvmeFormatNvmTestSuite,
+ Framework,
+ "NVM Express Format NVM Test Suite",
+ "Nvm.Express.Format.Nvm",
+ NULL,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for NvmeFormatNvmTestSuite. Status = %r\n", Status));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ //
+ // Add baseline sanity test case
+ //
+ AddTestCase (
+ NvmeFormatNvmTestSuite, // Test Suite Handle
+ "Baseline Format NVM Unit Test", // Test Description
+ "FormatNVM", // Test Class
+ UnitTestBaseline, // UNIT_TEST_FUNCTION()
+ NULL, // (Optional) UNIT_TEST_PREREQUISITE()
+ NULL, // (Optional) UNIT_TEST_CLEANUP()
+ NULL // (Optional) UNIT_TEST_CONTEXT
+ );
+
+ //
+ // Add test case for NvmExpressFormatNvm()
+ //
+ AddTestCase (
+ NvmeFormatNvmTestSuite, // Test Suite Handle
+ "Admin Format NVM Command Unit Test", // Test Description
+ "FormatNVM", // Test Class
+ NvmeFormatNvmUnitTest, // UNIT_TEST_FUNCTION()
+ NULL, // (Optional) UNIT_TEST_PREREQUISITE()
+ NULL, // (Optional) UNIT_TEST_CLEANUP()
+ NULL // (Optional) UNIT_TEST_CONTEXT
+ );
+
+ //
+ // Populate the NVM Express Sanitize Unit Test Suite.
+ //
+ Status = CreateUnitTestSuite (
+ &NvmeSanitizeTestSuite,
+ Framework,
+ "NVM Express Sanitize Test Suite",
+ "Nvm.Express.Sanitize",
+ NULL,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for NvmeSanitizTestSuite. Status = %r\n", Status));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ //
+ // Add baseline sanity test
+ //
+ AddTestCase (
+ NvmeSanitizeTestSuite, // Test Suite Handle
+ "Baseline Sanitize Unit Test", // Test Description
+ "Sanitize", // Test Class
+ UnitTestBaseline, // UNIT_TEST_FUNCTION()
+ NULL, // (Optional) UNIT_TEST_PREREQUISITE()
+ NULL, // (Optional) UNIT_TEST_CLEANUP()
+ NULL // (Optional) UNIT_TEST_CONTEXT
+ );
+
+ //
+ // Add test case for NvmExressSanitize()
+ //
+ AddTestCase (
+ NvmeSanitizeTestSuite, // Test Suite Handle
+ "Admin Sanitize Command Unit Test", // Test Description
+ "Sanitize", // Test Class
+ NvmeSanitizeUnitTest, // UNIT_TEST_FUNCTION()
+ NULL, // (Optional) UNIT_TEST_PREREQUISITE()
+ NULL, // (Optional) UNIT_TEST_CLEANUP()
+ NULL // (Optional) UNIT_TEST_CONTEXT
+ );
+
+ //
+ // Populate the Media Sanitize Protocol Unit Test Suite.
+ //
+ Status = CreateUnitTestSuite (
+ &MediaSanitizeProtocolTestSuite,
+ Framework,
+ "Media Sanitize Protocol Test Suite",
+ "Media.Sanitize.Protocol",
+ NULL,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for MediaSanitizeProtocolTestSuite. Status = %r\n", Status));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ //
+ // Add test case for Media Purge
+ //
+ AddTestCase (
+ MediaSanitizeProtocolTestSuite, // Test Suite Handle
+ "Baseline MediaSanitize Unit Test", // Test Description
+ "MediaSanitize", // Test Class
+ UnitTestBaseline, // UNIT_TEST_FUNCTION()
+ NULL, // (Optional) UNIT_TEST_PREREQUISITE()
+ NULL, // (Optional) UNIT_TEST_CLEANUP()
+ NULL // (Optional) UNIT_TEST_CONTEXT
+ );
+
+ //
+ // Add test case for Media Purge
+ //
+ AddTestCase (
+ MediaSanitizeProtocolTestSuite, // Test Suite Handle
+ "Protocol Media Sanitize Unit Test", // Test Description
+ "MediaPurge", // Test Class
+ MediaSanitizePurgeUnitTest, // UNIT_TEST_FUNCTION()
+ NULL, // (Optional) UNIT_TEST_PREREQUISITE()
+ NULL, // (Optional) UNIT_TEST_CLEANUP()
+ NULL // (Optional) UNIT_TEST_CONTEXT
+ );
+
+ //
+ // Execute the tests.
+ //
+ Status = RunAllTestSuites (Framework);
+
+EXIT:
+ if (Framework) {
+ FreeUnitTestFramework (Framework);
+ }
+
+ return Status;
+}
+
+///
+/// Avoid ECC error for function name that starts with lower case letter
+///
+#define MediaSanitizeUnitTestMain main
+
+/**
+ Standard POSIX C entry point for host based unit test execution.
+
+ @param[in] Argc Number of arguments
+ @param[in] Argv Array of pointers to arguments
+
+ @retval 0 Success
+ @retval other Error
+**/
+INT32
+MediaSanitizeUnitTestMain (
+ IN INT32 Argc,
+ IN CHAR8 *Argv[]
+ )
+{
+ return MediaSanitizeUnitTestEntry ();
+}
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/UnitTest/MediaSanitizeUnitTestHost.inf b/MdeModulePkg/Bus/Pci/NvmExpressDxe/UnitTest/MediaSanitizeUnitTestHost.inf
new file mode 100644
index 0000000..feeeea3
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/NvmExpressDxe/UnitTest/MediaSanitizeUnitTestHost.inf
@@ -0,0 +1,37 @@
+## @file
+# Unit tests for MEDIA_SANITIZE_PROTOCOL and mapping to NVM Express native commands (Sanitize and FormatNVM)
+#
+# Copyright (C) Microsoft Corporation.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = MediaSanitizeUnitTestHost
+ FILE_GUID = AAE328E9-37C3-4F4A-A2C0-0BE0E681ADA6
+ MODULE_TYPE = HOST_APPLICATION
+ VERSION_STRING = 1.0
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ MediaSanitizeUnitTest.c
+ ../NvmExpressMediaSanitize.c
+ ../NvmExpressMediaSanitize.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ UnitTestLib
+ PrintLib
+ MemoryAllocationLib
diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c b/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c
index cf6b329..a9d7e36 100644
--- a/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c
+++ b/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c
@@ -2077,7 +2077,12 @@ XhcDriverBindingStart (
XhcSetBiosOwnership (Xhc);
- XhcResetHC (Xhc, XHC_RESET_TIMEOUT);
+ Status = XhcResetHC (Xhc, XHC_RESET_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: failed to reset HC\n", __func__));
+ goto FREE_POOL;
+ }
+
ASSERT (XhcIsHalt (Xhc));
//
diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c b/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c
index 525942a..dc8228b 100644
--- a/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c
+++ b/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c
@@ -29,6 +29,8 @@ XhcReadCapReg8 (
UINT8 Data;
EFI_STATUS Status;
+ Data = 0;
+
Status = Xhc->PciIo->Mem.Read (
Xhc->PciIo,
EfiPciIoWidthUint8,
diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c b/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
index a97ed44..3caa060 100644
--- a/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
+++ b/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
@@ -2165,6 +2165,7 @@ XhcInitializeDeviceSlot (
DEVICE_CONTEXT *ParentDeviceContext;
EFI_PHYSICAL_ADDRESS PhyAddr;
+ EvtTrb = NULL;
ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
CmdTrb.CycleBit = 1;
CmdTrb.Type = TRB_TYPE_EN_SLOT;
@@ -2175,7 +2176,7 @@ XhcInitializeDeviceSlot (
XHC_GENERIC_TIMEOUT,
(TRB_TEMPLATE **)(UINTN)&EvtTrb
);
- if (EFI_ERROR (Status)) {
+ if (EFI_ERROR (Status) || (EvtTrb == NULL)) {
DEBUG ((DEBUG_ERROR, "XhcInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status));
return Status;
}
@@ -2390,6 +2391,7 @@ XhcInitializeDeviceSlot64 (
DEVICE_CONTEXT_64 *ParentDeviceContext;
EFI_PHYSICAL_ADDRESS PhyAddr;
+ EvtTrb = NULL;
ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
CmdTrb.CycleBit = 1;
CmdTrb.Type = TRB_TYPE_EN_SLOT;
@@ -2400,7 +2402,7 @@ XhcInitializeDeviceSlot64 (
XHC_GENERIC_TIMEOUT,
(TRB_TEMPLATE **)(UINTN)&EvtTrb
);
- if (EFI_ERROR (Status)) {
+ if (EFI_ERROR (Status) || (EvtTrb == NULL)) {
DEBUG ((DEBUG_ERROR, "XhcInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status));
return Status;
}
@@ -2602,6 +2604,8 @@ XhcDisableSlotCmd (
UINT8 Index;
VOID *RingSeg;
+ EvtTrb = NULL;
+
//
// Disable the device slots occupied by these devices on its downstream ports.
// Entry 0 is reserved.
@@ -2637,7 +2641,7 @@ XhcDisableSlotCmd (
XHC_GENERIC_TIMEOUT,
(TRB_TEMPLATE **)(UINTN)&EvtTrb
);
- if (EFI_ERROR (Status)) {
+ if (EFI_ERROR (Status) || (EvtTrb == NULL)) {
DEBUG ((DEBUG_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));
return Status;
}
@@ -2713,6 +2717,8 @@ XhcDisableSlotCmd64 (
UINT8 Index;
VOID *RingSeg;
+ EvtTrb = NULL;
+
//
// Disable the device slots occupied by these devices on its downstream ports.
// Entry 0 is reserved.
@@ -2748,7 +2754,7 @@ XhcDisableSlotCmd64 (
XHC_GENERIC_TIMEOUT,
(TRB_TEMPLATE **)(UINTN)&EvtTrb
);
- if (EFI_ERROR (Status)) {
+ if (EFI_ERROR (Status) || (EvtTrb == NULL)) {
DEBUG ((DEBUG_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));
return Status;
}
@@ -3240,6 +3246,8 @@ XhcSetConfigCmd (
DEVICE_CONTEXT *OutputContext;
EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ EvtTrb = NULL;
+
//
// 4.6.6 Configure Endpoint
//
@@ -3290,7 +3298,7 @@ XhcSetConfigCmd (
XHC_GENERIC_TIMEOUT,
(TRB_TEMPLATE **)(UINTN)&EvtTrb
);
- if (EFI_ERROR (Status)) {
+ if (EFI_ERROR (Status) || (EvtTrb == NULL)) {
DEBUG ((DEBUG_ERROR, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status));
} else {
Xhc->UsbDevContext[SlotId].ActiveConfiguration = ConfigDesc->ConfigurationValue;
@@ -3331,6 +3339,8 @@ XhcSetConfigCmd64 (
DEVICE_CONTEXT_64 *OutputContext;
EVT_TRB_COMMAND_COMPLETION *EvtTrb;
+ EvtTrb = NULL;
+
//
// 4.6.6 Configure Endpoint
//
@@ -3381,7 +3391,7 @@ XhcSetConfigCmd64 (
XHC_GENERIC_TIMEOUT,
(TRB_TEMPLATE **)(UINTN)&EvtTrb
);
- if (EFI_ERROR (Status)) {
+ if (EFI_ERROR (Status) || (EvtTrb == NULL)) {
DEBUG ((DEBUG_ERROR, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status));
} else {
Xhc->UsbDevContext[SlotId].ActiveConfiguration = ConfigDesc->ConfigurationValue;
@@ -3417,6 +3427,8 @@ XhcStopEndpoint (
DEBUG ((DEBUG_VERBOSE, "XhcStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));
+ EvtTrb = NULL;
+
//
// When XhcCheckUrbResult waits for the Stop_Endpoint completion, it also checks
// the PendingUrb completion status, because it's possible that the PendingUrb is
@@ -3454,7 +3466,7 @@ XhcStopEndpoint (
XHC_GENERIC_TIMEOUT,
(TRB_TEMPLATE **)(UINTN)&EvtTrb
);
- if (EFI_ERROR (Status)) {
+ if (EFI_ERROR (Status) || (EvtTrb == NULL)) {
DEBUG ((DEBUG_ERROR, "XhcStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status));
}
@@ -3488,6 +3500,8 @@ XhcResetEndpoint (
DEBUG ((DEBUG_INFO, "XhcResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));
+ EvtTrb = NULL;
+
//
// Send stop endpoint command to transit Endpoint from running to stop state
//
@@ -3502,7 +3516,7 @@ XhcResetEndpoint (
XHC_GENERIC_TIMEOUT,
(TRB_TEMPLATE **)(UINTN)&EvtTrb
);
- if (EFI_ERROR (Status)) {
+ if (EFI_ERROR (Status) || (EvtTrb == NULL)) {
DEBUG ((DEBUG_ERROR, "XhcResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status));
}
@@ -3538,6 +3552,8 @@ XhcSetTrDequeuePointer (
DEBUG ((DEBUG_VERBOSE, "XhcSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId, Dci, Urb));
+ EvtTrb = NULL;
+
//
// Send stop endpoint command to transit Endpoint from running to stop state
//
@@ -3555,7 +3571,7 @@ XhcSetTrDequeuePointer (
XHC_GENERIC_TIMEOUT,
(TRB_TEMPLATE **)(UINTN)&EvtTrb
);
- if (EFI_ERROR (Status)) {
+ if (EFI_ERROR (Status) || (EvtTrb == NULL)) {
DEBUG ((DEBUG_ERROR, "XhcSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status));
}
@@ -3604,6 +3620,7 @@ XhcSetInterface (
EVT_TRB_COMMAND_COMPLETION *EvtTrb;
Status = EFI_SUCCESS;
+ EvtTrb = NULL;
InputContext = Xhc->UsbDevContext[SlotId].InputContext;
OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
@@ -3755,7 +3772,7 @@ XhcSetInterface (
XHC_GENERIC_TIMEOUT,
(TRB_TEMPLATE **)(UINTN)&EvtTrb
);
- if (EFI_ERROR (Status)) {
+ if (EFI_ERROR (Status) || (EvtTrb == NULL)) {
DEBUG ((DEBUG_ERROR, "SetInterface: Config Endpoint Failed, Status = %r\n", Status));
} else {
//
@@ -3810,6 +3827,7 @@ XhcSetInterface64 (
EVT_TRB_COMMAND_COMPLETION *EvtTrb;
Status = EFI_SUCCESS;
+ EvtTrb = NULL;
InputContext = Xhc->UsbDevContext[SlotId].InputContext;
OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
@@ -3961,7 +3979,7 @@ XhcSetInterface64 (
XHC_GENERIC_TIMEOUT,
(TRB_TEMPLATE **)(UINTN)&EvtTrb
);
- if (EFI_ERROR (Status)) {
+ if (EFI_ERROR (Status) || (EvtTrb == NULL)) {
DEBUG ((DEBUG_ERROR, "SetInterface64: Config Endpoint Failed, Status = %r\n", Status));
} else {
//
@@ -4001,6 +4019,8 @@ XhcEvaluateContext (
ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
+ EvtTrb = NULL;
+
//
// 4.6.7 Evaluate Context
//
@@ -4028,7 +4048,7 @@ XhcEvaluateContext (
XHC_GENERIC_TIMEOUT,
(TRB_TEMPLATE **)(UINTN)&EvtTrb
);
- if (EFI_ERROR (Status)) {
+ if (EFI_ERROR (Status) || (EvtTrb == NULL)) {
DEBUG ((DEBUG_ERROR, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status));
}
@@ -4062,6 +4082,8 @@ XhcEvaluateContext64 (
ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
+ EvtTrb = NULL;
+
//
// 4.6.7 Evaluate Context
//
@@ -4089,7 +4111,7 @@ XhcEvaluateContext64 (
XHC_GENERIC_TIMEOUT,
(TRB_TEMPLATE **)(UINTN)&EvtTrb
);
- if (EFI_ERROR (Status)) {
+ if (EFI_ERROR (Status) || (EvtTrb == NULL)) {
DEBUG ((DEBUG_ERROR, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status));
}
@@ -4125,6 +4147,7 @@ XhcConfigHubContext (
EFI_PHYSICAL_ADDRESS PhyAddr;
ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
+ EvtTrb = NULL;
InputContext = Xhc->UsbDevContext[SlotId].InputContext;
OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
@@ -4158,7 +4181,7 @@ XhcConfigHubContext (
XHC_GENERIC_TIMEOUT,
(TRB_TEMPLATE **)(UINTN)&EvtTrb
);
- if (EFI_ERROR (Status)) {
+ if (EFI_ERROR (Status) || (EvtTrb == NULL)) {
DEBUG ((DEBUG_ERROR, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status));
}
diff --git a/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.c b/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.c
index b8651ff..e04a93d 100644
--- a/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.c
+++ b/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.c
@@ -1,6 +1,6 @@
/** @file
- Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2014 - 2024, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -1017,6 +1017,55 @@ UfsEndOfPei (
}
/**
+ Finishes device initialization by setting fDeviceInit flag and waiting until device responds by
+ clearing it.
+
+ @param[in] Private Pointer to the UFS_PEIM_HC_PRIVATE_DATA.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+UfsFinishDeviceInitialization (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ UINT8 DeviceInitStatus;
+ UINT32 Timeout;
+
+ DeviceInitStatus = 0xFF;
+ Timeout = PcdGet32 (PcdUfsInitialCompletionTimeout);
+
+ //
+ // The host enables the device initialization completion by setting fDeviceInit flag.
+ //
+ Status = UfsSetFlag (Private, UfsFlagDevInit);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ do {
+ Status = UfsReadFlag (Private, UfsFlagDevInit, &DeviceInitStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ MicroSecondDelay (1);
+ Timeout--;
+ } while (DeviceInitStatus != 0 && Timeout != 0);
+
+ if (Timeout == 0) {
+ DEBUG ((DEBUG_ERROR, "%a: DeviceInitStatus = %x EFI_TIMEOUT \n", __func__, DeviceInitStatus));
+ return EFI_TIMEOUT;
+ } else {
+ DEBUG ((DEBUG_INFO, "%a: Timeout left = %x EFI_SUCCESS \n", __func__, Timeout));
+ return EFI_SUCCESS;
+ }
+}
+
+/**
The user code starts with this function.
@param FileHandle Handle of the file being invoked.
@@ -1116,11 +1165,11 @@ InitializeUfsBlockIoPeim (
}
//
- // The host enables the device initialization completion by setting fDeviceInit flag.
+ // Check the UFS device is initialized completed.
//
- Status = UfsSetFlag (Private, UfsFlagDevInit);
+ Status = UfsFinishDeviceInitialization (Private);
if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "Ufs Set fDeviceInit Flag Error, Status = %r\n", Status));
+ DEBUG ((DEBUG_ERROR, "Device failed to finish initialization, Status = %r\n", Status));
Controller++;
continue;
}
diff --git a/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.h b/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.h
index ed4776f..869332f 100644
--- a/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.h
+++ b/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.h
@@ -1,6 +1,6 @@
/** @file
- Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2014 - 2024, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -22,6 +22,7 @@
#include <Library/MemoryAllocationLib.h>
#include <Library/IoLib.h>
#include <Library/TimerLib.h>
+#include <Library/PcdLib.h>
#include <Library/PeiServicesLib.h>
#include <IndustryStandard/Scsi.h>
@@ -227,6 +228,25 @@ UfsSetFlag (
);
/**
+ Read specified flag from a UFS device.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+ @param[in] FlagId The ID of flag to be read.
+ @param[out] Value The flag's value.
+
+ @retval EFI_SUCCESS The flag was read successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
+
+**/
+EFI_STATUS
+UfsReadFlag (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,
+ IN UINT8 FlagId,
+ OUT UINT8 *Value
+ );
+
+/**
Read or write specified device descriptor of a UFS device.
@param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
diff --git a/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.inf b/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.inf
index 6e1cbfd..5da906e 100644
--- a/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.inf
+++ b/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.inf
@@ -41,6 +41,7 @@
IoLib
TimerLib
BaseMemoryLib
+ PcdLib
PeimEntryPoint
PeiServicesLib
DebugLib
@@ -52,9 +53,11 @@
gEdkiiIoMmuPpiGuid ## CONSUMES
gEfiEndOfPeiSignalPpiGuid ## CONSUMES
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUfsInitialCompletionTimeout ## CONSUMES
+
[Depex]
gEfiPeiMemoryDiscoveredPpiGuid AND gEdkiiPeiUfsHostControllerPpiGuid
[UserExtensions.TianoCore."ExtraFiles"]
UfsBlockIoPeiExtra.uni
-
diff --git a/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.c b/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.c
index d19a7fe..360b642 100644
--- a/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.c
+++ b/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.c
@@ -1,6 +1,6 @@
/** @file
- Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2014 - 2024, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -1066,6 +1066,32 @@ UfsSetFlag (
}
/**
+ Read specified flag from a UFS device.
+
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
+ @param[in] FlagId The ID of flag to be read.
+ @param[out] Value The flag's value.
+
+ @retval EFI_SUCCESS The flag was read successfully.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
+
+**/
+EFI_STATUS
+UfsReadFlag (
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,
+ IN UINT8 FlagId,
+ OUT UINT8 *Value
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UfsRwFlags (Private, TRUE, FlagId, Value);
+
+ return Status;
+}
+
+/**
Sends NOP IN cmd to a UFS device for initialization process request.
For more details, please refer to UFS 2.0 spec Figure 13.3.
diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c
index 880e7d8..816532d 100644
--- a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c
+++ b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c
@@ -759,6 +759,7 @@ UfsFinishDeviceInitialization (
UINT32 Timeout;
DeviceInitStatus = 0xFF;
+ Timeout = PcdGet32 (PcdUfsInitialCompletionTimeout);
//
// The host enables the device initialization completion by setting fDeviceInit flag.
@@ -768,10 +769,6 @@ UfsFinishDeviceInitialization (
return Status;
}
- //
- // There are cards that can take upto 600ms to clear fDeviceInit flag.
- //
- Timeout = UFS_INIT_COMPLETION_TIMEOUT;
do {
Status = UfsReadFlag (Private, UfsFlagDevInit, &DeviceInitStatus);
if (EFI_ERROR (Status)) {
diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h
index bc1139d..d380650 100644
--- a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h
+++ b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h
@@ -24,6 +24,7 @@
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DevicePathLib.h>
+#include <Library/PcdLib.h>
#include <Library/TimerLib.h>
#include "UfsPassThruHci.h"
@@ -38,9 +39,8 @@
// Lun 10: BOOT
// Lun 11: RPMB
//
-#define UFS_MAX_LUNS 12
-#define UFS_WLUN_PREFIX 0xC1
-#define UFS_INIT_COMPLETION_TIMEOUT 600000
+#define UFS_MAX_LUNS 12
+#define UFS_WLUN_PREFIX 0xC1
typedef struct {
UINT8 Lun[UFS_MAX_LUNS];
diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruDxe.inf b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruDxe.inf
index 92dc257..0e12b7a 100644
--- a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruDxe.inf
+++ b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruDxe.inf
@@ -48,6 +48,7 @@
UefiDriverEntryPoint
DebugLib
DevicePathLib
+ PcdLib
TimerLib
[Protocols]
@@ -56,5 +57,8 @@
gEdkiiUfsHostControllerProtocolGuid ## TO_START
gEdkiiUfsHcPlatformProtocolGuid ## SOMETIMES_CONSUMES
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUfsInitialCompletionTimeout ## CONSUMES
+
[UserExtensions.TianoCore."ExtraFiles"]
UfsPassThruExtra.uni
diff --git a/MdeModulePkg/Core/Dxe/DxeMain.h b/MdeModulePkg/Core/Dxe/DxeMain.h
index 53e2670..cd3940d 100644
--- a/MdeModulePkg/Core/Dxe/DxeMain.h
+++ b/MdeModulePkg/Core/Dxe/DxeMain.h
@@ -84,6 +84,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include <Library/DxeServicesLib.h>
#include <Library/DebugAgentLib.h>
#include <Library/CpuExceptionHandlerLib.h>
+#include <Library/OrderedCollectionLib.h>
//
// attributes for reserved memory before it is promoted to system memory
@@ -2790,4 +2791,15 @@ MergeMemoryMap (
IN UINTN DescriptorSize
);
+/**
+ Initializes "handle" support.
+
+ @return Status code.
+
++**/
+EFI_STATUS
+CoreInitializeHandleServices (
+ VOID
+ );
+
#endif
diff --git a/MdeModulePkg/Core/Dxe/DxeMain.inf b/MdeModulePkg/Core/Dxe/DxeMain.inf
index 090970a..cc315ac 100644
--- a/MdeModulePkg/Core/Dxe/DxeMain.inf
+++ b/MdeModulePkg/Core/Dxe/DxeMain.inf
@@ -95,6 +95,7 @@
CpuExceptionHandlerLib
PcdLib
ImagePropertiesRecordLib
+ OrderedCollectionLib
[Guids]
gEfiEventMemoryMapChangeGuid ## PRODUCES ## Event
diff --git a/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c b/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c
index 17d510a..8a87733 100644
--- a/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c
+++ b/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c
@@ -277,6 +277,12 @@ DxeMain (
MemoryProfileInit (HobStart);
//
+ // Start the Handle Services.
+ //
+ Status = CoreInitializeHandleServices ();
+ ASSERT_EFI_ERROR (Status);
+
+ //
// Start the Image Services.
//
Status = CoreInitializeImageServices (HobStart);
diff --git a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
index 9936450..6ea89fb 100644
--- a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
+++ b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
@@ -989,6 +989,20 @@ CoreConvertSpace (
//
case GCD_SET_CAPABILITIES_MEMORY_OPERATION:
Entry->Capabilities = Capabilities;
+
+ // Only SystemMemory and MoreReliable memory is in gMemoryMap
+ // so only attempt to update the attributes there if this is
+ // a relevant GCD type
+ if ((Entry->GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
+ (Entry->GcdMemoryType == EfiGcdMemoryTypeMoreReliable))
+ {
+ CoreUpdateMemoryAttributes (
+ BaseAddress,
+ RShiftU64 (Length, EFI_PAGE_SHIFT),
+ Capabilities & (~EFI_MEMORY_RUNTIME)
+ );
+ }
+
break;
}
@@ -1700,17 +1714,10 @@ CoreSetMemorySpaceCapabilities (
IN UINT64 Capabilities
)
{
- EFI_STATUS Status;
-
DEBUG ((DEBUG_GCD, "GCD:CoreSetMemorySpaceCapabilities(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
DEBUG ((DEBUG_GCD, " Capabilities = %016lx\n", Capabilities));
- Status = CoreConvertSpace (GCD_SET_CAPABILITIES_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE)0, (EFI_GCD_IO_TYPE)0, BaseAddress, Length, Capabilities, 0);
- if (!EFI_ERROR (Status)) {
- CoreUpdateMemoryAttributes (BaseAddress, RShiftU64 (Length, EFI_PAGE_SHIFT), Capabilities & (~EFI_MEMORY_RUNTIME));
- }
-
- return Status;
+ return CoreConvertSpace (GCD_SET_CAPABILITIES_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE)0, (EFI_GCD_IO_TYPE)0, BaseAddress, Length, Capabilities, 0);
}
/**
diff --git a/MdeModulePkg/Core/Dxe/Hand/Handle.c b/MdeModulePkg/Core/Dxe/Hand/Handle.c
index 24e4fbf..b5ff3fd 100644
--- a/MdeModulePkg/Core/Dxe/Hand/Handle.c
+++ b/MdeModulePkg/Core/Dxe/Hand/Handle.c
@@ -15,10 +15,11 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
// gProtocolDatabaseLock - Lock to protect the mProtocolDatabase
// gHandleDatabaseKey - The Key to show that the handle has been created/modified
//
-LIST_ENTRY mProtocolDatabase = INITIALIZE_LIST_HEAD_VARIABLE (mProtocolDatabase);
-LIST_ENTRY gHandleList = INITIALIZE_LIST_HEAD_VARIABLE (gHandleList);
-EFI_LOCK gProtocolDatabaseLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
-UINT64 gHandleDatabaseKey = 0;
+LIST_ENTRY mProtocolDatabase = INITIALIZE_LIST_HEAD_VARIABLE (mProtocolDatabase);
+LIST_ENTRY gHandleList = INITIALIZE_LIST_HEAD_VARIABLE (gHandleList);
+EFI_LOCK gProtocolDatabaseLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+UINT64 gHandleDatabaseKey = 0;
+ORDERED_COLLECTION *gOrderedHandleList = NULL;
/**
Acquire lock on gProtocolDatabaseLock.
@@ -45,6 +46,60 @@ CoreReleaseProtocolLock (
}
/**
+ Comparator function for two opaque pointers, ordering on (unsigned) pointer
+ value itself.
+ Can be used as both Key and UserStruct comparator.
+
+ @param[in] Pointer1 First pointer.
+
+ @param[in] Pointer2 Second pointer.
+
+ @retval <0 If Pointer1 compares less than Pointer2.
+
+ @retval 0 If Pointer1 compares equal to Pointer2.
+
+ @retval >0 If Pointer1 compares greater than Pointer2.
+**/
+STATIC
+INTN
+EFIAPI
+PointerCompare (
+ IN CONST VOID *Pointer1,
+ IN CONST VOID *Pointer2
+ )
+{
+ if (Pointer1 == Pointer2) {
+ return 0;
+ }
+
+ if ((UINTN)Pointer1 < (UINTN)Pointer2) {
+ return -1;
+ }
+
+ return 1;
+}
+
+/**
+ Initializes "handle" support.
+
+ @return Status code.
+
+**/
+EFI_STATUS
+CoreInitializeHandleServices (
+ VOID
+ )
+{
+ gOrderedHandleList = OrderedCollectionInit (PointerCompare, PointerCompare);
+
+ if (gOrderedHandleList == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
Check whether a handle is a valid EFI_HANDLE
The gProtocolDatabaseLock must be owned
@@ -59,8 +114,7 @@ CoreValidateHandle (
IN EFI_HANDLE UserHandle
)
{
- IHANDLE *Handle;
- LIST_ENTRY *Link;
+ ORDERED_COLLECTION_ENTRY *Entry;
if (UserHandle == NULL) {
return EFI_INVALID_PARAMETER;
@@ -68,11 +122,9 @@ CoreValidateHandle (
ASSERT_LOCKED (&gProtocolDatabaseLock);
- for (Link = gHandleList.BackLink; Link != &gHandleList; Link = Link->BackLink) {
- Handle = CR (Link, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);
- if (Handle == (IHANDLE *)UserHandle) {
- return EFI_SUCCESS;
- }
+ Entry = OrderedCollectionFind (gOrderedHandleList, UserHandle);
+ if (Entry != NULL) {
+ return EFI_SUCCESS;
}
return EFI_INVALID_PARAMETER;
@@ -453,6 +505,16 @@ CoreInstallProtocolInterfaceNotify (
}
//
+ // Add this handle to the ordered list of all handles
+ // in the system
+ //
+ Status = OrderedCollectionInsert (gOrderedHandleList, NULL, Handle);
+ if (EFI_ERROR (Status)) {
+ CoreFreePool (Handle);
+ goto Done;
+ }
+
+ //
// Initialize new handler structure
//
Handle->Signature = EFI_HANDLE_SIGNATURE;
@@ -825,6 +887,11 @@ CoreUninstallProtocolInterface (
//
if (IsListEmpty (&Handle->Protocols)) {
Handle->Signature = 0;
+ OrderedCollectionDelete (
+ gOrderedHandleList,
+ OrderedCollectionFind (gOrderedHandleList, Handle),
+ NULL
+ );
RemoveEntryList (&Handle->AllHandles);
CoreFreePool (Handle);
}
diff --git a/MdeModulePkg/Core/Dxe/Image/Image.c b/MdeModulePkg/Core/Dxe/Image/Image.c
index 37fc74d..8d12f93 100644
--- a/MdeModulePkg/Core/Dxe/Image/Image.c
+++ b/MdeModulePkg/Core/Dxe/Image/Image.c
@@ -1725,7 +1725,9 @@ CoreStartImage (
// Image has completed. Verify the tpl is the same
//
ASSERT (Image->Tpl == gEfiCurrentTpl);
- CoreRestoreTpl (Image->Tpl);
+ if (Image->Tpl != gEfiCurrentTpl) {
+ CoreRestoreTpl (Image->Tpl);
+ }
CoreFreePool (Image->JumpBuffer);
diff --git a/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c b/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c
index 0c0ca61..4071053 100644
--- a/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c
+++ b/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c
@@ -1406,34 +1406,39 @@ GuardAllFreedPages (
TableEntry = ((UINT64 *)(UINTN)(Tables[Level]))[Indices[Level]];
Address = Addresses[Level];
- if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
- Level += 1;
- Tables[Level] = TableEntry;
- Addresses[Level] = Address;
- Indices[Level] = 0;
-
- continue;
+ if (TableEntry == 0) {
+ GuardPageNumber = 0;
+ GuardPage = (UINT64)-1;
} else {
- BitIndex = 1;
- while (BitIndex != 0) {
- if ((TableEntry & BitIndex) != 0) {
- if (GuardPage == (UINT64)-1) {
- GuardPage = Address;
+ if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
+ Level += 1;
+ Tables[Level] = TableEntry;
+ Addresses[Level] = Address;
+ Indices[Level] = 0;
+
+ continue;
+ } else {
+ BitIndex = 1;
+ while (BitIndex != 0) {
+ if ((TableEntry & BitIndex) != 0) {
+ if (GuardPage == (UINT64)-1) {
+ GuardPage = Address;
+ }
+
+ ++GuardPageNumber;
+ } else if (GuardPageNumber > 0) {
+ GuardFreedPages (GuardPage, GuardPageNumber);
+ GuardPageNumber = 0;
+ GuardPage = (UINT64)-1;
}
- ++GuardPageNumber;
- } else if (GuardPageNumber > 0) {
- GuardFreedPages (GuardPage, GuardPageNumber);
- GuardPageNumber = 0;
- GuardPage = (UINT64)-1;
- }
+ if (TableEntry == 0) {
+ break;
+ }
- if (TableEntry == 0) {
- break;
+ Address += EFI_PAGES_TO_SIZE (1);
+ BitIndex = LShiftU64 (BitIndex, 1);
}
-
- Address += EFI_PAGES_TO_SIZE (1);
- BitIndex = LShiftU64 (BitIndex, 1);
}
}
}
diff --git a/MdeModulePkg/Core/Dxe/Mem/Imem.h b/MdeModulePkg/Core/Dxe/Mem/Imem.h
index 2f0bf2b..84027d6 100644
--- a/MdeModulePkg/Core/Dxe/Mem/Imem.h
+++ b/MdeModulePkg/Core/Dxe/Mem/Imem.h
@@ -10,22 +10,6 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#define _IMEM_H_
//
-// +---------------------------------------------------+
-// | 0..(EfiMaxMemoryType - 1) - Normal memory type |
-// +---------------------------------------------------+
-// | EfiMaxMemoryType..0x6FFFFFFF - Invalid |
-// +---------------------------------------------------+
-// | 0x70000000..0x7FFFFFFF - OEM reserved |
-// +---------------------------------------------------+
-// | 0x80000000..0xFFFFFFFF - OS reserved |
-// +---------------------------------------------------+
-//
-#define MEMORY_TYPE_OS_RESERVED_MIN 0x80000000
-#define MEMORY_TYPE_OS_RESERVED_MAX 0xFFFFFFFF
-#define MEMORY_TYPE_OEM_RESERVED_MIN 0x70000000
-#define MEMORY_TYPE_OEM_RESERVED_MAX 0x7FFFFFFF
-
-//
// MEMORY_MAP_ENTRY
//
diff --git a/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c b/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c
index e9343a2..58b9474 100644
--- a/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c
+++ b/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c
@@ -426,7 +426,7 @@ MergeMemoryMap (
/**
Enforce memory map attributes.
- This function will set EfiRuntimeServicesData/EfiMemoryMappedIO/EfiMemoryMappedIOPortSpace to be EFI_MEMORY_XP.
+ This function will set EfiRuntimeServicesData to be EFI_MEMORY_XP.
@param MemoryMap A pointer to the buffer in which firmware places
the current memory map.
@@ -447,18 +447,23 @@ EnforceMemoryMapAttribute (
MemoryMapEntry = MemoryMap;
MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize);
while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
- switch (MemoryMapEntry->Type) {
- case EfiRuntimeServicesCode:
- // do nothing
- break;
- case EfiRuntimeServicesData:
- case EfiMemoryMappedIO:
- case EfiMemoryMappedIOPortSpace:
- MemoryMapEntry->Attribute |= EFI_MEMORY_XP;
- break;
- case EfiReservedMemoryType:
- case EfiACPIMemoryNVS:
- break;
+ if ((MemoryMapEntry->Attribute & EFI_MEMORY_ACCESS_MASK) == 0) {
+ switch (MemoryMapEntry->Type) {
+ case EfiRuntimeServicesCode:
+ // If at this point the attributes have not been set on an EfiRuntimeServicesCode
+ // region, the memory range must not contain a loaded image. It's possible these
+ // non-image EfiRuntimeServicesCode regions are part of the unused memory bucket.
+ // It could also be that this region was explicitly allocated outside of the PE
+ // loader but the UEFI spec requires that all EfiRuntimeServicesCode regions contain
+ // EFI modules. In either case, set the attributes to RO and XP.
+ MemoryMapEntry->Attribute |= (EFI_MEMORY_RO | EFI_MEMORY_XP);
+ break;
+ case EfiRuntimeServicesData:
+ MemoryMapEntry->Attribute |= EFI_MEMORY_XP;
+ break;
+ default:
+ break;
+ }
}
MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
diff --git a/MdeModulePkg/Core/DxeIplPeim/DxeLoad.c b/MdeModulePkg/Core/DxeIplPeim/DxeLoad.c
index 2c19f1a..933b245 100644
--- a/MdeModulePkg/Core/DxeIplPeim/DxeLoad.c
+++ b/MdeModulePkg/Core/DxeIplPeim/DxeLoad.c
@@ -3,7 +3,7 @@
Responsibility of this module is to load the DXE Core from a Firmware Volume.
Copyright (c) 2016 HP Development Company, L.P.
-Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2024, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -487,10 +487,10 @@ DxeIplFindDxeCore (
//
if (EFI_ERROR (Status)) {
REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_CORE_EC_DXE_CORRUPT));
+ ASSERT_EFI_ERROR (Status);
+ break;
}
- ASSERT_EFI_ERROR (Status);
-
//
// Find the DxeCore file type from the beginning in this firmware volume.
//
@@ -509,6 +509,13 @@ DxeIplFindDxeCore (
//
Instance++;
}
+
+ //
+ // DxeCore cannot find in any firmware volume.
+ //
+ CpuDeadLoop ();
+
+ return NULL;
}
/**
diff --git a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
index ca37bde..79ff8d1 100644
--- a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
+++ b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
@@ -1205,16 +1205,21 @@ EvacuateTempRam (
PeiCoreFvHandle.FvHandle = (EFI_PEI_FV_HANDLE)SecCoreData->BootFirmwareVolumeBase;
}
- for (FvIndex = 0; FvIndex < Private->FvCount; FvIndex++) {
- if (Private->Fv[FvIndex].FvHandle == PeiCoreFvHandle.FvHandle) {
- CopyMem (&PeiCoreFvHandle, &Private->Fv[FvIndex], sizeof (PEI_CORE_FV_HANDLE));
- break;
+ if (Private->PeimDispatcherReenter) {
+ //
+ // PEI_CORE should be migrated after dispatcher re-enters from main memory.
+ //
+ for (FvIndex = 0; FvIndex < Private->FvCount; FvIndex++) {
+ if (Private->Fv[FvIndex].FvHandle == PeiCoreFvHandle.FvHandle) {
+ CopyMem (&PeiCoreFvHandle, &Private->Fv[FvIndex], sizeof (PEI_CORE_FV_HANDLE));
+ break;
+ }
}
- }
- Status = EFI_SUCCESS;
+ Status = EFI_SUCCESS;
- ConvertPeiCorePpiPointers (Private, &PeiCoreFvHandle);
+ ConvertPeiCorePpiPointers (Private, &PeiCoreFvHandle);
+ }
Hob.Raw = GetFirstGuidHob (&gEdkiiMigrationInfoGuid);
if (Hob.Raw != NULL) {
@@ -1237,6 +1242,14 @@ EvacuateTempRam (
)
{
if ((MigrationInfo == NULL) || (MigrationInfo->MigrateAll == TRUE)) {
+ if (!Private->PeimDispatcherReenter) {
+ //
+ // Migration before dispatcher reentery is supported only when gEdkiiMigrationInfoGuid
+ // HOB is built for selective FV migration.
+ //
+ return EFI_SUCCESS;
+ }
+
//
// Migrate all FVs and copy raw data
//
@@ -1253,10 +1266,18 @@ EvacuateTempRam (
}
}
- if (Index == MigrationInfo->ToMigrateFvCount) {
+ if ((Index == MigrationInfo->ToMigrateFvCount) ||
+ ((!Private->PeimDispatcherReenter) &&
+ (((FvMigrationFlags & FLAGS_FV_MIGRATE_BEFORE_PEI_CORE_REENTRY) == 0) ||
+ (FvHeader == PeiCoreFvHandle.FvHandle))))
+ {
//
// This FV is not expected to migrate
//
+ // FV should not be migrated before dispatcher reentry if any of the below condition is true:
+ // a. MigrationInfo HOB is not built with flag FLAGS_FV_MIGRATE_BEFORE_PEI_CORE_REENTRY.
+ // b. FV contains currently executing PEI Core.
+ //
continue;
}
}
diff --git a/MdeModulePkg/Core/Pei/FwVol/FwVol.c b/MdeModulePkg/Core/Pei/FwVol/FwVol.c
index f7cc94c..04bec98 100644
--- a/MdeModulePkg/Core/Pei/FwVol/FwVol.c
+++ b/MdeModulePkg/Core/Pei/FwVol/FwVol.c
@@ -819,6 +819,10 @@ ProcessSection (
if (!IsFfs3Fv) {
DEBUG ((DEBUG_ERROR, "Found a FFS3 formatted section in a non-FFS3 formatted FV.\n"));
SectionLength = SECTION2_SIZE (Section);
+ if (SectionLength == 0) {
+ break;
+ }
+
//
// SectionLength is adjusted it is 4 byte aligned.
// Go to the next section
@@ -854,6 +858,10 @@ ProcessSection (
SectionLength = SECTION_SIZE (Section);
}
+ if (SectionLength == 0) {
+ break;
+ }
+
//
// SectionLength is adjusted it is 4 byte aligned.
// Go to the next section
@@ -991,6 +999,10 @@ ProcessSection (
SectionLength = SECTION_SIZE (Section);
}
+ if (SectionLength == 0) {
+ break;
+ }
+
//
// SectionLength is adjusted it is 4 byte aligned.
// Go to the next section
diff --git a/MdeModulePkg/Core/Pei/Memory/MemoryServices.c b/MdeModulePkg/Core/Pei/Memory/MemoryServices.c
index 52f37c9..59613e5 100644
--- a/MdeModulePkg/Core/Pei/Memory/MemoryServices.c
+++ b/MdeModulePkg/Core/Pei/Memory/MemoryServices.c
@@ -862,8 +862,6 @@ PeiAllocatePool (
(UINT16)(sizeof (EFI_HOB_MEMORY_POOL) + Size),
(VOID **)&Hob
);
- ASSERT_EFI_ERROR (Status);
-
if (EFI_ERROR (Status)) {
*Buffer = NULL;
} else {
diff --git a/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c b/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c
index 0e3d9a8..61f5699 100644
--- a/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c
+++ b/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c
@@ -323,6 +323,21 @@ PeiCore (
//
OldCoreData->PeiMemoryInstalled = TRUE;
+ if (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes)) {
+ DEBUG ((DEBUG_VERBOSE, "Early Migration - PPI lists before temporary RAM evacuation:\n"));
+ DumpPpiList (OldCoreData);
+
+ //
+ // Migrate installed content from Temporary RAM to Permanent RAM at this
+ // stage when PEI core still runs from a cached location.
+ // FVs that doesn't contain PEI_CORE should be migrated here.
+ //
+ EvacuateTempRam (OldCoreData, SecCoreData);
+
+ DEBUG ((DEBUG_VERBOSE, "Early Migration - PPI lists after temporary RAM evacuation:\n"));
+ DumpPpiList (OldCoreData);
+ }
+
//
// Indicate that PeiCore reenter
//
@@ -451,6 +466,7 @@ PeiCore (
//
// Migrate installed content from Temporary RAM to Permanent RAM
+ // FVs containing PEI_CORE should be migrated here.
//
EvacuateTempRam (&PrivateData, SecCoreData);
diff --git a/MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c b/MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c
index 27da289..e48532c 100644
--- a/MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c
+++ b/MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c
@@ -2,6 +2,7 @@
SMI handler profile support.
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -48,6 +49,14 @@ RegisterSmiHandlerProfileHandler (
);
/**
+ Build SMI handler profile database.
+**/
+VOID
+BuildSmiHandlerProfileDatabase (
+ VOID
+ );
+
+/**
Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded
into system memory with the PE/COFF Loader Library functions.
@@ -495,6 +504,8 @@ SmmReadyToLockInSmiHandlerProfile (
IN EFI_HANDLE Handle
)
{
+ RegisterSmiHandlerProfileHandler ();
+
//
// Dump all image
//
@@ -528,7 +539,7 @@ SmmReadyToLockInSmiHandlerProfile (
DEBUG ((DEBUG_INFO, "\n"));
- RegisterSmiHandlerProfileHandler ();
+ BuildSmiHandlerProfileDatabase ();
if (mImageStruct != NULL) {
FreePool (mImageStruct);
@@ -860,7 +871,7 @@ GetSmiHandlerProfileDatabaseData (
}
/**
- build SMI handler profile database.
+ Build SMI handler profile database.
**/
VOID
BuildSmiHandlerProfileDatabase (
@@ -1074,8 +1085,6 @@ RegisterSmiHandlerProfileHandler (
&DispatchHandle
);
ASSERT_EFI_ERROR (Status);
-
- BuildSmiHandlerProfileDatabase ();
}
/**
diff --git a/MdeModulePkg/Include/Guid/MigratedFvInfo.h b/MdeModulePkg/Include/Guid/MigratedFvInfo.h
index 255e278..99681fb 100644
--- a/MdeModulePkg/Include/Guid/MigratedFvInfo.h
+++ b/MdeModulePkg/Include/Guid/MigratedFvInfo.h
@@ -18,7 +18,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
// 1: FV raw data will be copied to permanent memory for later phase use (such as
// FV measurement).
//
-#define FLAGS_FV_RAW_DATA_COPY BIT0
+#define FLAGS_FV_RAW_DATA_COPY BIT0
+#define FLAGS_FV_MIGRATE_BEFORE_PEI_CORE_REENTRY BIT1
///
/// In real use cases, not all FVs need migrate to permanent memory before TempRam tears
diff --git a/MdeModulePkg/Include/Guid/MmCommBuffer.h b/MdeModulePkg/Include/Guid/MmCommBuffer.h
new file mode 100644
index 0000000..df4ea31
--- /dev/null
+++ b/MdeModulePkg/Include/Guid/MmCommBuffer.h
@@ -0,0 +1,63 @@
+/** @file
+ MM Communication buffer data.
+
+Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef MM_COMM_BUFFER_H_
+#define MM_COMM_BUFFER_H_
+
+///
+/// The GUID of the MM Communication buffer HOB.
+///
+#define MM_COMM_BUFFER_HOB_GUID \
+ { 0x6c2a2520, 0x0131, 0x4aee, { 0xa7, 0x50, 0xcc, 0x38, 0x4a, 0xac, 0xe8, 0xc6 }}
+
+///
+/// The MM communicate buffer facilitates data sharing between non-MM and MM code.
+/// The MM IPL code allocates a "fixed" runtime type memory as the MM communication buffer,
+/// and communicates its address and size to MM Core via MmCommBuffer GUIDed HOB.
+/// Here, "fixed" implies that the buffer's location remains constant throughout the boot process.
+/// Data is exchanged between the MM Communication PPI/Protocol and a software MMI handler
+/// using this fixed MM communication buffer.
+///
+typedef struct {
+ ///
+ /// The address of the 4-KiB aligned fixed MM communication buffer.
+ ///
+ EFI_PHYSICAL_ADDRESS PhysicalStart;
+
+ ///
+ /// Size of the fixed MM communication buffer, in 4KiB pages.
+ ///
+ UINT64 NumberOfPages;
+
+ ///
+ /// Point to MM_COMM_BUFFER_STATUS structure.
+ ///
+ EFI_PHYSICAL_ADDRESS Status;
+} MM_COMM_BUFFER;
+
+typedef struct {
+ ///
+ /// Whether the data in the fixed MM communication buffer is valid when entering from non-MM to MM.
+ ///
+ BOOLEAN IsCommBufferValid;
+
+ ///
+ /// The return status when returning from MM to non-MM.
+ ///
+ UINT64 ReturnStatus;
+
+ ///
+ /// The size in bytes of the output buffer when returning from MM to non-MM.
+ ///
+ UINT64 ReturnBufferSize;
+} MM_COMM_BUFFER_STATUS;
+
+extern EFI_GUID gMmCommBufferHobGuid;
+
+#endif
diff --git a/MdeModulePkg/Include/Guid/NVMeEventGroup.h b/MdeModulePkg/Include/Guid/NVMeEventGroup.h
new file mode 100644
index 0000000..bd59b0c
--- /dev/null
+++ b/MdeModulePkg/Include/Guid/NVMeEventGroup.h
@@ -0,0 +1,16 @@
+/** @file
+
+Copyright (c) Microsoft Corporation.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef NVME_EVENT_GROUP_GUID_
+#define NVME_EVENT_GROUP_GUID_
+
+// gNVMeEnableStartEventGroupGuid is used to signal the start of enabling the NVMe controller
+extern EFI_GUID gNVMeEnableStartEventGroupGuid;
+// gNVMeEnableCompleteEventGroupGuid is used to signal that the NVMe controller enable has finished
+extern EFI_GUID gNVMeEnableCompleteEventGroupGuid;
+
+#endif
diff --git a/MdeModulePkg/Include/Protocol/MediaSanitize.h b/MdeModulePkg/Include/Protocol/MediaSanitize.h
new file mode 100644
index 0000000..029b135
--- /dev/null
+++ b/MdeModulePkg/Include/Protocol/MediaSanitize.h
@@ -0,0 +1,173 @@
+/** @file
+ This file defines the Media Sanitize Protocol.
+
+ Copyright (c) Microsoft Corporation.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef MEDIA_SANITIZE_PROTOCOL_H_
+#define MEDIA_SANITIZE_PROTOCOL_H_
+
+#define MEDIA_SANITIZE_PROTOCOL_GUID \
+ { \
+ 0x0d799a99, 0x25af, 0x429e, { 0x92, 0x72, 0xd0, 0xb2, 0x7d, 0x6d, 0x5f, 0x14 } \
+ }
+
+typedef struct _MEDIA_SANITIZE_PROTOCOL MEDIA_SANITIZE_PROTOCOL;
+
+#define MEDIA_SANITIZE_PROTOCOL_REVISION 0x00010000
+
+///
+/// Sanitize actions for purge operation.
+///
+/// NOTE: First four actions (no action, overwrite, block erase, crypto erase) cannot
+/// be overlapped. All other fields may be overlapped as they apply.
+///
+#define PURGE_ACTION_NO_ACTION 0x00000000 // No purge action requested
+#define PURGE_ACTION_OVERWRITE 0x00000001 // Overwrite with 32-bit pattern
+#define PURGE_ACTION_BLOCK_ERASE 0x00000002 // Erase Blocks with indeterminate pattern
+#define PURGE_ACTION_CRYPTO_ERASE 0x00000004 // Delete encryption keys only
+#define PURGE_ACTION_RESET_REQUIRED 0x00000008 // Reset required after purge
+#define PURGE_ACTION_NO_DEALLOCATE 0x00000010 // Do no deallocate (trim) flash medai after sanitize
+#define PURGE_ACTION_INVERT_OW_PATTERN 0x00000020 // Invert overwrite pattern between passes
+#define PURGE_ACTION_ALLOW_UNRESTRICTED_SANITIZE_EXIT 0x00000040 // Allow exit without restrictions
+
+///
+/// Secure erase action for media format operation
+///
+#define FORMAT_SES_NO_SECURE_ERASE_REQUESTED 0x0 // No secure erase operation requested
+#define FORMAT_SES_USER_DATA_ERASE 0x1 // User Data Erase
+#define FORMAT_SES_CRYPTOGRAPHIC_ERASE 0x2 // Cryptographic Erase
+
+/**
+ Clear Media utilizes transport native WRITE commands to write a fixed pattern
+ of non-sensitive data. The size of the overwrite buffer shall be equal to the
+ one sector/LBA (in bytes).
+
+ NOTE: This function must be called from TPL aaplication or callback.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the clear request is for.
+ @param[in] PassCount Number of passes to write over the media.
+ @param[in] SectorOwBuffer Pointer to overwrite pattern buffer.
+
+ @retval EFI_SUCCESS The media clear request completed successfully
+ on the device.
+ @retval EFI_WRITE_PROTECTED The device can't be cleared due to write
+ protection.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to perform the clear operation.
+ @retval EFI_INVALID_PARAMETER The clear request contains parameters that
+ are not valid.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *BLOCK_MEDIA_CLEAR)(
+ IN MEDIA_SANITIZE_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT32 PassCount,
+ IN VOID *SectorOwBuffer
+ );
+
+/**
+ Purge Media utilizes native Sanitize operations. Transport specific
+ overwrite, block erase, or crypto erase functions shall be invoked based
+ on transport.
+
+ NOTE: This function must be called from TPL aaplication or callback.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the clear request is for.
+ @param[in] PurgeAction Purge action: overwrite, crypto or block erase.
+ @param[in] OverwritePattern 32-bit pattern to overwrite on media.
+
+ @retval EFI_SUCCESS The media purge request completed successfully
+ on the device.
+ @retval EFI_WRITE_PROTECTED The device can't be purged due to write
+ protection.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to perform the purge operation.
+ @retval EFI_INVALID_PARAMETER The purge request contains parameters that
+ are not valid.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *BLOCK_MEDIA_PURGE)(
+ IN MEDIA_SANITIZE_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT32 PurgeAction,
+ IN UINT32 OverwritePattern
+ );
+
+/**
+ Format Media utilizes native format operations to modify sector/LBA size.
+ Secure erase actions are used to define how latent user data is erased.
+
+ NOTE: This function must be called from TPL aaplication or callback.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the clear request is for.
+ @param[in] LbaSize Size of LBA (in terms of power of two: 2^n).
+ @param[in] SecureEraseAction Secure erase action, if any, to apply to format.
+
+ @retval EFI_SUCCESS The media format request comopleted
+ successfully on the device.
+ @retval EFI_WRITE_PROTECTED The device can't be formatted due to write
+ protection.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to perform the format operation.
+ @retval EFI_INVALID_PARAMETER The format request contains parameters that
+ are not valid.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+
+ **/
+typedef
+EFI_STATUS
+(EFIAPI *BLOCK_MEDIA_FORMAT)(
+ IN MEDIA_SANITIZE_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT32 LbaSize,
+ IN UINT32 SecureEraseAction
+ );
+
+///
+/// The Media Sanitize Protocol provides the ability for a device to expose
+/// sanitize functionality. This optional protocol is installed on the same handle
+/// as the EFI_BLOCK_IO_PROTOCOL or EFI_BLOCK_IO2_PROTOCOL.
+///
+struct _MEDIA_SANITIZE_PROTOCOL {
+ ///
+ /// The revision to which the MEDIA_SANITIZE_PROTOCOL adheres. All future
+ /// revisions must be backwards compatible. If a future version is not
+ /// backwards compatible, it is not the same GUID.
+ ///
+ UINT64 Revision;
+
+ ///
+ /// A pointer to the EFI_BLOCK_IO_MEDIA data for this device.
+ /// Type EFI_BLOCK_IO_MEDIA is defined in BlockIo.h.
+ ///
+ EFI_BLOCK_IO_MEDIA *Media;
+
+ ///
+ /// SanitizeCapabilities shall which sanitize operations (crypto erase, block
+ /// erase, overwrite) is supported by this Block Io device.
+ ///
+ UINT32 SanitizeCapabilities;
+
+ BLOCK_MEDIA_CLEAR MediaClear;
+ BLOCK_MEDIA_PURGE MediaPurge;
+ BLOCK_MEDIA_FORMAT MediaFormat;
+};
+
+extern EFI_GUID gMediaSanitizeProtocolGuid;
+
+#endif
diff --git a/MdeModulePkg/Library/RuntimeResetSystemLib/RuntimeResetSystemLib.c b/MdeModulePkg/Library/RuntimeResetSystemLib/RuntimeResetSystemLib.c
index 59b5c2b..8e9f632 100644
--- a/MdeModulePkg/Library/RuntimeResetSystemLib/RuntimeResetSystemLib.c
+++ b/MdeModulePkg/Library/RuntimeResetSystemLib/RuntimeResetSystemLib.c
@@ -12,8 +12,8 @@
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DebugLib.h>
-EFI_EVENT mRuntimeResetSystemLibVirtualAddressChangeEvent;
-EFI_RUNTIME_SERVICES *mInternalRT;
+EFI_EVENT mRuntimeResetSystemLibVirtualAddressChangeEvent;
+static EFI_RUNTIME_SERVICES *mInternalRT;
/**
This function causes a system-wide reset (cold reset), in which
diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c b/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
index 7a97f7c..8d62b0c 100644
--- a/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
+++ b/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
@@ -147,6 +147,12 @@ BmFindBootOptionInVariable (
if (OptionNumber == LoadOptionNumberUnassigned) {
BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
+ // Only assert if the BootOption is non-zero
+ if ((BootOptions == NULL) && (BootOptionCount > 0)) {
+ ASSERT (BootOptions != NULL);
+ return LoadOptionNumberUnassigned;
+ }
+
Index = EfiBootManagerFindLoadOption (OptionToFind, BootOptions, BootOptionCount);
if (Index != -1) {
OptionNumber = BootOptions[Index].OptionNumber;
diff --git a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHii.h b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHii.h
index 89de54d..59b51e8 100644
--- a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHii.h
+++ b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHii.h
@@ -1,7 +1,7 @@
/** @file
Include file for Var Check Hii handler and bin.
-Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2015 - 2024, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -51,7 +51,11 @@ DumpVarCheckHii (
IN UINTN VarCheckHiiBinSize
);
-extern VAR_CHECK_HII_VARIABLE_HEADER *mVarCheckHiiBin;
-extern UINTN mVarCheckHiiBinSize;
+#define VAR_CHECK_RECEIVED_HII_BIN_HANDLER_GUID \
+ { \
+ 0xe63095c7, 0x2b34, 0x4163, { 0x80, 0x3d, 0xc8, 0x3c, 0x2e, 0xd6, 0xa0, 0x37 } \
+ }
+
+extern EFI_GUID gVarCheckReceivedHiiBinHandlerGuid;
#endif
diff --git a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.c b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.c
index ca8227d..abc5fd4 100644
--- a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.c
+++ b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.c
@@ -1,14 +1,17 @@
/** @file
Var Check Hii bin generation.
-Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2015 - 2024, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "VarCheckHiiGen.h"
+#include "VarCheckHii.h"
-LIST_ENTRY mVarCheckHiiList = INITIALIZE_LIST_HEAD_VARIABLE (mVarCheckHiiList);
+VAR_CHECK_HII_VARIABLE_HEADER *mVarCheckHiiBin = NULL;
+UINTN mVarCheckHiiBinSize = 0;
+LIST_ENTRY mVarCheckHiiList = INITIALIZE_LIST_HEAD_VARIABLE (mVarCheckHiiList);
#define VAR_CHECK_HII_VARIABLE_NODE_SIGNATURE SIGNATURE_32 ('V', 'C', 'H', 'V')
@@ -1511,7 +1514,7 @@ DestroyHiiVariableNode (
**/
VOID *
BuildVarCheckHiiBin (
- OUT UINTN *Size
+ IN OUT UINTN *Size
)
{
VAR_CHECK_HII_VARIABLE_NODE *HiiVariableNode;
diff --git a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.h b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.h
index c70bf72..ace1fe6 100644
--- a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.h
+++ b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.h
@@ -1,7 +1,7 @@
/** @file
Include file for Var Check Hii bin generation.
-Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -10,6 +10,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#define _VAR_CHECK_HII_GEN_H_
#include "VarCheckHii.h"
+extern VAR_CHECK_HII_VARIABLE_HEADER *mVarCheckHiiBin;
+extern UINTN mVarCheckHiiBinSize;
/**
Dump Hii Package.
diff --git a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromHii.c b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromHii.c
index 27d10f8..6f152d4 100644
--- a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromHii.c
+++ b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromHii.c
@@ -65,3 +65,254 @@ VarCheckHiiGenFromHiiDatabase (
gBS->FreePages (BufferAddress, EFI_SIZE_TO_PAGES (BufferSize));
}
}
+
+#ifdef DUMP_VAR_CHECK_HII
+GLOBAL_REMOVE_IF_UNREFERENCED VAR_CHECK_HII_OPCODE_STRING mHiiOpCodeStringTable[] = {
+ { EFI_IFR_VARSTORE_EFI_OP, "EfiVarStore" },
+ { EFI_IFR_ONE_OF_OP, "OneOf" },
+ { EFI_IFR_CHECKBOX_OP, "CheckBox" },
+ { EFI_IFR_NUMERIC_OP, "Numeric" },
+ { EFI_IFR_ORDERED_LIST_OP, "OrderedList" },
+};
+
+/**
+ HII opcode to string.
+
+ @param[in] HiiOpCode Hii OpCode.
+
+ @return Pointer to string.
+
+**/
+CHAR8 *
+HiiOpCodeToStr (
+ IN UINT8 HiiOpCode
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < ARRAY_SIZE (mHiiOpCodeStringTable); Index++) {
+ if (mHiiOpCodeStringTable[Index].HiiOpCode == HiiOpCode) {
+ return mHiiOpCodeStringTable[Index].HiiOpCodeStr;
+ }
+ }
+
+ return "<UnknownHiiOpCode>";
+}
+
+/**
+ Dump Hii Question.
+
+ @param[in] HiiQuestion Pointer to Hii Question.
+
+**/
+VOID
+DumpHiiQuestion (
+ IN VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion
+ )
+{
+ UINT64 Minimum;
+ UINT64 Maximum;
+ UINT64 OneValue;
+ UINT8 *Ptr;
+
+ DEBUG ((DEBUG_INFO, " VAR_CHECK_HII_QUESTION_HEADER\n"));
+ DEBUG ((DEBUG_INFO, " OpCode - 0x%02x (%a) (%a)\n", HiiQuestion->OpCode, HiiOpCodeToStr (HiiQuestion->OpCode), (HiiQuestion->BitFieldStore ? "bit level" : "byte level")));
+ DEBUG ((DEBUG_INFO, " Length - 0x%02x\n", HiiQuestion->Length));
+ DEBUG ((DEBUG_INFO, " VarOffset - 0x%04x (%a)\n", HiiQuestion->VarOffset, (HiiQuestion->BitFieldStore ? "bit level" : "byte level")));
+ DEBUG ((DEBUG_INFO, " StorageWidth - 0x%02x (%a)\n", HiiQuestion->StorageWidth, (HiiQuestion->BitFieldStore ? "bit level" : "byte level")));
+
+ switch (HiiQuestion->OpCode) {
+ case EFI_IFR_ONE_OF_OP:
+ Ptr = (UINT8 *)((VAR_CHECK_HII_QUESTION_ONEOF *)HiiQuestion + 1);
+ while ((UINTN)Ptr < ((UINTN)HiiQuestion + HiiQuestion->Length)) {
+ OneValue = 0;
+ if (HiiQuestion->BitFieldStore) {
+ //
+ // For OneOf stored in bit field, the value of options are saved as UINT32 type.
+ //
+ CopyMem (&OneValue, Ptr, sizeof (UINT32));
+ DEBUG ((DEBUG_INFO, " OneOfOption - 0x%08x\n", OneValue));
+ } else {
+ CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth);
+ switch (HiiQuestion->StorageWidth) {
+ case sizeof (UINT8):
+ DEBUG ((DEBUG_INFO, " OneOfOption - 0x%02x\n", OneValue));
+ break;
+ case sizeof (UINT16):
+ DEBUG ((DEBUG_INFO, " OneOfOption - 0x%04x\n", OneValue));
+ break;
+ case sizeof (UINT32):
+ DEBUG ((DEBUG_INFO, " OneOfOption - 0x%08x\n", OneValue));
+ break;
+ case sizeof (UINT64):
+ DEBUG ((DEBUG_INFO, " OneOfOption - 0x%016lx\n", OneValue));
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ }
+
+ if (HiiQuestion->BitFieldStore) {
+ Ptr += sizeof (UINT32);
+ } else {
+ Ptr += HiiQuestion->StorageWidth;
+ }
+ }
+
+ break;
+
+ case EFI_IFR_CHECKBOX_OP:
+ break;
+
+ case EFI_IFR_NUMERIC_OP:
+ Minimum = 0;
+ Maximum = 0;
+ Ptr = (UINT8 *)((VAR_CHECK_HII_QUESTION_NUMERIC *)HiiQuestion + 1);
+ if (HiiQuestion->BitFieldStore) {
+ //
+ // For Numeric stored in bit field, the value of Maximum/Minimum are saved as UINT32 type.
+ //
+ CopyMem (&Minimum, Ptr, sizeof (UINT32));
+ Ptr += sizeof (UINT32);
+ CopyMem (&Maximum, Ptr, sizeof (UINT32));
+ Ptr += sizeof (UINT32);
+
+ DEBUG ((DEBUG_INFO, " Minimum - 0x%08x\n", Minimum));
+ DEBUG ((DEBUG_INFO, " Maximum - 0x%08x\n", Maximum));
+ } else {
+ CopyMem (&Minimum, Ptr, HiiQuestion->StorageWidth);
+ Ptr += HiiQuestion->StorageWidth;
+ CopyMem (&Maximum, Ptr, HiiQuestion->StorageWidth);
+ Ptr += HiiQuestion->StorageWidth;
+
+ switch (HiiQuestion->StorageWidth) {
+ case sizeof (UINT8):
+ DEBUG ((DEBUG_INFO, " Minimum - 0x%02x\n", Minimum));
+ DEBUG ((DEBUG_INFO, " Maximum - 0x%02x\n", Maximum));
+ break;
+ case sizeof (UINT16):
+ DEBUG ((DEBUG_INFO, " Minimum - 0x%04x\n", Minimum));
+ DEBUG ((DEBUG_INFO, " Maximum - 0x%04x\n", Maximum));
+ break;
+ case sizeof (UINT32):
+ DEBUG ((DEBUG_INFO, " Minimum - 0x%08x\n", Minimum));
+ DEBUG ((DEBUG_INFO, " Maximum - 0x%08x\n", Maximum));
+ break;
+ case sizeof (UINT64):
+ DEBUG ((DEBUG_INFO, " Minimum - 0x%016lx\n", Minimum));
+ DEBUG ((DEBUG_INFO, " Maximum - 0x%016lx\n", Maximum));
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ }
+
+ break;
+
+ case EFI_IFR_ORDERED_LIST_OP:
+ DEBUG ((DEBUG_INFO, " MaxContainers - 0x%02x\n", ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *)HiiQuestion)->MaxContainers));
+ Ptr = (UINT8 *)((VAR_CHECK_HII_QUESTION_ORDEREDLIST *)HiiQuestion + 1);
+ while ((UINTN)Ptr < ((UINTN)HiiQuestion + HiiQuestion->Length)) {
+ OneValue = 0;
+ CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth);
+ switch (HiiQuestion->StorageWidth) {
+ case sizeof (UINT8):
+ DEBUG ((DEBUG_INFO, " OneOfOption - 0x%02x\n", OneValue));
+ break;
+ case sizeof (UINT16):
+ DEBUG ((DEBUG_INFO, " OneOfOption - 0x%04x\n", OneValue));
+ break;
+ case sizeof (UINT32):
+ DEBUG ((DEBUG_INFO, " OneOfOption - 0x%08x\n", OneValue));
+ break;
+ case sizeof (UINT64):
+ DEBUG ((DEBUG_INFO, " OneOfOption - 0x%016lx\n", OneValue));
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ Ptr += HiiQuestion->StorageWidth;
+ }
+
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+}
+
+/**
+ Dump Hii Variable.
+
+ @param[in] HiiVariable Pointer to Hii Variable.
+
+**/
+VOID
+DumpHiiVariable (
+ IN VAR_CHECK_HII_VARIABLE_HEADER *HiiVariable
+ )
+{
+ VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion;
+
+ DEBUG ((DEBUG_INFO, "VAR_CHECK_HII_VARIABLE_HEADER\n"));
+ DEBUG ((DEBUG_INFO, " Revision - 0x%04x\n", HiiVariable->Revision));
+ DEBUG ((DEBUG_INFO, " HeaderLength - 0x%04x\n", HiiVariable->HeaderLength));
+ DEBUG ((DEBUG_INFO, " Length - 0x%08x\n", HiiVariable->Length));
+ DEBUG ((DEBUG_INFO, " OpCode - 0x%02x (%a)\n", HiiVariable->OpCode, HiiOpCodeToStr (HiiVariable->OpCode)));
+ DEBUG ((DEBUG_INFO, " Size - 0x%04x\n", HiiVariable->Size));
+ DEBUG ((DEBUG_INFO, " Attributes - 0x%08x\n", HiiVariable->Attributes));
+ DEBUG ((DEBUG_INFO, " Guid - %g\n", &HiiVariable->Guid));
+ DEBUG ((DEBUG_INFO, " Name - %s\n", HiiVariable + 1));
+
+ //
+ // For Hii Question header align.
+ //
+ HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *)HEADER_ALIGN (((UINTN)HiiVariable + HiiVariable->HeaderLength));
+ while ((UINTN)HiiQuestion < ((UINTN)HiiVariable + HiiVariable->Length)) {
+ //
+ // Dump Hii Question related to the Hii Variable.
+ //
+ DumpHiiQuestion (HiiQuestion);
+ //
+ // For Hii Question header align.
+ //
+ HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *)HEADER_ALIGN (((UINTN)HiiQuestion + HiiQuestion->Length));
+ }
+}
+
+/**
+ Dump Var Check HII.
+
+ @param[in] VarCheckHiiBin Pointer to VarCheckHiiBin.
+ @param[in] VarCheckHiiBinSize VarCheckHiiBin size.
+
+**/
+VOID
+DumpVarCheckHii (
+ IN VOID *VarCheckHiiBin,
+ IN UINTN VarCheckHiiBinSize
+ )
+{
+ VAR_CHECK_HII_VARIABLE_HEADER *HiiVariable;
+
+ DEBUG ((DEBUG_INFO, "DumpVarCheckHii\n"));
+
+ //
+ // For Hii Variable header align.
+ //
+ HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *)HEADER_ALIGN (VarCheckHiiBin);
+ while ((UINTN)HiiVariable < ((UINTN)VarCheckHiiBin + VarCheckHiiBinSize)) {
+ DumpHiiVariable (HiiVariable);
+ //
+ // For Hii Variable header align.
+ //
+ HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *)HEADER_ALIGN (((UINTN)HiiVariable + HiiVariable->Length));
+ }
+}
+
+#endif
diff --git a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.c b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.c
new file mode 100644
index 0000000..22b2755
--- /dev/null
+++ b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.c
@@ -0,0 +1,57 @@
+/** @file
+ Var Check Hii handler.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "VarCheckHii.h"
+#include "VarCheckHiiGen.h"
+#include "VarCheckHiiLibCommon.h"
+
+/**
+ Sets the variable check handler for HII.
+ @param[in] VariableName Name of Variable to set.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Attributes Attribute value of the variable.
+ @param[in] DataSize Size of Data to set.
+ @param[in] Data Data pointer.
+ @retval EFI_SUCCESS The SetVariable check result was success.
+ @retval EFI_SECURITY_VIOLATION Check fail.
+**/
+EFI_STATUS
+EFIAPI
+SetVariableCheckHandlerHii (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ return CheckHiiVariableCommon (mVarCheckHiiBin, mVarCheckHiiBinSize, VariableName, VendorGuid, Attributes, DataSize, Data);
+}
+
+/**
+ Constructor function of VarCheckHiiLib to register var check HII handler.
+
+ @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 executed correctly.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckHiiLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ VarCheckLibRegisterEndOfDxeCallback (VarCheckHiiGen);
+ VarCheckLibRegisterAddressPointer ((VOID **)&mVarCheckHiiBin);
+ VarCheckLibRegisterSetVariableCheckHandler (SetVariableCheckHandlerHii);
+
+ return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
index 9e55d20..f25b190 100644
--- a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
+++ b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
@@ -1,5 +1,5 @@
## @file
-# NULL class library to register var check HII handler.
+# VarCheckHiiLib library to register var check HII handler.
#
# Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
#
@@ -15,16 +15,18 @@
MODULE_TYPE = DXE_RUNTIME_DRIVER
VERSION_STRING = 1.0
LIBRARY_CLASS = NULL|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER
- CONSTRUCTOR = VarCheckHiiLibNullClassConstructor
+ CONSTRUCTOR = VarCheckHiiLibConstructor
[Sources]
- VarCheckHiiLibNullClass.c
+ VarCheckHiiLib.c
VarCheckHii.h
VarCheckHiiGenFromFv.c
VarCheckHiiGenFromHii.c
VarCheckHiiGen.c
VarCheckHiiGen.h
InternalVarCheckStructure.h
+ VarCheckHiiLibCommon.c
+ VarCheckHiiLibCommon.h
[Packages]
MdePkg/MdePkg.dec
diff --git a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibCommon.c b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibCommon.c
new file mode 100644
index 0000000..00a37df
--- /dev/null
+++ b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibCommon.c
@@ -0,0 +1,349 @@
+/** @file
+ Var Check Hii Lib Common logic
+Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include <Uefi.h>
+#include <Library/DebugLib.h>
+
+#include "VarCheckHii.h"
+#include "VarCheckHiiLibCommon.h"
+EFI_HANDLE mEfiVariableCheckHiiHandle = NULL;
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mVarCheckHiiHex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+/**
+ Dump some hexadecimal data.
+ @param[in] Indent How many spaces to indent the output.
+ @param[in] Offset The offset of the dump.
+ @param[in] DataSize The size in bytes of UserData.
+ @param[in] UserData The data to dump.
+**/
+VOID
+VarCheckHiiInternalDumpHex (
+ IN UINTN Indent,
+ IN UINTN Offset,
+ IN UINTN DataSize,
+ IN VOID *UserData
+ )
+{
+ UINT8 *Data;
+
+ CHAR8 Val[50];
+
+ CHAR8 Str[20];
+
+ UINT8 TempByte;
+ UINTN Size;
+ UINTN Index;
+
+ Data = UserData;
+ while (DataSize != 0) {
+ Size = 16;
+ if (Size > DataSize) {
+ Size = DataSize;
+ }
+
+ for (Index = 0; Index < Size; Index += 1) {
+ TempByte = Data[Index];
+ Val[Index * 3 + 0] = mVarCheckHiiHex[TempByte >> 4];
+ Val[Index * 3 + 1] = mVarCheckHiiHex[TempByte & 0xF];
+ Val[Index * 3 + 2] = (CHAR8)((Index == 7) ? '-' : ' ');
+ Str[Index] = (CHAR8)((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);
+ }
+
+ Val[Index * 3] = 0;
+ Str[Index] = 0;
+ DEBUG ((DEBUG_INFO, "%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str));
+
+ Data += Size;
+ Offset += Size;
+ DataSize -= Size;
+ }
+}
+
+/**
+ Var Check Hii Question.
+ @param[in] HiiQuestion Pointer to Hii Question
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data to set.
+ @retval TRUE Check pass
+ @retval FALSE Check fail.
+**/
+BOOLEAN
+VarCheckHiiQuestion (
+ IN VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion,
+ IN VOID *Data,
+ IN UINTN DataSize
+ )
+{
+ UINT64 OneData;
+ UINT64 Minimum;
+ UINT64 Maximum;
+ UINT64 OneValue;
+ UINT8 *Ptr;
+ UINT8 Index;
+ UINT8 MaxContainers;
+ UINT8 StartBit;
+ UINT8 EndBit;
+ UINT8 TotalBits;
+ UINT16 VarOffsetByteLevel;
+ UINT8 StorageWidthByteLevel;
+
+ if (HiiQuestion->BitFieldStore) {
+ VarOffsetByteLevel = HiiQuestion->VarOffset / 8;
+ TotalBits = HiiQuestion->VarOffset % 8 + HiiQuestion->StorageWidth;
+ StorageWidthByteLevel = (TotalBits % 8 == 0 ? TotalBits / 8 : TotalBits / 8 + 1);
+ } else {
+ VarOffsetByteLevel = HiiQuestion->VarOffset;
+ StorageWidthByteLevel = HiiQuestion->StorageWidth;
+ }
+
+ if (((UINT32)VarOffsetByteLevel + StorageWidthByteLevel) > DataSize) {
+ DEBUG ((DEBUG_INFO, "VarCheckHiiQuestion fail: (VarOffset(0x%04x) + StorageWidth(0x%02x)) > Size(0x%x)\n", VarOffsetByteLevel, StorageWidthByteLevel, DataSize));
+ return FALSE;
+ }
+
+ OneData = 0;
+ CopyMem (&OneData, (UINT8 *)Data + VarOffsetByteLevel, StorageWidthByteLevel);
+ if (HiiQuestion->BitFieldStore) {
+ //
+ // Get the value from the bit field.
+ //
+ StartBit = HiiQuestion->VarOffset % 8;
+ EndBit = StartBit + HiiQuestion->StorageWidth - 1;
+ OneData = BitFieldRead64 (OneData, StartBit, EndBit);
+ }
+
+ switch (HiiQuestion->OpCode) {
+ case EFI_IFR_ONE_OF_OP:
+ Ptr = (UINT8 *)((VAR_CHECK_HII_QUESTION_ONEOF *)HiiQuestion + 1);
+ while ((UINTN)Ptr < (UINTN)HiiQuestion + HiiQuestion->Length) {
+ OneValue = 0;
+ if (HiiQuestion->BitFieldStore) {
+ //
+ // For OneOf stored in bit field, the value of options are saved as UINT32 type.
+ //
+ CopyMem (&OneValue, Ptr, sizeof (UINT32));
+ } else {
+ CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth);
+ }
+
+ if (OneData == OneValue) {
+ //
+ // Match
+ //
+ break;
+ }
+
+ if (HiiQuestion->BitFieldStore) {
+ Ptr += sizeof (UINT32);
+ } else {
+ Ptr += HiiQuestion->StorageWidth;
+ }
+ }
+
+ if ((UINTN)Ptr >= ((UINTN)HiiQuestion + HiiQuestion->Length)) {
+ //
+ // No match
+ //
+ DEBUG ((DEBUG_INFO, "VarCheckHiiQuestion fail: OneOf mismatch (0x%lx)\n", OneData));
+ DEBUG_CODE (
+ VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, (UINT8 *)HiiQuestion);
+ );
+ return FALSE;
+ }
+
+ break;
+
+ case EFI_IFR_CHECKBOX_OP:
+ if ((OneData != 0) && (OneData != 1)) {
+ DEBUG ((DEBUG_INFO, "VarCheckHiiQuestion fail: CheckBox mismatch (0x%lx)\n", OneData));
+ DEBUG_CODE (
+ VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, (UINT8 *)HiiQuestion);
+ );
+ return FALSE;
+ }
+
+ break;
+
+ case EFI_IFR_NUMERIC_OP:
+ Minimum = 0;
+ Maximum = 0;
+ Ptr = (UINT8 *)((VAR_CHECK_HII_QUESTION_NUMERIC *)HiiQuestion + 1);
+ if (HiiQuestion->BitFieldStore) {
+ //
+ // For Numeric stored in bit field, the value of Maximum/Minimum are saved as UINT32 type.
+ //
+ CopyMem (&Minimum, Ptr, sizeof (UINT32));
+ Ptr += sizeof (UINT32);
+ CopyMem (&Maximum, Ptr, sizeof (UINT32));
+ Ptr += sizeof (UINT32);
+ } else {
+ CopyMem (&Minimum, Ptr, HiiQuestion->StorageWidth);
+ Ptr += HiiQuestion->StorageWidth;
+ CopyMem (&Maximum, Ptr, HiiQuestion->StorageWidth);
+ Ptr += HiiQuestion->StorageWidth;
+ }
+
+ //
+ // No need to check Step, because it is ONLY for UI.
+ //
+ if ((OneData < Minimum) || (OneData > Maximum)) {
+ DEBUG ((DEBUG_INFO, "VarCheckHiiQuestion fail: Numeric mismatch (0x%lx)\n", OneData));
+ DEBUG_CODE (
+ VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, (UINT8 *)HiiQuestion);
+ );
+ return FALSE;
+ }
+
+ break;
+
+ case EFI_IFR_ORDERED_LIST_OP:
+ MaxContainers = ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *)HiiQuestion)->MaxContainers;
+ if (((UINT32)HiiQuestion->VarOffset + HiiQuestion->StorageWidth * MaxContainers) > DataSize) {
+ DEBUG ((DEBUG_INFO, "VarCheckHiiQuestion fail: (VarOffset(0x%04x) + StorageWidth(0x%02x) * MaxContainers(0x%02x)) > Size(0x%x)\n", HiiQuestion->VarOffset, HiiQuestion->StorageWidth, MaxContainers, DataSize));
+ return FALSE;
+ }
+
+ for (Index = 0; Index < MaxContainers; Index++) {
+ OneData = 0;
+ CopyMem (&OneData, (UINT8 *)Data + HiiQuestion->VarOffset + HiiQuestion->StorageWidth * Index, HiiQuestion->StorageWidth);
+ if (OneData == 0) {
+ //
+ // The value of 0 is used to determine if a particular "slot" in the array is empty.
+ //
+ continue;
+ }
+
+ Ptr = (UINT8 *)((VAR_CHECK_HII_QUESTION_ORDEREDLIST *)HiiQuestion + 1);
+ while ((UINTN)Ptr < ((UINTN)HiiQuestion + HiiQuestion->Length)) {
+ OneValue = 0;
+ CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth);
+ if (OneData == OneValue) {
+ //
+ // Match
+ //
+ break;
+ }
+
+ Ptr += HiiQuestion->StorageWidth;
+ }
+
+ if ((UINTN)Ptr >= ((UINTN)HiiQuestion + HiiQuestion->Length)) {
+ //
+ // No match
+ //
+ DEBUG ((DEBUG_INFO, "VarCheckHiiQuestion fail: OrderedList mismatch\n"));
+ DEBUG_CODE (
+ VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->StorageWidth * MaxContainers, (UINT8 *)Data + HiiQuestion->VarOffset);
+ );
+ DEBUG_CODE (
+ VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, (UINT8 *)HiiQuestion);
+ );
+ return FALSE;
+ }
+ }
+
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ return TRUE;
+}
+
+/**
+ SetVariable check handler HII.
+ @param[in] HiiVariableBin Variable BIN.
+ @param[in] HiiVariableBinSize The size of Variable BIN.
+ @param[in] VariableName Name of Variable to set.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Attributes Attribute value of the variable.
+ @param[in] DataSize Size of Data to set.
+ @param[in] Data Data pointer.
+ @retval EFI_SUCCESS The SetVariable check result was success.
+ @retval EFI_SECURITY_VIOLATION Check fail.
+**/
+EFI_STATUS
+EFIAPI
+CheckHiiVariableCommon (
+ IN VAR_CHECK_HII_VARIABLE_HEADER *HiiVariableBin,
+ IN UINTN HiiVariableBinSize,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ VAR_CHECK_HII_VARIABLE_HEADER *HiiVariable;
+ VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion;
+
+ if (HiiVariableBin == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0)) {
+ //
+ // Do not check delete variable.
+ //
+ }
+
+ //
+ // For Hii Variable header align.
+ //
+ HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *)HEADER_ALIGN (HiiVariableBin);
+ while ((UINTN)HiiVariable < ((UINTN)HiiVariableBin + HiiVariableBinSize)) {
+ if ((StrCmp ((CHAR16 *)(HiiVariable + 1), VariableName) == 0) &&
+ (CompareGuid (&HiiVariable->Guid, VendorGuid)))
+ {
+ //
+ // Found the Hii Variable that could be used to do check.
+ //
+ DEBUG ((DEBUG_INFO, "VarCheckHiiVariable - %s:%g with Attributes = 0x%08x Size = 0x%x\n", VariableName, VendorGuid, Attributes, DataSize));
+ if (HiiVariable->Attributes != Attributes) {
+ DEBUG ((DEBUG_INFO, "VarCheckHiiVariable fail for Attributes - 0x%08x\n", HiiVariable->Attributes));
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ if (DataSize == 0) {
+ DEBUG ((DEBUG_INFO, "VarCheckHiiVariable - CHECK PASS with DataSize == 0 !\n"));
+ return EFI_SUCCESS;
+ }
+
+ if (HiiVariable->Size != DataSize) {
+ DEBUG ((DEBUG_INFO, "VarCheckHiiVariable fail for Size - 0x%x\n", HiiVariable->Size));
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ //
+ // Do the check.
+ // For Hii Question header align.
+ //
+ HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *)HEADER_ALIGN (((UINTN)HiiVariable + HiiVariable->HeaderLength));
+ while ((UINTN)HiiQuestion < ((UINTN)HiiVariable + HiiVariable->Length)) {
+ if (!VarCheckHiiQuestion (HiiQuestion, Data, DataSize)) {
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ //
+ // For Hii Question header align.
+ //
+ HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *)HEADER_ALIGN (((UINTN)HiiQuestion + HiiQuestion->Length));
+ }
+
+ DEBUG ((DEBUG_INFO, "VarCheckHiiVariable - ALL CHECK PASS!\n"));
+ return EFI_SUCCESS;
+ }
+
+ //
+ // For Hii Variable header align.
+ //
+ HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *)HEADER_ALIGN (((UINTN)HiiVariable + HiiVariable->Length));
+ }
+
+ // Not found, so pass.
+ return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibCommon.h b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibCommon.h
new file mode 100644
index 0000000..06249f0
--- /dev/null
+++ b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibCommon.h
@@ -0,0 +1,43 @@
+/** @file
+ Var Check Hii Lib Common logic
+Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef VAR_CHECK_HII_LIB_GUID_H_
+#define VAR_CHECK_HII_LIB_GUID_H_
+
+#include <Uefi.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/MmServicesTableLib.h>
+#include <Protocol/MmCommunication.h>
+#include <Library/VarCheckLib.h>
+
+#include "VarCheckHii.h"
+
+/**
+ SetVariable check handler HII.
+ @param[in] HiiVariableBin Variable BIN.
+ @param[in] HiiVariableBinSize The size of Variable BIN.
+ @param[in] VariableName Name of Variable to set.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Attributes Attribute value of the variable.
+ @param[in] DataSize Size of Data to set.
+ @param[in] Data Data pointer.
+ @retval EFI_SUCCESS The SetVariable check result was success.
+ @retval EFI_SECURITY_VIOLATION Check fail.
+**/
+EFI_STATUS
+EFIAPI
+CheckHiiVariableCommon (
+ IN VAR_CHECK_HII_VARIABLE_HEADER *HiiVariableBin,
+ IN UINTN HiiVariableBinSize,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ );
+
+#endif
diff --git a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibMmDependency.c b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibMmDependency.c
new file mode 100644
index 0000000..9ba75b7
--- /dev/null
+++ b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibMmDependency.c
@@ -0,0 +1,138 @@
+/** @file
+ VarCheckHiiLib Dependency library.
+ It sends HII variable checking data to SMM via the MM Communication protocol.
+ Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Uefi.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Protocol/MmCommunication.h>
+#include <Guid/PiSmmCommunicationRegionTable.h>
+#include "InternalVarCheckStructure.h"
+#include "VarCheckHiiGen.h"
+#include "VarCheckHii.h"
+#include <Library/UefiLib.h>
+#include <Guid/EventGroup.h>
+
+extern VAR_CHECK_HII_VARIABLE_HEADER *mVarCheckHiiBin;
+extern UINTN mVarCheckHiiBinSize;
+EFI_GUID gVarCheckReceivedHiiBinHandlerGuid = VAR_CHECK_RECEIVED_HII_BIN_HANDLER_GUID;
+
+/**
+ Sends HII variable checking data to SMM at the end of DXE phase.
+ This function is triggered by the End of DXE. It locates a memory
+ region for MM communication, prepares the communication buffer with HII variable
+ checking data, and communicates with SMM using the MM Communication protocol.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context, which
+ is implementation-dependent.
+**/
+VOID
+EFIAPI
+VarCheckHiiLibSmmEndOfDxeNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_MM_COMMUNICATION_PROTOCOL *MmCommunication;
+ EFI_MM_COMMUNICATE_HEADER *CommHeader;
+ EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *PiSmmCommunicationRegionTable;
+ EFI_MEMORY_DESCRIPTOR *MmCommMemRegion;
+ UINTN CommBufferSize;
+ UINTN Index;
+ VAR_CHECK_HII_VARIABLE_HEADER *VarCheckHiiVariable;
+
+ DEBUG ((DEBUG_INFO, "%a starts.\n", __func__));
+ VarCheckHiiGen ();
+ if ((mVarCheckHiiBinSize == 0) || (mVarCheckHiiBin == NULL)) {
+ DEBUG ((DEBUG_INFO, "%a: mVarCheckHiiBinSize = 0x%x, mVarCheckHiiBin = 0x%x \n", __func__, mVarCheckHiiBinSize, mVarCheckHiiBin));
+ return;
+ }
+
+ //
+ // Retrieve SMM Communication Region Table
+ //
+ Status = EfiGetSystemConfigurationTable (
+ &gEdkiiPiSmmCommunicationRegionTableGuid,
+ (VOID **)&PiSmmCommunicationRegionTable
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to get PiSmmCommunicationRegionTable - %r\n", __func__, Status));
+ return;
+ }
+
+ ASSERT (PiSmmCommunicationRegionTable != NULL);
+ //
+ // Find a memory region for MM communication
+ //
+ CommBufferSize = 0;
+ MmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *)(PiSmmCommunicationRegionTable + 1);
+ for (Index = 0; Index < PiSmmCommunicationRegionTable->NumberOfEntries; Index++) {
+ if (MmCommMemRegion->Type == EfiConventionalMemory) {
+ CommBufferSize = EFI_PAGES_TO_SIZE ((UINTN)MmCommMemRegion->NumberOfPages);
+ if (CommBufferSize >= (sizeof (EFI_MM_COMMUNICATE_HEADER) + mVarCheckHiiBinSize)) {
+ break;
+ }
+ }
+
+ MmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MmCommMemRegion + PiSmmCommunicationRegionTable->DescriptorSize);
+ }
+
+ if (Index >= PiSmmCommunicationRegionTable->NumberOfEntries) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to find a suitable memory region for MM communication!\n", __func__));
+ return;
+ }
+
+ //
+ // Prepare the communication buffer
+ //
+ CommHeader = (EFI_MM_COMMUNICATE_HEADER *)(UINTN)MmCommMemRegion->PhysicalStart;
+ CommBufferSize = OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data) + mVarCheckHiiBinSize;
+ ZeroMem (CommHeader, CommBufferSize);
+ CopyGuid (&CommHeader->HeaderGuid, &gVarCheckReceivedHiiBinHandlerGuid);
+ CommHeader->MessageLength = mVarCheckHiiBinSize;
+ VarCheckHiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *)(CommHeader->Data);
+ CopyMem (VarCheckHiiVariable, mVarCheckHiiBin, mVarCheckHiiBinSize);
+ //
+ // Locate the MM Communication protocol and signal SMI
+ //
+ Status = gBS->LocateProtocol (&gEfiMmCommunicationProtocolGuid, NULL, (VOID **)&MmCommunication);
+
+ if (!EFI_ERROR (Status)) {
+ Status = MmCommunication->Communicate (MmCommunication, CommHeader, &CommBufferSize);
+ DEBUG ((DEBUG_INFO, "%a: Communicate to smm environment = %r\n", __func__, Status));
+ } else {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to locate MmCommunication protocol - %r\n", __func__, Status));
+ return;
+ }
+
+ DEBUG ((DEBUG_INFO, "%a ends.\n", __func__));
+ return;
+}
+
+/**
+ Constructor function of the VarCheckHiiLibMmDependency.
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the Management mode System Table.
+ @retval EFI_SUCCESS The protocol was successfully installed into the DXE database.
+**/
+EFI_STATUS
+EFIAPI
+VarCheckHiiLibMmDependencyConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+
+ DEBUG ((DEBUG_INFO, "%a starts.\n", __func__));
+ Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_NOTIFY, VarCheckHiiLibSmmEndOfDxeNotify, NULL, &gEfiEndOfDxeEventGroupGuid, &Event);
+ ASSERT_EFI_ERROR (Status);
+ DEBUG ((DEBUG_INFO, "%a ends.\n", __func__));
+ return Status;
+}
diff --git a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibMmDependency.inf b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibMmDependency.inf
new file mode 100644
index 0000000..9798a1b
--- /dev/null
+++ b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibMmDependency.inf
@@ -0,0 +1,53 @@
+## @file
+# VarCheckHiiLib Dependency library.
+#
+# Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001A
+ BASE_NAME = VarCheckHiiLibMmDependency
+ FILE_GUID = DF61C3DC-B08C-44B7-B771-9E4BCBBE0811
+ MODULE_TYPE = DXE_DRIVER
+ LIBRARY_CLASS = NULL
+ CONSTRUCTOR = VarCheckHiiLibMmDependencyConstructor
+
+[Sources]
+ VarCheckHiiLibMmDependency.c
+ VarCheckHii.h
+ VarCheckHiiGenFromFv.c
+ VarCheckHiiGenFromHii.c
+ VarCheckHiiGen.c
+ VarCheckHiiGen.h
+ InternalVarCheckStructure.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ UefiBootServicesTableLib
+ BaseLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ UefiLib
+ PcdLib
+
+[Guids]
+ gEdkiiIfrBitVarstoreGuid
+ gEfiEndOfDxeEventGroupGuid
+ gEdkiiPiSmmCommunicationRegionTableGuid
+
+[Protocols]
+ gEfiMmEndOfDxeProtocolGuid
+ gEfiMmCommunicationProtocolGuid
+ gEfiFirmwareVolume2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiFirmwareVolumeBlock2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiHiiDatabaseProtocolGuid ## SOMETIMES_CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVarCheckVfrDriverGuidArray ## SOMETIMES_CONSUMES
diff --git a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibNullClass.c b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibNullClass.c
deleted file mode 100644
index ee2d98c..0000000
--- a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibNullClass.c
+++ /dev/null
@@ -1,630 +0,0 @@
-/** @file
- Var Check Hii handler.
-
-Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "VarCheckHii.h"
-
-GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mVarCheckHiiHex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
-
-/**
- Dump some hexadecimal data.
-
- @param[in] Indent How many spaces to indent the output.
- @param[in] Offset The offset of the dump.
- @param[in] DataSize The size in bytes of UserData.
- @param[in] UserData The data to dump.
-
-**/
-VOID
-VarCheckHiiInternalDumpHex (
- IN UINTN Indent,
- IN UINTN Offset,
- IN UINTN DataSize,
- IN VOID *UserData
- )
-{
- UINT8 *Data;
-
- CHAR8 Val[50];
-
- CHAR8 Str[20];
-
- UINT8 TempByte;
- UINTN Size;
- UINTN Index;
-
- Data = UserData;
- while (DataSize != 0) {
- Size = 16;
- if (Size > DataSize) {
- Size = DataSize;
- }
-
- for (Index = 0; Index < Size; Index += 1) {
- TempByte = Data[Index];
- Val[Index * 3 + 0] = mVarCheckHiiHex[TempByte >> 4];
- Val[Index * 3 + 1] = mVarCheckHiiHex[TempByte & 0xF];
- Val[Index * 3 + 2] = (CHAR8)((Index == 7) ? '-' : ' ');
- Str[Index] = (CHAR8)((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);
- }
-
- Val[Index * 3] = 0;
- Str[Index] = 0;
- DEBUG ((DEBUG_INFO, "%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str));
-
- Data += Size;
- Offset += Size;
- DataSize -= Size;
- }
-}
-
-/**
- Var Check Hii Question.
-
- @param[in] HiiQuestion Pointer to Hii Question
- @param[in] Data Data pointer.
- @param[in] DataSize Size of Data to set.
-
- @retval TRUE Check pass
- @retval FALSE Check fail.
-
-**/
-BOOLEAN
-VarCheckHiiQuestion (
- IN VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion,
- IN VOID *Data,
- IN UINTN DataSize
- )
-{
- UINT64 OneData;
- UINT64 Minimum;
- UINT64 Maximum;
- UINT64 OneValue;
- UINT8 *Ptr;
- UINT8 Index;
- UINT8 MaxContainers;
- UINT8 StartBit;
- UINT8 EndBit;
- UINT8 TotalBits;
- UINT16 VarOffsetByteLevel;
- UINT8 StorageWidthByteLevel;
-
- if (HiiQuestion->BitFieldStore) {
- VarOffsetByteLevel = HiiQuestion->VarOffset / 8;
- TotalBits = HiiQuestion->VarOffset % 8 + HiiQuestion->StorageWidth;
- StorageWidthByteLevel = (TotalBits % 8 == 0 ? TotalBits / 8 : TotalBits / 8 + 1);
- } else {
- VarOffsetByteLevel = HiiQuestion->VarOffset;
- StorageWidthByteLevel = HiiQuestion->StorageWidth;
- }
-
- if (((UINT32)VarOffsetByteLevel + StorageWidthByteLevel) > DataSize) {
- DEBUG ((DEBUG_INFO, "VarCheckHiiQuestion fail: (VarOffset(0x%04x) + StorageWidth(0x%02x)) > Size(0x%x)\n", VarOffsetByteLevel, StorageWidthByteLevel, DataSize));
- return FALSE;
- }
-
- OneData = 0;
- CopyMem (&OneData, (UINT8 *)Data + VarOffsetByteLevel, StorageWidthByteLevel);
- if (HiiQuestion->BitFieldStore) {
- //
- // Get the value from the bit field.
- //
- StartBit = HiiQuestion->VarOffset % 8;
- EndBit = StartBit + HiiQuestion->StorageWidth - 1;
- OneData = BitFieldRead64 (OneData, StartBit, EndBit);
- }
-
- switch (HiiQuestion->OpCode) {
- case EFI_IFR_ONE_OF_OP:
- Ptr = (UINT8 *)((VAR_CHECK_HII_QUESTION_ONEOF *)HiiQuestion + 1);
- while ((UINTN)Ptr < (UINTN)HiiQuestion + HiiQuestion->Length) {
- OneValue = 0;
- if (HiiQuestion->BitFieldStore) {
- //
- // For OneOf stored in bit field, the value of options are saved as UINT32 type.
- //
- CopyMem (&OneValue, Ptr, sizeof (UINT32));
- } else {
- CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth);
- }
-
- if (OneData == OneValue) {
- //
- // Match
- //
- break;
- }
-
- if (HiiQuestion->BitFieldStore) {
- Ptr += sizeof (UINT32);
- } else {
- Ptr += HiiQuestion->StorageWidth;
- }
- }
-
- if ((UINTN)Ptr >= ((UINTN)HiiQuestion + HiiQuestion->Length)) {
- //
- // No match
- //
- DEBUG ((DEBUG_INFO, "VarCheckHiiQuestion fail: OneOf mismatch (0x%lx)\n", OneData));
- DEBUG_CODE (
- VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, (UINT8 *)HiiQuestion);
- );
- return FALSE;
- }
-
- break;
-
- case EFI_IFR_CHECKBOX_OP:
- if ((OneData != 0) && (OneData != 1)) {
- DEBUG ((DEBUG_INFO, "VarCheckHiiQuestion fail: CheckBox mismatch (0x%lx)\n", OneData));
- DEBUG_CODE (
- VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, (UINT8 *)HiiQuestion);
- );
- return FALSE;
- }
-
- break;
-
- case EFI_IFR_NUMERIC_OP:
- Minimum = 0;
- Maximum = 0;
- Ptr = (UINT8 *)((VAR_CHECK_HII_QUESTION_NUMERIC *)HiiQuestion + 1);
- if (HiiQuestion->BitFieldStore) {
- //
- // For Numeric stored in bit field, the value of Maximum/Minimum are saved as UINT32 type.
- //
- CopyMem (&Minimum, Ptr, sizeof (UINT32));
- Ptr += sizeof (UINT32);
- CopyMem (&Maximum, Ptr, sizeof (UINT32));
- Ptr += sizeof (UINT32);
- } else {
- CopyMem (&Minimum, Ptr, HiiQuestion->StorageWidth);
- Ptr += HiiQuestion->StorageWidth;
- CopyMem (&Maximum, Ptr, HiiQuestion->StorageWidth);
- Ptr += HiiQuestion->StorageWidth;
- }
-
- //
- // No need to check Step, because it is ONLY for UI.
- //
- if ((OneData < Minimum) || (OneData > Maximum)) {
- DEBUG ((DEBUG_INFO, "VarCheckHiiQuestion fail: Numeric mismatch (0x%lx)\n", OneData));
- DEBUG_CODE (
- VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, (UINT8 *)HiiQuestion);
- );
- return FALSE;
- }
-
- break;
-
- case EFI_IFR_ORDERED_LIST_OP:
- MaxContainers = ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *)HiiQuestion)->MaxContainers;
- if (((UINT32)HiiQuestion->VarOffset + HiiQuestion->StorageWidth * MaxContainers) > DataSize) {
- DEBUG ((DEBUG_INFO, "VarCheckHiiQuestion fail: (VarOffset(0x%04x) + StorageWidth(0x%02x) * MaxContainers(0x%02x)) > Size(0x%x)\n", HiiQuestion->VarOffset, HiiQuestion->StorageWidth, MaxContainers, DataSize));
- return FALSE;
- }
-
- for (Index = 0; Index < MaxContainers; Index++) {
- OneData = 0;
- CopyMem (&OneData, (UINT8 *)Data + HiiQuestion->VarOffset + HiiQuestion->StorageWidth * Index, HiiQuestion->StorageWidth);
- if (OneData == 0) {
- //
- // The value of 0 is used to determine if a particular "slot" in the array is empty.
- //
- continue;
- }
-
- Ptr = (UINT8 *)((VAR_CHECK_HII_QUESTION_ORDEREDLIST *)HiiQuestion + 1);
- while ((UINTN)Ptr < ((UINTN)HiiQuestion + HiiQuestion->Length)) {
- OneValue = 0;
- CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth);
- if (OneData == OneValue) {
- //
- // Match
- //
- break;
- }
-
- Ptr += HiiQuestion->StorageWidth;
- }
-
- if ((UINTN)Ptr >= ((UINTN)HiiQuestion + HiiQuestion->Length)) {
- //
- // No match
- //
- DEBUG ((DEBUG_INFO, "VarCheckHiiQuestion fail: OrderedList mismatch\n"));
- DEBUG_CODE (
- VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->StorageWidth * MaxContainers, (UINT8 *)Data + HiiQuestion->VarOffset);
- );
- DEBUG_CODE (
- VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, (UINT8 *)HiiQuestion);
- );
- return FALSE;
- }
- }
-
- break;
-
- default:
- ASSERT (FALSE);
- break;
- }
-
- return TRUE;
-}
-
-VAR_CHECK_HII_VARIABLE_HEADER *mVarCheckHiiBin = NULL;
-UINTN mVarCheckHiiBinSize = 0;
-
-/**
- SetVariable check handler HII.
-
- @param[in] VariableName Name of Variable to set.
- @param[in] VendorGuid Variable vendor GUID.
- @param[in] Attributes Attribute value of the variable.
- @param[in] DataSize Size of Data to set.
- @param[in] Data Data pointer.
-
- @retval EFI_SUCCESS The SetVariable check result was success.
- @retval EFI_SECURITY_VIOLATION Check fail.
-
-**/
-EFI_STATUS
-EFIAPI
-SetVariableCheckHandlerHii (
- IN CHAR16 *VariableName,
- IN EFI_GUID *VendorGuid,
- IN UINT32 Attributes,
- IN UINTN DataSize,
- IN VOID *Data
- )
-{
- VAR_CHECK_HII_VARIABLE_HEADER *HiiVariable;
- VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion;
-
- if (mVarCheckHiiBin == NULL) {
- return EFI_SUCCESS;
- }
-
- if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0)) {
- //
- // Do not check delete variable.
- //
- return EFI_SUCCESS;
- }
-
- //
- // For Hii Variable header align.
- //
- HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *)HEADER_ALIGN (mVarCheckHiiBin);
- while ((UINTN)HiiVariable < ((UINTN)mVarCheckHiiBin + mVarCheckHiiBinSize)) {
- if ((StrCmp ((CHAR16 *)(HiiVariable + 1), VariableName) == 0) &&
- (CompareGuid (&HiiVariable->Guid, VendorGuid)))
- {
- //
- // Found the Hii Variable that could be used to do check.
- //
- DEBUG ((DEBUG_INFO, "VarCheckHiiVariable - %s:%g with Attributes = 0x%08x Size = 0x%x\n", VariableName, VendorGuid, Attributes, DataSize));
- if (HiiVariable->Attributes != Attributes) {
- DEBUG ((DEBUG_INFO, "VarCheckHiiVariable fail for Attributes - 0x%08x\n", HiiVariable->Attributes));
- return EFI_SECURITY_VIOLATION;
- }
-
- if (DataSize == 0) {
- DEBUG ((DEBUG_INFO, "VarCheckHiiVariable - CHECK PASS with DataSize == 0 !\n"));
- return EFI_SUCCESS;
- }
-
- if (HiiVariable->Size != DataSize) {
- DEBUG ((DEBUG_INFO, "VarCheckHiiVariable fail for Size - 0x%x\n", HiiVariable->Size));
- return EFI_SECURITY_VIOLATION;
- }
-
- //
- // Do the check.
- // For Hii Question header align.
- //
- HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *)HEADER_ALIGN (((UINTN)HiiVariable + HiiVariable->HeaderLength));
- while ((UINTN)HiiQuestion < ((UINTN)HiiVariable + HiiVariable->Length)) {
- if (!VarCheckHiiQuestion (HiiQuestion, Data, DataSize)) {
- return EFI_SECURITY_VIOLATION;
- }
-
- //
- // For Hii Question header align.
- //
- HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *)HEADER_ALIGN (((UINTN)HiiQuestion + HiiQuestion->Length));
- }
-
- DEBUG ((DEBUG_INFO, "VarCheckHiiVariable - ALL CHECK PASS!\n"));
- return EFI_SUCCESS;
- }
-
- //
- // For Hii Variable header align.
- //
- HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *)HEADER_ALIGN (((UINTN)HiiVariable + HiiVariable->Length));
- }
-
- // Not found, so pass.
- return EFI_SUCCESS;
-}
-
-#ifdef DUMP_VAR_CHECK_HII
-GLOBAL_REMOVE_IF_UNREFERENCED VAR_CHECK_HII_OPCODE_STRING mHiiOpCodeStringTable[] = {
- { EFI_IFR_VARSTORE_EFI_OP, "EfiVarStore" },
- { EFI_IFR_ONE_OF_OP, "OneOf" },
- { EFI_IFR_CHECKBOX_OP, "CheckBox" },
- { EFI_IFR_NUMERIC_OP, "Numeric" },
- { EFI_IFR_ORDERED_LIST_OP, "OrderedList" },
-};
-
-/**
- HII opcode to string.
-
- @param[in] HiiOpCode Hii OpCode.
-
- @return Pointer to string.
-
-**/
-CHAR8 *
-HiiOpCodeToStr (
- IN UINT8 HiiOpCode
- )
-{
- UINTN Index;
-
- for (Index = 0; Index < ARRAY_SIZE (mHiiOpCodeStringTable); Index++) {
- if (mHiiOpCodeStringTable[Index].HiiOpCode == HiiOpCode) {
- return mHiiOpCodeStringTable[Index].HiiOpCodeStr;
- }
- }
-
- return "<UnknownHiiOpCode>";
-}
-
-/**
- Dump Hii Question.
-
- @param[in] HiiQuestion Pointer to Hii Question.
-
-**/
-VOID
-DumpHiiQuestion (
- IN VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion
- )
-{
- UINT64 Minimum;
- UINT64 Maximum;
- UINT64 OneValue;
- UINT8 *Ptr;
-
- DEBUG ((DEBUG_INFO, " VAR_CHECK_HII_QUESTION_HEADER\n"));
- DEBUG ((DEBUG_INFO, " OpCode - 0x%02x (%a) (%a)\n", HiiQuestion->OpCode, HiiOpCodeToStr (HiiQuestion->OpCode), (HiiQuestion->BitFieldStore ? "bit level" : "byte level")));
- DEBUG ((DEBUG_INFO, " Length - 0x%02x\n", HiiQuestion->Length));
- DEBUG ((DEBUG_INFO, " VarOffset - 0x%04x (%a)\n", HiiQuestion->VarOffset, (HiiQuestion->BitFieldStore ? "bit level" : "byte level")));
- DEBUG ((DEBUG_INFO, " StorageWidth - 0x%02x (%a)\n", HiiQuestion->StorageWidth, (HiiQuestion->BitFieldStore ? "bit level" : "byte level")));
-
- switch (HiiQuestion->OpCode) {
- case EFI_IFR_ONE_OF_OP:
- Ptr = (UINT8 *)((VAR_CHECK_HII_QUESTION_ONEOF *)HiiQuestion + 1);
- while ((UINTN)Ptr < ((UINTN)HiiQuestion + HiiQuestion->Length)) {
- OneValue = 0;
- if (HiiQuestion->BitFieldStore) {
- //
- // For OneOf stored in bit field, the value of options are saved as UINT32 type.
- //
- CopyMem (&OneValue, Ptr, sizeof (UINT32));
- DEBUG ((DEBUG_INFO, " OneOfOption - 0x%08x\n", OneValue));
- } else {
- CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth);
- switch (HiiQuestion->StorageWidth) {
- case sizeof (UINT8):
- DEBUG ((DEBUG_INFO, " OneOfOption - 0x%02x\n", OneValue));
- break;
- case sizeof (UINT16):
- DEBUG ((DEBUG_INFO, " OneOfOption - 0x%04x\n", OneValue));
- break;
- case sizeof (UINT32):
- DEBUG ((DEBUG_INFO, " OneOfOption - 0x%08x\n", OneValue));
- break;
- case sizeof (UINT64):
- DEBUG ((DEBUG_INFO, " OneOfOption - 0x%016lx\n", OneValue));
- break;
- default:
- ASSERT (FALSE);
- break;
- }
- }
-
- if (HiiQuestion->BitFieldStore) {
- Ptr += sizeof (UINT32);
- } else {
- Ptr += HiiQuestion->StorageWidth;
- }
- }
-
- break;
-
- case EFI_IFR_CHECKBOX_OP:
- break;
-
- case EFI_IFR_NUMERIC_OP:
- Minimum = 0;
- Maximum = 0;
- Ptr = (UINT8 *)((VAR_CHECK_HII_QUESTION_NUMERIC *)HiiQuestion + 1);
- if (HiiQuestion->BitFieldStore) {
- //
- // For Numeric stored in bit field, the value of Maximum/Minimum are saved as UINT32 type.
- //
- CopyMem (&Minimum, Ptr, sizeof (UINT32));
- Ptr += sizeof (UINT32);
- CopyMem (&Maximum, Ptr, sizeof (UINT32));
- Ptr += sizeof (UINT32);
-
- DEBUG ((DEBUG_INFO, " Minimum - 0x%08x\n", Minimum));
- DEBUG ((DEBUG_INFO, " Maximum - 0x%08x\n", Maximum));
- } else {
- CopyMem (&Minimum, Ptr, HiiQuestion->StorageWidth);
- Ptr += HiiQuestion->StorageWidth;
- CopyMem (&Maximum, Ptr, HiiQuestion->StorageWidth);
- Ptr += HiiQuestion->StorageWidth;
-
- switch (HiiQuestion->StorageWidth) {
- case sizeof (UINT8):
- DEBUG ((DEBUG_INFO, " Minimum - 0x%02x\n", Minimum));
- DEBUG ((DEBUG_INFO, " Maximum - 0x%02x\n", Maximum));
- break;
- case sizeof (UINT16):
- DEBUG ((DEBUG_INFO, " Minimum - 0x%04x\n", Minimum));
- DEBUG ((DEBUG_INFO, " Maximum - 0x%04x\n", Maximum));
- break;
- case sizeof (UINT32):
- DEBUG ((DEBUG_INFO, " Minimum - 0x%08x\n", Minimum));
- DEBUG ((DEBUG_INFO, " Maximum - 0x%08x\n", Maximum));
- break;
- case sizeof (UINT64):
- DEBUG ((DEBUG_INFO, " Minimum - 0x%016lx\n", Minimum));
- DEBUG ((DEBUG_INFO, " Maximum - 0x%016lx\n", Maximum));
- break;
- default:
- ASSERT (FALSE);
- break;
- }
- }
-
- break;
-
- case EFI_IFR_ORDERED_LIST_OP:
- DEBUG ((DEBUG_INFO, " MaxContainers - 0x%02x\n", ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *)HiiQuestion)->MaxContainers));
- Ptr = (UINT8 *)((VAR_CHECK_HII_QUESTION_ORDEREDLIST *)HiiQuestion + 1);
- while ((UINTN)Ptr < ((UINTN)HiiQuestion + HiiQuestion->Length)) {
- OneValue = 0;
- CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth);
- switch (HiiQuestion->StorageWidth) {
- case sizeof (UINT8):
- DEBUG ((DEBUG_INFO, " OneOfOption - 0x%02x\n", OneValue));
- break;
- case sizeof (UINT16):
- DEBUG ((DEBUG_INFO, " OneOfOption - 0x%04x\n", OneValue));
- break;
- case sizeof (UINT32):
- DEBUG ((DEBUG_INFO, " OneOfOption - 0x%08x\n", OneValue));
- break;
- case sizeof (UINT64):
- DEBUG ((DEBUG_INFO, " OneOfOption - 0x%016lx\n", OneValue));
- break;
- default:
- ASSERT (FALSE);
- break;
- }
-
- Ptr += HiiQuestion->StorageWidth;
- }
-
- break;
-
- default:
- ASSERT (FALSE);
- break;
- }
-}
-
-/**
- Dump Hii Variable.
-
- @param[in] HiiVariable Pointer to Hii Variable.
-
-**/
-VOID
-DumpHiiVariable (
- IN VAR_CHECK_HII_VARIABLE_HEADER *HiiVariable
- )
-{
- VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion;
-
- DEBUG ((DEBUG_INFO, "VAR_CHECK_HII_VARIABLE_HEADER\n"));
- DEBUG ((DEBUG_INFO, " Revision - 0x%04x\n", HiiVariable->Revision));
- DEBUG ((DEBUG_INFO, " HeaderLength - 0x%04x\n", HiiVariable->HeaderLength));
- DEBUG ((DEBUG_INFO, " Length - 0x%08x\n", HiiVariable->Length));
- DEBUG ((DEBUG_INFO, " OpCode - 0x%02x (%a)\n", HiiVariable->OpCode, HiiOpCodeToStr (HiiVariable->OpCode)));
- DEBUG ((DEBUG_INFO, " Size - 0x%04x\n", HiiVariable->Size));
- DEBUG ((DEBUG_INFO, " Attributes - 0x%08x\n", HiiVariable->Attributes));
- DEBUG ((DEBUG_INFO, " Guid - %g\n", &HiiVariable->Guid));
- DEBUG ((DEBUG_INFO, " Name - %s\n", HiiVariable + 1));
-
- //
- // For Hii Question header align.
- //
- HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *)HEADER_ALIGN (((UINTN)HiiVariable + HiiVariable->HeaderLength));
- while ((UINTN)HiiQuestion < ((UINTN)HiiVariable + HiiVariable->Length)) {
- //
- // Dump Hii Question related to the Hii Variable.
- //
- DumpHiiQuestion (HiiQuestion);
- //
- // For Hii Question header align.
- //
- HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *)HEADER_ALIGN (((UINTN)HiiQuestion + HiiQuestion->Length));
- }
-}
-
-/**
- Dump Var Check HII.
-
- @param[in] VarCheckHiiBin Pointer to VarCheckHiiBin.
- @param[in] VarCheckHiiBinSize VarCheckHiiBin size.
-
-**/
-VOID
-DumpVarCheckHii (
- IN VOID *VarCheckHiiBin,
- IN UINTN VarCheckHiiBinSize
- )
-{
- VAR_CHECK_HII_VARIABLE_HEADER *HiiVariable;
-
- DEBUG ((DEBUG_INFO, "DumpVarCheckHii\n"));
-
- //
- // For Hii Variable header align.
- //
- HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *)HEADER_ALIGN (VarCheckHiiBin);
- while ((UINTN)HiiVariable < ((UINTN)VarCheckHiiBin + VarCheckHiiBinSize)) {
- DumpHiiVariable (HiiVariable);
- //
- // For Hii Variable header align.
- //
- HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *)HEADER_ALIGN (((UINTN)HiiVariable + HiiVariable->Length));
- }
-}
-
-#endif
-
-/**
- Constructor function of VarCheckHiiLib to register var check HII handler.
-
- @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 executed correctly.
-
-**/
-EFI_STATUS
-EFIAPI
-VarCheckHiiLibNullClassConstructor (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- VarCheckLibRegisterEndOfDxeCallback (VarCheckHiiGen);
- VarCheckLibRegisterAddressPointer ((VOID **)&mVarCheckHiiBin);
- VarCheckLibRegisterSetVariableCheckHandler (SetVariableCheckHandlerHii);
-
- return EFI_SUCCESS;
-}
diff --git a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibStandaloneMm.c b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibStandaloneMm.c
new file mode 100644
index 0000000..c1ee55b
--- /dev/null
+++ b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibStandaloneMm.c
@@ -0,0 +1,152 @@
+/** @file
+
+ Implementation functions and structures for var check services.
+ This file provides functions and structures to register and handle variable checks
+ in the Standalone MM environment, specifically for HII variables.
+
+Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/MmServicesTableLib.h>
+#include <Protocol/MmCommunication.h>
+#include <Library/VarCheckLib.h>
+
+#include "VarCheckHii.h"
+#include "VarCheckHiiLibCommon.h"
+
+//
+// In the standalone setup, mVarCheckHiiBin is used for sending, while mVarCheckHiiBinMmReceived is used for receiving,
+// while in the traditional setup, mVarCheckHiiBin is used for both sending and receiving.
+//
+VAR_CHECK_HII_VARIABLE_HEADER *mMmReceivedVarCheckHiiBin = NULL;
+UINTN mMmReceivedVarCheckHiiBinSize = 0;
+EFI_GUID gVarCheckReceivedHiiBinHandlerGuid = VAR_CHECK_RECEIVED_HII_BIN_HANDLER_GUID;
+
+/**
+ Registers a handler for HII variable checks in MM environment.
+ This function is intended to be called to register a handler for checking variables
+ in the Standalone MM environment. It allocates memory for the variable
+ check data and copies the data from the communication buffer.
+
+ @param[in] DispatchHandle The handle of the dispatch function.
+ @param[in] Context Optional context for the handler, not used in this implementation.
+ @param CommBuffer The buffer of data being passed in.
+ @param CommBufferSize The size of the data being passed in.
+ @retval EFI_SUCCESS Registration and memory allocation were successful.
+ @retval EFI_INVALID_PARAMETER The CommBuffer or CommBufferSize is NULL.
+ @retval EFI_ACCESS_DENIED The buffer size is invalid or the buffer is in an invalid location.
+ @retval EFI_OUT_OF_RESOURCES Memory allocation for the variable check data failed.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckHiiLibReceiveHiiBinHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context OPTIONAL,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // If input is invalid, stop processing this SMI
+ //
+ if ((CommBuffer == NULL) || (CommBufferSize == NULL)) {
+ return EFI_SUCCESS;
+ }
+
+ mMmReceivedVarCheckHiiBinSize = *CommBufferSize;
+
+ if (mMmReceivedVarCheckHiiBinSize < sizeof (VAR_CHECK_HII_VARIABLE_HEADER)) {
+ DEBUG ((DEBUG_ERROR, "%a: MM Communication buffer size is invalid for this handler!\n", __func__));
+ return EFI_ACCESS_DENIED;
+ }
+
+ mMmReceivedVarCheckHiiBin = AllocateZeroPool (mMmReceivedVarCheckHiiBinSize);
+ if (mMmReceivedVarCheckHiiBin == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to allocate memory for mVarCheckHiiBinMm\n", __func__));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (mMmReceivedVarCheckHiiBin, CommBuffer, mMmReceivedVarCheckHiiBinSize);
+ if (DispatchHandle != NULL) {
+ Status = gMmst->MmiHandlerUnRegister (DispatchHandle);
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to unregister handler - %r!\n", __func__, Status));
+ } else {
+ DEBUG ((DEBUG_INFO, "%a: Handler unregistered successfully.\n", __func__));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Sets the variable check handler for HII.
+ This function registers a handler that will be invoked for variable checks
+ in the HII environment. It allows for custom validation logic to be implemented
+ for setting HII variables.
+ @param[in] VariableName Name of Variable to set.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Attributes Attribute value of the variable.
+ @param[in] DataSize Size of Data to set.
+ @param[in] Data Data pointer.
+
+**/
+EFI_STATUS
+EFIAPI
+SetVariableCheckHandlerHii (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ return CheckHiiVariableCommon (mMmReceivedVarCheckHiiBin, mMmReceivedVarCheckHiiBinSize, VariableName, VendorGuid, Attributes, DataSize, Data);
+}
+
+/**
+ Constructor function for variable check library in Standalone MM.
+ This function registers a handler for variable checks and sets up the environment
+ for variable checking in the Standalone MM environment.
+ @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 executed successfully.
+ @retval Others An error occurred during execution.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckHiiLibConstructorStandaloneMm (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_MM_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE DispatchHandle;
+
+ DEBUG ((DEBUG_INFO, "%a: starts.\n", __func__));
+ //
+ // Register a handler to recieve the HII variable checking data.
+ //
+ Status = gMmst->MmiHandlerRegister (VarCheckHiiLibReceiveHiiBinHandler, &gVarCheckReceivedHiiBinHandlerGuid, &DispatchHandle);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to register handler - %r!\n", __func__, Status));
+
+ return Status;
+ }
+
+ VarCheckLibRegisterAddressPointer ((VOID **)&mMmReceivedVarCheckHiiBin);
+ VarCheckLibRegisterSetVariableCheckHandler (SetVariableCheckHandlerHii);
+ DEBUG ((DEBUG_INFO, "%a: ends.\n", __func__));
+ return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibStandaloneMm.inf b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibStandaloneMm.inf
new file mode 100644
index 0000000..dcef802
--- /dev/null
+++ b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibStandaloneMm.inf
@@ -0,0 +1,47 @@
+## @file
+# Implementation functions and structures for var check services.
+#
+# Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010017
+ BASE_NAME = VarCheckHiiLib
+ MODULE_UNI_FILE = VarCheckHiiLibStandaloneMm.uni
+ FILE_GUID = 8545E553-AF7D-4FA0-B402-9B5A67ABC812
+ MODULE_TYPE = MM_STANDALONE
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x00010032
+ LIBRARY_CLASS = VarCheckHiiLib|MM_STANDALONE
+ CONSTRUCTOR = VarCheckHiiLibConstructorStandaloneMm
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ VarCheckHiiLibStandaloneMm.c
+ VarCheckHii.h
+ InternalVarCheckStructure.h
+ VarCheckHiiLibCommon.c
+ VarCheckHiiLibCommon.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ StandaloneMmPkg/StandaloneMmPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ VarCheckLib
+
+[Protocols]
+ gEfiMmEndOfDxeProtocolGuid
diff --git a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibStandaloneMm.uni b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibStandaloneMm.uni
new file mode 100644
index 0000000..a84a1cc
--- /dev/null
+++ b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibStandaloneMm.uni
@@ -0,0 +1,15 @@
+// /** @file
+// Provides variable check services and database management.
+//
+// Provides variable check services and database management.
+//
+// Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides StandaloneMm variable check services and database management"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides StandaloneMm variable check services and database management."
diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c
index 7686628..053b48d 100644
--- a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c
+++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c
@@ -178,7 +178,7 @@ IsValidVariablePolicyStructure (
WildcardCount = 0;
while (*CheckChar != CHAR_NULL) {
// Make sure there aren't excessive wildcards.
- if (*CheckChar == '#') {
+ if (*CheckChar == L'#') {
WildcardCount++;
if (WildcardCount > MATCH_PRIORITY_MIN) {
return FALSE;
@@ -263,7 +263,7 @@ EvaluatePolicyMatch (
// Keep going until the end of both strings.
while (PolicyName[Index] != CHAR_NULL || VariableName[Index] != CHAR_NULL) {
// If we don't have a match...
- if ((PolicyName[Index] != VariableName[Index]) || (PolicyName[Index] == '#')) {
+ if ((PolicyName[Index] != VariableName[Index]) || (PolicyName[Index] == L'#')) {
// If this is a numerical wildcard, we can consider
// it a match if we alter the priority.
if ((PolicyName[Index] == L'#') &&
diff --git a/MdeModulePkg/MdeModulePkg.ci.yaml b/MdeModulePkg/MdeModulePkg.ci.yaml
index a3de60a..34d8b7e 100644
--- a/MdeModulePkg/MdeModulePkg.ci.yaml
+++ b/MdeModulePkg/MdeModulePkg.ci.yaml
@@ -23,6 +23,7 @@
"8005", "UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGE.UID",
"8005", "UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGE.HID",
"8001", "UefiSortLibUnitTestMain",
+ "8001", "MediaSanitizeUnitTestMain",
],
## Both file path and directory path are accepted.
"IgnoreFiles": [
diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index e6e0139..1324b6d 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -413,6 +413,13 @@
## Include/Guid/EndofS3Resume.h
gEdkiiEndOfS3ResumeGuid = { 0x96f5296d, 0x05f7, 0x4f3c, {0x84, 0x67, 0xe4, 0x56, 0x89, 0x0e, 0x0c, 0xb5 } }
+ #
+ # Guids for NVMe Timeout Events
+ # {4754469d-6528-4dfc-84aa-8c8a03a2158b}
+ gNVMeEnableStartEventGroupGuid = { 0x4754469d, 0x6528, 0x4dfc, { 0x84, 0xaa, 0x8c, 0x8a, 0x03, 0xa2, 0x15, 0x8b } }
+ # {da383315-906b-486f-80db-847f268451e4}
+ gNVMeEnableCompleteEventGroupGuid = { 0xda383315, 0x906b, 0x486f, { 0x80, 0xdb, 0x84, 0x7f, 0x26, 0x84, 0x51, 0xe4 } }
+
## Used (similar to Variable Services) to communicate policies to the enforcement engine.
# {DA1B0D11-D1A7-46C4-9DC9-F3714875C6EB}
gVarCheckPolicyLibMmiHandlerGuid = { 0xda1b0d11, 0xd1a7, 0x46c4, { 0x9d, 0xc9, 0xf3, 0x71, 0x48, 0x75, 0xc6, 0xeb }}
@@ -475,6 +482,12 @@
## Include/Guid/VariableRuntimeCacheInfo.h
gEdkiiVariableRuntimeCacheInfoHobGuid = { 0x0f472f7d, 0x6713, 0x4915, { 0x96, 0x14, 0x5d, 0xda, 0x28, 0x40, 0x10, 0x56 }}
+ ## HOB GUID to get ACPI table after FSP is done. The ACPI table that related SOC will be pass by this HOB.
+ gAcpiTableHobGuid = { 0xf9886b57, 0x8a35, 0x455e, { 0xbb, 0xb1, 0x14, 0x65, 0x5e, 0x7b, 0xe7, 0xec }}
+
+ ## Include/Guid/MmCommBuffer.h
+ gMmCommBufferHobGuid = { 0x6c2a2520, 0x0131, 0x4aee, { 0xa7, 0x50, 0xcc, 0x38, 0x4a, 0xac, 0xe8, 0xc6 }}
+
[Ppis]
## Include/Ppi/FirmwareVolumeShadowPpi.h
gEdkiiPeiFirmwareVolumeShadowPpiGuid = { 0x7dfe756c, 0xed8d, 0x4d77, {0x9e, 0xc4, 0x39, 0x9a, 0x8a, 0x81, 0x51, 0x16 } }
@@ -576,6 +589,10 @@
gEfiPrint2ProtocolGuid = { 0xf05976ef, 0x83f1, 0x4f3d, { 0x86, 0x19, 0xf7, 0x59, 0x5d, 0x41, 0xe5, 0x38 } }
gEfiPrint2SProtocolGuid = { 0xcc252d2, 0xc106, 0x4661, { 0xb5, 0xbd, 0x31, 0x47, 0xa4, 0xf8, 0x1f, 0x92 } }
+ ## This protocol defines the Media Clear and Sanitize operations defined by NIST
+ # Include/Protocol/MediaSanitize.h
+ gMediaSanitizeProtocolGuid = { 0x0d799a99, 0x25af, 0x429e, {0x92, 0x72, 0xd0, 0xb2, 0x7d, 0x6d, 0x5f, 0x14 } }
+
## This protocol defines the generic memory test interfaces in Dxe phase.
# Include/Protocol/GenericMemoryTest.h
gEfiGenericMemTestProtocolGuid = { 0x309DE7F1, 0x7F5E, 0x4ACE, { 0xB4, 0x9C, 0x53, 0x1B, 0xE5, 0xAA, 0x95, 0xEF }}
@@ -1177,6 +1194,10 @@
# @Prompt Delay access XHCI register after it issues HCRST (us)
gEfiMdeModulePkgTokenSpaceGuid.PcdDelayXhciHCReset|2000|UINT16|0x30001060
+ ## Specifies the page count allocated for the MM communication buffer.
+ # @Prompt Defines the page allocation for the MM communication buffer; default is 128 pages (512KB).
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMmCommBufferPages|128|UINT32|0x30001061
+
[PcdsFixedAtBuild, PcdsPatchableInModule]
## Dynamic type PCD can be registered callback function for Pcd setting action.
# PcdMaxPeiPcdCallBackNumberPerPcdEntry indicates the maximum number of callback function
@@ -1694,6 +1715,11 @@
# @Prompt SPI NOR Flash Operation Delay in Microseconds (16 us)
gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashOperationDelayMicroseconds|0x00000010|UINT32|0x00000035
+ ## Indicate the default timeout value for UFS device initial completetion in microseconds.
+ #
+ # @Prompt UFS device initial completion timoeout (us), default value is 600ms.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUfsInitialCompletionTimeout|600000|UINT32|0x00000036
+
[PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
## This PCD defines the Console output row. The default value is 25 according to UEFI spec.
# This PCD could be set to 0 then console output would be at max column and max row.
diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc
index fe7ab97..8c864fe 100644
--- a/MdeModulePkg/MdeModulePkg.dsc
+++ b/MdeModulePkg/MdeModulePkg.dsc
@@ -2,7 +2,7 @@
# EFI/PI Reference Module Package for All Architectures
#
# (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
-# Copyright (c) 2007 - 2021, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2007 - 2024, Intel Corporation. All rights reserved.<BR>
# Copyright (c) Microsoft Corporation.
# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
#
@@ -178,6 +178,8 @@
MmServicesTableLib|MdePkg/Library/StandaloneMmServicesTableLib/StandaloneMmServicesTableLib.inf
LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxStandaloneMmLib.inf
MemLib|StandaloneMmPkg/Library/StandaloneMmMemLib/StandaloneMmMemLib.inf
+ VarCheckHiiLibMmDependency|MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibMmDependency.inf
+ VarCheckHiiLib|MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibStandaloneMm.inf
[LibraryClasses.ARM, LibraryClasses.AARCH64]
LockBoxLib|MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf
@@ -339,6 +341,8 @@
MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf
MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf
+ MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibMmDependency.inf
+ MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibStandaloneMm.inf
MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.inf
MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf
MdeModulePkg/Library/DxeFileExplorerProtocol/DxeFileExplorerProtocol.inf
diff --git a/MdeModulePkg/Test/MdeModulePkgHostTest.dsc b/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
index 198cdd8..5ee5053 100644
--- a/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
+++ b/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
@@ -60,6 +60,11 @@
PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
}
+ MdeModulePkg/Bus/Pci/NvmExpressDxe/UnitTest/MediaSanitizeUnitTestHost.inf {
+ <LibraryClasses>
+ NvmExpressDxe|MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf
+ }
+
#
# Build HOST_APPLICATION Libraries
#
diff --git a/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.h b/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.h
index 9cfef3d..3caa20d 100644
--- a/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.h
+++ b/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTable.h
@@ -127,6 +127,12 @@ typedef struct {
)
//
+// ACPI HOB produced by silicon initialization code will provide the RSDP structure.
+//
+typedef struct {
+ EFI_PHYSICAL_ADDRESS Rsdp;
+} ACPI_SILICON_HOB;
+//
// Protocol Constructor functions
//
diff --git a/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf b/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
index be498a5..8d147a3 100644
--- a/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
+++ b/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
@@ -57,6 +57,7 @@
gEfiAcpi10TableGuid ## PRODUCES ## SystemTable
gEfiAcpiTableGuid ## PRODUCES ## SystemTable
gUniversalPayloadAcpiTableGuid ## SOMETIMES_CONSUMES ## HOB
+ gAcpiTableHobGuid ## SOMETIMES_CONSUMES ## HOB
[FeaturePcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol ## CONSUMES
diff --git a/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c b/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c
index 45c0ae6..f2a7be5 100644
--- a/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c
+++ b/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c
@@ -1948,6 +1948,107 @@ InstallAcpiTableFromHob (
}
/**
+ This function is updating the instance with RSDP and RSDT, these are steps in the constructor that will be skipped if this HOB is available.
+
+ @param AcpiTableInstance Protocol instance private data.
+ @param GuidHob GUID HOB header.
+
+ @return EFI_SUCCESS The function completed successfully.
+ @return EFI_NOT_FOUND The function doesn't find the Rsdp from AcpiSiliconHob.
+ @return EFI_ABORTED The function could not complete successfully.
+
+**/
+EFI_STATUS
+InstallAcpiTableFromAcpiSiliconHob (
+ EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance,
+ EFI_HOB_GUID_TYPE *GuidHob
+ )
+{
+ ACPI_SILICON_HOB *AcpiSiliconHob;
+ EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *SiAcpiHobRsdp;
+ EFI_ACPI_DESCRIPTION_HEADER *SiCommonAcpiTable;
+ EFI_STATUS Status;
+ UINT8 *TempBuffer;
+ UINTN NumOfTblEntries;
+
+ DEBUG ((DEBUG_INFO, "InstallAcpiTableFromAcpiSiliconHob\n"));
+ //
+ // Initial variable.
+ //
+ SiAcpiHobRsdp = NULL;
+ SiCommonAcpiTable = NULL;
+ AcpiSiliconHob = GET_GUID_HOB_DATA (GuidHob);
+ Status = EFI_SUCCESS;
+ //
+ // Got RSDP table from ACPI Silicon Hob.
+ //
+ SiAcpiHobRsdp = (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)(UINTN)(AcpiSiliconHob->Rsdp);
+ if (SiAcpiHobRsdp == NULL) {
+ DEBUG ((DEBUG_ERROR, "InstallAcpiTableFromAcpiSiliconHob: Fail to locate RSDP Acpi table!!\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ DEBUG ((DEBUG_INFO, "Silicon ACPI RSDP address : 0x%lx\n", SiAcpiHobRsdp));
+ AcpiTableInstance->Rsdp3 = SiAcpiHobRsdp;
+
+ if (SiAcpiHobRsdp->RsdtAddress != 0x00000000) {
+ //
+ // Initial RSDT.
+ //
+ TempBuffer = (UINT8 *)(UINTN)(SiAcpiHobRsdp->RsdtAddress);
+ SiCommonAcpiTable = (EFI_ACPI_DESCRIPTION_HEADER *)TempBuffer;
+ AcpiTableInstance->Rsdt3 = SiCommonAcpiTable;
+
+ if (SiCommonAcpiTable->Length <= sizeof (EFI_ACPI_DESCRIPTION_HEADER)) {
+ DEBUG ((DEBUG_ERROR, "RSDT length is incorrect\n"));
+ return EFI_ABORTED;
+ }
+
+ //
+ // Calcaue 32bit Acpi table number.
+ //
+ NumOfTblEntries = (SiCommonAcpiTable->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof (UINT32);
+ AcpiTableInstance->NumberOfTableEntries1 = NumOfTblEntries;
+ DEBUG ((DEBUG_INFO, "32bit NumOfTblEntries : 0x%x\n", NumOfTblEntries));
+ //
+ // Enlarge the max table number from mEfiAcpiMaxNumTables to current ACPI tables + EFI_ACPI_MAX_NUM_TABLES
+ //
+ if (AcpiTableInstance->NumberOfTableEntries1 >= EFI_ACPI_MAX_NUM_TABLES) {
+ mEfiAcpiMaxNumTables = AcpiTableInstance->NumberOfTableEntries1 + EFI_ACPI_MAX_NUM_TABLES;
+ DEBUG ((DEBUG_ERROR, "mEfiAcpiMaxNumTables : 0x%x\n", mEfiAcpiMaxNumTables));
+ }
+ } else {
+ //
+ // Initial XSDT.
+ //
+ TempBuffer = (UINT8 *)(UINTN)(SiAcpiHobRsdp->XsdtAddress);
+ SiCommonAcpiTable = (EFI_ACPI_DESCRIPTION_HEADER *)TempBuffer;
+ AcpiTableInstance->Xsdt = SiCommonAcpiTable;
+
+ if (SiCommonAcpiTable->Length <= sizeof (EFI_ACPI_DESCRIPTION_HEADER)) {
+ DEBUG ((DEBUG_ERROR, "XSDT length is incorrect\n"));
+ return EFI_ABORTED;
+ }
+
+ //
+ // Calcaue 64bit Acpi table number.
+ //
+ NumOfTblEntries = (SiCommonAcpiTable->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof (UINT64);
+ AcpiTableInstance->NumberOfTableEntries3 = NumOfTblEntries;
+ DEBUG ((DEBUG_ERROR, "64bit NumOfTblEntries : 0x%x\n", NumOfTblEntries));
+ //
+ // Enlarge the max table number from mEfiAcpiMaxNumTables to current ACPI tables + EFI_ACPI_MAX_NUM_TABLES
+ //
+ if (AcpiTableInstance->NumberOfTableEntries3 >= EFI_ACPI_MAX_NUM_TABLES) {
+ mEfiAcpiMaxNumTables = AcpiTableInstance->NumberOfTableEntries3 + EFI_ACPI_MAX_NUM_TABLES;
+ DEBUG ((DEBUG_ERROR, "mEfiAcpiMaxNumTables : 0x%x\n", mEfiAcpiMaxNumTables));
+ }
+ }
+
+ return Status;
+}
+
+/**
Constructor for the ACPI table protocol. Initializes instance
data.
@@ -1969,6 +2070,7 @@ AcpiTableAcpiTableConstructor (
UINT8 *Pointer;
EFI_PHYSICAL_ADDRESS PageAddress;
EFI_MEMORY_TYPE AcpiAllocateMemoryType;
+ EFI_HOB_GUID_TYPE *GuidHob;
//
// Check for invalid input parameters
@@ -1996,6 +2098,23 @@ AcpiTableAcpiTableConstructor (
}
//
+ // Check Silicon ACPI Hob.
+ //
+ GuidHob = GetFirstGuidHob (&gAcpiTableHobGuid);
+ if (GuidHob != NULL) {
+ Status = InstallAcpiTableFromAcpiSiliconHob (AcpiTableInstance, GuidHob);
+ if (Status == EFI_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "Installed ACPI Table from AcpiSiliconHob.\n"));
+ return EFI_SUCCESS;
+ } else {
+ DEBUG ((DEBUG_ERROR, "Fail to Installed ACPI Table from AcpiSiliconHob!!\n"));
+ ASSERT (Status != EFI_SUCCESS);
+ }
+ } else {
+ DEBUG ((DEBUG_INFO, "Fail to locate AcpiSiliconHob!!\n"));
+ }
+
+ //
// Create RSDP table
//
RsdpTableSize = sizeof (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER);
diff --git a/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatform.c b/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatform.c
index 700ea9d..a7f0225 100644
--- a/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatform.c
+++ b/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatform.c
@@ -27,6 +27,15 @@ EFI_DRIVER_BINDING_PROTOCOL gConPlatformTextOutDriverBinding = {
NULL
};
+//
+// Values from Usb Inteface Association Descriptor Device
+// Class Code and Usage Model specification (iadclasscode_r10.pdf)
+// from Usb.org
+//
+#define USB_BASE_CLASS_MISCELLANEOUS 0xEF
+#define USB_MISCELLANEOUS_SUBCLASS_COMMON 0x02
+#define USB_MISCELLANEOUS_PROTOCOL_IAD 0x01
+
/**
Entrypoint of this module.
@@ -808,10 +817,16 @@ MatchUsbClass (
DeviceClass = DevDesc.DeviceClass;
DeviceSubClass = DevDesc.DeviceSubClass;
DeviceProtocol = DevDesc.DeviceProtocol;
- if (DeviceClass == 0) {
+
+ if ((DeviceClass == 0) ||
+ ((DeviceClass == USB_BASE_CLASS_MISCELLANEOUS) &&
+ (DeviceSubClass == USB_MISCELLANEOUS_SUBCLASS_COMMON) &&
+ (DeviceProtocol == USB_MISCELLANEOUS_PROTOCOL_IAD)))
+ {
//
- // If Class in Device Descriptor is set to 0, use the Class, SubClass and
- // Protocol in Interface Descriptor instead.
+ // If Class in Device Descriptor is set to 0 (Device), or
+ // Class/SubClass/Protocol is 0xEF/0x02/0x01 (IAD), use the Class, SubClass
+ // and Protocol in Interface Descriptor instead.
//
Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
if (EFI_ERROR (Status)) {
diff --git a/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c b/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c
index 38af39f..54b634a 100644
--- a/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c
+++ b/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c
@@ -846,7 +846,8 @@ DiskIo2ReadWriteDisk (
LIST_ENTRY Subtasks;
DISK_IO_SUBTASK *Subtask;
DISK_IO2_TASK *Task;
- EFI_TPL OldTpl;
+ EFI_TPL SubtaskPerformTpl;
+ EFI_TPL SubtaskLockTpl;
BOOLEAN Blocking;
BOOLEAN SubtaskBlocking;
LIST_ENTRY *SubtasksPtr;
@@ -896,7 +897,7 @@ DiskIo2ReadWriteDisk (
ASSERT (!IsListEmpty (SubtasksPtr));
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ SubtaskPerformTpl = gBS->RaiseTPL (TPL_CALLBACK);
for ( Link = GetFirstNode (SubtasksPtr), NextLink = GetNextNode (SubtasksPtr, Link)
; !IsNull (SubtasksPtr, Link)
; Link = NextLink, NextLink = GetNextNode (SubtasksPtr, NextLink)
@@ -977,7 +978,7 @@ DiskIo2ReadWriteDisk (
}
}
- gBS->RaiseTPL (TPL_NOTIFY);
+ SubtaskLockTpl = gBS->RaiseTPL (TPL_NOTIFY);
//
// Remove all the remaining subtasks when failure.
@@ -1012,7 +1013,8 @@ DiskIo2ReadWriteDisk (
FreePool (Task);
}
- gBS->RestoreTPL (OldTpl);
+ gBS->RestoreTPL (SubtaskLockTpl);
+ gBS->RestoreTPL (SubtaskPerformTpl);
return Status;
}
diff --git a/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.c b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.c
index 60cf3c8..2dac121 100644
--- a/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.c
+++ b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.c
@@ -404,7 +404,8 @@ HiiCreateRamDisk (
);
} while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
- return EFI_DEVICE_ERROR;
+ Status = EFI_DEVICE_ERROR;
+ goto ErrorExit;
}
}
@@ -431,7 +432,7 @@ HiiCreateRamDisk (
);
} while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
- return Status;
+ goto ErrorExit;
}
//
@@ -442,6 +443,10 @@ HiiCreateRamDisk (
PrivateData->CreateMethod = RamDiskCreateHii;
return EFI_SUCCESS;
+
+ErrorExit:
+ gBS->FreePool (StartingAddr);
+ return Status;
}
/**
diff --git a/MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c b/MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c
index 508184f..d442ccb 100644
--- a/MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c
+++ b/MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c
@@ -810,12 +810,18 @@ FtwGetLastWriteHeader (
FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *)(FtwWorkSpaceHeader + 1);
Offset = sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER);
+ if (!CompareGuid (&FtwWorkSpaceHeader->Signature, &gEdkiiWorkingBlockSignatureGuid)) {
+ *FtwWriteHeader = FtwHeader;
+ return EFI_ABORTED;
+ }
+
while (FtwHeader->Complete == FTW_VALID_STATE) {
Offset += FTW_WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);
//
// If Offset exceed the FTW work space boudary, return error.
//
- if (Offset >= FtwWorkSpaceSize) {
+
+ if ((Offset + sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER)) >= FtwWorkSpaceSize) {
*FtwWriteHeader = FtwHeader;
return EFI_ABORTED;
}
diff --git a/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferDxe.c b/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferDxe.c
index 663cfff..a47311c 100644
--- a/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferDxe.c
+++ b/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferDxe.c
@@ -19,7 +19,9 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
#include <Library/UefiLib.h>
+#include <Guid/MmCommBuffer.h>
#include <Guid/PiSmmCommunicationRegionTable.h>
#define DEFAULT_COMMON_PI_SMM_COMMUNIATION_REGION_PAGES 4
@@ -44,8 +46,11 @@ SmmCommunicationBufferEntryPoint (
UINT32 DescriptorSize;
EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *PiSmmCommunicationRegionTable;
EFI_MEMORY_DESCRIPTOR *Entry;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ MM_COMM_BUFFER *MmCommBuffer;
DescriptorSize = sizeof (EFI_MEMORY_DESCRIPTOR);
+
//
// Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
// prevent people from having pointer math bugs in their code.
@@ -65,11 +70,21 @@ SmmCommunicationBufferEntryPoint (
PiSmmCommunicationRegionTable->DescriptorSize = DescriptorSize;
Entry = (EFI_MEMORY_DESCRIPTOR *)(PiSmmCommunicationRegionTable + 1);
Entry->Type = EfiConventionalMemory;
- Entry->PhysicalStart = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateReservedPages (DEFAULT_COMMON_PI_SMM_COMMUNIATION_REGION_PAGES);
+
+ GuidHob = GetFirstGuidHob (&gMmCommBufferHobGuid);
+
+ if (GuidHob == NULL) {
+ Entry->PhysicalStart = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateReservedPages (DEFAULT_COMMON_PI_SMM_COMMUNIATION_REGION_PAGES);
+ Entry->NumberOfPages = DEFAULT_COMMON_PI_SMM_COMMUNIATION_REGION_PAGES;
+ } else {
+ MmCommBuffer = GET_GUID_HOB_DATA (GuidHob);
+ Entry->PhysicalStart = MmCommBuffer->PhysicalStart;
+ Entry->NumberOfPages = MmCommBuffer->NumberOfPages;
+ }
+
ASSERT (Entry->PhysicalStart != 0);
- Entry->VirtualStart = 0;
- Entry->NumberOfPages = DEFAULT_COMMON_PI_SMM_COMMUNIATION_REGION_PAGES;
- Entry->Attribute = 0;
+ Entry->VirtualStart = 0;
+ Entry->Attribute = 0;
DEBUG ((DEBUG_INFO, "PiSmmCommunicationRegionTable:(0x%x)\n", PiSmmCommunicationRegionTable));
DEBUG ((DEBUG_INFO, " Version - 0x%x\n", PiSmmCommunicationRegionTable->Version));
diff --git a/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferDxe.inf b/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferDxe.inf
index 5c867ba..1c9bbdc 100644
--- a/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferDxe.inf
+++ b/MdeModulePkg/Universal/SmmCommunicationBufferDxe/SmmCommunicationBufferDxe.inf
@@ -47,6 +47,7 @@
[Guids]
gEdkiiPiSmmCommunicationRegionTableGuid ## PRODUCES ## SystemTable
+ gMmCommBufferHobGuid ## CONSUMES
[Depex]
TRUE
diff --git a/MdeModulePkg/Universal/Variable/Pei/Variable.c b/MdeModulePkg/Universal/Variable/Pei/Variable.c
index 26f95c6..9f3d434 100644
--- a/MdeModulePkg/Universal/Variable/Pei/Variable.c
+++ b/MdeModulePkg/Universal/Variable/Pei/Variable.c
@@ -1336,6 +1336,7 @@ CalculateHobVariableCacheSize (
VARIABLE_STORE_HEADER *VariableStoreHeader;
VariableStoreHeader = NULL;
+ ZeroMem (&StoreInfo, sizeof (VARIABLE_STORE_INFO));
GetHobVariableStore (&StoreInfo, &VariableStoreHeader);
if (VariableStoreHeader == NULL) {
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/PrivilegePolymorphic.h b/MdeModulePkg/Universal/Variable/RuntimeDxe/PrivilegePolymorphic.h
index e7bd4c9..969a4f7 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/PrivilegePolymorphic.h
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/PrivilegePolymorphic.h
@@ -156,17 +156,13 @@ VariableSmmIsNonPrimaryBufferValid (
);
/**
- Whether the TCG or TCG2 protocols are installed in the UEFI protocol database.
- This information is used by the MorLock code to infer whether an existing
- MOR variable is legitimate or not.
-
- @retval TRUE Either the TCG or TCG2 protocol is installed in the UEFI
- protocol database
- @retval FALSE Neither the TCG nor the TCG2 protocol is installed in the UEFI
- protocol database
+ Whether the MOR variable is legitimate or not.
+
+ @retval TRUE MOR Variable is legitimate.
+ @retval FALSE MOR Variable in not legitimate.
**/
BOOLEAN
-VariableHaveTcgProtocols (
+VariableIsMorVariableLegitimate (
VOID
);
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockSmm.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockSmm.c
index 28e8cc5..7f8b2a7 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockSmm.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockSmm.c
@@ -475,7 +475,7 @@ MorLockInitAtEndOfDxe (
// can be deduced from the absence of the TCG / TCG2 protocols, as edk2's
// MOR implementation depends on (one of) those protocols.
//
- if (VariableHaveTcgProtocols ()) {
+ if (VariableIsMorVariableLegitimate ()) {
//
// The MOR variable originates from the platform firmware; set the MOR
// Control Lock variable to report the locking capability to the OS.
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.c
index 1b9cf6d..1057822 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.c
@@ -7,6 +7,8 @@ Copyright (c) 2018, Linaro, Ltd. All rights reserved. <BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
+
+#include <Library/MmServicesTableLib.h>
#include <Library/StandaloneMmMemLib.h>
#include "Variable.h"
@@ -67,6 +69,17 @@ VariableNotifySmmWriteReady (
VOID
)
{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ Handle = NULL;
+ Status = gMmst->MmInstallProtocolInterface (
+ &Handle,
+ &gSmmVariableWriteGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
}
/**
@@ -89,19 +102,15 @@ VariableServiceInitialize (
}
/**
- Whether the TCG or TCG2 protocols are installed in the UEFI protocol database.
- This information is used by the MorLock code to infer whether an existing
- MOR variable is legitimate or not.
-
- @retval TRUE Either the TCG or TCG2 protocol is installed in the UEFI
- protocol database
- @retval FALSE Neither the TCG nor the TCG2 protocol is installed in the UEFI
- protocol database
+ Whether the MOR variable is legitimate or not.
+
+ @retval TRUE MOR Variable is legitimate.
+ @retval FALSE MOR Variable in not legitimate.
**/
BOOLEAN
-VariableHaveTcgProtocols (
+VariableIsMorVariableLegitimate (
VOID
)
{
- return FALSE;
+ return TRUE;
}
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
index c418571..2d651c3 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
@@ -115,6 +115,7 @@
gEfiMemoryOverwriteControlDataGuid ## SOMETIMES_CONSUMES ## Variable:L"MemoryOverwriteRequestControl"
gEfiMemoryOverwriteRequestControlLockGuid ## SOMETIMES_PRODUCES ## Variable:L"MemoryOverwriteRequestControlLock"
+ gSmmVariableWriteGuid ## PRODUCES ## GUID # Install protocol
gEfiSystemNvDataFvGuid ## CONSUMES ## GUID
gEdkiiFaultTolerantWriteGuid ## SOMETIMES_CONSUMES ## HOB
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableTraditionalMm.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableTraditionalMm.c
index 7247f75..cd82bb5 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableTraditionalMm.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableTraditionalMm.c
@@ -118,12 +118,12 @@ VariableServiceInitialize (
MOR variable is legitimate or not.
@retval TRUE Either the TCG or TCG2 protocol is installed in the UEFI
- protocol database
+ protocol database. MOR variable is legitimate.
@retval FALSE Neither the TCG nor the TCG2 protocol is installed in the UEFI
- protocol database
+ protocol database. MOR variable is not legitimate.
**/
BOOLEAN
-VariableHaveTcgProtocols (
+VariableIsMorVariableLegitimate (
VOID
)
{