summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRay Robles <rayrobles@microsoft.com>2024-07-18 10:26:05 -0700
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2024-08-29 18:51:07 +0000
commitb6c4708c4d3470cfd9f465771a665510d3ad1a66 (patch)
treed2e34bd5478065d1635b349b520ee37e17f769cc
parent7801fe428b0b43099966b68f2441329f4dfc0234 (diff)
downloadedk2-b6c4708c4d3470cfd9f465771a665510d3ad1a66.tar.gz
edk2-b6c4708c4d3470cfd9f465771a665510d3ad1a66.tar.bz2
edk2-b6c4708c4d3470cfd9f465771a665510d3ad1a66.zip
MdeModulePkg/Bus/Pci/NvmExpressDxe: Nvm Express Media Sanitize Protocol.
Implementation of MEDIA_SANITIZE_PROTOCOL for NIST purge/clear actions with mapping to NVM Express native commands. Signed-off-by: Aaron Pop <aaronpop@microsoft.com>
-rw-r--r--MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c27
-rw-r--r--MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.h36
-rw-r--r--MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf5
-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/UnitTest/MediaSanitizeUnitTest.c1128
-rw-r--r--MdeModulePkg/Bus/Pci/NvmExpressDxe/UnitTest/MediaSanitizeUnitTestHost.inf37
-rw-r--r--MdeModulePkg/Include/Protocol/MediaSanitize.h173
-rw-r--r--MdeModulePkg/MdeModulePkg.ci.yaml1
-rw-r--r--MdeModulePkg/MdeModulePkg.dec4
-rw-r--r--MdeModulePkg/Test/MdeModulePkgHostTest.dsc5
11 files changed, 2188 insertions, 1 deletions
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c
index 069da12a9b..c8d8be32b0 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 2b9ab8a08e..11207afa63 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>
@@ -49,6 +51,7 @@ 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;
@@ -77,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
//
@@ -202,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;
@@ -243,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 1a29c0b907..5fd0e468a9 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,6 +40,8 @@
NvmExpressHci.c
NvmExpressHci.h
NvmExpressPassthru.c
+ NvmExpressMediaSanitize.c
+ NvmExpressMediaSanitize.h
[Guids]
gNVMeEnableStartEventGroupGuid
@@ -72,6 +74,7 @@
gEfiDiskInfoProtocolGuid ## BY_START
gEfiStorageSecurityCommandProtocolGuid ## BY_START
gEfiDriverSupportedEfiVersionProtocolGuid ## PRODUCES
+ gMediaSanitizeProtocolGuid ## PRODUCES
gEfiResetNotificationProtocolGuid ## CONSUMES
# [Event]
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressMediaSanitize.c b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressMediaSanitize.c
new file mode 100644
index 0000000000..8632924899
--- /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 0000000000..197b923977
--- /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/UnitTest/MediaSanitizeUnitTest.c b/MdeModulePkg/Bus/Pci/NvmExpressDxe/UnitTest/MediaSanitizeUnitTest.c
new file mode 100644
index 0000000000..b8728580c5
--- /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 0000000000..feeeea340f
--- /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/Include/Protocol/MediaSanitize.h b/MdeModulePkg/Include/Protocol/MediaSanitize.h
new file mode 100644
index 0000000000..029b13561f
--- /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/MdeModulePkg.ci.yaml b/MdeModulePkg/MdeModulePkg.ci.yaml
index a3de60a12c..34d8b7e409 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 a25f380d02..1324b6d100 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -589,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 }}
diff --git a/MdeModulePkg/Test/MdeModulePkgHostTest.dsc b/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
index 198cdd814f..5ee505349f 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
#