public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH v3 00/12] Split the S3 PEI phase HW init codes from Opal driver
@ 2019-02-01  5:47 Hao Wu
  2019-02-01  5:47 ` [PATCH v3 01/12] MdeModulePkg: Add definitions for ATA AHCI host controller PPI Hao Wu
                   ` (11 more replies)
  0 siblings, 12 replies; 19+ messages in thread
From: Hao Wu @ 2019-02-01  5:47 UTC (permalink / raw)
  To: edk2-devel
  Cc: Hao Wu, Jian J Wang, Ray Ni, Eric Dong, Star Zeng, Chao Zhang,
	Jiewen Yao

The series is also available at:
https://github.com/hwu25/edk2/tree/opal_remodel_v3

V3 changes:

For patch 2, reuse the definitions within AtaPassThru protocol header file
to reduce code duplication.

For patch 4, add detailed comments to illustrate the content that will be
stored in the newly introduced LockBox.

For patch 6, device path validity check refinement within function
NvmeCheckHcDevicePath().

For patch 7:
* Remove a redundant check within function NvmeS3SkipThisController();
* Replace internal implementation of GetNextDevicePathInstance() with
  GetDevicePathInstanceSize(), which avoids unnecessary memory allocation.

For patch 8:
* Device path validity check refinement within function
  AhciCheckHcDevicePath();
* Remove a redundant check within function AhciS3GetEumeratePorts();
* Replace internal implementation of GetNextDevicePathInstance() with
  GetDevicePathInstanceSize(), which avoids unnecessary memory allocation.

For patch 11:
* Remove the ASSERT() for memory allocation failure. Since error handling
  codes already exist, no new code is added for this;
* Refine the codes to only allocate new SMM buffer when the required
  LockBox size is greater than the size of origin pages allocated;
* Add additional parameter check for 'Offset' & 'Length' to prevent
  potential numeric overflow.


V2 history:

For patch 8, the new series removes the codes to produce the Block IO PPIs
from the AhciPei driver.

The task to produce the Block IO services is out of the scope of BZ-1409
(actually covered by BZ-1483). And we will later propose seperate patch(s)
to address this.

V1 history:

For the below 2 types of storage device:

1. NVM Express devices;
2. ATA hard disk devices working under AHCI mode.

the OpalPassword driver supports auto-unlocking those devices during S3
resume.

Current implementation of the OpalPassword driver is handling the device
initialization (using boot script to restore the host controller PCI
configuration space also counts) in the PEI phase during S3 resume by
itself.

Meanwhile, the NvmExpressPei driver in MdeModulePkg also handles the NVME
device initialization during the PEI phase in order to produce the Block
IO PPI.

Moreover, there is a Bugzilla request (BZ-1483) for adding the Block IO
PPI support for ATA device as well. So there is likely to be an PEI driver
for ATA device that will handle the ATA device initialization.

In order to remove code duplication, the series will split the S3 phase
device initialization related codes out from the OpalPassword driver. And
let the existing NvmExpressPei driver and the new AhciPei driver to handle
the task.

After this remodel, NvmExpressPei and AhciPei drivers will produce a PPI
called Storage Security Command PPI. And the OpalPassword driver will
consume this PPI to perform the device auto-unlock in S3 resume.


Patch   1~4: Add the definitions of PPIs and GUIDs;
Patch     5: Refinement for the NvmExpressPei driver;
Patch   6~7: Update the NvmExpressPei driver to produce the PPI needed by
             OpalPassword;
Patch     8: Add the Ahci mode ATA device support in the PEI phase, it
             will produce the PPI needed by OpalPassword;
Patch  9~10: Refinements for the SmmLockBoxLib;
Patch    11: Support LockBox enlarge for LockBoxLib API UpdateLockBox();
Patch    12: Remove the hardware initialization codes from the
             OpalPassword driver. And consume the SSC PPI to unlock device
	     in S3 resume.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Cc: Chao Zhang <chao.b.zhang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>

Hao Wu (12):
  MdeModulePkg: Add definitions for ATA AHCI host controller PPI
  MdeModulePkg: Add definitions for EDKII PEI ATA PassThru PPI
  MdeModulePkg: Add definitions for Storage Security Command PPI
  MdeModulePkg: Add GUID for LockBox to save storage dev to init in S3
  MdeModulePkg/NvmExpressPei: Avoid updating the module-level variable
  MdeModulePkg/NvmExpressPei: Add logic to produce SSC PPI
  MdeModulePkg/NvmExpressPei: Consume S3StorageDeviceInitList LockBox
  MdeModulePkg/AhciPei: Add AHCI mode ATA device support in PEI
  MdeModulePkg/SmmLockBoxLib: Use 'DEBUG_' prefix instead of 'EFI_D_'
  MdeModulePkg/SmmLockBox(PEI): Remove an ASSERT in RestoreLockBox()
  MdeModulePkg/SmmLockBoxLib: Support LockBox enlarge in UpdateLockBox()
  SecurityPkg/OpalPassword: Remove HW init codes and consume SSC PPI

 MdeModulePkg/MdeModulePkg.dec                                     |   12 +
 MdeModulePkg/MdeModulePkg.dsc                                     |    1 +
 MdeModulePkg/Bus/Ata/AhciPei/AhciPei.inf                          |   74 +
 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf              |   18 +-
 SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordDxe.inf             |    6 +-
 SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.inf             |   12 +-
 MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h                            |  708 +++++++
 MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.h                    |  184 ++
 MdeModulePkg/Bus/Ata/AhciPei/AhciPeiStorageSecurity.h             |  247 +++
 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h                |  106 +-
 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.h             |   20 +-
 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiStorageSecurity.h |  247 +++
 MdeModulePkg/Include/Guid/S3StorageDeviceInitList.h               |   64 +
 MdeModulePkg/Include/Library/LockBoxLib.h                         |    7 +-
 MdeModulePkg/Include/Ppi/AtaAhciController.h                      |   89 +
 MdeModulePkg/Include/Ppi/AtaPassThru.h                            |  219 +++
 MdeModulePkg/Include/Ppi/StorageSecurityCommand.h                 |  283 +++
 SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.h                  |  412 ----
 SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.h                    |    4 +-
 SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.h                  |  327 ----
 SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeReg.h                   |  815 --------
 SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordCommon.h            |   45 +-
 SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.h               |  106 +-
 MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c                           | 2015 ++++++++++++++++++++
 MdeModulePkg/Bus/Ata/AhciPei/AhciPei.c                            |  304 +++
 MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.c                    |  521 +++++
 MdeModulePkg/Bus/Ata/AhciPei/AhciPeiS3.c                          |  139 ++
 MdeModulePkg/Bus/Ata/AhciPei/AhciPeiStorageSecurity.c             |  391 ++++
 MdeModulePkg/Bus/Ata/AhciPei/DevicePath.c                         |  284 +++
 MdeModulePkg/Bus/Ata/AhciPei/DmaMem.c                             |  270 +++
 MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c                   |  284 +++
 MdeModulePkg/Bus/Pci/NvmExpressPei/DmaMem.c                       |  153 +-
 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c                |  166 +-
 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.c             |   32 +-
 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiS3.c              |  114 ++
 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiStorageSecurity.c |  423 ++++
 MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c              |    7 +-
 MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c             |   27 +-
 MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c             |   32 +-
 MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c             |  148 +-
 SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.c                  | 1282 -------------
 SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c                    |  408 ++--
 SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.c                  | 1823 ------------------
 SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.c               |  757 ++------
 MdeModulePkg/Bus/Ata/AhciPei/AhciPei.uni                          |   21 +
 MdeModulePkg/Bus/Ata/AhciPei/AhciPeiExtra.uni                     |   19 +
 46 files changed, 7741 insertions(+), 5885 deletions(-)
 create mode 100644 MdeModulePkg/Bus/Ata/AhciPei/AhciPei.inf
 create mode 100644 MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h
 create mode 100644 MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.h
 create mode 100644 MdeModulePkg/Bus/Ata/AhciPei/AhciPeiStorageSecurity.h
 create mode 100644 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiStorageSecurity.h
 create mode 100644 MdeModulePkg/Include/Guid/S3StorageDeviceInitList.h
 create mode 100644 MdeModulePkg/Include/Ppi/AtaAhciController.h
 create mode 100644 MdeModulePkg/Include/Ppi/AtaPassThru.h
 create mode 100644 MdeModulePkg/Include/Ppi/StorageSecurityCommand.h
 delete mode 100644 SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.h
 delete mode 100644 SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.h
 delete mode 100644 SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeReg.h
 create mode 100644 MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c
 create mode 100644 MdeModulePkg/Bus/Ata/AhciPei/AhciPei.c
 create mode 100644 MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.c
 create mode 100644 MdeModulePkg/Bus/Ata/AhciPei/AhciPeiS3.c
 create mode 100644 MdeModulePkg/Bus/Ata/AhciPei/AhciPeiStorageSecurity.c
 create mode 100644 MdeModulePkg/Bus/Ata/AhciPei/DevicePath.c
 create mode 100644 MdeModulePkg/Bus/Ata/AhciPei/DmaMem.c
 create mode 100644 MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c
 create mode 100644 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiS3.c
 create mode 100644 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiStorageSecurity.c
 delete mode 100644 SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.c
 delete mode 100644 SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.c
 create mode 100644 MdeModulePkg/Bus/Ata/AhciPei/AhciPei.uni
 create mode 100644 MdeModulePkg/Bus/Ata/AhciPei/AhciPeiExtra.uni

-- 
2.12.0.windows.1



^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 01/12] MdeModulePkg: Add definitions for ATA AHCI host controller PPI
  2019-02-01  5:47 [PATCH v3 00/12] Split the S3 PEI phase HW init codes from Opal driver Hao Wu
@ 2019-02-01  5:47 ` Hao Wu
  2019-02-01  5:47 ` [PATCH v3 02/12] MdeModulePkg: Add definitions for EDKII PEI ATA PassThru PPI Hao Wu
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Hao Wu @ 2019-02-01  5:47 UTC (permalink / raw)
  To: edk2-devel; +Cc: Hao Wu, Jian J Wang, Eric Dong

REF:https://bugzilla.tianocore.org/show_bug.cgi?id=1409

This commit will add the definitions for ATA AHCI host controller PPI. The
purpose of the PPI in to provide:

* MMIO base address
* Controller identification information (DevicePath)

for ATA host controllers working under AHCI mode.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Hao Wu <hao.a.wu@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
---
 MdeModulePkg/MdeModulePkg.dec                |  3 +
 MdeModulePkg/Include/Ppi/AtaAhciController.h | 89 ++++++++++++++++++++
 2 files changed, 92 insertions(+)

diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index e5c32d15ed..4411185073 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -480,6 +480,9 @@
   ## Include/Ppi/NvmExpressHostController.h
   gEdkiiPeiNvmExpressHostControllerPpiGuid  = { 0xcae3aa63, 0x676f, 0x4da3, { 0xbd, 0x50, 0x6c, 0xc5, 0xed, 0xde, 0x9a, 0xad } }
 
+  ## Include/Ppi/AtaAhciController.h
+  gEdkiiPeiAtaAhciHostControllerPpiGuid     = { 0x61dd33ea, 0x421f, 0x4cc0, { 0x89, 0x29, 0xff, 0xee, 0xa9, 0xa1, 0xa2, 0x61 } }
+
 [Protocols]
   ## Load File protocol provides capability to load and unload EFI image into memory and execute it.
   #  Include/Protocol/LoadPe32Image.h
diff --git a/MdeModulePkg/Include/Ppi/AtaAhciController.h b/MdeModulePkg/Include/Ppi/AtaAhciController.h
new file mode 100644
index 0000000000..2bdd53ff36
--- /dev/null
+++ b/MdeModulePkg/Include/Ppi/AtaAhciController.h
@@ -0,0 +1,89 @@
+/** @file
+
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _EDKII_ATA_AHCI_HOST_CONTROLLER_PPI_H_
+#define _EDKII_ATA_AHCI_HOST_CONTROLLER_PPI_H_
+
+#include <Protocol/DevicePath.h>
+
+///
+/// Global ID for the EDKII_ATA_AHCI_HOST_CONTROLLER_PPI.
+///
+#define EDKII_ATA_AHCI_HOST_CONTROLLER_PPI_GUID \
+  { \
+    0x61dd33ea, 0x421f, 0x4cc0, { 0x89, 0x29, 0xff, 0xee, 0xa9, 0xa1, 0xa2, 0x61 } \
+  }
+
+//
+// Forward declaration for the EDKII_ATA_AHCI_HOST_CONTROLLER_PPI.
+//
+typedef struct _EDKII_ATA_AHCI_HOST_CONTROLLER_PPI  EDKII_ATA_AHCI_HOST_CONTROLLER_PPI;
+
+/**
+  Get the MMIO base address of ATA AHCI host controller.
+
+  @param[in]  This                 The PPI instance pointer.
+  @param[in]  ControllerId         The ID of the ATA AHCI host controller.
+  @param[out] MmioBar              The MMIO base address of the controller.
+
+  @retval EFI_SUCCESS              The operation succeeds.
+  @retval EFI_INVALID_PARAMETER    The parameters are invalid.
+  @retval EFI_NOT_FOUND            The specified ATA AHCI host controller not found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_ATA_AHCI_HC_GET_MMIO_BAR) (
+  IN  EDKII_ATA_AHCI_HOST_CONTROLLER_PPI    *This,
+  IN  UINT8                                 ControllerId,
+  OUT UINTN                                 *MmioBar
+  );
+
+/**
+  Get the device path of ATA AHCI host controller.
+
+  @param[in]  This                 The PPI instance pointer.
+  @param[in]  ControllerId         The ID of the ATA AHCI host controller.
+  @param[out] DevicePathLength     The length of the device path in bytes specified
+                                   by DevicePath.
+  @param[out] DevicePath           The device path of ATA AHCI host controller.
+                                   This field re-uses EFI Device Path Protocol as
+                                   defined by Section 10.2 EFI Device Path Protocol
+                                   of UEFI 2.7 Specification.
+
+  @retval EFI_SUCCESS              The operation succeeds.
+  @retval EFI_INVALID_PARAMETER    The parameters are invalid.
+  @retval EFI_NOT_FOUND            The specified ATA AHCI host controller not found.
+  @retval EFI_OUT_OF_RESOURCES     The operation fails due to lack of resources.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_ATA_AHCI_HC_GET_DEVICE_PATH) (
+  IN  EDKII_ATA_AHCI_HOST_CONTROLLER_PPI    *This,
+  IN  UINT8                                 ControllerId,
+  OUT UINTN                                 *DevicePathLength,
+  OUT EFI_DEVICE_PATH_PROTOCOL              **DevicePath
+  );
+
+//
+// This PPI contains a set of services to interact with the ATA AHCI host controller.
+//
+struct _EDKII_ATA_AHCI_HOST_CONTROLLER_PPI {
+  EDKII_ATA_AHCI_HC_GET_MMIO_BAR       GetAhciHcMmioBar;
+  EDKII_ATA_AHCI_HC_GET_DEVICE_PATH    GetAhciHcDevicePath;
+};
+
+extern EFI_GUID gEdkiiPeiAtaAhciHostControllerPpiGuid;
+
+#endif
-- 
2.12.0.windows.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 02/12] MdeModulePkg: Add definitions for EDKII PEI ATA PassThru PPI
  2019-02-01  5:47 [PATCH v3 00/12] Split the S3 PEI phase HW init codes from Opal driver Hao Wu
  2019-02-01  5:47 ` [PATCH v3 01/12] MdeModulePkg: Add definitions for ATA AHCI host controller PPI Hao Wu
@ 2019-02-01  5:47 ` Hao Wu
  2019-02-01  5:47 ` [PATCH v3 03/12] MdeModulePkg: Add definitions for Storage Security Command PPI Hao Wu
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Hao Wu @ 2019-02-01  5:47 UTC (permalink / raw)
  To: edk2-devel; +Cc: Hao Wu, Jian J Wang, Ruiyu Ni, Eric Dong

REF:https://bugzilla.tianocore.org/show_bug.cgi?id=1409

This commit will add the definitions for EDKII PEI ATA PassThru PPI. This
PPI will provide services that allow ATA commands to be sent to ATA
devices attached to an ATA controller in the PEI phase.

More specifically, the PPI will provide services to:

* Send ATA commands to an ATA device (by service 'PassThru');
* Get the list of the attached ATA device on a controller (by services
  'GetNextPort' and 'GetNextDevice');
* Get the identification information (DevicePath) of the underlying ATA
  host controller (by service 'GetDevicePath').

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Hao Wu <hao.a.wu@intel.com>
---
 MdeModulePkg/MdeModulePkg.dec          |   3 +
 MdeModulePkg/Include/Ppi/AtaPassThru.h | 219 ++++++++++++++++++++
 2 files changed, 222 insertions(+)

diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index 4411185073..8efb19e626 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -483,6 +483,9 @@
   ## Include/Ppi/AtaAhciController.h
   gEdkiiPeiAtaAhciHostControllerPpiGuid     = { 0x61dd33ea, 0x421f, 0x4cc0, { 0x89, 0x29, 0xff, 0xee, 0xa9, 0xa1, 0xa2, 0x61 } }
 
+  ## Include/Ppi/AtaPassThru.h
+  gEdkiiPeiAtaPassThruPpiGuid               = { 0xa16473fd, 0xd474, 0x4c89, { 0xae, 0xc7, 0x90, 0xb8, 0x3c, 0x73, 0x86, 0x9  } }
+
 [Protocols]
   ## Load File protocol provides capability to load and unload EFI image into memory and execute it.
   #  Include/Protocol/LoadPe32Image.h
diff --git a/MdeModulePkg/Include/Ppi/AtaPassThru.h b/MdeModulePkg/Include/Ppi/AtaPassThru.h
new file mode 100644
index 0000000000..78bdaef9e2
--- /dev/null
+++ b/MdeModulePkg/Include/Ppi/AtaPassThru.h
@@ -0,0 +1,219 @@
+/** @file
+
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _EDKII_ATA_PASS_THRU_PPI_H_
+#define _EDKII_ATA_PASS_THRU_PPI_H_
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/AtaPassThru.h>
+
+///
+/// Global ID for the EDKII_PEI_ATA_PASS_THRU_PPI.
+///
+#define EDKII_PEI_ATA_PASS_THRU_PPI_GUID \
+  { \
+    0xa16473fd, 0xd474, 0x4c89, { 0xae, 0xc7, 0x90, 0xb8, 0x3c, 0x73, 0x86, 0x9 } \
+  }
+
+//
+// Forward declaration for the EDKII_PEI_ATA_PASS_THRU_PPI.
+//
+typedef struct _EDKII_PEI_ATA_PASS_THRU_PPI  EDKII_PEI_ATA_PASS_THRU_PPI;
+
+//
+// Revision The revision to which the ATA Pass Thru PPI interface adheres.
+//          All future revisions must be backwards compatible.
+//          If a future version is not back wards compatible it is not the same GUID.
+//
+#define EDKII_PEI_ATA_PASS_THRU_PPI_REVISION    0x00010000
+
+
+/**
+  Sends an ATA command to an ATA device that is attached to the ATA controller.
+
+  @param[in]     This                  The PPI instance pointer.
+  @param[in]     Port                  The port number of the ATA device to send
+                                       the command.
+  @param[in]     PortMultiplierPort    The port multiplier port number of the ATA
+                                       device to send the command.
+                                       If there is no port multiplier, then specify
+                                       0xFFFF.
+  @param[in,out] Packet                A pointer to the ATA command to send to
+                                       the ATA device specified by Port and
+                                       PortMultiplierPort.
+
+  @retval EFI_SUCCESS              The ATA command was sent by the host. For
+                                   bi-directional commands, InTransferLength bytes
+                                   were transferred from InDataBuffer. For write
+                                   and bi-directional commands, OutTransferLength
+                                   bytes were transferred by OutDataBuffer.
+  @retval EFI_NOT_FOUND            The specified ATA device is not found.
+  @retval EFI_INVALID_PARAMETER    The contents of Acb are invalid. The ATA command
+                                   was not sent, so no additional status information
+                                   is available.
+  @retval EFI_BAD_BUFFER_SIZE      The ATA command was not executed. The number
+                                   of bytes that could be transferred is returned
+                                   in InTransferLength. For write and bi-directional
+                                   commands, OutTransferLength bytes were transferred
+                                   by OutDataBuffer.
+  @retval EFI_NOT_READY            The ATA command could not be sent because there
+                                   are too many ATA commands already queued. The
+                                   caller may retry again later.
+  @retval EFI_DEVICE_ERROR         A device error occurred while attempting to
+                                   send the ATA command.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_ATA_PASS_THRU_PASSTHRU) (
+  IN     EDKII_PEI_ATA_PASS_THRU_PPI         *This,
+  IN     UINT16                              Port,
+  IN     UINT16                              PortMultiplierPort,
+  IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET    *Packet
+  );
+
+/**
+  Used to retrieve the list of legal port numbers for ATA devices on an ATA controller.
+  These can either be the list of ports where ATA devices are actually present or the
+  list of legal port numbers for the ATA controller. Regardless, the caller of this
+  function must probe the port number returned to see if an ATA device is actually
+  present at that location on the ATA controller.
+
+  The GetNextPort() function retrieves the port number on an ATA controller. If on
+  input Port is 0xFFFF, then the port number of the first port on the ATA controller
+  is returned in Port and EFI_SUCCESS is returned.
+
+  If Port is a port number that was returned on a previous call to GetNextPort(),
+  then the port number of the next port on the ATA controller is returned in Port,
+  and EFI_SUCCESS is returned. If Port is not 0xFFFF and Port was not returned on
+  a previous call to GetNextPort(), then EFI_INVALID_PARAMETER is returned.
+
+  If Port is the port number of the last port on the ATA controller, then EFI_NOT_FOUND
+  is returned.
+
+  @param[in]     This    The PPI instance pointer.
+  @param[in,out] Port    On input, a pointer to the port number on the ATA controller.
+                         On output, a pointer to the next port number on the ATA
+                         controller. An input value of 0xFFFF retrieves the first
+                         port number on the ATA controller.
+
+  @retval EFI_SUCCESS              The next port number on the ATA controller was
+                                   returned in Port.
+  @retval EFI_NOT_FOUND            There are no more ports on this ATA controller.
+  @retval EFI_INVALID_PARAMETER    Port is not 0xFFFF and Port was not returned
+                                   on a previous call to GetNextPort().
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_ATA_PASS_THRU_THRU_GET_NEXT_PORT) (
+  IN     EDKII_PEI_ATA_PASS_THRU_PPI    *This,
+  IN OUT UINT16                         *Port
+  );
+
+/**
+  Used to retrieve the list of legal port multiplier port numbers for ATA devices
+  on a port of an ATA controller. These can either be the list of port multiplier
+  ports where ATA devices are actually present on port or the list of legal port
+  multiplier ports on that port. Regardless, the caller of this function must probe
+  the port number and port multiplier port number returned to see if an ATA device
+  is actually present.
+
+  The GetNextDevice() function retrieves the port multiplier port number of an ATA
+  device present on a port of an ATA controller.
+
+  If PortMultiplierPort points to a port multiplier port number value that was
+  returned on a previous call to GetNextDevice(), then the port multiplier port
+  number of the next ATA device on the port of the ATA controller is returned in
+  PortMultiplierPort, and EFI_SUCCESS is returned.
+
+  If PortMultiplierPort points to 0xFFFF, then the port multiplier port number
+  of the first ATA device on port of the ATA controller is returned in PortMultiplierPort
+  and EFI_SUCCESS is returned.
+
+  If PortMultiplierPort is not 0xFFFF and the value pointed to by PortMultiplierPort
+  was not returned on a previous call to GetNextDevice(), then EFI_INVALID_PARAMETER
+  is returned.
+
+  If PortMultiplierPort is the port multiplier port number of the last ATA device
+  on the port of the ATA controller, then EFI_NOT_FOUND is returned.
+
+  @param[in]     This                  The PPI instance pointer.
+  @param[in]     Port                  The port number present on the ATA controller.
+  @param[in,out] PortMultiplierPort    On input, a pointer to the port multiplier
+                                       port number of an ATA device present on the
+                                       ATA controller. If on input a PortMultiplierPort
+                                       of 0xFFFF is specified, then the port multiplier
+                                       port number of the first ATA device is returned.
+                                       On output, a pointer to the port multiplier port
+                                       number of the next ATA device present on an ATA
+                                       controller.
+
+  @retval EFI_SUCCESS              The port multiplier port number of the next ATA
+                                   device on the port of the ATA controller was
+                                   returned in PortMultiplierPort.
+  @retval EFI_NOT_FOUND            There are no more ATA devices on this port of
+                                   the ATA controller.
+  @retval EFI_INVALID_PARAMETER    PortMultiplierPort is not 0xFFFF, and PortMultiplierPort
+                                   was not returned on a previous call to GetNextDevice().
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_ATA_PASS_THRU_GET_NEXT_DEVICE) (
+  IN     EDKII_PEI_ATA_PASS_THRU_PPI    *This,
+  IN     UINT16                         Port,
+  IN OUT UINT16                         *PortMultiplierPort
+  );
+
+/**
+  Gets the device path information of the underlying ATA host controller.
+
+  @param[in]  This                The PPI instance pointer.
+  @param[out] DevicePathLength    The length of the device path in bytes specified
+                                  by DevicePath.
+  @param[out] DevicePath          The device path of the underlying ATA host controller.
+                                  This field re-uses EFI Device Path Protocol as
+                                  defined by Section 10.2 EFI Device Path Protocol
+                                  of UEFI 2.7 Specification.
+
+  @retval EFI_SUCCESS              The device path of the ATA host controller has
+                                   been successfully returned.
+  @retval EFI_INVALID_PARAMETER    DevicePathLength or DevicePath is NULL.
+  @retval EFI_OUT_OF_RESOURCES     Not enough resource to return the device path.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_ATA_PASS_THRU_GET_DEVICE_PATH) (
+  IN  EDKII_PEI_ATA_PASS_THRU_PPI    *This,
+  OUT UINTN                          *DevicePathLength,
+  OUT EFI_DEVICE_PATH_PROTOCOL       **DevicePath
+  );
+
+//
+// EDKII_PEI_ATA_PASS_THRU_PPI provides the services that are required to send
+// ATA commands to an ATA device during PEI.
+//
+struct _EDKII_PEI_ATA_PASS_THRU_PPI {
+  UINT64                                        Revision;
+  EFI_ATA_PASS_THRU_MODE                        *Mode;
+  EDKII_PEI_ATA_PASS_THRU_PASSTHRU              PassThru;
+  EDKII_PEI_ATA_PASS_THRU_THRU_GET_NEXT_PORT    GetNextPort;
+  EDKII_PEI_ATA_PASS_THRU_GET_NEXT_DEVICE       GetNextDevice;
+  EDKII_PEI_ATA_PASS_THRU_GET_DEVICE_PATH       GetDevicePath;
+};
+
+extern EFI_GUID gEdkiiPeiAtaPassThruPpiGuid;
+
+#endif
-- 
2.12.0.windows.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 03/12] MdeModulePkg: Add definitions for Storage Security Command PPI
  2019-02-01  5:47 [PATCH v3 00/12] Split the S3 PEI phase HW init codes from Opal driver Hao Wu
  2019-02-01  5:47 ` [PATCH v3 01/12] MdeModulePkg: Add definitions for ATA AHCI host controller PPI Hao Wu
  2019-02-01  5:47 ` [PATCH v3 02/12] MdeModulePkg: Add definitions for EDKII PEI ATA PassThru PPI Hao Wu
@ 2019-02-01  5:47 ` Hao Wu
  2019-02-01  5:47 ` [PATCH v3 04/12] MdeModulePkg: Add GUID for LockBox to save storage dev to init in S3 Hao Wu
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Hao Wu @ 2019-02-01  5:47 UTC (permalink / raw)
  To: edk2-devel; +Cc: Hao Wu, Jian J Wang, Eric Dong

REF:https://bugzilla.tianocore.org/show_bug.cgi?id=1409

This commit will add the definitions for Storage Security Command (SSC)
PPI. This PPI will be be used to abstract mass storage devices to allow
code running in the PEI phase to send security protocol commands to mass
storage devices without specific knowledge of the type of device or
controller that manages the device.

More specifically, the PPI will provide services to:

* Get the number of mass storage devices managed by a instance of the SSC
  PPI (by service 'GetNumberofDevices');
* Get the identification information (DevicePath) of a managing mass
  storage devices (by service 'GetDevicePath');
* Send security protocol commands to mass storage devices (by services
  'ReceiveData' and 'SendData').

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Hao Wu <hao.a.wu@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
---
 MdeModulePkg/MdeModulePkg.dec                     |   3 +
 MdeModulePkg/Include/Ppi/StorageSecurityCommand.h | 283 ++++++++++++++++++++
 2 files changed, 286 insertions(+)

diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index 8efb19e626..7f646d7702 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -483,6 +483,9 @@
   ## Include/Ppi/AtaAhciController.h
   gEdkiiPeiAtaAhciHostControllerPpiGuid     = { 0x61dd33ea, 0x421f, 0x4cc0, { 0x89, 0x29, 0xff, 0xee, 0xa9, 0xa1, 0xa2, 0x61 } }
 
+  ## Include/Ppi/StorageSecurityCommand.h
+  gEdkiiPeiStorageSecurityCommandPpiGuid    = { 0x35de0b4e, 0x30fb, 0x46c3, { 0xbd, 0x84, 0x1f, 0xdb, 0xa1, 0x58, 0xbb, 0x56 } }
+
   ## Include/Ppi/AtaPassThru.h
   gEdkiiPeiAtaPassThruPpiGuid               = { 0xa16473fd, 0xd474, 0x4c89, { 0xae, 0xc7, 0x90, 0xb8, 0x3c, 0x73, 0x86, 0x9  } }
 
diff --git a/MdeModulePkg/Include/Ppi/StorageSecurityCommand.h b/MdeModulePkg/Include/Ppi/StorageSecurityCommand.h
new file mode 100644
index 0000000000..cc1688dabb
--- /dev/null
+++ b/MdeModulePkg/Include/Ppi/StorageSecurityCommand.h
@@ -0,0 +1,283 @@
+/** @file
+
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _EDKII_STORAGE_SECURITY_COMMAND_PPI_H_
+#define _EDKII_STORAGE_SECURITY_COMMAND_PPI_H_
+
+#include <Protocol/DevicePath.h>
+
+///
+/// Global ID for the EDKII_PEI_STORAGE_SECURITY_CMD_PPI.
+///
+#define EDKII_PEI_STORAGE_SECURITY_CMD_PPI_GUID \
+  { \
+    0x35de0b4e, 0x30fb, 0x46c3, { 0xbd, 0x84, 0x1f, 0xdb, 0xa1, 0x58, 0xbb, 0x56 } \
+  }
+
+//
+// Forward declaration for the EDKII_PEI_STORAGE_SECURITY_CMD_PPI.
+//
+typedef struct _EDKII_PEI_STORAGE_SECURITY_CMD_PPI  EDKII_PEI_STORAGE_SECURITY_CMD_PPI;
+
+//
+// Revision The revision to which the Storage Security Command interface adheres.
+//          All future revisions must be backwards compatible.
+//          If a future version is not back wards compatible it is not the same GUID.
+//
+#define EDKII_STORAGE_SECURITY_PPI_REVISION  0x00010000
+
+
+/**
+  Gets the count of storage security devices that one specific driver detects.
+
+  @param[in]  This               The PPI instance pointer.
+  @param[out] NumberofDevices    The number of storage security devices discovered.
+
+  @retval EFI_SUCCESS              The operation performed successfully.
+  @retval EFI_INVALID_PARAMETER    The parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_STORAGE_SECURITY_GET_NUMBER_DEVICES) (
+  IN  EDKII_PEI_STORAGE_SECURITY_CMD_PPI    *This,
+  OUT UINTN                                 *NumberofDevices
+  );
+
+/**
+  Gets the device path of a specific storage security device.
+
+  @param[in]  This                 The PPI instance pointer.
+  @param[in]  DeviceIndex          Specifies the storage security device to which
+                                   the function wants to talk. Because the driver
+                                   that implements Storage Security Command PPIs
+                                   will manage multiple storage devices, the PPIs
+                                   that want to talk to a single device must specify
+                                   the device index that was assigned during the
+                                   enumeration process. This index is a number from
+                                   one to NumberofDevices.
+  @param[out] DevicePathLength     The length of the device path in bytes specified
+                                   by DevicePath.
+  @param[out] DevicePath           The device path of storage security device.
+                                   This field re-uses EFI Device Path Protocol as
+                                   defined by Section 10.2 EFI Device Path Protocol
+                                   of UEFI 2.7 Specification.
+
+  @retval EFI_SUCCESS              The operation succeeds.
+  @retval EFI_INVALID_PARAMETER    DevicePathLength or DevicePath is NULL.
+  @retval EFI_NOT_FOUND            The specified storage security device not found.
+  @retval EFI_OUT_OF_RESOURCES     The operation fails due to lack of resources.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_STORAGE_SECURITY_GET_DEVICE_PATH) (
+  IN  EDKII_PEI_STORAGE_SECURITY_CMD_PPI    *This,
+  IN  UINTN                                 DeviceIndex,
+  OUT UINTN                                 *DevicePathLength,
+  OUT EFI_DEVICE_PATH_PROTOCOL              **DevicePath
+  );
+
+/**
+  Send a security protocol command to a device that receives data and/or the result
+  of one or more commands sent by SendData.
+
+  The ReceiveData function sends a security protocol command to the given DeviceIndex.
+  The security protocol command sent is defined by SecurityProtocolId and contains
+  the security protocol specific data SecurityProtocolSpecificData. The function
+  returns the data from the security protocol command in PayloadBuffer.
+
+  For devices supporting the SCSI command set, the security protocol command is sent
+  using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+  For devices supporting the ATA command set, the security protocol command is sent
+  using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+  is non-zero.
+
+  If the PayloadBufferSize is zero, the security protocol command is sent using the
+  Trusted Non-Data command defined in ATA8-ACS.
+
+  If PayloadBufferSize is too small to store the available data from the security
+  protocol command, the function shall copy PayloadBufferSize bytes into the
+  PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+  If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+  the function shall return EFI_INVALID_PARAMETER.
+
+  If the given DeviceIndex does not support security protocol commands, the function
+  shall return EFI_UNSUPPORTED.
+
+  If the security protocol fails to complete within the Timeout period, the function
+  shall return EFI_TIMEOUT.
+
+  If the security protocol command completes without an error, the function shall
+  return EFI_SUCCESS. If the security protocol command completes with an error, the
+  function shall return EFI_DEVICE_ERROR.
+
+  @param[in]  This             The PPI instance pointer.
+  @param[in]  DeviceIndex      Specifies the storage security device to which the
+                               function wants to talk. Because the driver that
+                               implements Storage Security Command PPIs will manage
+                               multiple storage devices, the PPIs that want to talk
+                               to a single device must specify the device index
+                               that was assigned during the enumeration process.
+                               This index is a number from one to NumberofDevices.
+  @param[in]  Timeout          The timeout, in 100ns units, to use for the execution
+                               of the security protocol command. A Timeout value
+                               of 0 means that this function will wait indefinitely
+                               for the security protocol command to execute. If
+                               Timeout is greater than zero, then this function
+                               will return EFI_TIMEOUT if the time required to
+                               execute the receive data command is greater than
+                               Timeout.
+  @param[in]  SecurityProtocolId
+                               The value of the "Security Protocol" parameter of
+                               the security protocol command to be sent.
+  @param[in]  SecurityProtocolSpecificData
+                               The value of the "Security Protocol Specific"
+                               parameter of the security protocol command to be
+                               sent.
+  @param[in]  PayloadBufferSize
+                               Size in bytes of the payload data buffer.
+  @param[out] PayloadBuffer    A pointer to a destination buffer to store the
+                               security protocol command specific payload data
+                               for the security protocol command. The caller is
+                               responsible for having either implicit or explicit
+                               ownership of the buffer.
+  @param[out] PayloadTransferSize
+                               A pointer to a buffer to store the size in bytes
+                               of the data written to the payload data buffer.
+
+  @retval EFI_SUCCESS                  The security protocol command completed
+                                       successfully.
+  @retval EFI_WARN_BUFFER_TOO_SMALL    The PayloadBufferSize was too small to
+                                       store the available data from the device.
+                                       The PayloadBuffer contains the truncated
+                                       data.
+  @retval EFI_UNSUPPORTED              The given DeviceIndex does not support
+                                       security protocol commands.
+  @retval EFI_DEVICE_ERROR             The security protocol command completed
+                                       with an error.
+  @retval EFI_INVALID_PARAMETER        The PayloadBuffer or PayloadTransferSize
+                                       is NULL and PayloadBufferSize is non-zero.
+  @retval EFI_TIMEOUT                  A timeout occurred while waiting for the
+                                       security protocol command to execute.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_STORAGE_SECURITY_RECEIVE_DATA) (
+  IN  EDKII_PEI_STORAGE_SECURITY_CMD_PPI    *This,
+  IN  UINTN                                 DeviceIndex,
+  IN  UINT64                                Timeout,
+  IN  UINT8                                 SecurityProtocolId,
+  IN  UINT16                                SecurityProtocolSpecificData,
+  IN  UINTN                                 PayloadBufferSize,
+  OUT VOID                                  *PayloadBuffer,
+  OUT UINTN                                 *PayloadTransferSize
+  );
+
+/**
+  Send a security protocol command to a device.
+
+  The SendData function sends a security protocol command containing the payload
+  PayloadBuffer to the given DeviceIndex. The security protocol command sent is
+  defined by SecurityProtocolId and contains the security protocol specific data
+  SecurityProtocolSpecificData. If the underlying protocol command requires a
+  specific padding for the command payload, the SendData function shall add padding
+  bytes to the command payload to satisfy the padding requirements.
+
+  For devices supporting the SCSI command set, the security protocol command is
+  sent using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+  For devices supporting the ATA command set, the security protocol command is
+  sent using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
+  is non-zero. If the PayloadBufferSize is zero, the security protocol command
+  is sent using the Trusted Non-Data command defined in ATA8-ACS.
+
+  If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
+  return EFI_INVALID_PARAMETER.
+
+  If the given DeviceIndex does not support security protocol commands, the function
+  shall return EFI_UNSUPPORTED.
+
+  If the security protocol fails to complete within the Timeout period, the function
+  shall return EFI_TIMEOUT.
+
+  If the security protocol command completes without an error, the function shall
+  return EFI_SUCCESS. If the security protocol command completes with an error,
+  the functio shall return EFI_DEVICE_ERROR.
+
+  @param[in] This              The PPI instance pointer.
+  @param[in] DeviceIndex       The ID of the device.
+  @param[in] Timeout           The timeout, in 100ns units, to use for the execution
+                               of the security protocol command. A Timeout value
+                               of 0 means that this function will wait indefinitely
+                               for the security protocol command to execute. If
+                               Timeout is greater than zero, then this function
+                               will return EFI_TIMEOUT if the time required to
+                               execute the receive data command is greater than
+                               Timeout.
+  @param[in] SecurityProtocolId
+                               The value of the "Security Protocol" parameter of
+                               the security protocol command to be sent.
+  @param[in] SecurityProtocolSpecificData
+                               The value of the "Security Protocol Specific"
+                               parameter of the security protocol command to be
+                               sent.
+  @param[in] PayloadBufferSize Size in bytes of the payload data buffer.
+  @param[in] PayloadBuffer     A pointer to a destination buffer to store the
+                               security protocol command specific payload data
+                               for the security protocol command.
+
+  @retval EFI_SUCCESS              The security protocol command completed successfully.
+  @retval EFI_UNSUPPORTED          The given DeviceIndex does not support security
+                                   protocol commands.
+  @retval EFI_DEVICE_ERROR         The security protocol command completed with
+                                   an error.
+  @retval EFI_INVALID_PARAMETER    The PayloadBuffer is NULL and PayloadBufferSize
+                                   is non-zero.
+  @retval EFI_TIMEOUT              A timeout occurred while waiting for the security
+                                   protocol command to execute.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PEI_STORAGE_SECURITY_SEND_DATA) (
+  IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI    *This,
+  IN UINTN                                 DeviceIndex,
+  IN UINT64                                Timeout,
+  IN UINT8                                 SecurityProtocolId,
+  IN UINT16                                SecurityProtocolSpecificData,
+  IN UINTN                                 PayloadBufferSize,
+  IN VOID                                  *PayloadBuffer
+  );
+
+//
+// EDKII_PEI_STORAGE_SECURITY_CMD_PPI contains a set of services to send security
+// protocol commands to a mass storage device. Two types of security protocol
+// commands are supported. SendData sends a command with data to a device.
+// ReceiveData sends a command that receives data and/or the result of one or
+// more commands sent by SendData.
+//
+struct _EDKII_PEI_STORAGE_SECURITY_CMD_PPI {
+  UINT64                                           Revision;
+  EDKII_PEI_STORAGE_SECURITY_GET_NUMBER_DEVICES    GetNumberofDevices;
+  EDKII_PEI_STORAGE_SECURITY_GET_DEVICE_PATH       GetDevicePath;
+  EDKII_PEI_STORAGE_SECURITY_RECEIVE_DATA          ReceiveData;
+  EDKII_PEI_STORAGE_SECURITY_SEND_DATA             SendData;
+};
+
+extern EFI_GUID gEdkiiPeiStorageSecurityCommandPpiGuid;
+
+#endif
-- 
2.12.0.windows.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 04/12] MdeModulePkg: Add GUID for LockBox to save storage dev to init in S3
  2019-02-01  5:47 [PATCH v3 00/12] Split the S3 PEI phase HW init codes from Opal driver Hao Wu
                   ` (2 preceding siblings ...)
  2019-02-01  5:47 ` [PATCH v3 03/12] MdeModulePkg: Add definitions for Storage Security Command PPI Hao Wu
@ 2019-02-01  5:47 ` Hao Wu
  2019-02-01  5:47 ` [PATCH v3 05/12] MdeModulePkg/NvmExpressPei: Avoid updating the module-level variable Hao Wu
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Hao Wu @ 2019-02-01  5:47 UTC (permalink / raw)
  To: edk2-devel; +Cc: Hao Wu, Jian J Wang, Ray Ni, Eric Dong

REF:https://bugzilla.tianocore.org/show_bug.cgi?id=1409

This commit will add the GUID definitions for LockBox which is used to
save a list of storage devices that need to get initialized during the S3
resume.

The content of the LockBox will be a DevicePath structure that contains
zero or more DevicePath instances. Each instance denotes a storage device
that needs to get initialized during the S3 resume.

The producers of the content of this LockBox will be drivers like
OpalPassword DXE driver. This kind of drivers requires some specific
storage devices to be initialized during the PEI phase of in S3 resume.
(For the OpalPasword case, it requires the managing devices to be
automatically unlocked during the S3 resume).

The attribute of the LockBox should be set to
LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY.

The consumers of the content of this LockBox will be PEI storage device
controller/bus drivers (e.g. NvmExpressPei) during S3 resume. This kind of
drivers can use the DevicePath instances stored in the LockBox to get a
list of devices that need to get initialized. In such way, an on-demand
(partial) device enumeration/initialization can be performed to benefit
the S3 resume performance.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Hao Wu <hao.a.wu@intel.com>
---
 MdeModulePkg/MdeModulePkg.dec                       |  3 +
 MdeModulePkg/Include/Guid/S3StorageDeviceInitList.h | 64 ++++++++++++++++++++
 2 files changed, 67 insertions(+)

diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index 7f646d7702..a2130bc439 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -422,6 +422,9 @@
   ## Include/Guid/S3SmmInitDone.h
   gEdkiiS3SmmInitDoneGuid = { 0x8f9d4825, 0x797d, 0x48fc, { 0x84, 0x71, 0x84, 0x50, 0x25, 0x79, 0x2e, 0xf6 } }
 
+  ## Include/Guid/S3StorageDeviceInitList.h
+  gS3StorageDeviceInitListGuid = { 0x310e9b8c, 0xcf90, 0x421e, { 0x8e, 0x9b, 0x9e, 0xef, 0xb6, 0x17, 0xc8, 0xef } }
+
 [Ppis]
   ## Include/Ppi/AtaController.h
   gPeiAtaControllerPpiGuid       = { 0xa45e60d1, 0xc719, 0x44aa, { 0xb0, 0x7a, 0xaa, 0x77, 0x7f, 0x85, 0x90, 0x6d }}
diff --git a/MdeModulePkg/Include/Guid/S3StorageDeviceInitList.h b/MdeModulePkg/Include/Guid/S3StorageDeviceInitList.h
new file mode 100644
index 0000000000..bd300b2696
--- /dev/null
+++ b/MdeModulePkg/Include/Guid/S3StorageDeviceInitList.h
@@ -0,0 +1,64 @@
+/** @file
+  Define the LockBox GUID for list of storage devices need to be initialized in
+  S3.
+
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions
+  of the BSD License which accompanies this distribution.  The
+  full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __S3_STORAGE_DEVICE_INIT_LIST_H__
+#define __S3_STORAGE_DEVICE_INIT_LIST_H__
+
+#define S3_STORAGE_DEVICE_INIT_LIST \
+  { \
+    0x310e9b8c, 0xcf90, 0x421e, { 0x8e, 0x9b, 0x9e, 0xef, 0xb6, 0x17, 0xc8, 0xef } \
+  }
+
+//
+// The LockBox will store a DevicePath structure that contains one or more
+// DevicePath instances. Each instance denotes a storage device that needs to
+// get initialized during the S3 resume.
+//
+// For example, if there is only one storage device stored in the list, the
+// content of this LockBox will be:
+//
+// +-------------------------------------------------------+
+// |                 DevPath Instance #1                   |
+// | (Terminated by an End of Hardware Device Path node    |
+// |  with an End Entire Device Path sub-type)             |
+// +-------------------------------------------------------+
+//
+// If there are n (n > 1) storage devices in the list, the content of this
+// LockBox will be:
+//
+// +-------------------------------------------------------+
+// |                 DevPath Instance #1                   |
+// | (Terminated by an End of Hardware Device Path node    |
+// |  with an End This Instance of a Device Path sub-type) |
+// +-------------------------------------------------------+
+// |                 DevPath Instance #2                   |
+// | (Terminated by an End of Hardware Device Path node    |
+// |  with an End This Instance of a Device Path sub-type) |
+// +-------------------------------------------------------+
+// |                        ...                            |
+// +-------------------------------------------------------+
+// |                 DevPath Instance #n                   |
+// | (Terminated by an End of Hardware Device Path node    |
+// |  with an End Entire Device Path sub-type)             |
+// +-------------------------------------------------------+
+//
+// The attribute of the LockBox should be set to
+// 'LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY'.
+//
+extern EFI_GUID  gS3StorageDeviceInitListGuid;
+
+#endif  // __S3_STORAGE_DEVICE_INIT_LIST_H__
-- 
2.12.0.windows.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 05/12] MdeModulePkg/NvmExpressPei: Avoid updating the module-level variable
  2019-02-01  5:47 [PATCH v3 00/12] Split the S3 PEI phase HW init codes from Opal driver Hao Wu
                   ` (3 preceding siblings ...)
  2019-02-01  5:47 ` [PATCH v3 04/12] MdeModulePkg: Add GUID for LockBox to save storage dev to init in S3 Hao Wu
@ 2019-02-01  5:47 ` Hao Wu
  2019-02-01  5:47 ` [PATCH v3 06/12] MdeModulePkg/NvmExpressPei: Add logic to produce SSC PPI Hao Wu
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Hao Wu @ 2019-02-01  5:47 UTC (permalink / raw)
  To: edk2-devel; +Cc: Hao Wu, Jian J Wang

This commit is out of the scope for BZ-1409. The commit will remove the
call of RegisterForShadow() at the entry point of the driver. By doing so,
the driver is now possible to be executed without being re-loaded into
permanent memory.

Thus, this commit will update the NvmExpressPei driver to avoid updating
the content of a global variable.

Cc: Jian J Wang <jian.j.wang@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Hao Wu <hao.a.wu@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
---
 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h |  12 +-
 MdeModulePkg/Bus/Pci/NvmExpressPei/DmaMem.c        | 153 +++++++++++---------
 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c |  11 +-
 3 files changed, 92 insertions(+), 84 deletions(-)

diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h
index 0bd62c2459..0135eca6f0 100644
--- a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h
+++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h
@@ -2,7 +2,7 @@
   The NvmExpressPei driver is used to manage non-volatile memory subsystem
   which follows NVM Express specification at PEI phase.
 
-  Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
 
   This program and the accompanying materials
   are licensed and made available under the terms and conditions
@@ -147,13 +147,9 @@ struct _PEI_NVME_CONTROLLER_PRIVATE_DATA {
   CR (a, PEI_NVME_CONTROLLER_PRIVATE_DATA, EndOfPeiNotifyList, NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE)
 
 
-/**
-  Initialize IOMMU.
-**/
-VOID
-IoMmuInit (
-  VOID
-  );
+//
+// Internal functions
+//
 
 /**
   Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/DmaMem.c b/MdeModulePkg/Bus/Pci/NvmExpressPei/DmaMem.c
index 51b48d38dd..cb629c16b0 100644
--- a/MdeModulePkg/Bus/Pci/NvmExpressPei/DmaMem.c
+++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/DmaMem.c
@@ -1,7 +1,7 @@
 /** @file
   The DMA memory help function.
 
-  Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
 
   This program and the accompanying materials
   are licensed and made available under the terms and conditions
@@ -16,7 +16,33 @@
 
 #include "NvmExpressPei.h"
 
-EDKII_IOMMU_PPI  *mIoMmu;
+/**
+  Get IOMMU PPI.
+
+  @return Pointer to IOMMU PPI.
+
+**/
+EDKII_IOMMU_PPI *
+GetIoMmu (
+  VOID
+  )
+{
+  EFI_STATUS         Status;
+  EDKII_IOMMU_PPI    *IoMmu;
+
+  IoMmu  = NULL;
+  Status = PeiServicesLocatePpi (
+             &gEdkiiIoMmuPpiGuid,
+             0,
+             NULL,
+             (VOID **) &IoMmu
+             );
+  if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
+    return IoMmu;
+  }
+
+  return NULL;
+}
 
 /**
   Provides the controller-specific addresses required to access system memory from a
@@ -46,18 +72,21 @@ IoMmuMap (
   OUT VOID                  **Mapping
   )
 {
-  EFI_STATUS  Status;
-  UINT64      Attribute;
-
-  if (mIoMmu != NULL) {
-    Status = mIoMmu->Map (
-                       mIoMmu,
-                       Operation,
-                       HostAddress,
-                       NumberOfBytes,
-                       DeviceAddress,
-                       Mapping
-                       );
+  EFI_STATUS         Status;
+  UINT64             Attribute;
+  EDKII_IOMMU_PPI    *IoMmu;
+
+  IoMmu = GetIoMmu ();
+
+  if (IoMmu != NULL) {
+    Status = IoMmu->Map (
+                     IoMmu,
+                     Operation,
+                     HostAddress,
+                     NumberOfBytes,
+                     DeviceAddress,
+                     Mapping
+                     );
     if (EFI_ERROR (Status)) {
       return EFI_OUT_OF_RESOURCES;
     }
@@ -78,11 +107,11 @@ IoMmuMap (
       ASSERT(FALSE);
       return EFI_INVALID_PARAMETER;
     }
-    Status = mIoMmu->SetAttribute (
-                       mIoMmu,
-                       *Mapping,
-                       Attribute
-                       );
+    Status = IoMmu->SetAttribute (
+                      IoMmu,
+                      *Mapping,
+                      Attribute
+                      );
     if (EFI_ERROR (Status)) {
       return Status;
     }
@@ -108,11 +137,14 @@ IoMmuUnmap (
   IN VOID                  *Mapping
   )
 {
-  EFI_STATUS  Status;
+  EFI_STATUS         Status;
+  EDKII_IOMMU_PPI    *IoMmu;
+
+  IoMmu = GetIoMmu ();
 
-  if (mIoMmu != NULL) {
-    Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0);
-    Status = mIoMmu->Unmap (mIoMmu, Mapping);
+  if (IoMmu != NULL) {
+    Status = IoMmu->SetAttribute (IoMmu, Mapping, 0);
+    Status = IoMmu->Unmap (IoMmu, Mapping);
   } else {
     Status = EFI_SUCCESS;
   }
@@ -148,39 +180,42 @@ IoMmuAllocateBuffer (
   EFI_STATUS            Status;
   UINTN                 NumberOfBytes;
   EFI_PHYSICAL_ADDRESS  HostPhyAddress;
+  EDKII_IOMMU_PPI       *IoMmu;
 
   *HostAddress = NULL;
   *DeviceAddress = 0;
 
-  if (mIoMmu != NULL) {
-    Status = mIoMmu->AllocateBuffer (
-                       mIoMmu,
-                       EfiBootServicesData,
-                       Pages,
-                       HostAddress,
-                       0
-                       );
+  IoMmu = GetIoMmu ();
+
+  if (IoMmu != NULL) {
+    Status = IoMmu->AllocateBuffer (
+                      IoMmu,
+                      EfiBootServicesData,
+                      Pages,
+                      HostAddress,
+                      0
+                      );
     if (EFI_ERROR (Status)) {
       return EFI_OUT_OF_RESOURCES;
     }
 
     NumberOfBytes = EFI_PAGES_TO_SIZE(Pages);
-    Status = mIoMmu->Map (
-                       mIoMmu,
-                       EdkiiIoMmuOperationBusMasterCommonBuffer,
-                       *HostAddress,
-                       &NumberOfBytes,
-                       DeviceAddress,
-                       Mapping
-                       );
+    Status = IoMmu->Map (
+                      IoMmu,
+                      EdkiiIoMmuOperationBusMasterCommonBuffer,
+                      *HostAddress,
+                      &NumberOfBytes,
+                      DeviceAddress,
+                      Mapping
+                      );
     if (EFI_ERROR (Status)) {
       return EFI_OUT_OF_RESOURCES;
     }
-    Status = mIoMmu->SetAttribute (
-                       mIoMmu,
-                       *Mapping,
-                       EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
-                       );
+    Status = IoMmu->SetAttribute (
+                      IoMmu,
+                      *Mapping,
+                      EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
+                      );
     if (EFI_ERROR (Status)) {
       return Status;
     }
@@ -219,31 +254,17 @@ IoMmuFreeBuffer (
   IN VOID                   *Mapping
   )
 {
-  EFI_STATUS  Status;
+  EFI_STATUS         Status;
+  EDKII_IOMMU_PPI    *IoMmu;
 
-  if (mIoMmu != NULL) {
-    Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0);
-    Status = mIoMmu->Unmap (mIoMmu, Mapping);
-    Status = mIoMmu->FreeBuffer (mIoMmu, Pages, HostAddress);
+  IoMmu = GetIoMmu ();
+
+  if (IoMmu != NULL) {
+    Status = IoMmu->SetAttribute (IoMmu, Mapping, 0);
+    Status = IoMmu->Unmap (IoMmu, Mapping);
+    Status = IoMmu->FreeBuffer (IoMmu, Pages, HostAddress);
   } else {
     Status = EFI_SUCCESS;
   }
   return Status;
 }
-
-/**
-  Initialize IOMMU.
-**/
-VOID
-IoMmuInit (
-  VOID
-  )
-{
-  PeiServicesLocatePpi (
-    &gEdkiiIoMmuPpiGuid,
-    0,
-    NULL,
-    (VOID **)&mIoMmu
-    );
-}
-
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c
index fabec37e36..2fe73e942c 100644
--- a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c
+++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c
@@ -2,7 +2,7 @@
   The NvmExpressPei driver is used to manage non-volatile memory subsystem
   which follows NVM Express specification at PEI phase.
 
-  Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
 
   This program and the accompanying materials
   are licensed and made available under the terms and conditions
@@ -215,13 +215,6 @@ NvmExpressPeimEntry (
   EFI_PHYSICAL_ADDRESS                     DeviceAddress;
 
   //
-  // Shadow this PEIM to run from memory
-  //
-  if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
-    return EFI_SUCCESS;
-  }
-
-  //
   // Locate the NVME host controller PPI
   //
   Status = PeiServicesLocatePpi (
@@ -235,8 +228,6 @@ NvmExpressPeimEntry (
     return EFI_UNSUPPORTED;
   }
 
-  IoMmuInit ();
-
   Controller = 0;
   MmioBase   = 0;
   while (TRUE) {
-- 
2.12.0.windows.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 06/12] MdeModulePkg/NvmExpressPei: Add logic to produce SSC PPI
  2019-02-01  5:47 [PATCH v3 00/12] Split the S3 PEI phase HW init codes from Opal driver Hao Wu
                   ` (4 preceding siblings ...)
  2019-02-01  5:47 ` [PATCH v3 05/12] MdeModulePkg/NvmExpressPei: Avoid updating the module-level variable Hao Wu
@ 2019-02-01  5:47 ` Hao Wu
  2019-02-01  5:47 ` [PATCH v3 07/12] MdeModulePkg/NvmExpressPei: Consume S3StorageDeviceInitList LockBox Hao Wu
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Hao Wu @ 2019-02-01  5:47 UTC (permalink / raw)
  To: edk2-devel; +Cc: Hao Wu, Jian J Wang, Ray Ni, Eric Dong

REF:https://bugzilla.tianocore.org/show_bug.cgi?id=1409

For the NvmExpressPei driver, this commit will add codes to produce the
Storage Security Command PPI if the underlying NVM Express controller
supports the Security Send and Security Receive commands.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Hao Wu <hao.a.wu@intel.com>
---
 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf              |  10 +-
 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h                |  58 ++-
 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.h             |  20 +-
 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiStorageSecurity.h | 247 ++++++++++++
 MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c                   | 231 +++++++++++
 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c                | 143 +++++--
 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.c             |  32 +-
 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiStorageSecurity.c | 423 ++++++++++++++++++++
 8 files changed, 1075 insertions(+), 89 deletions(-)

diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf
index 9591572fec..0666e5892b 100644
--- a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf
+++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf
@@ -2,7 +2,7 @@
 #  The NvmExpressPei driver is used to manage non-volatile memory subsystem
 #  which follows NVM Express specification at PEI phase.
 #
-#  Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
 #
 #  This program and the accompanying materials
 #  are licensed and made available under the terms and conditions of the BSD License
@@ -30,6 +30,7 @@
 #
 
 [Sources]
+  DevicePath.c
   DmaMem.c
   NvmExpressPei.c
   NvmExpressPei.h
@@ -39,6 +40,8 @@
   NvmExpressPeiHci.h
   NvmExpressPeiPassThru.c
   NvmExpressPeiPassThru.h
+  NvmExpressPeiStorageSecurity.c
+  NvmExpressPeiStorageSecurity.h
 
 [Packages]
   MdePkg/MdePkg.dec
@@ -54,11 +57,12 @@
   PeimEntryPoint
 
 [Ppis]
-  gEfiPeiVirtualBlockIoPpiGuid                   ## PRODUCES
-  gEfiPeiVirtualBlockIo2PpiGuid                  ## PRODUCES
   gEdkiiPeiNvmExpressHostControllerPpiGuid       ## CONSUMES
   gEdkiiIoMmuPpiGuid                             ## CONSUMES
   gEfiEndOfPeiSignalPpiGuid                      ## CONSUMES
+  gEfiPeiVirtualBlockIoPpiGuid                   ## SOMETIMES_PRODUCES
+  gEfiPeiVirtualBlockIo2PpiGuid                  ## SOMETIMES_PRODUCES
+  gEdkiiPeiStorageSecurityCommandPpiGuid         ## SOMETIMES_PRODUCES
 
 [Depex]
   gEfiPeiMemoryDiscoveredPpiGuid AND
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h
index 0135eca6f0..92c3854c6e 100644
--- a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h
+++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h
@@ -25,6 +25,7 @@
 #include <Ppi/NvmExpressHostController.h>
 #include <Ppi/BlockIo.h>
 #include <Ppi/BlockIo2.h>
+#include <Ppi/StorageSecurityCommand.h>
 #include <Ppi/IoMmu.h>
 #include <Ppi/EndOfPeiPhase.h>
 
@@ -44,6 +45,7 @@ typedef struct _PEI_NVME_CONTROLLER_PRIVATE_DATA  PEI_NVME_CONTROLLER_PRIVATE_DA
 #include "NvmExpressPeiHci.h"
 #include "NvmExpressPeiPassThru.h"
 #include "NvmExpressPeiBlockIo.h"
+#include "NvmExpressPeiStorageSecurity.h"
 
 //
 // NVME PEI driver implementation related definitions
@@ -90,10 +92,15 @@ struct _PEI_NVME_NAMESPACE_INFO {
 struct _PEI_NVME_CONTROLLER_PRIVATE_DATA {
   UINT32                                    Signature;
   UINTN                                     MmioBase;
+  UINTN                                     DevicePathLength;
+  EFI_DEVICE_PATH_PROTOCOL                  *DevicePath;
+
   EFI_PEI_RECOVERY_BLOCK_IO_PPI             BlkIoPpi;
   EFI_PEI_RECOVERY_BLOCK_IO2_PPI            BlkIo2Ppi;
+  EDKII_PEI_STORAGE_SECURITY_CMD_PPI        StorageSecurityPpi;
   EFI_PEI_PPI_DESCRIPTOR                    BlkIoPpiList;
   EFI_PEI_PPI_DESCRIPTOR                    BlkIo2PpiList;
+  EFI_PEI_PPI_DESCRIPTOR                    StorageSecurityPpiList;
   EFI_PEI_NOTIFY_DESCRIPTOR                 EndOfPeiNotifyList;
 
   //
@@ -139,11 +146,13 @@ struct _PEI_NVME_CONTROLLER_PRIVATE_DATA {
   PEI_NVME_NAMESPACE_INFO                   *NamespaceInfo;
 };
 
-#define GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO(a)     \
+#define GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO(a)               \
   CR (a, PEI_NVME_CONTROLLER_PRIVATE_DATA, BlkIoPpi, NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE)
-#define GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2(a)    \
+#define GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2(a)              \
   CR (a, PEI_NVME_CONTROLLER_PRIVATE_DATA, BlkIo2Ppi, NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE)
-#define GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY(a)    \
+#define GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY(a)    \
+  CR (a, PEI_NVME_CONTROLLER_PRIVATE_DATA, StorageSecurityPpi, NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE)
+#define GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY(a)              \
   CR (a, PEI_NVME_CONTROLLER_PRIVATE_DATA, EndOfPeiNotifyList, NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE)
 
 
@@ -257,4 +266,47 @@ NvmePeimEndOfPei (
   IN VOID                       *Ppi
   );
 
+/**
+  Check the validity of the device path of a NVM Express host controller.
+
+  @param[in] DevicePath          A pointer to the EFI_DEVICE_PATH_PROTOCOL
+                                 structure.
+  @param[in] DevicePathLength    The length of the device path.
+
+  @retval EFI_SUCCESS              The device path is valid.
+  @retval EFI_INVALID_PARAMETER    The device path is invalid.
+
+**/
+EFI_STATUS
+NvmeCheckHcDevicePath (
+  IN EFI_DEVICE_PATH_PROTOCOL    *DevicePath,
+  IN UINTN                       DevicePathLength
+  );
+
+/**
+  Build the device path for an Nvm Express device with given namespace identifier
+  and namespace extended unique identifier.
+
+  @param[in]  Private              A pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA
+                                   data structure.
+  @param[in]  NamespaceId          The given namespace identifier.
+  @param[in]  NamespaceUuid        The given namespace extended unique identifier.
+  @param[out] DevicePathLength     The length of the device path in bytes specified
+                                   by DevicePath.
+  @param[out] DevicePath           The device path of Nvm Express device.
+
+  @retval EFI_SUCCESS              The operation succeeds.
+  @retval EFI_INVALID_PARAMETER    The parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES     The operation fails due to lack of resources.
+
+**/
+EFI_STATUS
+NvmeBuildDevicePath (
+  IN  PEI_NVME_CONTROLLER_PRIVATE_DATA    *Private,
+  IN  UINT32                              NamespaceId,
+  IN  UINT64                              NamespaceUuid,
+  OUT UINTN                               *DevicePathLength,
+  OUT EFI_DEVICE_PATH_PROTOCOL            **DevicePath
+  );
+
 #endif
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.h b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.h
index ff334e3e17..ad1d5d0d8a 100644
--- a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.h
+++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.h
@@ -2,7 +2,7 @@
   The NvmExpressPei driver is used to manage non-volatile memory subsystem
   which follows NVM Express specification at PEI phase.
 
-  Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
 
   This program and the accompanying materials
   are licensed and made available under the terms and conditions
@@ -107,20 +107,6 @@ NvmeBaseMemPageOffset (
   );
 
 /**
-  Disable the Nvm Express controller.
-
-  @param[in] Private     The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
-
-  @return EFI_SUCCESS    Successfully disable the controller.
-  @return others         Fail to disable the controller.
-
-**/
-EFI_STATUS
-NvmeDisableController (
-  IN PEI_NVME_CONTROLLER_PRIVATE_DATA    *Private
-  );
-
-/**
   Initialize the Nvm Express controller.
 
   @param[in] Private     The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
@@ -153,13 +139,13 @@ NvmeIdentifyNamespace (
   );
 
 /**
-  Free the resources allocated by an NVME controller.
+  Free the DMA resources allocated by an NVME controller.
 
   @param[in] Private     The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
 
 **/
 VOID
-NvmeFreeControllerResource (
+NvmeFreeDmaResource (
   IN PEI_NVME_CONTROLLER_PRIVATE_DATA    *Private
   );
 
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiStorageSecurity.h b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiStorageSecurity.h
new file mode 100644
index 0000000000..8ccfb425e7
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiStorageSecurity.h
@@ -0,0 +1,247 @@
+/** @file
+  The NvmExpressPei driver is used to manage non-volatile memory subsystem
+  which follows NVM Express specification at PEI phase.
+
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions
+  of the BSD License which accompanies this distribution.  The
+  full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _NVM_EXPRESS_PEI_STORAGE_SECURITY_H_
+#define _NVM_EXPRESS_PEI_STORAGE_SECURITY_H_
+
+/**
+  Gets the count of storage security devices that one specific driver detects.
+
+  @param[in]  This               The PPI instance pointer.
+  @param[out] NumberofDevices    The number of storage security devices discovered.
+
+  @retval EFI_SUCCESS              The operation performed successfully.
+  @retval EFI_INVALID_PARAMETER    The parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeStorageSecurityGetDeviceNo (
+  IN  EDKII_PEI_STORAGE_SECURITY_CMD_PPI    *This,
+  OUT UINTN                                 *NumberofDevices
+  );
+
+/**
+  Gets the device path of a specific storage security device.
+
+  @param[in]  This                 The PPI instance pointer.
+  @param[in]  DeviceIndex          Specifies the storage security device to which
+                                   the function wants to talk. Because the driver
+                                   that implements Storage Security Command PPIs
+                                   will manage multiple storage devices, the PPIs
+                                   that want to talk to a single device must specify
+                                   the device index that was assigned during the
+                                   enumeration process. This index is a number from
+                                   one to NumberofDevices.
+  @param[out] DevicePathLength     The length of the device path in bytes specified
+                                   by DevicePath.
+  @param[out] DevicePath           The device path of storage security device.
+                                   This field re-uses EFI Device Path Protocol as
+                                   defined by Section 10.2 EFI Device Path Protocol
+                                   of UEFI 2.7 Specification.
+
+  @retval EFI_SUCCESS              The operation succeeds.
+  @retval EFI_INVALID_PARAMETER    DevicePathLength or DevicePath is NULL.
+  @retval EFI_NOT_FOUND            The specified storage security device not found.
+  @retval EFI_OUT_OF_RESOURCES     The operation fails due to lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeStorageSecurityGetDevicePath (
+  IN  EDKII_PEI_STORAGE_SECURITY_CMD_PPI  *This,
+  IN  UINTN                               DeviceIndex,
+  OUT UINTN                               *DevicePathLength,
+  OUT EFI_DEVICE_PATH_PROTOCOL            **DevicePath
+  );
+
+/**
+  Send a security protocol command to a device that receives data and/or the result
+  of one or more commands sent by SendData.
+
+  The ReceiveData function sends a security protocol command to the given DeviceIndex.
+  The security protocol command sent is defined by SecurityProtocolId and contains
+  the security protocol specific data SecurityProtocolSpecificData. The function
+  returns the data from the security protocol command in PayloadBuffer.
+
+  For devices supporting the SCSI command set, the security protocol command is sent
+  using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+  For devices supporting the ATA command set, the security protocol command is sent
+  using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+  is non-zero.
+
+  If the PayloadBufferSize is zero, the security protocol command is sent using the
+  Trusted Non-Data command defined in ATA8-ACS.
+
+  If PayloadBufferSize is too small to store the available data from the security
+  protocol command, the function shall copy PayloadBufferSize bytes into the
+  PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+  If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+  the function shall return EFI_INVALID_PARAMETER.
+
+  If the given DeviceIndex does not support security protocol commands, the function
+  shall return EFI_UNSUPPORTED.
+
+  If the security protocol fails to complete within the Timeout period, the function
+  shall return EFI_TIMEOUT.
+
+  If the security protocol command completes without an error, the function shall
+  return EFI_SUCCESS. If the security protocol command completes with an error, the
+  function shall return EFI_DEVICE_ERROR.
+
+  @param[in]  This             The PPI instance pointer.
+  @param[in]  DeviceIndex      Specifies the storage security device to which the
+                               function wants to talk. Because the driver that
+                               implements Storage Security Command PPIs will manage
+                               multiple storage devices, the PPIs that want to talk
+                               to a single device must specify the device index
+                               that was assigned during the enumeration process.
+                               This index is a number from one to NumberofDevices.
+  @param[in]  Timeout          The timeout, in 100ns units, to use for the execution
+                               of the security protocol command. A Timeout value
+                               of 0 means that this function will wait indefinitely
+                               for the security protocol command to execute. If
+                               Timeout is greater than zero, then this function
+                               will return EFI_TIMEOUT if the time required to
+                               execute the receive data command is greater than
+                               Timeout.
+  @param[in]  SecurityProtocolId
+                               The value of the "Security Protocol" parameter of
+                               the security protocol command to be sent.
+  @param[in]  SecurityProtocolSpecificData
+                               The value of the "Security Protocol Specific"
+                               parameter of the security protocol command to be
+                               sent.
+  @param[in]  PayloadBufferSize
+                               Size in bytes of the payload data buffer.
+  @param[out] PayloadBuffer    A pointer to a destination buffer to store the
+                               security protocol command specific payload data
+                               for the security protocol command. The caller is
+                               responsible for having either implicit or explicit
+                               ownership of the buffer.
+  @param[out] PayloadTransferSize
+                               A pointer to a buffer to store the size in bytes
+                               of the data written to the payload data buffer.
+
+  @retval EFI_SUCCESS                  The security protocol command completed
+                                       successfully.
+  @retval EFI_WARN_BUFFER_TOO_SMALL    The PayloadBufferSize was too small to
+                                       store the available data from the device.
+                                       The PayloadBuffer contains the truncated
+                                       data.
+  @retval EFI_UNSUPPORTED              The given DeviceIndex does not support
+                                       security protocol commands.
+  @retval EFI_DEVICE_ERROR             The security protocol command completed
+                                       with an error.
+  @retval EFI_INVALID_PARAMETER        The PayloadBuffer or PayloadTransferSize
+                                       is NULL and PayloadBufferSize is non-zero.
+  @retval EFI_TIMEOUT                  A timeout occurred while waiting for the
+                                       security protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeStorageSecurityReceiveData (
+  IN  EDKII_PEI_STORAGE_SECURITY_CMD_PPI  *This,
+  IN  UINTN                               DeviceIndex,
+  IN  UINT64                              Timeout,
+  IN  UINT8                               SecurityProtocolId,
+  IN  UINT16                              SecurityProtocolSpecificData,
+  IN  UINTN                               PayloadBufferSize,
+  OUT VOID                                *PayloadBuffer,
+  OUT UINTN                               *PayloadTransferSize
+  );
+
+/**
+  Send a security protocol command to a device.
+
+  The SendData function sends a security protocol command containing the payload
+  PayloadBuffer to the given DeviceIndex. The security protocol command sent is
+  defined by SecurityProtocolId and contains the security protocol specific data
+  SecurityProtocolSpecificData. If the underlying protocol command requires a
+  specific padding for the command payload, the SendData function shall add padding
+  bytes to the command payload to satisfy the padding requirements.
+
+  For devices supporting the SCSI command set, the security protocol command is
+  sent using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+  For devices supporting the ATA command set, the security protocol command is
+  sent using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
+  is non-zero. If the PayloadBufferSize is zero, the security protocol command
+  is sent using the Trusted Non-Data command defined in ATA8-ACS.
+
+  If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
+  return EFI_INVALID_PARAMETER.
+
+  If the given DeviceIndex does not support security protocol commands, the function
+  shall return EFI_UNSUPPORTED.
+
+  If the security protocol fails to complete within the Timeout period, the function
+  shall return EFI_TIMEOUT.
+
+  If the security protocol command completes without an error, the function shall
+  return EFI_SUCCESS. If the security protocol command completes with an error,
+  the functio shall return EFI_DEVICE_ERROR.
+
+  @param[in] This              The PPI instance pointer.
+  @param[in] DeviceIndex       The ID of the device.
+  @param[in] Timeout           The timeout, in 100ns units, to use for the execution
+                               of the security protocol command. A Timeout value
+                               of 0 means that this function will wait indefinitely
+                               for the security protocol command to execute. If
+                               Timeout is greater than zero, then this function
+                               will return EFI_TIMEOUT if the time required to
+                               execute the receive data command is greater than
+                               Timeout.
+  @param[in] SecurityProtocolId
+                               The value of the "Security Protocol" parameter of
+                               the security protocol command to be sent.
+  @param[in] SecurityProtocolSpecificData
+                               The value of the "Security Protocol Specific"
+                               parameter of the security protocol command to be
+                               sent.
+  @param[in] PayloadBufferSize Size in bytes of the payload data buffer.
+  @param[in] PayloadBuffer     A pointer to a destination buffer to store the
+                               security protocol command specific payload data
+                               for the security protocol command.
+
+  @retval EFI_SUCCESS              The security protocol command completed successfully.
+  @retval EFI_UNSUPPORTED          The given DeviceIndex does not support security
+                                   protocol commands.
+  @retval EFI_DEVICE_ERROR         The security protocol command completed with
+                                   an error.
+  @retval EFI_INVALID_PARAMETER    The PayloadBuffer is NULL and PayloadBufferSize
+                                   is non-zero.
+  @retval EFI_TIMEOUT              A timeout occurred while waiting for the security
+                                   protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeStorageSecuritySendData (
+  IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI  *This,
+  IN UINTN                               DeviceIndex,
+  IN UINT64                              Timeout,
+  IN UINT8                               SecurityProtocolId,
+  IN UINT16                              SecurityProtocolSpecificData,
+  IN UINTN                               PayloadBufferSize,
+  IN VOID                                *PayloadBuffer
+  );
+
+#endif
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c b/MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c
new file mode 100644
index 0000000000..5dab447f09
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c
@@ -0,0 +1,231 @@
+/** @file
+  The device path help function.
+
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions
+  of the BSD License which accompanies this distribution.  The
+  full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "NvmExpressPei.h"
+
+//
+// Template for an Nvm Express Device Path node
+//
+NVME_NAMESPACE_DEVICE_PATH  mNvmeDevicePathNodeTemplate = {
+  {        // Header
+    MESSAGING_DEVICE_PATH,
+    MSG_NVME_NAMESPACE_DP,
+    {
+      (UINT8) (sizeof (NVME_NAMESPACE_DEVICE_PATH)),
+      (UINT8) ((sizeof (NVME_NAMESPACE_DEVICE_PATH)) >> 8)
+    }
+  },
+  0x0,     // NamespaceId
+  0x0      // NamespaceUuid
+};
+
+//
+// Template for an End of entire Device Path node
+//
+EFI_DEVICE_PATH_PROTOCOL  mNvmeEndDevicePathNodeTemplate = {
+  END_DEVICE_PATH_TYPE,
+  END_ENTIRE_DEVICE_PATH_SUBTYPE,
+  {
+    (UINT8) (sizeof (EFI_DEVICE_PATH_PROTOCOL)),
+    (UINT8) ((sizeof (EFI_DEVICE_PATH_PROTOCOL)) >> 8)
+  }
+};
+
+/**
+  Returns the 16-bit Length field of a device path node.
+
+  Returns the 16-bit Length field of the device path node specified by Node.
+  Node is not required to be aligned on a 16-bit boundary, so it is recommended
+  that a function such as ReadUnaligned16() be used to extract the contents of
+  the Length field.
+
+  If Node is NULL, then ASSERT().
+
+  @param  Node      A pointer to a device path node data structure.
+
+  @return The 16-bit Length field of the device path node specified by Node.
+
+**/
+UINTN
+DevicePathNodeLength (
+  IN CONST VOID  *Node
+  )
+{
+  ASSERT (Node != NULL);
+  return ReadUnaligned16 ((UINT16 *)&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0]);
+}
+
+/**
+  Returns a pointer to the next node in a device path.
+
+  If Node is NULL, then ASSERT().
+
+  @param  Node    A pointer to a device path node data structure.
+
+  @return a pointer to the device path node that follows the device path node
+  specified by Node.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+NextDevicePathNode (
+  IN CONST VOID  *Node
+  )
+{
+  ASSERT (Node != NULL);
+  return (EFI_DEVICE_PATH_PROTOCOL *)((UINT8 *)(Node) + DevicePathNodeLength(Node));
+}
+
+/**
+  Check the validity of the device path of a NVM Express host controller.
+
+  @param[in] DevicePath          A pointer to the EFI_DEVICE_PATH_PROTOCOL
+                                 structure.
+  @param[in] DevicePathLength    The length of the device path.
+
+  @retval EFI_SUCCESS              The device path is valid.
+  @retval EFI_INVALID_PARAMETER    The device path is invalid.
+
+**/
+EFI_STATUS
+NvmeCheckHcDevicePath (
+  IN EFI_DEVICE_PATH_PROTOCOL    *DevicePath,
+  IN UINTN                       DevicePathLength
+  )
+{
+  EFI_DEVICE_PATH_PROTOCOL    *Start;
+  UINTN                       Size;
+
+  if (DevicePath == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Validate the DevicePathLength is big enough to touch the first node.
+  //
+  if (DevicePathLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Start = DevicePath;
+  while (!(DevicePath->Type == END_DEVICE_PATH_TYPE &&
+           DevicePath->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE)) {
+    DevicePath = NextDevicePathNode (DevicePath);
+
+    //
+    // Prevent overflow and invalid zero in the 'Length' field of a device path
+    // node.
+    //
+    if ((UINTN) DevicePath <= (UINTN) Start) {
+      return EFI_INVALID_PARAMETER;
+    }
+
+    //
+    // Prevent touching memory beyond given DevicePathLength.
+    //
+    if ((UINTN) DevicePath - (UINTN) Start >
+        DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  //
+  // Check if the device path and its size match exactly with each other.
+  //
+  Size = ((UINTN) DevicePath - (UINTN) Start) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
+  if (Size != DevicePathLength) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Build the device path for an Nvm Express device with given namespace identifier
+  and namespace extended unique identifier.
+
+  @param[in]  Private              A pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA
+                                   data structure.
+  @param[in]  NamespaceId          The given namespace identifier.
+  @param[in]  NamespaceUuid        The given namespace extended unique identifier.
+  @param[out] DevicePathLength     The length of the device path in bytes specified
+                                   by DevicePath.
+  @param[out] DevicePath           The device path of Nvm Express device.
+
+  @retval EFI_SUCCESS              The operation succeeds.
+  @retval EFI_INVALID_PARAMETER    The parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES     The operation fails due to lack of resources.
+
+**/
+EFI_STATUS
+NvmeBuildDevicePath (
+  IN  PEI_NVME_CONTROLLER_PRIVATE_DATA    *Private,
+  IN  UINT32                              NamespaceId,
+  IN  UINT64                              NamespaceUuid,
+  OUT UINTN                               *DevicePathLength,
+  OUT EFI_DEVICE_PATH_PROTOCOL            **DevicePath
+  )
+{
+  EFI_DEVICE_PATH_PROTOCOL      *DevicePathWalker;
+  NVME_NAMESPACE_DEVICE_PATH    *NvmeDeviceNode;
+
+  if (DevicePathLength == NULL || DevicePath == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *DevicePathLength = Private->DevicePathLength + sizeof (NVME_NAMESPACE_DEVICE_PATH);
+  *DevicePath       = AllocatePool (*DevicePathLength);
+  if (*DevicePath == NULL) {
+    *DevicePathLength = 0;
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Construct the host controller part device nodes
+  //
+  DevicePathWalker = *DevicePath;
+  CopyMem (
+    DevicePathWalker,
+    Private->DevicePath,
+    Private->DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)
+    );
+
+  //
+  // Construct the Nvm Express device node
+  //
+  DevicePathWalker = (EFI_DEVICE_PATH_PROTOCOL *) ((UINT8 *)DevicePathWalker +
+                     (Private->DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)));
+  CopyMem (
+    DevicePathWalker,
+    &mNvmeDevicePathNodeTemplate,
+    sizeof (mNvmeDevicePathNodeTemplate)
+    );
+  NvmeDeviceNode                = (NVME_NAMESPACE_DEVICE_PATH *)DevicePathWalker;
+  NvmeDeviceNode->NamespaceId   = NamespaceId;
+  NvmeDeviceNode->NamespaceUuid = NamespaceUuid;
+
+  //
+  // Construct the end device node
+  //
+  DevicePathWalker = (EFI_DEVICE_PATH_PROTOCOL *) ((UINT8 *)DevicePathWalker +
+                     sizeof (NVME_NAMESPACE_DEVICE_PATH));
+  CopyMem (
+    DevicePathWalker,
+    &mNvmeEndDevicePathNodeTemplate,
+    sizeof (mNvmeEndDevicePathNodeTemplate)
+    );
+
+  return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c
index 2fe73e942c..96622e6fd5 100644
--- a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c
+++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c
@@ -24,11 +24,17 @@ EFI_PEI_PPI_DESCRIPTOR  mNvmeBlkIoPpiListTemplate = {
 };
 
 EFI_PEI_PPI_DESCRIPTOR  mNvmeBlkIo2PpiListTemplate = {
-  EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
   &gEfiPeiVirtualBlockIo2PpiGuid,
   NULL
 };
 
+EFI_PEI_PPI_DESCRIPTOR  mNvmeStorageSecurityPpiListTemplate = {
+  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+  &gEdkiiPeiStorageSecurityCommandPpiGuid,
+  NULL
+};
+
 EFI_PEI_NOTIFY_DESCRIPTOR  mNvmeEndOfPeiNotifyListTemplate = {
   (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
   &gEfiEndOfPeiSignalPpiGuid,
@@ -185,8 +191,7 @@ NvmePeimEndOfPei (
   PEI_NVME_CONTROLLER_PRIVATE_DATA    *Private;
 
   Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor);
-  NvmeDisableController (Private);
-  NvmeFreeControllerResource (Private);
+  NvmeFreeDmaResource (Private);
 
   return EFI_SUCCESS;
 }
@@ -211,9 +216,13 @@ NvmExpressPeimEntry (
   EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI    *NvmeHcPpi;
   UINT8                                    Controller;
   UINTN                                    MmioBase;
+  UINTN                                    DevicePathLength;
+  EFI_DEVICE_PATH_PROTOCOL                 *DevicePath;
   PEI_NVME_CONTROLLER_PRIVATE_DATA         *Private;
   EFI_PHYSICAL_ADDRESS                     DeviceAddress;
 
+  DEBUG ((DEBUG_INFO, "%a: Enters.\n", __FUNCTION__));
+
   //
   // Locate the NVME host controller PPI
   //
@@ -243,16 +252,41 @@ NvmExpressPeimEntry (
       break;
     }
 
+    Status = NvmeHcPpi->GetNvmeHcDevicePath (
+                          NvmeHcPpi,
+                          Controller,
+                          &DevicePathLength,
+                          &DevicePath
+                          );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((
+        DEBUG_ERROR, "%a: Fail to allocate get the device path for Controller %d.\n",
+        __FUNCTION__, Controller
+        ));
+      return Status;
+    }
+
+    //
+    // Check validity of the device path of the NVM Express controller.
+    //
+    Status = NvmeCheckHcDevicePath (DevicePath, DevicePathLength);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((
+        DEBUG_ERROR, "%a: The device path is invalid for Controller %d.\n",
+        __FUNCTION__, Controller
+        ));
+      Controller++;
+      continue;
+    }
+
     //
     // Memory allocation for controller private data
     //
     Private = AllocateZeroPool (sizeof (PEI_NVME_CONTROLLER_PRIVATE_DATA));
     if (Private == NULL) {
       DEBUG ((
-        DEBUG_ERROR,
-        "%a: Fail to allocate private data for Controller %d.\n",
-        __FUNCTION__,
-        Controller
+        DEBUG_ERROR, "%a: Fail to allocate private data for Controller %d.\n",
+        __FUNCTION__, Controller
         ));
       return EFI_OUT_OF_RESOURCES;
     }
@@ -268,12 +302,9 @@ NvmExpressPeimEntry (
                );
     if (EFI_ERROR (Status)) {
       DEBUG ((
-        DEBUG_ERROR,
-        "%a: Fail to allocate DMA buffers for Controller %d.\n",
-        __FUNCTION__,
-        Controller
+        DEBUG_ERROR, "%a: Fail to allocate DMA buffers for Controller %d.\n",
+        __FUNCTION__, Controller
         ));
-      NvmeFreeControllerResource (Private);
       return Status;
     }
     ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Private->Buffer));
@@ -282,20 +313,10 @@ NvmExpressPeimEntry (
     //
     // Initialize controller private data
     //
-    Private->Signature = NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE;
-    Private->MmioBase  = MmioBase;
-    Private->BlkIoPpi.GetNumberOfBlockDevices  = NvmeBlockIoPeimGetDeviceNo;
-    Private->BlkIoPpi.GetBlockDeviceMediaInfo  = NvmeBlockIoPeimGetMediaInfo;
-    Private->BlkIoPpi.ReadBlocks               = NvmeBlockIoPeimReadBlocks;
-    Private->BlkIo2Ppi.Revision                = EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION;
-    Private->BlkIo2Ppi.GetNumberOfBlockDevices = NvmeBlockIoPeimGetDeviceNo2;
-    Private->BlkIo2Ppi.GetBlockDeviceMediaInfo = NvmeBlockIoPeimGetMediaInfo2;
-    Private->BlkIo2Ppi.ReadBlocks              = NvmeBlockIoPeimReadBlocks2;
-    CopyMem (&Private->BlkIoPpiList, &mNvmeBlkIoPpiListTemplate, sizeof (EFI_PEI_PPI_DESCRIPTOR));
-    CopyMem (&Private->BlkIo2PpiList, &mNvmeBlkIo2PpiListTemplate, sizeof (EFI_PEI_PPI_DESCRIPTOR));
-    CopyMem (&Private->EndOfPeiNotifyList, &mNvmeEndOfPeiNotifyListTemplate, sizeof (EFI_PEI_NOTIFY_DESCRIPTOR));
-    Private->BlkIoPpiList.Ppi   = &Private->BlkIoPpi;
-    Private->BlkIo2PpiList.Ppi  = &Private->BlkIo2Ppi;
+    Private->Signature        = NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE;
+    Private->MmioBase         = MmioBase;
+    Private->DevicePathLength = DevicePathLength;
+    Private->DevicePath       = DevicePath;
 
     //
     // Initialize the NVME controller
@@ -305,11 +326,9 @@ NvmExpressPeimEntry (
       DEBUG ((
         DEBUG_ERROR,
         "%a: Controller initialization fail for Controller %d with Status - %r.\n",
-        __FUNCTION__,
-        Controller,
-        Status
+        __FUNCTION__, Controller, Status
         ));
-      NvmeFreeControllerResource (Private);
+      NvmeFreeDmaResource (Private);
       Controller++;
       continue;
     }
@@ -325,22 +344,68 @@ NvmExpressPeimEntry (
       DEBUG ((
         DEBUG_ERROR,
         "%a: Namespaces discovery fail for Controller %d with Status - %r.\n",
-        __FUNCTION__,
-        Controller,
-        Status
+        __FUNCTION__, Controller, Status
         ));
-      NvmeFreeControllerResource (Private);
+      NvmeFreeDmaResource (Private);
       Controller++;
       continue;
     }
 
+    Private->BlkIoPpi.GetNumberOfBlockDevices  = NvmeBlockIoPeimGetDeviceNo;
+    Private->BlkIoPpi.GetBlockDeviceMediaInfo  = NvmeBlockIoPeimGetMediaInfo;
+    Private->BlkIoPpi.ReadBlocks               = NvmeBlockIoPeimReadBlocks;
+    CopyMem (
+      &Private->BlkIoPpiList,
+      &mNvmeBlkIoPpiListTemplate,
+      sizeof (EFI_PEI_PPI_DESCRIPTOR)
+      );
+    Private->BlkIoPpiList.Ppi                  = &Private->BlkIoPpi;
+
+    Private->BlkIo2Ppi.Revision                = EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION;
+    Private->BlkIo2Ppi.GetNumberOfBlockDevices = NvmeBlockIoPeimGetDeviceNo2;
+    Private->BlkIo2Ppi.GetBlockDeviceMediaInfo = NvmeBlockIoPeimGetMediaInfo2;
+    Private->BlkIo2Ppi.ReadBlocks              = NvmeBlockIoPeimReadBlocks2;
+    CopyMem (
+      &Private->BlkIo2PpiList,
+      &mNvmeBlkIo2PpiListTemplate,
+      sizeof (EFI_PEI_PPI_DESCRIPTOR)
+      );
+    Private->BlkIo2PpiList.Ppi                 = &Private->BlkIo2Ppi;
     PeiServicesInstallPpi (&Private->BlkIoPpiList);
-    PeiServicesNotifyPpi (&Private->EndOfPeiNotifyList);
+
+    //
+    // Check if the NVME controller supports the Security Receive/Send commands
+    //
+    if ((Private->ControllerData->Oacs & SECURITY_SEND_RECEIVE_SUPPORTED) != 0) {
+      DEBUG ((
+        DEBUG_INFO,
+        "%a: Security Security Command PPI will be produced for Controller %d.\n",
+        __FUNCTION__, Controller
+        ));
+      Private->StorageSecurityPpi.Revision           = EDKII_STORAGE_SECURITY_PPI_REVISION;
+      Private->StorageSecurityPpi.GetNumberofDevices = NvmeStorageSecurityGetDeviceNo;
+      Private->StorageSecurityPpi.GetDevicePath      = NvmeStorageSecurityGetDevicePath;
+      Private->StorageSecurityPpi.ReceiveData        = NvmeStorageSecurityReceiveData;
+      Private->StorageSecurityPpi.SendData           = NvmeStorageSecuritySendData;
+      CopyMem (
+        &Private->StorageSecurityPpiList,
+        &mNvmeStorageSecurityPpiListTemplate,
+        sizeof (EFI_PEI_PPI_DESCRIPTOR)
+        );
+      Private->StorageSecurityPpiList.Ppi            = &Private->StorageSecurityPpi;
+      PeiServicesInstallPpi (&Private->StorageSecurityPpiList);
+    }
+
+    CopyMem (
+      &Private->EndOfPeiNotifyList,
+      &mNvmeEndOfPeiNotifyListTemplate,
+      sizeof (EFI_PEI_NOTIFY_DESCRIPTOR)
+      );
+    PeiServicesNotifyPpi  (&Private->EndOfPeiNotifyList);
+
     DEBUG ((
-      DEBUG_INFO,
-      "%a: BlockIO PPI has been installed on Controller %d.\n",
-      __FUNCTION__,
-      Controller
+      DEBUG_INFO, "%a: Controller %d has been successfully initialized.\n",
+      __FUNCTION__, Controller
       ));
     Controller++;
   }
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.c b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.c
index d4056a2a5b..b9fa3230f8 100644
--- a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.c
+++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.c
@@ -2,7 +2,7 @@
   The NvmExpressPei driver is used to manage non-volatile memory subsystem
   which follows NVM Express specification at PEI phase.
 
-  Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
 
   This program and the accompanying materials
   are licensed and made available under the terms and conditions
@@ -702,47 +702,25 @@ NvmeControllerInit (
 }
 
 /**
-  Free the resources allocated by an NVME controller.
+  Free the DMA resources allocated by an NVME controller.
 
   @param[in] Private     The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
 
 **/
 VOID
-NvmeFreeControllerResource (
+NvmeFreeDmaResource (
   IN PEI_NVME_CONTROLLER_PRIVATE_DATA    *Private
   )
 {
-  //
-  // Free the controller data buffer
-  //
-  if (Private->ControllerData != NULL) {
-    FreePool (Private->ControllerData);
-    Private->ControllerData = NULL;
-  }
+  ASSERT (Private != NULL);
 
-  //
-  // Free the DMA buffers
-  //
-  if (Private->Buffer != NULL) {
+  if (Private->BufferMapping != NULL) {
     IoMmuFreeBuffer (
        NVME_MEM_MAX_PAGES,
        Private->Buffer,
        Private->BufferMapping
        );
-    Private->Buffer = NULL;
   }
 
-  //
-  // Free the namespaces information buffer
-  //
-  if (Private->NamespaceInfo != NULL) {
-    FreePool (Private->NamespaceInfo);
-    Private->NamespaceInfo = NULL;
-  }
-
-  //
-  // Free the controller private data structure
-  //
-  FreePool (Private);
   return;
 }
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiStorageSecurity.c b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiStorageSecurity.c
new file mode 100644
index 0000000000..e5a2cef3d6
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiStorageSecurity.c
@@ -0,0 +1,423 @@
+/** @file
+  The NvmExpressPei driver is used to manage non-volatile memory subsystem
+  which follows NVM Express specification at PEI phase.
+
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions
+  of the BSD License which accompanies this distribution.  The
+  full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "NvmExpressPei.h"
+
+/**
+  Trust transfer data from/to NVM Express device.
+
+  This function performs one NVMe transaction to do a trust transfer from/to NVM
+  Express device.
+
+  @param[in]     Private           The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA
+                                   data structure.
+  @param[in,out] Buffer            The pointer to the current transaction buffer.
+  @param[in]     SecurityProtocolId
+                                   The value of the "Security Protocol" parameter
+                                   of the security protocol command to be sent.
+  @param[in]     SecurityProtocolSpecificData
+                                   The value of the "Security Protocol Specific"
+                                   parameter of the security protocol command to
+                                   be sent.
+  @param[in]     TransferLength    The block number or sector count of the transfer.
+  @param[in]     IsTrustSend       Indicates whether it is a trust send operation
+                                   or not.
+  @param[in]     Timeout           The timeout, in 100ns units, to use for the
+                                   execution of the security protocol command.
+                                   A Timeout value of 0 means that this function
+                                   will wait indefinitely for the security protocol
+                                   command to execute. If Timeout is greater than
+                                   zero, then this function will return EFI_TIMEOUT
+                                   if the time required to execute the receive
+                                   data command is greater than Timeout.
+  @param[out]    TransferLengthOut A pointer to a buffer to store the size in bytes
+                                   of the data written to the buffer. Ignore it
+                                   when IsTrustSend is TRUE.
+
+  @retval EFI_SUCCESS    The data transfer is complete successfully.
+  @return others         Some error occurs when transferring data.
+
+**/
+EFI_STATUS
+TrustTransferNvmeDevice (
+  IN     PEI_NVME_CONTROLLER_PRIVATE_DATA    *Private,
+  IN OUT VOID                                *Buffer,
+  IN     UINT8                               SecurityProtocolId,
+  IN     UINT16                              SecurityProtocolSpecificData,
+  IN     UINTN                               TransferLength,
+  IN     BOOLEAN                             IsTrustSend,
+  IN     UINT64                              Timeout,
+     OUT UINTN                               *TransferLengthOut
+  )
+{
+  EDKII_PEI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET    CommandPacket;
+  EDKII_PEI_NVM_EXPRESS_COMMAND                     Command;
+  EDKII_PEI_NVM_EXPRESS_COMPLETION                  Completion;
+  EFI_STATUS                                        Status;
+  UINT16                                            SpecificData;
+
+  ZeroMem (&CommandPacket, sizeof(EDKII_PEI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+  ZeroMem (&Command, sizeof(EDKII_PEI_NVM_EXPRESS_COMMAND));
+  ZeroMem (&Completion, sizeof(EDKII_PEI_NVM_EXPRESS_COMPLETION));
+
+  CommandPacket.NvmeCmd        = &Command;
+  CommandPacket.NvmeCompletion = &Completion;
+
+  //
+  // Change Endianness of SecurityProtocolSpecificData
+  //
+  SpecificData = (((SecurityProtocolSpecificData << 8) & 0xFF00) | (SecurityProtocolSpecificData >> 8));
+
+  if (IsTrustSend) {
+    Command.Cdw0.Opcode          = NVME_ADMIN_SECURITY_SEND_CMD;
+    CommandPacket.TransferBuffer = Buffer;
+    CommandPacket.TransferLength = (UINT32)TransferLength;
+    CommandPacket.NvmeCmd->Cdw10 = (UINT32)((SecurityProtocolId << 24) | (SpecificData << 8));
+    CommandPacket.NvmeCmd->Cdw11 = (UINT32)TransferLength;
+  } else {
+    Command.Cdw0.Opcode          = NVME_ADMIN_SECURITY_RECEIVE_CMD;
+    CommandPacket.TransferBuffer = Buffer;
+    CommandPacket.TransferLength = (UINT32)TransferLength;
+    CommandPacket.NvmeCmd->Cdw10 = (UINT32)((SecurityProtocolId << 24) | (SpecificData << 8));
+    CommandPacket.NvmeCmd->Cdw11 = (UINT32)TransferLength;
+  }
+
+  CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
+  CommandPacket.NvmeCmd->Nsid  = NVME_CONTROLLER_NSID;
+  CommandPacket.CommandTimeout = Timeout;
+  CommandPacket.QueueType      = NVME_ADMIN_QUEUE;
+
+  Status = NvmePassThru (
+             Private,
+             NVME_CONTROLLER_NSID,
+             &CommandPacket
+             );
+
+  if (!IsTrustSend) {
+    if (EFI_ERROR (Status))  {
+      *TransferLengthOut = 0;
+    } else {
+      *TransferLengthOut = (UINTN) TransferLength;
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Gets the count of storage security devices that one specific driver detects.
+
+  @param[in]  This               The PPI instance pointer.
+  @param[out] NumberofDevices    The number of storage security devices discovered.
+
+  @retval EFI_SUCCESS              The operation performed successfully.
+  @retval EFI_INVALID_PARAMETER    The parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeStorageSecurityGetDeviceNo (
+  IN  EDKII_PEI_STORAGE_SECURITY_CMD_PPI    *This,
+  OUT UINTN                                 *NumberofDevices
+  )
+{
+  PEI_NVME_CONTROLLER_PRIVATE_DATA    *Private;
+
+  if (This == NULL || NumberofDevices == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
+  *NumberofDevices = Private->ActiveNamespaceNum;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Gets the device path of a specific storage security device.
+
+  @param[in]  This                 The PPI instance pointer.
+  @param[in]  DeviceIndex          Specifies the storage security device to which
+                                   the function wants to talk. Because the driver
+                                   that implements Storage Security Command PPIs
+                                   will manage multiple storage devices, the PPIs
+                                   that want to talk to a single device must specify
+                                   the device index that was assigned during the
+                                   enumeration process. This index is a number from
+                                   one to NumberofDevices.
+  @param[out] DevicePathLength     The length of the device path in bytes specified
+                                   by DevicePath.
+  @param[out] DevicePath           The device path of storage security device.
+                                   This field re-uses EFI Device Path Protocol as
+                                   defined by Section 10.2 EFI Device Path Protocol
+                                   of UEFI 2.7 Specification.
+
+  @retval EFI_SUCCESS              The operation succeeds.
+  @retval EFI_INVALID_PARAMETER    DevicePathLength or DevicePath is NULL.
+  @retval EFI_NOT_FOUND            The specified storage security device not found.
+  @retval EFI_OUT_OF_RESOURCES     The operation fails due to lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeStorageSecurityGetDevicePath (
+  IN  EDKII_PEI_STORAGE_SECURITY_CMD_PPI  *This,
+  IN  UINTN                               DeviceIndex,
+  OUT UINTN                               *DevicePathLength,
+  OUT EFI_DEVICE_PATH_PROTOCOL            **DevicePath
+  )
+{
+  PEI_NVME_CONTROLLER_PRIVATE_DATA         *Private;
+
+  if (This == NULL || DevicePathLength == NULL || DevicePath == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
+  if ((DeviceIndex == 0) || (DeviceIndex > Private->ActiveNamespaceNum)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return NvmeBuildDevicePath (
+           Private,
+           Private->NamespaceInfo[DeviceIndex-1].NamespaceId,
+           Private->NamespaceInfo[DeviceIndex-1].NamespaceUuid,
+           DevicePathLength,
+           DevicePath
+           );
+}
+
+/**
+  Send a security protocol command to a device that receives data and/or the result
+  of one or more commands sent by SendData.
+
+  The ReceiveData function sends a security protocol command to the given DeviceIndex.
+  The security protocol command sent is defined by SecurityProtocolId and contains
+  the security protocol specific data SecurityProtocolSpecificData. The function
+  returns the data from the security protocol command in PayloadBuffer.
+
+  For devices supporting the SCSI command set, the security protocol command is sent
+  using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+  For devices supporting the ATA command set, the security protocol command is sent
+  using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+  is non-zero.
+
+  If the PayloadBufferSize is zero, the security protocol command is sent using the
+  Trusted Non-Data command defined in ATA8-ACS.
+
+  If PayloadBufferSize is too small to store the available data from the security
+  protocol command, the function shall copy PayloadBufferSize bytes into the
+  PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+  If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+  the function shall return EFI_INVALID_PARAMETER.
+
+  If the given DeviceIndex does not support security protocol commands, the function
+  shall return EFI_UNSUPPORTED.
+
+  If the security protocol fails to complete within the Timeout period, the function
+  shall return EFI_TIMEOUT.
+
+  If the security protocol command completes without an error, the function shall
+  return EFI_SUCCESS. If the security protocol command completes with an error, the
+  function shall return EFI_DEVICE_ERROR.
+
+  @param[in]  This             The PPI instance pointer.
+  @param[in]  DeviceIndex      Specifies the storage security device to which the
+                               function wants to talk. Because the driver that
+                               implements Storage Security Command PPIs will manage
+                               multiple storage devices, the PPIs that want to talk
+                               to a single device must specify the device index
+                               that was assigned during the enumeration process.
+                               This index is a number from one to NumberofDevices.
+  @param[in]  Timeout          The timeout, in 100ns units, to use for the execution
+                               of the security protocol command. A Timeout value
+                               of 0 means that this function will wait indefinitely
+                               for the security protocol command to execute. If
+                               Timeout is greater than zero, then this function
+                               will return EFI_TIMEOUT if the time required to
+                               execute the receive data command is greater than
+                               Timeout.
+  @param[in]  SecurityProtocolId
+                               The value of the "Security Protocol" parameter of
+                               the security protocol command to be sent.
+  @param[in]  SecurityProtocolSpecificData
+                               The value of the "Security Protocol Specific"
+                               parameter of the security protocol command to be
+                               sent.
+  @param[in]  PayloadBufferSize
+                               Size in bytes of the payload data buffer.
+  @param[out] PayloadBuffer    A pointer to a destination buffer to store the
+                               security protocol command specific payload data
+                               for the security protocol command. The caller is
+                               responsible for having either implicit or explicit
+                               ownership of the buffer.
+  @param[out] PayloadTransferSize
+                               A pointer to a buffer to store the size in bytes
+                               of the data written to the payload data buffer.
+
+  @retval EFI_SUCCESS                  The security protocol command completed
+                                       successfully.
+  @retval EFI_WARN_BUFFER_TOO_SMALL    The PayloadBufferSize was too small to
+                                       store the available data from the device.
+                                       The PayloadBuffer contains the truncated
+                                       data.
+  @retval EFI_UNSUPPORTED              The given DeviceIndex does not support
+                                       security protocol commands.
+  @retval EFI_DEVICE_ERROR             The security protocol command completed
+                                       with an error.
+  @retval EFI_INVALID_PARAMETER        The PayloadBuffer or PayloadTransferSize
+                                       is NULL and PayloadBufferSize is non-zero.
+  @retval EFI_TIMEOUT                  A timeout occurred while waiting for the
+                                       security protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeStorageSecurityReceiveData (
+  IN  EDKII_PEI_STORAGE_SECURITY_CMD_PPI  *This,
+  IN  UINTN                               DeviceIndex,
+  IN  UINT64                              Timeout,
+  IN  UINT8                               SecurityProtocolId,
+  IN  UINT16                              SecurityProtocolSpecificData,
+  IN  UINTN                               PayloadBufferSize,
+  OUT VOID                                *PayloadBuffer,
+  OUT UINTN                               *PayloadTransferSize
+  )
+{
+  PEI_NVME_CONTROLLER_PRIVATE_DATA    *Private;
+  EFI_STATUS                          Status;
+
+  if ((PayloadBuffer == NULL) || (PayloadTransferSize == NULL) || (PayloadBufferSize == 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
+
+  Status = TrustTransferNvmeDevice (
+             Private,
+             PayloadBuffer,
+             SecurityProtocolId,
+             SecurityProtocolSpecificData,
+             PayloadBufferSize,
+             FALSE,
+             Timeout,
+             PayloadTransferSize
+             );
+
+  return Status;
+}
+
+/**
+  Send a security protocol command to a device.
+
+  The SendData function sends a security protocol command containing the payload
+  PayloadBuffer to the given DeviceIndex. The security protocol command sent is
+  defined by SecurityProtocolId and contains the security protocol specific data
+  SecurityProtocolSpecificData. If the underlying protocol command requires a
+  specific padding for the command payload, the SendData function shall add padding
+  bytes to the command payload to satisfy the padding requirements.
+
+  For devices supporting the SCSI command set, the security protocol command is
+  sent using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+  For devices supporting the ATA command set, the security protocol command is
+  sent using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
+  is non-zero. If the PayloadBufferSize is zero, the security protocol command
+  is sent using the Trusted Non-Data command defined in ATA8-ACS.
+
+  If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
+  return EFI_INVALID_PARAMETER.
+
+  If the given DeviceIndex does not support security protocol commands, the function
+  shall return EFI_UNSUPPORTED.
+
+  If the security protocol fails to complete within the Timeout period, the function
+  shall return EFI_TIMEOUT.
+
+  If the security protocol command completes without an error, the function shall
+  return EFI_SUCCESS. If the security protocol command completes with an error,
+  the functio shall return EFI_DEVICE_ERROR.
+
+  @param[in] This              The PPI instance pointer.
+  @param[in] DeviceIndex       The ID of the device.
+  @param[in] Timeout           The timeout, in 100ns units, to use for the execution
+                               of the security protocol command. A Timeout value
+                               of 0 means that this function will wait indefinitely
+                               for the security protocol command to execute. If
+                               Timeout is greater than zero, then this function
+                               will return EFI_TIMEOUT if the time required to
+                               execute the receive data command is greater than
+                               Timeout.
+  @param[in] SecurityProtocolId
+                               The value of the "Security Protocol" parameter of
+                               the security protocol command to be sent.
+  @param[in] SecurityProtocolSpecificData
+                               The value of the "Security Protocol Specific"
+                               parameter of the security protocol command to be
+                               sent.
+  @param[in] PayloadBufferSize Size in bytes of the payload data buffer.
+  @param[in] PayloadBuffer     A pointer to a destination buffer to store the
+                               security protocol command specific payload data
+                               for the security protocol command.
+
+  @retval EFI_SUCCESS              The security protocol command completed successfully.
+  @retval EFI_UNSUPPORTED          The given DeviceIndex does not support security
+                                   protocol commands.
+  @retval EFI_DEVICE_ERROR         The security protocol command completed with
+                                   an error.
+  @retval EFI_INVALID_PARAMETER    The PayloadBuffer is NULL and PayloadBufferSize
+                                   is non-zero.
+  @retval EFI_TIMEOUT              A timeout occurred while waiting for the security
+                                   protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeStorageSecuritySendData (
+  IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI  *This,
+  IN UINTN                               DeviceIndex,
+  IN UINT64                              Timeout,
+  IN UINT8                               SecurityProtocolId,
+  IN UINT16                              SecurityProtocolSpecificData,
+  IN UINTN                               PayloadBufferSize,
+  IN VOID                                *PayloadBuffer
+  )
+{
+  PEI_NVME_CONTROLLER_PRIVATE_DATA    *Private;
+  EFI_STATUS                          Status;
+
+  if ((PayloadBuffer == NULL) && (PayloadBufferSize != 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
+
+  Status = TrustTransferNvmeDevice (
+             Private,
+             PayloadBuffer,
+             SecurityProtocolId,
+             SecurityProtocolSpecificData,
+             PayloadBufferSize,
+             TRUE,
+             Timeout,
+             NULL
+             );
+
+  return Status;
+}
-- 
2.12.0.windows.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 07/12] MdeModulePkg/NvmExpressPei: Consume S3StorageDeviceInitList LockBox
  2019-02-01  5:47 [PATCH v3 00/12] Split the S3 PEI phase HW init codes from Opal driver Hao Wu
                   ` (5 preceding siblings ...)
  2019-02-01  5:47 ` [PATCH v3 06/12] MdeModulePkg/NvmExpressPei: Add logic to produce SSC PPI Hao Wu
@ 2019-02-01  5:47 ` Hao Wu
  2019-02-01  5:47 ` [PATCH v3 08/12] MdeModulePkg/AhciPei: Add AHCI mode ATA device support in PEI Hao Wu
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Hao Wu @ 2019-02-01  5:47 UTC (permalink / raw)
  To: edk2-devel; +Cc: Hao Wu, Jian J Wang, Ray Ni, Eric Dong

REF:https://bugzilla.tianocore.org/show_bug.cgi?id=1409

For the NvmExpressPei driver, this commit will update the driver to
consume the S3StorageDeviceInitList LockBox in S3 phase. The purpose is to
perform an on-demand (partial) NVM Express device
enumeration/initialization to benefit the S3 resume performance.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Hao Wu <hao.a.wu@intel.com>
---
 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf |   8 +-
 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h   |  36 +++++++
 MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c      |  53 +++++++++
 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c   |  20 ++++
 MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiS3.c | 114 ++++++++++++++++++++
 5 files changed, 230 insertions(+), 1 deletion(-)

diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf
index 0666e5892b..22b703e971 100644
--- a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf
+++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf
@@ -40,6 +40,7 @@
   NvmExpressPeiHci.h
   NvmExpressPeiPassThru.c
   NvmExpressPeiPassThru.h
+  NvmExpressPeiS3.c
   NvmExpressPeiStorageSecurity.c
   NvmExpressPeiStorageSecurity.h
 
@@ -54,6 +55,7 @@
   BaseMemoryLib
   IoLib
   TimerLib
+  LockBoxLib
   PeimEntryPoint
 
 [Ppis]
@@ -64,9 +66,13 @@
   gEfiPeiVirtualBlockIo2PpiGuid                  ## SOMETIMES_PRODUCES
   gEdkiiPeiStorageSecurityCommandPpiGuid         ## SOMETIMES_PRODUCES
 
+[Guids]
+  gS3StorageDeviceInitListGuid                   ## SOMETIMES_CONSUMES ## UNDEFINED
+
 [Depex]
   gEfiPeiMemoryDiscoveredPpiGuid AND
-  gEdkiiPeiNvmExpressHostControllerPpiGuid
+  gEdkiiPeiNvmExpressHostControllerPpiGuid AND
+  gEfiPeiMasterBootModePpiGuid
 
 [UserExtensions.TianoCore."ExtraFiles"]
   NvmExpressPeiExtra.uni
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h
index 92c3854c6e..e2a693abe8 100644
--- a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h
+++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h
@@ -267,6 +267,26 @@ NvmePeimEndOfPei (
   );
 
 /**
+  Get the size of the current device path instance.
+
+  @param[in]  DevicePath             A pointer to the EFI_DEVICE_PATH_PROTOCOL
+                                     structure.
+  @param[out] InstanceSize           The size of the current device path instance.
+  @param[out] EntireDevicePathEnd    Indicate whether the instance is the last
+                                     one in the device path strucure.
+
+  @retval EFI_SUCCESS    The size of the current device path instance is fetched.
+  @retval Others         Fails to get the size of the current device path instance.
+
+**/
+EFI_STATUS
+GetDevicePathInstanceSize (
+  IN  EFI_DEVICE_PATH_PROTOCOL    *DevicePath,
+  OUT UINTN                       *InstanceSize,
+  OUT BOOLEAN                     *EntireDevicePathEnd
+  );
+
+/**
   Check the validity of the device path of a NVM Express host controller.
 
   @param[in] DevicePath          A pointer to the EFI_DEVICE_PATH_PROTOCOL
@@ -309,4 +329,20 @@ NvmeBuildDevicePath (
   OUT EFI_DEVICE_PATH_PROTOCOL            **DevicePath
   );
 
+/**
+  Determine if a specific NVM Express controller can be skipped for S3 phase.
+
+  @param[in]  HcDevicePath          Device path of the controller.
+  @param[in]  HcDevicePathLength    Length of the device path specified by
+                                    HcDevicePath.
+
+  @retval    The number of ports that need to be enumerated.
+
+**/
+BOOLEAN
+NvmeS3SkipThisController (
+  IN  EFI_DEVICE_PATH_PROTOCOL    *HcDevicePath,
+  IN  UINTN                       HcDevicePathLength
+  );
+
 #endif
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c b/MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c
index 5dab447f09..ed05d7a2be 100644
--- a/MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c
+++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c
@@ -89,6 +89,59 @@ NextDevicePathNode (
 }
 
 /**
+  Get the size of the current device path instance.
+
+  @param[in]  DevicePath             A pointer to the EFI_DEVICE_PATH_PROTOCOL
+                                     structure.
+  @param[out] InstanceSize           The size of the current device path instance.
+  @param[out] EntireDevicePathEnd    Indicate whether the instance is the last
+                                     one in the device path strucure.
+
+  @retval EFI_SUCCESS    The size of the current device path instance is fetched.
+  @retval Others         Fails to get the size of the current device path instance.
+
+**/
+EFI_STATUS
+GetDevicePathInstanceSize (
+  IN  EFI_DEVICE_PATH_PROTOCOL    *DevicePath,
+  OUT UINTN                       *InstanceSize,
+  OUT BOOLEAN                     *EntireDevicePathEnd
+  )
+{
+  EFI_DEVICE_PATH_PROTOCOL    *Walker;
+
+  if (DevicePath == NULL || InstanceSize == NULL || EntireDevicePathEnd == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Find the end of the device path instance
+  //
+  Walker = DevicePath;
+  while (Walker->Type != END_DEVICE_PATH_TYPE) {
+    Walker = NextDevicePathNode (Walker);
+  }
+
+  //
+  // Check if 'Walker' points to the end of an entire device path
+  //
+  if (Walker->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
+    *EntireDevicePathEnd = TRUE;
+  } else if (Walker->SubType == END_INSTANCE_DEVICE_PATH_SUBTYPE) {
+    *EntireDevicePathEnd = FALSE;
+  } else {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Compute the size of the device path instance
+  //
+  *InstanceSize = ((UINTN) Walker - (UINTN) (DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
+
+  return EFI_SUCCESS;
+}
+
+/**
   Check the validity of the device path of a NVM Express host controller.
 
   @param[in] DevicePath          A pointer to the EFI_DEVICE_PATH_PROTOCOL
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c
index 96622e6fd5..43b2dfc3e7 100644
--- a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c
+++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c
@@ -213,6 +213,7 @@ NvmExpressPeimEntry (
   )
 {
   EFI_STATUS                               Status;
+  EFI_BOOT_MODE                            BootMode;
   EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI    *NvmeHcPpi;
   UINT8                                    Controller;
   UINTN                                    MmioBase;
@@ -224,6 +225,15 @@ NvmExpressPeimEntry (
   DEBUG ((DEBUG_INFO, "%a: Enters.\n", __FUNCTION__));
 
   //
+  // Get the current boot mode.
+  //
+  Status = PeiServicesGetBootMode (&BootMode);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Fail to get the current boot mode.\n", __FUNCTION__));
+    return Status;
+  }
+
+  //
   // Locate the NVME host controller PPI
   //
   Status = PeiServicesLocatePpi (
@@ -279,6 +289,16 @@ NvmExpressPeimEntry (
       continue;
     }
 
+    if ((BootMode == BOOT_ON_S3_RESUME) &&
+        (NvmeS3SkipThisController (DevicePath, DevicePathLength))) {
+      DEBUG ((
+        DEBUG_ERROR, "%a: Controller %d is skipped during S3.\n",
+        __FUNCTION__, Controller
+        ));
+      Controller++;
+      continue;
+    }
+
     //
     // Memory allocation for controller private data
     //
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiS3.c b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiS3.c
new file mode 100644
index 0000000000..eb3af75b89
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiS3.c
@@ -0,0 +1,114 @@
+/** @file
+  The NvmExpressPei driver is used to manage non-volatile memory subsystem
+  which follows NVM Express specification at PEI phase.
+
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions
+  of the BSD License which accompanies this distribution.  The
+  full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "NvmExpressPei.h"
+
+#include <Guid/S3StorageDeviceInitList.h>
+
+#include <Library/LockBoxLib.h>
+
+/**
+  Determine if a specific NVM Express controller can be skipped for S3 phase.
+
+  @param[in]  HcDevicePath          Device path of the controller.
+  @param[in]  HcDevicePathLength    Length of the device path specified by
+                                    HcDevicePath.
+
+  @retval    The number of ports that need to be enumerated.
+
+**/
+BOOLEAN
+NvmeS3SkipThisController (
+  IN  EFI_DEVICE_PATH_PROTOCOL    *HcDevicePath,
+  IN  UINTN                       HcDevicePathLength
+  )
+{
+  EFI_STATUS                  Status;
+  UINT8                       DummyData;
+  UINTN                       S3InitDevicesLength;
+  EFI_DEVICE_PATH_PROTOCOL    *S3InitDevices;
+  EFI_DEVICE_PATH_PROTOCOL    *DevicePathInst;
+  UINTN                       DevicePathInstLength;
+  BOOLEAN                     EntireEnd;
+  BOOLEAN                     Skip;
+
+  //
+  // From the LockBox, get the list of device paths for devices need to be
+  // initialized in S3.
+  //
+  S3InitDevices       = NULL;
+  S3InitDevicesLength = sizeof (DummyData);
+  EntireEnd           = FALSE;
+  Skip                = TRUE;
+  Status = RestoreLockBox (&gS3StorageDeviceInitListGuid, &DummyData, &S3InitDevicesLength);
+  if (Status != EFI_BUFFER_TOO_SMALL) {
+    return Skip;
+  } else {
+    S3InitDevices = AllocatePool (S3InitDevicesLength);
+    if (S3InitDevices == NULL) {
+      return Skip;
+    }
+
+    Status = RestoreLockBox (&gS3StorageDeviceInitListGuid, S3InitDevices, &S3InitDevicesLength);
+    if (EFI_ERROR (Status)) {
+      return Skip;
+    }
+  }
+
+  if (S3InitDevices == NULL) {
+    return Skip;
+  }
+
+  //
+  // Only need to initialize the controllers that exist in the device list.
+  //
+  do {
+    //
+    // Fetch the size of current device path instance.
+    //
+    Status = GetDevicePathInstanceSize (
+               S3InitDevices,
+               &DevicePathInstLength,
+               &EntireEnd
+               );
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    DevicePathInst = S3InitDevices;
+    S3InitDevices  = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN) S3InitDevices + DevicePathInstLength);
+
+    if (HcDevicePathLength >= DevicePathInstLength) {
+      continue;
+    }
+
+    //
+    // Compare the device paths to determine if the device is managed by this
+    // controller.
+    //
+    if (CompareMem (
+          DevicePathInst,
+          HcDevicePath,
+          HcDevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)
+          ) == 0) {
+      Skip = FALSE;
+      break;
+    }
+  } while (!EntireEnd);
+
+  return Skip;
+}
-- 
2.12.0.windows.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 08/12] MdeModulePkg/AhciPei: Add AHCI mode ATA device support in PEI
  2019-02-01  5:47 [PATCH v3 00/12] Split the S3 PEI phase HW init codes from Opal driver Hao Wu
                   ` (6 preceding siblings ...)
  2019-02-01  5:47 ` [PATCH v3 07/12] MdeModulePkg/NvmExpressPei: Consume S3StorageDeviceInitList LockBox Hao Wu
@ 2019-02-01  5:47 ` Hao Wu
  2019-02-01  5:47 ` [PATCH v3 09/12] MdeModulePkg/SmmLockBoxLib: Use 'DEBUG_' prefix instead of 'EFI_D_' Hao Wu
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Hao Wu @ 2019-02-01  5:47 UTC (permalink / raw)
  To: edk2-devel; +Cc: Hao Wu, Jian J Wang, Ray Ni, Eric Dong

REF:https://bugzilla.tianocore.org/show_bug.cgi?id=1409

This commit will add the AHCI mode ATA device support in the PEI phase.

More specifically, the newly add AhciPei driver will consume the ATA AHCI
host controller PPI for ATA controllers working under AHCI code within the
system. And then produces the below PPIs for each controller:

EDKII PEI ATA PassThru PPI
Storage Security Command PPI

Also, the driver will consume the S3StorageDeviceInitList LockBox in S3
phase. The purpose is to perform an on-demand (partial) ATA device
enumeration/initialization on each controller to benefit the S3 resume
performance.

The implementation of this driver is currently based on the below
specifications:
Serial ATA Revision 2.6
Serial ATA Advanced Host Controller Interface (AHCI) 1.3.1
AT Attachment with Packet Interface - 6 (ATA/ATAPI-6)

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Hao Wu <hao.a.wu@intel.com>
---
 MdeModulePkg/MdeModulePkg.dsc                         |    1 +
 MdeModulePkg/Bus/Ata/AhciPei/AhciPei.inf              |   74 +
 MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h                |  708 +++++++
 MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.h        |  184 ++
 MdeModulePkg/Bus/Ata/AhciPei/AhciPeiStorageSecurity.h |  247 +++
 MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c               | 2015 ++++++++++++++++++++
 MdeModulePkg/Bus/Ata/AhciPei/AhciPei.c                |  304 +++
 MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.c        |  521 +++++
 MdeModulePkg/Bus/Ata/AhciPei/AhciPeiS3.c              |  139 ++
 MdeModulePkg/Bus/Ata/AhciPei/AhciPeiStorageSecurity.c |  391 ++++
 MdeModulePkg/Bus/Ata/AhciPei/DevicePath.c             |  284 +++
 MdeModulePkg/Bus/Ata/AhciPei/DmaMem.c                 |  270 +++
 MdeModulePkg/Bus/Ata/AhciPei/AhciPei.uni              |   21 +
 MdeModulePkg/Bus/Ata/AhciPei/AhciPeiExtra.uni         |   19 +
 14 files changed, 5178 insertions(+)

diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc
index 4f2ac8ae89..b4ebd845d3 100644
--- a/MdeModulePkg/MdeModulePkg.dsc
+++ b/MdeModulePkg/MdeModulePkg.dsc
@@ -241,6 +241,7 @@
   MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxe.inf
   MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf
   MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf
+  MdeModulePkg/Bus/Ata/AhciPei/AhciPei.inf
   MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf
   MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
   MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.inf b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.inf
new file mode 100644
index 0000000000..e02d2272fb
--- /dev/null
+++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.inf
@@ -0,0 +1,74 @@
+## @file
+#  The AhciPei driver is used to manage ATA hard disk device working under AHCI
+#  mode at PEI phase.
+#
+#  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+#
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD License
+#  which accompanies this distribution.  The full text of the license may be found at
+#  http://opensource.org/licenses/bsd-license.php
+#
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = AhciPei
+  MODULE_UNI_FILE                = AhciPei.uni
+  FILE_GUID                      = 79E5CA15-7A2D-4F37-A63B-D1C7BBCA47AD
+  MODULE_TYPE                    = PEIM
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = AtaAhciPeimEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  AhciPei.c
+  AhciPei.h
+  AhciPeiPassThru.c
+  AhciPeiPassThru.h
+  AhciPeiS3.c
+  AhciPeiStorageSecurity.c
+  AhciPeiStorageSecurity.h
+  AhciMode.c
+  DevicePath.c
+  DmaMem.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  DebugLib
+  PeiServicesLib
+  MemoryAllocationLib
+  BaseMemoryLib
+  IoLib
+  TimerLib
+  LockBoxLib
+  PeimEntryPoint
+
+[Ppis]
+  gEdkiiPeiAtaAhciHostControllerPpiGuid          ## CONSUMES
+  gEdkiiIoMmuPpiGuid                             ## CONSUMES
+  gEfiEndOfPeiSignalPpiGuid                      ## CONSUMES
+  gEdkiiPeiAtaPassThruPpiGuid                    ## SOMETIMES_PRODUCES
+  gEdkiiPeiStorageSecurityCommandPpiGuid         ## SOMETIMES_PRODUCES
+
+[Guids]
+  gS3StorageDeviceInitListGuid                   ## SOMETIMES_CONSUMES ## UNDEFINED
+
+[Depex]
+  gEfiPeiMemoryDiscoveredPpiGuid AND
+  gEfiPeiMasterBootModePpiGuid AND
+  gEdkiiPeiAtaAhciHostControllerPpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+  AhciPeiExtra.uni
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h
new file mode 100644
index 0000000000..e53330b2e1
--- /dev/null
+++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h
@@ -0,0 +1,708 @@
+/** @file
+  The AhciPei driver is used to manage ATA hard disk device working under AHCI
+  mode at PEI phase.
+
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions
+  of the BSD License which accompanies this distribution.  The
+  full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _AHCI_PEI_H_
+#define _AHCI_PEI_H_
+
+#include <PiPei.h>
+
+#include <IndustryStandard/Atapi.h>
+
+#include <Ppi/AtaAhciController.h>
+#include <Ppi/IoMmu.h>
+#include <Ppi/EndOfPeiPhase.h>
+#include <Ppi/AtaPassThru.h>
+#include <Ppi/BlockIo2.h>
+#include <Ppi/StorageSecurityCommand.h>
+
+#include <Library/DebugLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/IoLib.h>
+#include <Library/TimerLib.h>
+
+//
+// Structure forward declarations
+//
+typedef struct _PEI_AHCI_CONTROLLER_PRIVATE_DATA  PEI_AHCI_CONTROLLER_PRIVATE_DATA;
+
+#include "AhciPeiPassThru.h"
+#include "AhciPeiStorageSecurity.h"
+
+//
+// ATA AHCI driver implementation related definitions
+//
+//
+// Refer SATA1.0a spec section 5.2, the Phy detection time should be less than 10ms.
+// The value is in millisecond units. Add a bit of margin for robustness.
+//
+#define AHCI_BUS_PHY_DETECT_TIMEOUT            15
+//
+// Refer SATA1.0a spec, the bus reset time should be less than 1s.
+// The value is in 100ns units.
+//
+#define AHCI_PEI_RESET_TIMEOUT                 10000000
+//
+// Time out Value for ATA pass through protocol, in 100ns units.
+//
+#define ATA_TIMEOUT                            30000000
+//
+// Maximal number of Physical Region Descriptor Table entries supported.
+//
+#define AHCI_MAX_PRDT_NUMBER                   8
+
+#define AHCI_CAPABILITY_OFFSET                 0x0000
+#define   AHCI_CAP_SAM                         BIT18
+#define   AHCI_CAP_SSS                         BIT27
+
+#define AHCI_GHC_OFFSET                        0x0004
+#define   AHCI_GHC_RESET                       BIT0
+#define   AHCI_GHC_ENABLE                      BIT31
+
+#define AHCI_IS_OFFSET                         0x0008
+#define AHCI_PI_OFFSET                         0x000C
+
+#define AHCI_MAX_PORTS                         32
+
+typedef struct {
+  UINT32  Lower32;
+  UINT32  Upper32;
+} DATA_32;
+
+typedef union {
+  DATA_32   Uint32;
+  UINT64    Uint64;
+} DATA_64;
+
+#define AHCI_ATAPI_SIG_MASK                    0xFFFF0000
+#define AHCI_ATA_DEVICE_SIG                    0x00000000
+
+//
+// Each PRDT entry can point to a memory block up to 4M byte
+//
+#define AHCI_MAX_DATA_PER_PRDT                 0x400000
+
+#define AHCI_FIS_REGISTER_H2D                  0x27      //Register FIS - Host to Device
+#define   AHCI_FIS_REGISTER_H2D_LENGTH         20
+#define AHCI_FIS_REGISTER_D2H                  0x34      //Register FIS - Device to Host
+#define AHCI_FIS_PIO_SETUP                     0x5F      //PIO Setup FIS - Device to Host
+
+#define AHCI_D2H_FIS_OFFSET                    0x40
+#define AHCI_PIO_FIS_OFFSET                    0x20
+#define AHCI_FIS_TYPE_MASK                     0xFF
+
+//
+// Port register
+//
+#define AHCI_PORT_START                        0x0100
+#define AHCI_PORT_REG_WIDTH                    0x0080
+#define AHCI_PORT_CLB                          0x0000
+#define AHCI_PORT_CLBU                         0x0004
+#define AHCI_PORT_FB                           0x0008
+#define AHCI_PORT_FBU                          0x000C
+#define AHCI_PORT_IS                           0x0010
+#define AHCI_PORT_IE                           0x0014
+#define AHCI_PORT_CMD                          0x0018
+#define   AHCI_PORT_CMD_ST                     BIT0
+#define   AHCI_PORT_CMD_SUD                    BIT1
+#define   AHCI_PORT_CMD_POD                    BIT2
+#define   AHCI_PORT_CMD_CLO                    BIT3
+#define   AHCI_PORT_CMD_FRE                    BIT4
+#define   AHCI_PORT_CMD_FR                     BIT14
+#define   AHCI_PORT_CMD_CR                     BIT15
+#define   AHCI_PORT_CMD_CPD                    BIT20
+#define   AHCI_PORT_CMD_ATAPI                  BIT24
+#define   AHCI_PORT_CMD_DLAE                   BIT25
+#define   AHCI_PORT_CMD_ALPE                   BIT26
+#define   AHCI_PORT_CMD_ACTIVE                 (1 << 28)
+#define   AHCI_PORT_CMD_ICC_MASK               (BIT28 | BIT29 | BIT30 | BIT31)
+
+#define AHCI_PORT_TFD                          0x0020
+#define   AHCI_PORT_TFD_ERR                    BIT0
+#define   AHCI_PORT_TFD_DRQ                    BIT3
+#define   AHCI_PORT_TFD_BSY                    BIT7
+#define   AHCI_PORT_TFD_MASK                   (BIT7 | BIT3 | BIT0)
+
+#define AHCI_PORT_SIG                          0x0024
+#define AHCI_PORT_SSTS                         0x0028
+#define   AHCI_PORT_SSTS_DET_MASK              0x000F
+#define   AHCI_PORT_SSTS_DET                   0x0001
+#define   AHCI_PORT_SSTS_DET_PCE               0x0003
+
+#define AHCI_PORT_SCTL                         0x002C
+#define   AHCI_PORT_SCTL_IPM_INIT              0x0300
+
+#define AHCI_PORT_SERR                         0x0030
+#define AHCI_PORT_CI                           0x0038
+
+#define IS_ALIGNED(addr, size)                 (((UINTN) (addr) & (size - 1)) == 0)
+#define TIMER_PERIOD_SECONDS(Seconds)          MultU64x32((UINT64)(Seconds), 10000000)
+
+#pragma pack(1)
+
+//
+// Received FIS structure
+//
+typedef struct {
+  UINT8     AhciDmaSetupFis[0x1C];         // Dma Setup Fis: offset 0x00
+  UINT8     AhciDmaSetupFisRsvd[0x04];
+  UINT8     AhciPioSetupFis[0x14];         // Pio Setup Fis: offset 0x20
+  UINT8     AhciPioSetupFisRsvd[0x0C];
+  UINT8     AhciD2HRegisterFis[0x14];      // D2H Register Fis: offset 0x40
+  UINT8     AhciD2HRegisterFisRsvd[0x04];
+  UINT64    AhciSetDeviceBitsFis;          // Set Device Bits Fix: offset 0x58
+  UINT8     AhciUnknownFis[0x40];          // Unkonwn Fis: offset 0x60
+  UINT8     AhciUnknownFisRsvd[0x60];
+} EFI_AHCI_RECEIVED_FIS;
+
+//
+// Command List structure includes total 32 entries.
+// The entry Data structure is listed at the following.
+//
+typedef struct {
+  UINT32    AhciCmdCfl:5;      //Command FIS Length
+  UINT32    AhciCmdA:1;        //ATAPI
+  UINT32    AhciCmdW:1;        //Write
+  UINT32    AhciCmdP:1;        //Prefetchable
+  UINT32    AhciCmdR:1;        //Reset
+  UINT32    AhciCmdB:1;        //BIST
+  UINT32    AhciCmdC:1;        //Clear Busy upon R_OK
+  UINT32    AhciCmdRsvd:1;
+  UINT32    AhciCmdPmp:4;      //Port Multiplier Port
+  UINT32    AhciCmdPrdtl:16;   //Physical Region Descriptor Table Length
+  UINT32    AhciCmdPrdbc;      //Physical Region Descriptor Byte Count
+  UINT32    AhciCmdCtba;       //Command Table Descriptor Base Address
+  UINT32    AhciCmdCtbau;      //Command Table Descriptor Base Address Upper 32-BITs
+  UINT32    AhciCmdRsvd1[4];
+} EFI_AHCI_COMMAND_LIST;
+
+//
+// This is a software constructed FIS.
+// For Data transfer operations, this is the H2D Register FIS format as
+// specified in the Serial ATA Revision 2.6 specification.
+//
+typedef struct {
+  UINT8     AhciCFisType;
+  UINT8     AhciCFisPmNum:4;
+  UINT8     AhciCFisRsvd:1;
+  UINT8     AhciCFisRsvd1:1;
+  UINT8     AhciCFisRsvd2:1;
+  UINT8     AhciCFisCmdInd:1;
+  UINT8     AhciCFisCmd;
+  UINT8     AhciCFisFeature;
+  UINT8     AhciCFisSecNum;
+  UINT8     AhciCFisClyLow;
+  UINT8     AhciCFisClyHigh;
+  UINT8     AhciCFisDevHead;
+  UINT8     AhciCFisSecNumExp;
+  UINT8     AhciCFisClyLowExp;
+  UINT8     AhciCFisClyHighExp;
+  UINT8     AhciCFisFeatureExp;
+  UINT8     AhciCFisSecCount;
+  UINT8     AhciCFisSecCountExp;
+  UINT8     AhciCFisRsvd3;
+  UINT8     AhciCFisControl;
+  UINT8     AhciCFisRsvd4[4];
+  UINT8     AhciCFisRsvd5[44];
+} EFI_AHCI_COMMAND_FIS;
+
+//
+// ACMD: ATAPI command (12 or 16 bytes)
+//
+typedef struct {
+  UINT8    AtapiCmd[0x10];
+} EFI_AHCI_ATAPI_COMMAND;
+
+//
+// Physical Region Descriptor Table includes up to 65535 entries
+// The entry data structure is listed at the following.
+// the actual entry number comes from the PRDTL field in the command
+// list entry for this command slot.
+//
+typedef struct {
+  UINT32    AhciPrdtDba;       //Data Base Address
+  UINT32    AhciPrdtDbau;      //Data Base Address Upper 32-BITs
+  UINT32    AhciPrdtRsvd;
+  UINT32    AhciPrdtDbc:22;    //Data Byte Count
+  UINT32    AhciPrdtRsvd1:9;
+  UINT32    AhciPrdtIoc:1;     //Interrupt on Completion
+} EFI_AHCI_COMMAND_PRDT;
+
+//
+// Command table Data strucute which is pointed to by the entry in the command list
+//
+typedef struct {
+  EFI_AHCI_COMMAND_FIS      CommandFis;       // A software constructed FIS.
+  EFI_AHCI_ATAPI_COMMAND    AtapiCmd;         // 12 or 16 bytes ATAPI cmd.
+  UINT8                     Reserved[0x30];
+  //
+  // The scatter/gather list for Data transfer.
+  //
+  EFI_AHCI_COMMAND_PRDT     PrdtTable[AHCI_MAX_PRDT_NUMBER];
+} EFI_AHCI_COMMAND_TABLE;
+
+#pragma pack()
+
+typedef struct {
+  EFI_AHCI_RECEIVED_FIS     *AhciRFis;
+  EFI_AHCI_COMMAND_LIST     *AhciCmdList;
+  EFI_AHCI_COMMAND_TABLE    *AhciCmdTable;
+  UINTN                     MaxRFisSize;
+  UINTN                     MaxCmdListSize;
+  UINTN                     MaxCmdTableSize;
+  VOID                      *AhciRFisMap;
+  VOID                      *AhciCmdListMap;
+  VOID                      *AhciCmdTableMap;
+} EFI_AHCI_REGISTERS;
+
+//
+// Unique signature for AHCI ATA device information structure.
+//
+#define AHCI_PEI_ATA_DEVICE_DATA_SIGNATURE    SIGNATURE_32 ('A', 'P', 'A', 'D')
+
+//
+// AHCI mode device information structure.
+//
+typedef struct {
+  UINT32                              Signature;
+  LIST_ENTRY                          Link;
+
+  UINT16                              Port;
+  UINT16                              PortMultiplier;
+  UINT8                               FisIndex;
+  UINTN                               DeviceIndex;
+  ATA_IDENTIFY_DATA                   *IdentifyData;
+
+  BOOLEAN                             Lba48Bit;
+  BOOLEAN                             TrustComputing;
+  UINTN                               TrustComputingDeviceIndex;
+  EFI_PEI_BLOCK_IO2_MEDIA             Media;
+
+  PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private;
+} PEI_AHCI_ATA_DEVICE_DATA;
+
+#define AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS(a)  \
+  CR (a,                                       \
+      PEI_AHCI_ATA_DEVICE_DATA,                \
+      Link,                                    \
+      AHCI_PEI_ATA_DEVICE_DATA_SIGNATURE       \
+      );
+
+//
+// Unique signature for private data structure.
+//
+#define AHCI_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE    SIGNATURE_32 ('A','P','C','P')
+
+//
+// ATA AHCI controller private data structure.
+//
+struct _PEI_AHCI_CONTROLLER_PRIVATE_DATA {
+  UINT32                                Signature;
+  UINTN                                 MmioBase;
+  UINTN                                 DevicePathLength;
+  EFI_DEVICE_PATH_PROTOCOL              *DevicePath;
+
+  EFI_ATA_PASS_THRU_MODE                AtaPassThruMode;
+  EDKII_PEI_ATA_PASS_THRU_PPI           AtaPassThruPpi;
+  EDKII_PEI_STORAGE_SECURITY_CMD_PPI    StorageSecurityPpi;
+  EFI_PEI_PPI_DESCRIPTOR                AtaPassThruPpiList;
+  EFI_PEI_PPI_DESCRIPTOR                BlkIoPpiList;
+  EFI_PEI_PPI_DESCRIPTOR                BlkIo2PpiList;
+  EFI_PEI_PPI_DESCRIPTOR                StorageSecurityPpiList;
+  EFI_PEI_NOTIFY_DESCRIPTOR             EndOfPeiNotifyList;
+
+  EFI_AHCI_REGISTERS                    AhciRegisters;
+
+  UINT32                                PortBitMap;
+  UINT32                                ActiveDevices;
+  UINT32                                TrustComputingDevices;
+  LIST_ENTRY                            DeviceList;
+
+  UINT16                                PreviousPort;
+  UINT16                                PreviousPortMultiplier;
+};
+
+#define GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_PASS_THRU(a)           \
+  CR (a, PEI_AHCI_CONTROLLER_PRIVATE_DATA, AtaPassThruPpi, AHCI_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE)
+#define GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO(a)               \
+  CR (a, PEI_AHCI_CONTROLLER_PRIVATE_DATA, BlkIoPpi, AHCI_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE)
+#define GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2(a)              \
+  CR (a, PEI_AHCI_CONTROLLER_PRIVATE_DATA, BlkIo2Ppi, AHCI_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE)
+#define GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY(a)    \
+  CR (a, PEI_AHCI_CONTROLLER_PRIVATE_DATA, StorageSecurityPpi, AHCI_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE)
+#define GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY(a)              \
+  CR (a, PEI_AHCI_CONTROLLER_PRIVATE_DATA, EndOfPeiNotifyList, AHCI_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE)
+
+//
+// Global variables
+//
+extern UINT32    mMaxTransferBlockNumber[2];
+
+//
+// Internal functions
+//
+
+/**
+  Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+  OperationBusMasterCommonBuffer64 mapping.
+
+  @param  Pages                 The number of pages to allocate.
+  @param  HostAddress           A pointer to store the base system memory address of the
+                                allocated range.
+  @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to
+                                access the hosts HostAddress.
+  @param  Mapping               A resulting value to pass to Unmap().
+
+  @retval EFI_SUCCESS           The requested memory pages were allocated.
+  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are
+                                MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateBuffer (
+  IN UINTN                  Pages,
+  OUT VOID                  **HostAddress,
+  OUT EFI_PHYSICAL_ADDRESS  *DeviceAddress,
+  OUT VOID                  **Mapping
+  );
+
+/**
+  Frees memory that was allocated with AllocateBuffer().
+
+  @param  Pages                 The number of pages to free.
+  @param  HostAddress           The base system memory address of the allocated range.
+  @param  Mapping               The mapping value returned from Map().
+
+  @retval EFI_SUCCESS           The requested memory pages were freed.
+  @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+                                was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+IoMmuFreeBuffer (
+  IN UINTN                  Pages,
+  IN VOID                   *HostAddress,
+  IN VOID                   *Mapping
+  );
+
+/**
+  Provides the controller-specific addresses required to access system memory from a
+  DMA bus master.
+
+  @param  Operation             Indicates if the bus master is going to read or write to system memory.
+  @param  HostAddress           The system memory address to map to the PCI controller.
+  @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes
+                                that were mapped.
+  @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to
+                                access the hosts HostAddress.
+  @param  Mapping               A resulting value to pass to Unmap().
+
+  @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.
+  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+IoMmuMap (
+  IN  EDKII_IOMMU_OPERATION Operation,
+  IN VOID                   *HostAddress,
+  IN  OUT UINTN             *NumberOfBytes,
+  OUT EFI_PHYSICAL_ADDRESS  *DeviceAddress,
+  OUT VOID                  **Mapping
+  );
+
+/**
+  Completes the Map() operation and releases any corresponding resources.
+
+  @param  Mapping               The mapping value returned from Map().
+
+  @retval EFI_SUCCESS           The range was unmapped.
+  @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+  @retval EFI_DEVICE_ERROR      The data was not committed to the target system memory.
+**/
+EFI_STATUS
+IoMmuUnmap (
+  IN VOID                  *Mapping
+  );
+
+/**
+  One notified function to cleanup the allocated DMA buffers at EndOfPei.
+
+  @param[in] PeiServices         Pointer to PEI Services Table.
+  @param[in] NotifyDescriptor    Pointer to the descriptor for the Notification
+                                 event that caused this function to execute.
+  @param[in] Ppi                 Pointer to the PPI data associated with this function.
+
+  @retval EFI_SUCCESS    The function completes successfully
+
+**/
+EFI_STATUS
+EFIAPI
+AhciPeimEndOfPei (
+  IN EFI_PEI_SERVICES           **PeiServices,
+  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
+  IN VOID                       *Ppi
+  );
+
+/**
+  Collect the number of bits set within a port bitmap.
+
+  @param[in]    PortBitMap    A 32-bit wide bit map of ATA AHCI ports.
+
+  @retval The number of bits set in the bitmap.
+
+**/
+UINT8
+AhciGetNumberOfPortsFromMap (
+  IN UINT32    PortBitMap
+  );
+
+/**
+  Start a PIO Data transfer on specific port.
+
+  @param[in]     Private            The pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA.
+  @param[in]     Port               The number of port.
+  @param[in]     PortMultiplier     The number of port multiplier.
+  @param[in]     FisIndex           The offset index of the FIS base address.
+  @param[in]     Read               The transfer direction.
+  @param[in]     AtaCommandBlock    The EFI_ATA_COMMAND_BLOCK data.
+  @param[in,out] AtaStatusBlock     The EFI_ATA_STATUS_BLOCK data.
+  @param[in,out] MemoryAddr         The pointer to the data buffer.
+  @param[in]     DataCount          The data count to be transferred.
+  @param[in]     Timeout            The timeout value of PIO data transfer, uses
+                                    100ns as a unit.
+
+  @retval EFI_DEVICE_ERROR        The PIO data transfer abort with error occurs.
+  @retval EFI_TIMEOUT             The operation is time out.
+  @retval EFI_UNSUPPORTED         The device is not ready for transfer.
+  @retval EFI_OUT_OF_RESOURCES    The operation fails due to lack of resources.
+  @retval EFI_SUCCESS             The PIO data transfer executes successfully.
+
+**/
+EFI_STATUS
+AhciPioTransfer (
+  IN     PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private,
+  IN     UINT8                               Port,
+  IN     UINT8                               PortMultiplier,
+  IN     UINT8                               FisIndex,
+  IN     BOOLEAN                             Read,
+  IN     EFI_ATA_COMMAND_BLOCK               *AtaCommandBlock,
+  IN OUT EFI_ATA_STATUS_BLOCK                *AtaStatusBlock,
+  IN OUT VOID                                *MemoryAddr,
+  IN     UINT32                              DataCount,
+  IN     UINT64                              Timeout
+  );
+
+/**
+  Start a non data transfer on specific port.
+
+  @param[in]     Private            The pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA.
+  @param[in]     Port               The number of port.
+  @param[in]     PortMultiplier     The number of port multiplier.
+  @param[in]     FisIndex           The offset index of the FIS base address.
+  @param[in]     AtaCommandBlock    The EFI_ATA_COMMAND_BLOCK data.
+  @param[in,out] AtaStatusBlock     The EFI_ATA_STATUS_BLOCK data.
+  @param[in]     Timeout            The timeout value of non data transfer, uses
+                                    100ns as a unit.
+
+  @retval EFI_DEVICE_ERROR        The non data transfer abort with error occurs.
+  @retval EFI_TIMEOUT             The operation is time out.
+  @retval EFI_UNSUPPORTED         The device is not ready for transfer.
+  @retval EFI_SUCCESS             The non data transfer executes successfully.
+
+**/
+EFI_STATUS
+AhciNonDataTransfer (
+  IN     PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private,
+  IN     UINT8                               Port,
+  IN     UINT8                               PortMultiplier,
+  IN     UINT8                               FisIndex,
+  IN     EFI_ATA_COMMAND_BLOCK               *AtaCommandBlock,
+  IN OUT EFI_ATA_STATUS_BLOCK                *AtaStatusBlock,
+  IN     UINT64                              Timeout
+  );
+
+/**
+  Initialize ATA host controller at AHCI mode.
+
+  The function is designed to initialize ATA host controller.
+
+  @param[in,out] Private    A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA instance.
+
+  @retval EFI_SUCCESS             The ATA AHCI controller is initialized successfully.
+  @retval EFI_OUT_OF_RESOURCES    Not enough resource to complete while initializing
+                                  the controller.
+  @retval Others                  A device error occurred while initializing the
+                                  controller.
+
+**/
+EFI_STATUS
+AhciModeInitialization (
+  IN OUT PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private
+  );
+
+/**
+  Trust transfer data from/to ATA device.
+
+  This function performs one ATA pass through transaction to do a trust transfer
+  from/to ATA device. It chooses the appropriate ATA command and protocol to invoke
+  PassThru interface of ATA pass through.
+
+  @param[in]     DeviceData     Pointer to PEI_AHCI_ATA_DEVICE_DATA structure.
+  @param[in,out] Buffer         The pointer to the current transaction buffer.
+  @param[in]     SecurityProtocolId
+                                The value of the "Security Protocol" parameter
+                                of the security protocol command to be sent.
+  @param[in]     SecurityProtocolSpecificData
+                                The value of the "Security Protocol Specific"
+                                parameter of the security protocol command to
+                                be sent.
+  @param[in]     TransferLength The block number or sector count of the transfer.
+  @param[in]     IsTrustSend    Indicates whether it is a trust send operation
+                                or not.
+  @param[in]     Timeout        The timeout, in 100ns units, to use for the execution
+                                of the security protocol command. A Timeout value
+                                of 0 means that this function will wait indefinitely
+                                for the security protocol command to execute. If
+                                Timeout is greater than zero, then this function
+                                will return EFI_TIMEOUT if the time required to
+                                execute the receive data command is greater than
+                                Timeout.
+  @param[out]    TransferLengthOut
+                                A pointer to a buffer to store the size in bytes
+                                of the data written to the buffer. Ignore it when
+                                IsTrustSend is TRUE.
+
+  @retval EFI_SUCCESS    The data transfer is complete successfully.
+  @return others         Some error occurs when transferring data.
+
+**/
+EFI_STATUS
+TrustTransferAtaDevice (
+  IN     PEI_AHCI_ATA_DEVICE_DATA    *DeviceData,
+  IN OUT VOID                        *Buffer,
+  IN     UINT8                       SecurityProtocolId,
+  IN     UINT16                      SecurityProtocolSpecificData,
+  IN     UINTN                       TransferLength,
+  IN     BOOLEAN                     IsTrustSend,
+  IN     UINT64                      Timeout,
+  OUT    UINTN                       *TransferLengthOut
+  );
+
+/**
+  Returns a pointer to the next node in a device path.
+
+  If Node is NULL, then ASSERT().
+
+  @param  Node    A pointer to a device path node data structure.
+
+  @return a pointer to the device path node that follows the device path node
+  specified by Node.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+NextDevicePathNode (
+  IN CONST VOID  *Node
+  );
+
+/**
+  Get the size of the current device path instance.
+
+  @param[in]  DevicePath             A pointer to the EFI_DEVICE_PATH_PROTOCOL
+                                     structure.
+  @param[out] InstanceSize           The size of the current device path instance.
+  @param[out] EntireDevicePathEnd    Indicate whether the instance is the last
+                                     one in the device path strucure.
+
+  @retval EFI_SUCCESS    The size of the current device path instance is fetched.
+  @retval Others         Fails to get the size of the current device path instance.
+
+**/
+EFI_STATUS
+GetDevicePathInstanceSize (
+  IN  EFI_DEVICE_PATH_PROTOCOL    *DevicePath,
+  OUT UINTN                       *InstanceSize,
+  OUT BOOLEAN                     *EntireDevicePathEnd
+  );
+
+/**
+  Check the validity of the device path of a ATA AHCI host controller.
+
+  @param[in] DevicePath          A pointer to the EFI_DEVICE_PATH_PROTOCOL
+                                 structure.
+  @param[in] DevicePathLength    The length of the device path.
+
+  @retval EFI_SUCCESS              The device path is valid.
+  @retval EFI_INVALID_PARAMETER    The device path is invalid.
+
+**/
+EFI_STATUS
+AhciCheckHcDevicePath (
+  IN EFI_DEVICE_PATH_PROTOCOL    *DevicePath,
+  IN UINTN                       DevicePathLength
+  );
+
+/**
+  Build the device path for an ATA device with given port and port multiplier number.
+
+  @param[in]  Private               A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA
+                                    data structure.
+  @param[in]  Port                  The given port number.
+  @param[in]  PortMultiplierPort    The given port multiplier number.
+  @param[out] DevicePathLength      The length of the device path in bytes specified
+                                    by DevicePath.
+  @param[out] DevicePath            The device path of ATA device.
+
+  @retval EFI_SUCCESS               The operation succeeds.
+  @retval EFI_INVALID_PARAMETER     The parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES      The operation fails due to lack of resources.
+
+**/
+EFI_STATUS
+AhciBuildDevicePath (
+  IN  PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private,
+  IN  UINT16                              Port,
+  IN  UINT16                              PortMultiplierPort,
+  OUT UINTN                               *DevicePathLength,
+  OUT EFI_DEVICE_PATH_PROTOCOL            **DevicePath
+  );
+
+/**
+  Collect the ports that need to be enumerated on a controller for S3 phase.
+
+  @param[in]  HcDevicePath          Device path of the controller.
+  @param[in]  HcDevicePathLength    Length of the device path specified by
+                                    HcDevicePath.
+  @param[out] PortBitMap            Bitmap that indicates the ports that need
+                                    to be enumerated on the controller.
+
+  @retval    The number of ports that need to be enumerated.
+
+**/
+UINT8
+AhciS3GetEumeratePorts (
+  IN  EFI_DEVICE_PATH_PROTOCOL    *HcDevicePath,
+  IN  UINTN                       HcDevicePathLength,
+  OUT UINT32                      *PortBitMap
+  );
+
+#endif
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.h b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.h
new file mode 100644
index 0000000000..925ee27f93
--- /dev/null
+++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.h
@@ -0,0 +1,184 @@
+/** @file
+  The AhciPei driver is used to manage ATA hard disk device working under AHCI
+  mode at PEI phase.
+
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions
+  of the BSD License which accompanies this distribution.  The
+  full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _AHCI_PEI_PASSTHRU_H_
+#define _AHCI_PEI_PASSTHRU_H_
+
+/**
+  Sends an ATA command to an ATA device that is attached to the ATA controller.
+
+  @param[in]     This                  The PPI instance pointer.
+  @param[in]     Port                  The port number of the ATA device to send
+                                       the command.
+  @param[in]     PortMultiplierPort    The port multiplier port number of the ATA
+                                       device to send the command.
+                                       If there is no port multiplier, then specify
+                                       0xFFFF.
+  @param[in,out] Packet                A pointer to the ATA command to send to
+                                       the ATA device specified by Port and
+                                       PortMultiplierPort.
+
+  @retval EFI_SUCCESS              The ATA command was sent by the host. For
+                                   bi-directional commands, InTransferLength bytes
+                                   were transferred from InDataBuffer. For write
+                                   and bi-directional commands, OutTransferLength
+                                   bytes were transferred by OutDataBuffer.
+  @retval EFI_NOT_FOUND            The specified ATA device is not found.
+  @retval EFI_INVALID_PARAMETER    The contents of Acb are invalid. The ATA command
+                                   was not sent, so no additional status information
+                                   is available.
+  @retval EFI_BAD_BUFFER_SIZE      The ATA command was not executed. The number
+                                   of bytes that could be transferred is returned
+                                   in InTransferLength. For write and bi-directional
+                                   commands, OutTransferLength bytes were transferred
+                                   by OutDataBuffer.
+  @retval EFI_NOT_READY            The ATA command could not be sent because there
+                                   are too many ATA commands already queued. The
+                                   caller may retry again later.
+  @retval EFI_DEVICE_ERROR         A device error occurred while attempting to
+                                   send the ATA command.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciAtaPassThruPassThru (
+  IN     EDKII_PEI_ATA_PASS_THRU_PPI         *This,
+  IN     UINT16                              Port,
+  IN     UINT16                              PortMultiplierPort,
+  IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET    *Packet
+  );
+
+/**
+  Used to retrieve the list of legal port numbers for ATA devices on an ATA controller.
+  These can either be the list of ports where ATA devices are actually present or the
+  list of legal port numbers for the ATA controller. Regardless, the caller of this
+  function must probe the port number returned to see if an ATA device is actually
+  present at that location on the ATA controller.
+
+  The GetNextPort() function retrieves the port number on an ATA controller. If on
+  input Port is 0xFFFF, then the port number of the first port on the ATA controller
+  is returned in Port and EFI_SUCCESS is returned.
+
+  If Port is a port number that was returned on a previous call to GetNextPort(),
+  then the port number of the next port on the ATA controller is returned in Port,
+  and EFI_SUCCESS is returned. If Port is not 0xFFFF and Port was not returned on
+  a previous call to GetNextPort(), then EFI_INVALID_PARAMETER is returned.
+
+  If Port is the port number of the last port on the ATA controller, then EFI_NOT_FOUND
+  is returned.
+
+  @param[in]     This    The PPI instance pointer.
+  @param[in,out] Port    On input, a pointer to the port number on the ATA controller.
+                         On output, a pointer to the next port number on the ATA
+                         controller. An input value of 0xFFFF retrieves the first
+                         port number on the ATA controller.
+
+  @retval EFI_SUCCESS              The next port number on the ATA controller was
+                                   returned in Port.
+  @retval EFI_NOT_FOUND            There are no more ports on this ATA controller.
+  @retval EFI_INVALID_PARAMETER    Port is not 0xFFFF and Port was not returned
+                                   on a previous call to GetNextPort().
+
+**/
+EFI_STATUS
+EFIAPI
+AhciAtaPassThruGetNextPort (
+  IN     EDKII_PEI_ATA_PASS_THRU_PPI    *This,
+  IN OUT UINT16                         *Port
+  );
+
+/**
+  Used to retrieve the list of legal port multiplier port numbers for ATA devices
+  on a port of an ATA controller. These can either be the list of port multiplier
+  ports where ATA devices are actually present on port or the list of legal port
+  multiplier ports on that port. Regardless, the caller of this function must probe
+  the port number and port multiplier port number returned to see if an ATA device
+  is actually present.
+
+  The GetNextDevice() function retrieves the port multiplier port number of an ATA
+  device present on a port of an ATA controller.
+
+  If PortMultiplierPort points to a port multiplier port number value that was
+  returned on a previous call to GetNextDevice(), then the port multiplier port
+  number of the next ATA device on the port of the ATA controller is returned in
+  PortMultiplierPort, and EFI_SUCCESS is returned.
+
+  If PortMultiplierPort points to 0xFFFF, then the port multiplier port number
+  of the first ATA device on port of the ATA controller is returned in PortMultiplierPort
+  and EFI_SUCCESS is returned.
+
+  If PortMultiplierPort is not 0xFFFF and the value pointed to by PortMultiplierPort
+  was not returned on a previous call to GetNextDevice(), then EFI_INVALID_PARAMETER
+  is returned.
+
+  If PortMultiplierPort is the port multiplier port number of the last ATA device
+  on the port of the ATA controller, then EFI_NOT_FOUND is returned.
+
+  @param[in]     This                  The PPI instance pointer.
+  @param[in]     Port                  The port number present on the ATA controller.
+  @param[in,out] PortMultiplierPort    On input, a pointer to the port multiplier
+                                       port number of an ATA device present on the
+                                       ATA controller. If on input a PortMultiplierPort
+                                       of 0xFFFF is specified, then the port multiplier
+                                       port number of the first ATA device is returned.
+                                       On output, a pointer to the port multiplier port
+                                       number of the next ATA device present on an ATA
+                                       controller.
+
+  @retval EFI_SUCCESS              The port multiplier port number of the next ATA
+                                   device on the port of the ATA controller was
+                                   returned in PortMultiplierPort.
+  @retval EFI_NOT_FOUND            There are no more ATA devices on this port of
+                                   the ATA controller.
+  @retval EFI_INVALID_PARAMETER    PortMultiplierPort is not 0xFFFF, and PortMultiplierPort
+                                   was not returned on a previous call to GetNextDevice().
+
+**/
+EFI_STATUS
+EFIAPI
+AhciAtaPassThruGetNextDevice (
+  IN     EDKII_PEI_ATA_PASS_THRU_PPI    *This,
+  IN     UINT16                         Port,
+  IN OUT UINT16                         *PortMultiplierPort
+  );
+
+/**
+  Gets the device path information of the underlying ATA host controller.
+
+  @param[in]  This                The PPI instance pointer.
+  @param[out] DevicePathLength    The length of the device path in bytes specified
+                                  by DevicePath.
+  @param[out] DevicePath          The device path of the underlying ATA host controller.
+                                  This field re-uses EFI Device Path Protocol as
+                                  defined by Section 10.2 EFI Device Path Protocol
+                                  of UEFI 2.7 Specification.
+
+  @retval EFI_SUCCESS              The device path of the ATA host controller has
+                                   been successfully returned.
+  @retval EFI_INVALID_PARAMETER    DevicePathLength or DevicePath is NULL.
+  @retval EFI_OUT_OF_RESOURCES     Not enough resource to return the device path.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciAtaPassThruGetDevicePath (
+  IN  EDKII_PEI_ATA_PASS_THRU_PPI    *This,
+  OUT UINTN                          *DevicePathLength,
+  OUT EFI_DEVICE_PATH_PROTOCOL       **DevicePath
+  );
+
+#endif
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiStorageSecurity.h b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiStorageSecurity.h
new file mode 100644
index 0000000000..0bdb964ec7
--- /dev/null
+++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiStorageSecurity.h
@@ -0,0 +1,247 @@
+/** @file
+  The AhciPei driver is used to manage ATA hard disk device working under AHCI
+  mode at PEI phase.
+
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions
+  of the BSD License which accompanies this distribution.  The
+  full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _AHCI_PEI_STORAGE_SECURITY_H_
+#define _AHCI_PEI_STORAGE_SECURITY_H_
+
+/**
+  Gets the count of storage security devices that one specific driver detects.
+
+  @param[in]  This               The PPI instance pointer.
+  @param[out] NumberofDevices    The number of storage security devices discovered.
+
+  @retval EFI_SUCCESS              The operation performed successfully.
+  @retval EFI_INVALID_PARAMETER    The parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStorageSecurityGetDeviceNo (
+  IN  EDKII_PEI_STORAGE_SECURITY_CMD_PPI    *This,
+  OUT UINTN                                 *NumberofDevices
+  );
+
+/**
+  Gets the device path of a specific storage security device.
+
+  @param[in]  This                 The PPI instance pointer.
+  @param[in]  DeviceIndex          Specifies the storage security device to which
+                                   the function wants to talk. Because the driver
+                                   that implements Storage Security Command PPIs
+                                   will manage multiple storage devices, the PPIs
+                                   that want to talk to a single device must specify
+                                   the device index that was assigned during the
+                                   enumeration process. This index is a number from
+                                   one to NumberofDevices.
+  @param[out] DevicePathLength     The length of the device path in bytes specified
+                                   by DevicePath.
+  @param[out] DevicePath           The device path of storage security device.
+                                   This field re-uses EFI Device Path Protocol as
+                                   defined by Section 10.2 EFI Device Path Protocol
+                                   of UEFI 2.7 Specification.
+
+  @retval EFI_SUCCESS              The operation succeeds.
+  @retval EFI_INVALID_PARAMETER    DevicePathLength or DevicePath is NULL.
+  @retval EFI_NOT_FOUND            The specified storage security device not found.
+  @retval EFI_OUT_OF_RESOURCES     The operation fails due to lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStorageSecurityGetDevicePath (
+  IN  EDKII_PEI_STORAGE_SECURITY_CMD_PPI    *This,
+  IN  UINTN                                 DeviceIndex,
+  OUT UINTN                                 *DevicePathLength,
+  OUT EFI_DEVICE_PATH_PROTOCOL              **DevicePath
+  );
+
+/**
+  Send a security protocol command to a device that receives data and/or the result
+  of one or more commands sent by SendData.
+
+  The ReceiveData function sends a security protocol command to the given DeviceIndex.
+  The security protocol command sent is defined by SecurityProtocolId and contains
+  the security protocol specific data SecurityProtocolSpecificData. The function
+  returns the data from the security protocol command in PayloadBuffer.
+
+  For devices supporting the SCSI command set, the security protocol command is sent
+  using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+  For devices supporting the ATA command set, the security protocol command is sent
+  using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+  is non-zero.
+
+  If the PayloadBufferSize is zero, the security protocol command is sent using the
+  Trusted Non-Data command defined in ATA8-ACS.
+
+  If PayloadBufferSize is too small to store the available data from the security
+  protocol command, the function shall copy PayloadBufferSize bytes into the
+  PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+  If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+  the function shall return EFI_INVALID_PARAMETER.
+
+  If the given DeviceIndex does not support security protocol commands, the function
+  shall return EFI_UNSUPPORTED.
+
+  If the security protocol fails to complete within the Timeout period, the function
+  shall return EFI_TIMEOUT.
+
+  If the security protocol command completes without an error, the function shall
+  return EFI_SUCCESS. If the security protocol command completes with an error, the
+  function shall return EFI_DEVICE_ERROR.
+
+  @param[in]  This             The PPI instance pointer.
+  @param[in]  DeviceIndex      Specifies the storage security device to which the
+                               function wants to talk. Because the driver that
+                               implements Storage Security Command PPIs will manage
+                               multiple storage devices, the PPIs that want to talk
+                               to a single device must specify the device index
+                               that was assigned during the enumeration process.
+                               This index is a number from one to NumberofDevices.
+  @param[in]  Timeout          The timeout, in 100ns units, to use for the execution
+                               of the security protocol command. A Timeout value
+                               of 0 means that this function will wait indefinitely
+                               for the security protocol command to execute. If
+                               Timeout is greater than zero, then this function
+                               will return EFI_TIMEOUT if the time required to
+                               execute the receive data command is greater than
+                               Timeout.
+  @param[in]  SecurityProtocolId
+                               The value of the "Security Protocol" parameter of
+                               the security protocol command to be sent.
+  @param[in]  SecurityProtocolSpecificData
+                               The value of the "Security Protocol Specific"
+                               parameter of the security protocol command to be
+                               sent.
+  @param[in]  PayloadBufferSize
+                               Size in bytes of the payload data buffer.
+  @param[out] PayloadBuffer    A pointer to a destination buffer to store the
+                               security protocol command specific payload data
+                               for the security protocol command. The caller is
+                               responsible for having either implicit or explicit
+                               ownership of the buffer.
+  @param[out] PayloadTransferSize
+                               A pointer to a buffer to store the size in bytes
+                               of the data written to the payload data buffer.
+
+  @retval EFI_SUCCESS                  The security protocol command completed
+                                       successfully.
+  @retval EFI_WARN_BUFFER_TOO_SMALL    The PayloadBufferSize was too small to
+                                       store the available data from the device.
+                                       The PayloadBuffer contains the truncated
+                                       data.
+  @retval EFI_UNSUPPORTED              The given DeviceIndex does not support
+                                       security protocol commands.
+  @retval EFI_DEVICE_ERROR             The security protocol command completed
+                                       with an error.
+  @retval EFI_INVALID_PARAMETER        The PayloadBuffer or PayloadTransferSize
+                                       is NULL and PayloadBufferSize is non-zero.
+  @retval EFI_TIMEOUT                  A timeout occurred while waiting for the
+                                       security protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStorageSecurityReceiveData (
+  IN  EDKII_PEI_STORAGE_SECURITY_CMD_PPI    *This,
+  IN  UINTN                                 DeviceIndex,
+  IN  UINT64                                Timeout,
+  IN  UINT8                                 SecurityProtocolId,
+  IN  UINT16                                SecurityProtocolSpecificData,
+  IN  UINTN                                 PayloadBufferSize,
+  OUT VOID                                  *PayloadBuffer,
+  OUT UINTN                                 *PayloadTransferSize
+  );
+
+/**
+  Send a security protocol command to a device.
+
+  The SendData function sends a security protocol command containing the payload
+  PayloadBuffer to the given DeviceIndex. The security protocol command sent is
+  defined by SecurityProtocolId and contains the security protocol specific data
+  SecurityProtocolSpecificData. If the underlying protocol command requires a
+  specific padding for the command payload, the SendData function shall add padding
+  bytes to the command payload to satisfy the padding requirements.
+
+  For devices supporting the SCSI command set, the security protocol command is
+  sent using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+  For devices supporting the ATA command set, the security protocol command is
+  sent using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
+  is non-zero. If the PayloadBufferSize is zero, the security protocol command
+  is sent using the Trusted Non-Data command defined in ATA8-ACS.
+
+  If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
+  return EFI_INVALID_PARAMETER.
+
+  If the given DeviceIndex does not support security protocol commands, the function
+  shall return EFI_UNSUPPORTED.
+
+  If the security protocol fails to complete within the Timeout period, the function
+  shall return EFI_TIMEOUT.
+
+  If the security protocol command completes without an error, the function shall
+  return EFI_SUCCESS. If the security protocol command completes with an error,
+  the functio shall return EFI_DEVICE_ERROR.
+
+  @param[in] This              The PPI instance pointer.
+  @param[in] DeviceIndex       The ID of the device.
+  @param[in] Timeout           The timeout, in 100ns units, to use for the execution
+                               of the security protocol command. A Timeout value
+                               of 0 means that this function will wait indefinitely
+                               for the security protocol command to execute. If
+                               Timeout is greater than zero, then this function
+                               will return EFI_TIMEOUT if the time required to
+                               execute the receive data command is greater than
+                               Timeout.
+  @param[in] SecurityProtocolId
+                               The value of the "Security Protocol" parameter of
+                               the security protocol command to be sent.
+  @param[in] SecurityProtocolSpecificData
+                               The value of the "Security Protocol Specific"
+                               parameter of the security protocol command to be
+                               sent.
+  @param[in] PayloadBufferSize Size in bytes of the payload data buffer.
+  @param[in] PayloadBuffer     A pointer to a destination buffer to store the
+                               security protocol command specific payload data
+                               for the security protocol command.
+
+  @retval EFI_SUCCESS              The security protocol command completed successfully.
+  @retval EFI_UNSUPPORTED          The given DeviceIndex does not support security
+                                   protocol commands.
+  @retval EFI_DEVICE_ERROR         The security protocol command completed with
+                                   an error.
+  @retval EFI_INVALID_PARAMETER    The PayloadBuffer is NULL and PayloadBufferSize
+                                   is non-zero.
+  @retval EFI_TIMEOUT              A timeout occurred while waiting for the security
+                                   protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStorageSecuritySendData (
+  IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI  *This,
+  IN UINTN                               DeviceIndex,
+  IN UINT64                              Timeout,
+  IN UINT8                               SecurityProtocolId,
+  IN UINT16                              SecurityProtocolSpecificData,
+  IN UINTN                               PayloadBufferSize,
+  IN VOID                                *PayloadBuffer
+  );
+
+#endif
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c b/MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c
new file mode 100644
index 0000000000..54df31906f
--- /dev/null
+++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c
@@ -0,0 +1,2015 @@
+/** @file
+  The AhciPei driver is used to manage ATA hard disk device working under AHCI
+  mode at PEI phase.
+
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions
+  of the BSD License which accompanies this distribution.  The
+  full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "AhciPei.h"
+
+#define ATA_CMD_TRUST_NON_DATA           0x5B
+#define ATA_CMD_TRUST_RECEIVE            0x5C
+#define ATA_CMD_TRUST_SEND               0x5E
+
+//
+// Look up table (IsWrite) for EFI_ATA_PASS_THRU_CMD_PROTOCOL
+//
+EFI_ATA_PASS_THRU_CMD_PROTOCOL  mAtaPassThruCmdProtocols[2] = {
+  EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN,
+  EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT
+};
+
+//
+// Look up table (Lba48Bit, IsIsWrite) for ATA_CMD
+//
+UINT8 mAtaCommands[2][2] = {
+  {
+    ATA_CMD_READ_SECTORS,            // 28-bit LBA; PIO read
+    ATA_CMD_WRITE_SECTORS            // 28-bit LBA; PIO write
+  },
+  {
+    ATA_CMD_READ_SECTORS_EXT,        // 48-bit LBA; PIO read
+    ATA_CMD_WRITE_SECTORS_EXT        // 48-bit LBA; PIO write
+  }
+};
+
+//
+// Look up table (IsTrustSend) for ATA_CMD
+//
+UINT8  mAtaTrustCommands[2] = {
+  ATA_CMD_TRUST_RECEIVE,    // PIO read
+  ATA_CMD_TRUST_SEND        // PIO write
+};
+
+//
+// Look up table (Lba48Bit) for maximum transfer block number
+//
+#define MAX_28BIT_TRANSFER_BLOCK_NUM     0x100
+#define MAX_48BIT_TRANSFER_BLOCK_NUM     0xFFFF
+
+UINT32 mMaxTransferBlockNumber[2] = {
+  MAX_28BIT_TRANSFER_BLOCK_NUM,
+  MAX_48BIT_TRANSFER_BLOCK_NUM
+};
+
+//
+// The maximum total sectors count in 28 bit addressing mode
+//
+#define MAX_28BIT_ADDRESSING_CAPACITY    0xfffffff
+
+
+/**
+  Read AHCI Operation register.
+
+  @param[in] AhciBar    AHCI bar address.
+  @param[in] Offset     The operation register offset.
+
+  @return The register content read.
+
+**/
+UINT32
+AhciReadReg (
+  IN UINTN     AhciBar,
+  IN UINT32    Offset
+  )
+{
+  UINT32   Data;
+
+  Data = 0;
+  Data = MmioRead32 (AhciBar + Offset);
+
+  return Data;
+}
+
+/**
+  Write AHCI Operation register.
+
+  @param[in] AhciBar    AHCI bar address.
+  @param[in] Offset     The operation register offset.
+  @param[in] Data       The Data used to write down.
+
+**/
+VOID
+AhciWriteReg (
+  IN UINTN     AhciBar,
+  IN UINT32    Offset,
+  IN UINT32    Data
+  )
+{
+  MmioWrite32 (AhciBar + Offset, Data);
+}
+
+/**
+  Do AND operation with the value of AHCI Operation register.
+
+  @param[in] AhciBar    AHCI bar address.
+  @param[in] Offset     The operation register offset.
+  @param[in] AndData    The data used to do AND operation.
+
+**/
+VOID
+AhciAndReg (
+  IN UINTN     AhciBar,
+  IN UINT32    Offset,
+  IN UINT32    AndData
+  )
+{
+  UINT32 Data;
+
+  Data  = AhciReadReg (AhciBar, Offset);
+  Data &= AndData;
+
+  AhciWriteReg (AhciBar, Offset, Data);
+}
+
+/**
+  Do OR operation with the Value of AHCI Operation register.
+
+  @param[in] AhciBar    AHCI bar address.
+  @param[in] Offset     The operation register offset.
+  @param[in] OrData     The Data used to do OR operation.
+
+**/
+VOID
+AhciOrReg (
+  IN UINTN     AhciBar,
+  IN UINT32    Offset,
+  IN UINT32    OrData
+  )
+{
+  UINT32 Data;
+
+  Data  = AhciReadReg (AhciBar, Offset);
+  Data |= OrData;
+
+  AhciWriteReg (AhciBar, Offset, Data);
+}
+
+/**
+  Wait for memory set to the test Value.
+
+  @param[in] AhciBar      AHCI bar address.
+  @param[in] Offset       The memory offset to test.
+  @param[in] MaskValue    The mask Value of memory.
+  @param[in] TestValue    The test Value of memory.
+  @param[in] Timeout      The timeout, in 100ns units, for wait memory set.
+
+  @retval EFI_DEVICE_ERROR    The memory is not set.
+  @retval EFI_TIMEOUT         The memory setting is time out.
+  @retval EFI_SUCCESS         The memory is correct set.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciWaitMmioSet (
+  IN UINTN     AhciBar,
+  IN UINT32    Offset,
+  IN UINT32    MaskValue,
+  IN UINT32    TestValue,
+  IN UINT64    Timeout
+  )
+{
+  UINT32    Value;
+  UINT32    Delay;
+
+  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
+
+  do {
+    Value = AhciReadReg (AhciBar, Offset) & MaskValue;
+
+    if (Value == TestValue) {
+      return EFI_SUCCESS;
+    }
+
+    //
+    // Stall for 100 microseconds.
+    //
+    MicroSecondDelay (100);
+
+    Delay--;
+
+  } while (Delay > 0);
+
+  return EFI_TIMEOUT;
+}
+
+/**
+  Check the memory status to the test value.
+
+  @param[in] Address       The memory address to test.
+  @param[in] MaskValue     The mask value of memory.
+  @param[in] TestValue     The test value of memory.
+
+  @retval EFI_NOT_READY    The memory is not set.
+  @retval EFI_SUCCESS      The memory is correct set.
+
+**/
+EFI_STATUS
+AhciCheckMemSet (
+  IN UINTN     Address,
+  IN UINT32    MaskValue,
+  IN UINT32    TestValue
+  )
+{
+  UINT32     Value;
+
+  Value  = *(volatile UINT32 *) Address;
+  Value &= MaskValue;
+
+  if (Value == TestValue) {
+    return EFI_SUCCESS;
+  } else {
+    return EFI_NOT_READY;
+  }
+}
+
+/**
+  Wait for the value of the specified system memory set to the test value.
+
+  @param[in] Address      The system memory address to test.
+  @param[in] MaskValue    The mask value of memory.
+  @param[in] TestValue    The test value of memory.
+  @param[in] Timeout      The timeout, in 100ns units, for wait memory set.
+
+  @retval EFI_TIMEOUT    The system memory setting is time out.
+  @retval EFI_SUCCESS    The system memory is correct set.
+
+**/
+EFI_STATUS
+AhciWaitMemSet (
+  IN  EFI_PHYSICAL_ADDRESS    Address,
+  IN  UINT32                  MaskValue,
+  IN  UINT32                  TestValue,
+  IN  UINT64                  Timeout
+  )
+{
+  UINT32     Value;
+  UINT64     Delay;
+  BOOLEAN    InfiniteWait;
+
+  if (Timeout == 0) {
+    InfiniteWait = TRUE;
+  } else {
+    InfiniteWait = FALSE;
+  }
+
+  Delay =  DivU64x32 (Timeout, 1000) + 1;
+
+  do {
+    //
+    // Access sytem memory to see if the value is the tested one.
+    //
+    // The system memory pointed by Address will be updated by the
+    // SATA Host Controller, "volatile" is introduced to prevent
+    // compiler from optimizing the access to the memory address
+    // to only read once.
+    //
+    Value  = *(volatile UINT32 *) (UINTN) Address;
+    Value &= MaskValue;
+
+    if (Value == TestValue) {
+      return EFI_SUCCESS;
+    }
+
+    //
+    // Stall for 100 microseconds.
+    //
+    MicroSecondDelay (100);
+
+    Delay--;
+
+  } while (InfiniteWait || (Delay > 0));
+
+  return EFI_TIMEOUT;
+}
+
+/**
+
+  Clear the port interrupt and error status. It will also clear HBA interrupt
+  status.
+
+  @param[in] AhciBar    AHCI bar address.
+  @param[in] Port       The number of port.
+
+**/
+VOID
+AhciClearPortStatus (
+  IN UINTN    AhciBar,
+  IN UINT8    Port
+  )
+{
+  UINT32    Offset;
+
+  //
+  // Clear any error status
+  //
+  Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_SERR;
+  AhciWriteReg (AhciBar, Offset, AhciReadReg (AhciBar, Offset));
+
+  //
+  // Clear any port interrupt status
+  //
+  Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_IS;
+  AhciWriteReg (AhciBar, Offset, AhciReadReg (AhciBar, Offset));
+
+  //
+  // Clear any HBA interrupt status
+  //
+  AhciWriteReg (AhciBar, AHCI_IS_OFFSET, AhciReadReg (AhciBar, AHCI_IS_OFFSET));
+}
+
+/**
+  Enable the FIS running for giving port.
+
+  @param[in] AhciBar    AHCI bar address.
+  @param[in] Port       The number of port.
+  @param[in] Timeout    The timeout, in 100ns units, to enabling FIS.
+
+  @retval EFI_DEVICE_ERROR    The FIS enable setting fails.
+  @retval EFI_TIMEOUT         The FIS enable setting is time out.
+  @retval EFI_SUCCESS         The FIS enable successfully.
+
+**/
+EFI_STATUS
+AhciEnableFisReceive (
+  IN UINTN     AhciBar,
+  IN UINT8     Port,
+  IN UINT64    Timeout
+  )
+{
+  UINT32 Offset;
+
+  Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CMD;
+  AhciOrReg (AhciBar, Offset, AHCI_PORT_CMD_FRE);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Disable the FIS running for giving port.
+
+  @param[in] AhciBar    AHCI bar address.
+  @param[in] Port       The number of port.
+  @param[in] Timeout    The timeout value of disabling FIS, uses 100ns as a unit.
+
+  @retval EFI_DEVICE_ERROR    The FIS disable setting fails.
+  @retval EFI_TIMEOUT         The FIS disable setting is time out.
+  @retval EFI_UNSUPPORTED     The port is in running state.
+  @retval EFI_SUCCESS         The FIS disable successfully.
+
+**/
+EFI_STATUS
+AhciDisableFisReceive (
+  IN UINTN     AhciBar,
+  IN UINT8     Port,
+  IN UINT64    Timeout
+  )
+{
+  UINT32    Offset;
+  UINT32    Data;
+
+  Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CMD;
+  Data   = AhciReadReg (AhciBar, Offset);
+
+  //
+  // Before disabling Fis receive, the DMA engine of the port should NOT be in
+  // running status.
+  //
+  if ((Data & (AHCI_PORT_CMD_ST | AHCI_PORT_CMD_CR)) != 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Check if the Fis receive DMA engine for the port is running.
+  //
+  if ((Data & AHCI_PORT_CMD_FR) != AHCI_PORT_CMD_FR) {
+    return EFI_SUCCESS;
+  }
+
+  AhciAndReg (AhciBar, Offset, (UINT32)~(AHCI_PORT_CMD_FRE));
+
+  return AhciWaitMmioSet (
+           AhciBar,
+           Offset,
+           AHCI_PORT_CMD_FR,
+           0,
+           Timeout
+           );
+}
+
+/**
+  Build the command list, command table and prepare the fis receiver.
+
+  @param[in]     Private              The pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA.
+  @param[in]     Port                 The number of port.
+  @param[in]     PortMultiplier       The number of port multiplier.
+  @param[in]     FisIndex             The offset index of the FIS base address.
+  @param[in]     CommandFis           The control fis will be used for the transfer.
+  @param[in]     CommandList          The command list will be used for the transfer.
+  @param[in]     CommandSlotNumber    The command slot will be used for the transfer.
+  @param[in,out] DataPhysicalAddr     The pointer to the data buffer pci bus master
+                                      address.
+  @param[in]     DataLength           The data count to be transferred.
+
+**/
+VOID
+AhciBuildCommand (
+  IN     PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private,
+  IN     UINT8                               Port,
+  IN     UINT8                               PortMultiplier,
+  IN     UINT8                               FisIndex,
+  IN     EFI_AHCI_COMMAND_FIS                *CommandFis,
+  IN     EFI_AHCI_COMMAND_LIST               *CommandList,
+  IN     UINT8                               CommandSlotNumber,
+  IN OUT VOID                                *DataPhysicalAddr,
+  IN     UINT32                              DataLength
+  )
+{
+  EFI_AHCI_REGISTERS    *AhciRegisters;
+  UINTN                 AhciBar;
+  UINT64                BaseAddr;
+  UINT32                PrdtNumber;
+  UINT32                PrdtIndex;
+  UINTN                 RemainedData;
+  UINTN                 MemAddr;
+  DATA_64               Data64;
+  UINT32                Offset;
+
+  AhciRegisters = &Private->AhciRegisters;
+  AhciBar       = Private->MmioBase;
+
+  //
+  // Filling the PRDT
+  //
+  PrdtNumber = (UINT32)DivU64x32 (
+                         (UINT64)DataLength + AHCI_MAX_DATA_PER_PRDT - 1,
+                         AHCI_MAX_DATA_PER_PRDT
+                         );
+
+  //
+  // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB data block.
+  // It also limits that the maximum amount of the PRDT entry in the command table
+  // is 65535.
+  // Current driver implementation supports up to a maximum of AHCI_MAX_PRDT_NUMBER
+  // PRDT entries.
+  //
+  ASSERT (PrdtNumber <= AHCI_MAX_PRDT_NUMBER);
+  if (PrdtNumber > AHCI_MAX_PRDT_NUMBER) {
+    return;
+  }
+
+  Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis) + sizeof (EFI_AHCI_RECEIVED_FIS) * FisIndex;
+
+  BaseAddr = Data64.Uint64;
+
+  ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));
+
+  ZeroMem (AhciRegisters->AhciCmdTable, sizeof (EFI_AHCI_COMMAND_TABLE));
+
+  CommandFis->AhciCFisPmNum = PortMultiplier;
+
+  CopyMem (&AhciRegisters->AhciCmdTable->CommandFis, CommandFis, sizeof (EFI_AHCI_COMMAND_FIS));
+
+  Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CMD;
+  AhciAndReg (AhciBar, Offset, (UINT32)~(AHCI_PORT_CMD_DLAE | AHCI_PORT_CMD_ATAPI));
+
+  RemainedData = (UINTN) DataLength;
+  MemAddr      = (UINTN) DataPhysicalAddr;
+  CommandList->AhciCmdPrdtl = PrdtNumber;
+
+  for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {
+    if (RemainedData < AHCI_MAX_DATA_PER_PRDT) {
+      AhciRegisters->AhciCmdTable->PrdtTable[PrdtIndex].AhciPrdtDbc = (UINT32)RemainedData - 1;
+    } else {
+      AhciRegisters->AhciCmdTable->PrdtTable[PrdtIndex].AhciPrdtDbc = AHCI_MAX_DATA_PER_PRDT - 1;
+    }
+
+    Data64.Uint64 = (UINT64)MemAddr;
+    AhciRegisters->AhciCmdTable->PrdtTable[PrdtIndex].AhciPrdtDba  = Data64.Uint32.Lower32;
+    AhciRegisters->AhciCmdTable->PrdtTable[PrdtIndex].AhciPrdtDbau = Data64.Uint32.Upper32;
+    RemainedData -= AHCI_MAX_DATA_PER_PRDT;
+    MemAddr      += AHCI_MAX_DATA_PER_PRDT;
+  }
+
+  //
+  // Set the last PRDT to Interrupt On Complete
+  //
+  if (PrdtNumber > 0) {
+    AhciRegisters->AhciCmdTable->PrdtTable[PrdtNumber - 1].AhciPrdtIoc = 1;
+  }
+
+  CopyMem (
+    (VOID *) ((UINTN) AhciRegisters->AhciCmdList + (UINTN) CommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST)),
+    CommandList,
+    sizeof (EFI_AHCI_COMMAND_LIST)
+    );
+
+  Data64.Uint64 = (UINT64)(UINTN) AhciRegisters->AhciCmdTable;
+  AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtba  = Data64.Uint32.Lower32;
+  AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtbau = Data64.Uint32.Upper32;
+  AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdPmp   = PortMultiplier;
+}
+
+/**
+  Buid a command FIS.
+
+  @param[in,out] CmdFis             A pointer to the EFI_AHCI_COMMAND_FIS data
+                                    structure.
+  @param[in]     AtaCommandBlock    A pointer to the EFI_ATA_COMMAND_BLOCK data
+                                    structure.
+
+**/
+VOID
+AhciBuildCommandFis (
+  IN OUT EFI_AHCI_COMMAND_FIS     *CmdFis,
+  IN     EFI_ATA_COMMAND_BLOCK    *AtaCommandBlock
+  )
+{
+  ZeroMem (CmdFis, sizeof (EFI_AHCI_COMMAND_FIS));
+
+  CmdFis->AhciCFisType = AHCI_FIS_REGISTER_H2D;
+  //
+  // Indicator it's a command
+  //
+  CmdFis->AhciCFisCmdInd      = 0x1;
+  CmdFis->AhciCFisCmd         = AtaCommandBlock->AtaCommand;
+
+  CmdFis->AhciCFisFeature     = AtaCommandBlock->AtaFeatures;
+  CmdFis->AhciCFisFeatureExp  = AtaCommandBlock->AtaFeaturesExp;
+
+  CmdFis->AhciCFisSecNum      = AtaCommandBlock->AtaSectorNumber;
+  CmdFis->AhciCFisSecNumExp   = AtaCommandBlock->AtaSectorNumberExp;
+
+  CmdFis->AhciCFisClyLow      = AtaCommandBlock->AtaCylinderLow;
+  CmdFis->AhciCFisClyLowExp   = AtaCommandBlock->AtaCylinderLowExp;
+
+  CmdFis->AhciCFisClyHigh     = AtaCommandBlock->AtaCylinderHigh;
+  CmdFis->AhciCFisClyHighExp  = AtaCommandBlock->AtaCylinderHighExp;
+
+  CmdFis->AhciCFisSecCount    = AtaCommandBlock->AtaSectorCount;
+  CmdFis->AhciCFisSecCountExp = AtaCommandBlock->AtaSectorCountExp;
+
+  CmdFis->AhciCFisDevHead     = (UINT8) (AtaCommandBlock->AtaDeviceHead | 0xE0);
+}
+
+/**
+  Stop command running for giving port
+
+  @param[in] AhciBar    AHCI bar address.
+  @param[in] Port       The number of port.
+  @param[in] Timeout    The timeout value, in 100ns units, to stop.
+
+  @retval EFI_DEVICE_ERROR    The command stop unsuccessfully.
+  @retval EFI_TIMEOUT         The operation is time out.
+  @retval EFI_SUCCESS         The command stop successfully.
+
+**/
+EFI_STATUS
+AhciStopCommand (
+  IN  UINTN     AhciBar,
+  IN  UINT8     Port,
+  IN  UINT64    Timeout
+  )
+{
+  UINT32    Offset;
+  UINT32    Data;
+
+  Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CMD;
+  Data   = AhciReadReg (AhciBar, Offset);
+
+  if ((Data & (AHCI_PORT_CMD_ST | AHCI_PORT_CMD_CR)) == 0) {
+    return EFI_SUCCESS;
+  }
+
+  if ((Data & AHCI_PORT_CMD_ST) != 0) {
+    AhciAndReg (AhciBar, Offset, (UINT32)~(AHCI_PORT_CMD_ST));
+  }
+
+  return AhciWaitMmioSet (
+           AhciBar,
+           Offset,
+           AHCI_PORT_CMD_CR,
+           0,
+           Timeout
+           );
+}
+
+/**
+  Start command for give slot on specific port.
+
+  @param[in] AhciBar       AHCI bar address.
+  @param[in] Port          The number of port.
+  @param[in] CommandSlot   The number of Command Slot.
+  @param[in] Timeout       The timeout value, in 100ns units, to start.
+
+  @retval EFI_DEVICE_ERROR    The command start unsuccessfully.
+  @retval EFI_TIMEOUT         The operation is time out.
+  @retval EFI_SUCCESS         The command start successfully.
+
+**/
+EFI_STATUS
+AhciStartCommand (
+  IN  UINTN     AhciBar,
+  IN  UINT8     Port,
+  IN  UINT8     CommandSlot,
+  IN  UINT64    Timeout
+  )
+{
+  UINT32        CmdSlotBit;
+  EFI_STATUS    Status;
+  UINT32        PortStatus;
+  UINT32        StartCmd;
+  UINT32        PortTfd;
+  UINT32        Offset;
+  UINT32        Capability;
+
+  //
+  // Collect AHCI controller information
+  //
+  Capability = AhciReadReg (AhciBar, AHCI_CAPABILITY_OFFSET);
+
+  CmdSlotBit = (UINT32) (1 << CommandSlot);
+
+  AhciClearPortStatus (
+    AhciBar,
+    Port
+    );
+
+  Status = AhciEnableFisReceive (
+             AhciBar,
+             Port,
+             Timeout
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CMD;
+  PortStatus = AhciReadReg (AhciBar, Offset);
+
+  StartCmd = 0;
+  if ((PortStatus & AHCI_PORT_CMD_ALPE) != 0) {
+    StartCmd = AhciReadReg (AhciBar, Offset);
+    StartCmd &= ~AHCI_PORT_CMD_ICC_MASK;
+    StartCmd |= AHCI_PORT_CMD_ACTIVE;
+  }
+
+  Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_TFD;
+  PortTfd = AhciReadReg (AhciBar, Offset);
+
+  if ((PortTfd & (AHCI_PORT_TFD_BSY | AHCI_PORT_TFD_DRQ)) != 0) {
+    if ((Capability & BIT24) != 0) {
+      Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CMD;
+      AhciOrReg (AhciBar, Offset, AHCI_PORT_CMD_CLO);
+
+      AhciWaitMmioSet (
+        AhciBar,
+        Offset,
+        AHCI_PORT_CMD_CLO,
+        0,
+        Timeout
+        );
+    }
+  }
+
+  Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CMD;
+  AhciOrReg (AhciBar, Offset, AHCI_PORT_CMD_ST | StartCmd);
+
+  //
+  // Setting the command
+  //
+  Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CI;
+  AhciAndReg (AhciBar, Offset, 0);
+  AhciOrReg  (AhciBar, Offset, CmdSlotBit);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Start a PIO Data transfer on specific port.
+
+  @param[in]     Private            The pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA.
+  @param[in]     Port               The number of port.
+  @param[in]     PortMultiplier     The number of port multiplier.
+  @param[in]     FisIndex           The offset index of the FIS base address.
+  @param[in]     Read               The transfer direction.
+  @param[in]     AtaCommandBlock    The EFI_ATA_COMMAND_BLOCK data.
+  @param[in,out] AtaStatusBlock     The EFI_ATA_STATUS_BLOCK data.
+  @param[in,out] MemoryAddr         The pointer to the data buffer.
+  @param[in]     DataCount          The data count to be transferred.
+  @param[in]     Timeout            The timeout value of PIO data transfer, uses
+                                    100ns as a unit.
+
+  @retval EFI_DEVICE_ERROR        The PIO data transfer abort with error occurs.
+  @retval EFI_TIMEOUT             The operation is time out.
+  @retval EFI_UNSUPPORTED         The device is not ready for transfer.
+  @retval EFI_OUT_OF_RESOURCES    The operation fails due to lack of resources.
+  @retval EFI_SUCCESS             The PIO data transfer executes successfully.
+
+**/
+EFI_STATUS
+AhciPioTransfer (
+  IN     PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private,
+  IN     UINT8                               Port,
+  IN     UINT8                               PortMultiplier,
+  IN     UINT8                               FisIndex,
+  IN     BOOLEAN                             Read,
+  IN     EFI_ATA_COMMAND_BLOCK               *AtaCommandBlock,
+  IN OUT EFI_ATA_STATUS_BLOCK                *AtaStatusBlock,
+  IN OUT VOID                                *MemoryAddr,
+  IN     UINT32                              DataCount,
+  IN     UINT64                              Timeout
+  )
+{
+  EFI_STATUS                    Status;
+  EDKII_IOMMU_OPERATION         MapOp;
+  UINTN                         MapLength;
+  EFI_PHYSICAL_ADDRESS          PhyAddr;
+  VOID                          *MapData;
+  EFI_AHCI_REGISTERS            *AhciRegisters;
+  UINTN                         AhciBar;
+  BOOLEAN                       InfiniteWait;
+  UINT32                        Offset;
+  UINT32                        OldRfisLo;
+  UINT32                        OldRfisHi;
+  UINT32                        OldCmdListLo;
+  UINT32                        OldCmdListHi;
+  DATA_64                       Data64;
+  UINT32                        FisBaseAddr;
+  UINT32                        Delay;
+  EFI_AHCI_COMMAND_FIS          CFis;
+  EFI_AHCI_COMMAND_LIST         CmdList;
+  UINT32                        PortTfd;
+  UINT32                        PrdCount;
+  BOOLEAN                       PioFisReceived;
+  BOOLEAN                       D2hFisReceived;
+
+  //
+  // Current driver implementation supports up to a maximum of AHCI_MAX_PRDT_NUMBER
+  // PRDT entries.
+  //
+  if (DataCount / (UINT32)AHCI_MAX_PRDT_NUMBER > AHCI_MAX_DATA_PER_PRDT) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "%a: Driver only support a maximum of 0x%x PRDT entries, "
+      "current number of data byte 0x%x is too large, maximum allowed is 0x%x.\n",
+      __FUNCTION__, AHCI_MAX_PRDT_NUMBER, DataCount,
+      AHCI_MAX_PRDT_NUMBER * AHCI_MAX_DATA_PER_PRDT
+      ));
+    return EFI_UNSUPPORTED;
+  }
+
+  MapOp     = Read ? EdkiiIoMmuOperationBusMasterWrite :
+                     EdkiiIoMmuOperationBusMasterRead;
+  MapLength = DataCount;
+  Status    = IoMmuMap (
+                MapOp,
+                MemoryAddr,
+                &MapLength,
+                &PhyAddr,
+                &MapData
+                );
+  if (EFI_ERROR (Status) || (MapLength != DataCount)) {
+    DEBUG ((DEBUG_ERROR, "%a: Fail to map data buffer.\n", __FUNCTION__));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  AhciRegisters  = &Private->AhciRegisters;
+  AhciBar        = Private->MmioBase;
+  InfiniteWait   = (Timeout == 0) ? TRUE : FALSE;
+
+  //
+  // Fill FIS base address register
+  //
+  Offset        = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_FB;
+  OldRfisLo     = AhciReadReg (AhciBar, Offset);
+  Offset        = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_FBU;
+  OldRfisHi     = AhciReadReg (AhciBar, Offset);
+  Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis) + sizeof (EFI_AHCI_RECEIVED_FIS) * FisIndex;
+  Offset        = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_FB;
+  AhciWriteReg (AhciBar, Offset, Data64.Uint32.Lower32);
+  Offset        = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_FBU;
+  AhciWriteReg (AhciBar, Offset, Data64.Uint32.Upper32);
+
+  //
+  // Single task envrionment, we only use one command table for all port
+  //
+  Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CLB;
+  OldCmdListLo  = AhciReadReg (AhciBar, Offset);
+  Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CLBU;
+  OldCmdListHi  = AhciReadReg (AhciBar, Offset);
+  Data64.Uint64 = (UINTN) (AhciRegisters->AhciCmdList);
+  Offset        = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CLB;
+  AhciWriteReg (AhciBar, Offset, Data64.Uint32.Lower32);
+  Offset        = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CLBU;
+  AhciWriteReg (AhciBar, Offset, Data64.Uint32.Upper32);
+
+  //
+  // Package read needed
+  //
+  AhciBuildCommandFis (&CFis, AtaCommandBlock);
+
+  ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));
+
+  CmdList.AhciCmdCfl = AHCI_FIS_REGISTER_H2D_LENGTH / 4;
+  CmdList.AhciCmdW   = Read ? 0 : 1;
+
+  AhciBuildCommand (
+    Private,
+    Port,
+    PortMultiplier,
+    FisIndex,
+    &CFis,
+    &CmdList,
+    0,
+    (VOID *)(UINTN)PhyAddr,
+    DataCount
+    );
+
+  Status = AhciStartCommand (
+             AhciBar,
+             Port,
+             0,
+             Timeout
+             );
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  //
+  // Checking the status and wait the driver sending Data
+  //
+  FisBaseAddr = (UINT32)(UINTN)AhciRegisters->AhciRFis + sizeof (EFI_AHCI_RECEIVED_FIS) * FisIndex;
+  if (Read) {
+    //
+    // Wait device sends the PIO setup fis before data transfer
+    //
+    Status = EFI_TIMEOUT;
+    Delay  = (UINT32) DivU64x32 (Timeout, 1000) + 1;
+    do {
+      PioFisReceived = FALSE;
+      D2hFisReceived = FALSE;
+      Offset = FisBaseAddr + AHCI_PIO_FIS_OFFSET;
+      Status = AhciCheckMemSet (Offset, AHCI_FIS_TYPE_MASK, AHCI_FIS_PIO_SETUP);
+      if (!EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_INFO, "%a: PioFisReceived.\n", __FUNCTION__));
+        PioFisReceived = TRUE;
+      }
+      //
+      // According to SATA 2.6 spec section 11.7, D2h FIS means an error encountered.
+      // But Qemu and Marvel 9230 sata controller may just receive a D2h FIS from
+      // device after the transaction is finished successfully.
+      // To get better device compatibilities, we further check if the PxTFD's
+      // ERR bit is set. By this way, we can know if there is a real error happened.
+      //
+      Offset = FisBaseAddr + AHCI_D2H_FIS_OFFSET;
+      Status = AhciCheckMemSet (Offset, AHCI_FIS_TYPE_MASK, AHCI_FIS_REGISTER_D2H);
+      if (!EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_INFO, "%a: D2hFisReceived.\n", __FUNCTION__));
+        D2hFisReceived = TRUE;
+      }
+
+      if (PioFisReceived || D2hFisReceived) {
+        Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_TFD;
+        PortTfd = AhciReadReg (AhciBar, (UINT32) Offset);
+        //
+        // PxTFD will be updated if there is a D2H or SetupFIS received.
+        //
+        if ((PortTfd & AHCI_PORT_TFD_ERR) != 0) {
+          Status = EFI_DEVICE_ERROR;
+          break;
+        }
+
+        PrdCount = *(volatile UINT32 *) (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));
+        if (PrdCount == DataCount) {
+          Status = EFI_SUCCESS;
+          break;
+        }
+      }
+
+      //
+      // Stall for 100 microseconds.
+      //
+      MicroSecondDelay(100);
+
+      Delay--;
+      if (Delay == 0) {
+        Status = EFI_TIMEOUT;
+      }
+    } while (InfiniteWait || (Delay > 0));
+  } else {
+    //
+    // Wait for D2H Fis is received
+    //
+    Offset = FisBaseAddr + AHCI_D2H_FIS_OFFSET;
+    Status = AhciWaitMemSet (
+               Offset,
+               AHCI_FIS_TYPE_MASK,
+               AHCI_FIS_REGISTER_D2H,
+               Timeout
+               );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: AhciWaitMemSet (%r)\n", __FUNCTION__, Status));
+      goto Exit;
+    }
+
+    Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_TFD;
+    PortTfd = AhciReadReg (AhciBar, (UINT32) Offset);
+    if ((PortTfd & AHCI_PORT_TFD_ERR) != 0) {
+      Status = EFI_DEVICE_ERROR;
+    }
+  }
+
+Exit:
+  AhciStopCommand (
+    AhciBar,
+    Port,
+    Timeout
+    );
+
+  AhciDisableFisReceive (
+    AhciBar,
+    Port,
+    Timeout
+    );
+
+  if (MapData != NULL) {
+    IoMmuUnmap (MapData);
+  }
+
+  Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_FB;
+  AhciWriteReg (AhciBar, Offset, OldRfisLo);
+  Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_FBU;
+  AhciWriteReg (AhciBar, Offset, OldRfisHi);
+
+  Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CLB;
+  AhciWriteReg (AhciBar, Offset, OldCmdListLo);
+  Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CLBU;
+  AhciWriteReg (AhciBar, Offset, OldCmdListHi);
+
+  return Status;
+}
+
+/**
+  Start a non data transfer on specific port.
+
+  @param[in]     Private            The pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA.
+  @param[in]     Port               The number of port.
+  @param[in]     PortMultiplier     The number of port multiplier.
+  @param[in]     FisIndex           The offset index of the FIS base address.
+  @param[in]     AtaCommandBlock    The EFI_ATA_COMMAND_BLOCK data.
+  @param[in,out] AtaStatusBlock     The EFI_ATA_STATUS_BLOCK data.
+  @param[in]     Timeout            The timeout value of non data transfer, uses
+                                    100ns as a unit.
+
+  @retval EFI_DEVICE_ERROR        The non data transfer abort with error occurs.
+  @retval EFI_TIMEOUT             The operation is time out.
+  @retval EFI_UNSUPPORTED         The device is not ready for transfer.
+  @retval EFI_SUCCESS             The non data transfer executes successfully.
+
+**/
+EFI_STATUS
+AhciNonDataTransfer (
+  IN     PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private,
+  IN     UINT8                               Port,
+  IN     UINT8                               PortMultiplier,
+  IN     UINT8                               FisIndex,
+  IN     EFI_ATA_COMMAND_BLOCK               *AtaCommandBlock,
+  IN OUT EFI_ATA_STATUS_BLOCK                *AtaStatusBlock,
+  IN     UINT64                              Timeout
+  )
+{
+  EFI_STATUS                  Status;
+  UINTN                       AhciBar;
+  EFI_AHCI_REGISTERS          *AhciRegisters;
+  UINTN                       FisBaseAddr;
+  UINTN                       Offset;
+  UINT32                      PortTfd;
+  EFI_AHCI_COMMAND_FIS        CFis;
+  EFI_AHCI_COMMAND_LIST       CmdList;
+
+  AhciBar        = Private->MmioBase;
+  AhciRegisters = &Private->AhciRegisters;
+
+  //
+  // Package read needed
+  //
+  AhciBuildCommandFis (&CFis, AtaCommandBlock);
+
+  ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));
+
+  CmdList.AhciCmdCfl = AHCI_FIS_REGISTER_H2D_LENGTH / 4;
+
+  AhciBuildCommand (
+    Private,
+    Port,
+    PortMultiplier,
+    FisIndex,
+    &CFis,
+    &CmdList,
+    0,
+    NULL,
+    0
+    );
+
+  Status = AhciStartCommand (
+             AhciBar,
+             Port,
+             0,
+             Timeout
+             );
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  //
+  // Wait device sends the Response Fis
+  //
+  FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + sizeof (EFI_AHCI_RECEIVED_FIS) * FisIndex;
+  Offset      = FisBaseAddr + AHCI_D2H_FIS_OFFSET;
+  Status      = AhciWaitMemSet (
+                  Offset,
+                  AHCI_FIS_TYPE_MASK,
+                  AHCI_FIS_REGISTER_D2H,
+                  Timeout
+                  );
+
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_TFD;
+  PortTfd = AhciReadReg (AhciBar, (UINT32) Offset);
+  if ((PortTfd & AHCI_PORT_TFD_ERR) != 0) {
+    Status = EFI_DEVICE_ERROR;
+  }
+
+Exit:
+  AhciStopCommand (
+    AhciBar,
+    Port,
+    Timeout
+    );
+
+  AhciDisableFisReceive (
+    AhciBar,
+    Port,
+    Timeout
+    );
+
+  return Status;
+}
+
+/**
+  Do AHCI HBA reset.
+
+  @param[in] AhciBar         AHCI bar address.
+  @param[in] Timeout         The timeout, in 100ns units, to reset.
+
+  @retval EFI_DEVICE_ERROR   AHCI controller is failed to complete hardware reset.
+  @retval EFI_TIMEOUT        The reset operation is time out.
+  @retval EFI_SUCCESS        AHCI controller is reset successfully.
+
+**/
+EFI_STATUS
+AhciReset (
+  IN UINTN     AhciBar,
+  IN UINT64    Timeout
+  )
+{
+  UINT32    Delay;
+  UINT32    Value;
+  UINT32    Capability;
+
+  //
+  // Collect AHCI controller information
+  //
+  Capability = AhciReadReg (AhciBar, AHCI_CAPABILITY_OFFSET);
+
+  //
+  // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only is not set
+  //
+  if ((Capability & AHCI_CAP_SAM) == 0) {
+    AhciOrReg (AhciBar, AHCI_GHC_OFFSET, AHCI_GHC_ENABLE);
+  }
+
+  AhciOrReg (AhciBar, AHCI_GHC_OFFSET, AHCI_GHC_RESET);
+
+  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
+
+  do {
+    Value = AhciReadReg(AhciBar, AHCI_GHC_OFFSET);
+    if ((Value & AHCI_GHC_RESET) == 0) {
+      return EFI_SUCCESS;
+    }
+
+    //
+    // Stall for 100 microseconds.
+    //
+    MicroSecondDelay(100);
+
+    Delay--;
+  } while (Delay > 0);
+
+  return EFI_TIMEOUT;
+}
+
+/**
+  Send Identify Drive command to a specific device.
+
+  @param[in] Private           The pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA.
+  @param[in] Port              The number of port.
+  @param[in] PortMultiplier    The port multiplier port number.
+  @param[in] FisIndex          The offset index of the FIS base address.
+  @param[in] Buffer            The data buffer to store IDENTIFY PACKET data.
+
+  @retval EFI_SUCCESS              The cmd executes successfully.
+  @retval EFI_INVALID_PARAMETER    Buffer is NULL.
+  @retval EFI_DEVICE_ERROR         The cmd abort with error occurs.
+  @retval EFI_TIMEOUT              The operation is time out.
+  @retval EFI_UNSUPPORTED          The device is not ready for executing.
+
+**/
+EFI_STATUS
+AhciIdentify (
+  IN PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private,
+  IN UINT8                               Port,
+  IN UINT8                               PortMultiplier,
+  IN UINT8                               FisIndex,
+  IN ATA_IDENTIFY_DATA                   *Buffer
+  )
+{
+  EFI_STATUS                     Status;
+  EFI_ATA_COMMAND_BLOCK    Acb;
+  EFI_ATA_STATUS_BLOCK     Asb;
+
+  if (Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem (&Acb, sizeof (EFI_ATA_COMMAND_BLOCK));
+  ZeroMem (&Asb, sizeof (EFI_ATA_STATUS_BLOCK));
+
+  Acb.AtaCommand     = ATA_CMD_IDENTIFY_DRIVE;
+  Acb.AtaSectorCount = 1;
+
+  Status = AhciPioTransfer (
+             Private,
+             Port,
+             PortMultiplier,
+             FisIndex,
+             TRUE,
+             &Acb,
+             &Asb,
+             Buffer,
+             sizeof (ATA_IDENTIFY_DATA),
+             ATA_TIMEOUT
+             );
+
+  return Status;
+}
+
+
+/**
+  Collect the number of bits set within a port bitmap.
+
+  @param[in] PortBitMap    A 32-bit wide bit map of ATA AHCI ports.
+
+  @retval The number of bits set in the bitmap.
+
+**/
+UINT8
+AhciGetNumberOfPortsFromMap (
+  IN UINT32    PortBitMap
+  )
+{
+  UINT8    NumberOfPorts;
+
+  NumberOfPorts = 0;
+
+  while (PortBitMap != 0) {
+    if ((PortBitMap & ((UINT32)BIT0)) != 0) {
+      NumberOfPorts++;
+    }
+    PortBitMap = PortBitMap >> 1;
+  }
+
+  return NumberOfPorts;
+}
+
+/**
+  Get the specified port number from a port bitmap.
+
+  @param[in]  PortBitMap    A 32-bit wide bit map of ATA AHCI ports.
+  @param[in]  PortIndex     The specified port index.
+  @param[out] Port          The port number of the port specified by PortIndex.
+
+  @retval EFI_SUCCESS       The specified port is found and its port number is
+                            in Port.
+  @retval EFI_NOT_FOUND     Cannot find the specified port within the port bitmap.
+
+**/
+EFI_STATUS
+AhciGetPortFromMap (
+  IN  UINT32    PortBitMap,
+  IN  UINT8     PortIndex,
+  OUT UINT8     *Port
+  )
+{
+  if (PortIndex == 0) {
+    return EFI_NOT_FOUND;
+  }
+
+  *Port = 0;
+
+  while (PortBitMap != 0) {
+    if ((PortBitMap & ((UINT32)BIT0)) != 0) {
+      PortIndex--;
+
+      //
+      // Found the port specified by PortIndex.
+      //
+      if (PortIndex == 0) {
+        return EFI_SUCCESS;
+      }
+    }
+    PortBitMap = PortBitMap >> 1;
+    *Port      = *Port + 1;
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+/**
+  Allocate transfer-related data struct which is used at AHCI mode.
+
+  @param[in,out] Private    A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA instance.
+
+  @retval EFI_SUCCESS    Data structures are allocated successfully.
+  @retval Others         Data structures are not allocated successfully.
+
+**/
+EFI_STATUS
+AhciCreateTransferDescriptor (
+  IN OUT PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private
+  )
+{
+  EFI_STATUS              Status;
+  UINTN                   AhciBar;
+  EFI_AHCI_REGISTERS      *AhciRegisters;
+  EFI_PHYSICAL_ADDRESS    DeviceAddress;
+  VOID                    *Base;
+  VOID                    *Mapping;
+  UINT32                  Capability;
+  UINT32                  PortImplementBitMap;
+  UINT8                   MaxPortNumber;
+  UINT8                   MaxCommandSlotNumber;
+  UINTN                   MaxRFisSize;
+  UINTN                   MaxCmdListSize;
+  UINTN                   MaxCmdTableSize;
+
+  AhciBar       = Private->MmioBase;
+  AhciRegisters = &Private->AhciRegisters;
+
+  //
+  // Collect AHCI controller information
+  //
+  Capability = AhciReadReg (AhciBar, AHCI_CAPABILITY_OFFSET);
+
+  //
+  // Get the number of command slots per port supported by this HBA.
+  //
+  MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);
+  ASSERT (MaxCommandSlotNumber > 0);
+  if (MaxCommandSlotNumber == 0) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Get the highest bit of implemented ports which decides how many bytes are
+  // allocated for recived FIS.
+  //
+  PortImplementBitMap = AhciReadReg (AhciBar, AHCI_PI_OFFSET);
+  MaxPortNumber       = (UINT8)(UINTN)(HighBitSet32(PortImplementBitMap) + 1);
+  if (MaxPortNumber == 0) {
+    return EFI_DEVICE_ERROR;
+  }
+  //
+  // Get the number of ports that actually needed to be initialized.
+  //
+  MaxPortNumber = MIN (MaxPortNumber, AhciGetNumberOfPortsFromMap (Private->PortBitMap));
+
+  //
+  // Allocate memory for received FIS.
+  //
+  MaxRFisSize = MaxPortNumber * sizeof (EFI_AHCI_RECEIVED_FIS);
+  Status = IoMmuAllocateBuffer (
+             EFI_SIZE_TO_PAGES (MaxRFisSize),
+             &Base,
+             &DeviceAddress,
+             &Mapping
+             );
+  if (EFI_ERROR (Status)) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
+  AhciRegisters->AhciRFis    = Base;
+  AhciRegisters->AhciRFisMap = Mapping;
+  AhciRegisters->MaxRFisSize = MaxRFisSize;
+  ZeroMem (AhciRegisters->AhciRFis, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (MaxRFisSize));
+
+  //
+  // Allocate memory for command list.
+  // Note that the implemenation is a single task model which only use a command
+  // list for each port.
+  //
+  MaxCmdListSize = 1 * sizeof (EFI_AHCI_COMMAND_LIST);
+  Status = IoMmuAllocateBuffer (
+             EFI_SIZE_TO_PAGES (MaxCmdListSize),
+             &Base,
+             &DeviceAddress,
+             &Mapping
+             );
+  if (EFI_ERROR (Status)) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto ErrorExit;
+  }
+  ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
+  AhciRegisters->AhciCmdList    = Base;
+  AhciRegisters->AhciCmdListMap = Mapping;
+  AhciRegisters->MaxCmdListSize = MaxCmdListSize;
+  ZeroMem (AhciRegisters->AhciCmdList, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (MaxCmdListSize));
+
+  //
+  // Allocate memory for command table
+  // According to AHCI 1.3 spec, a PRD table can contain maximum 65535 entries.
+  //
+  MaxCmdTableSize = sizeof (EFI_AHCI_COMMAND_TABLE);
+  Status = IoMmuAllocateBuffer (
+             EFI_SIZE_TO_PAGES (MaxCmdTableSize),
+             &Base,
+             &DeviceAddress,
+             &Mapping
+             );
+  if (EFI_ERROR (Status)) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto ErrorExit;
+  }
+  ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
+  AhciRegisters->AhciCmdTable    = Base;
+  AhciRegisters->AhciCmdTableMap = Mapping;
+  AhciRegisters->MaxCmdTableSize = MaxCmdTableSize;
+  ZeroMem (AhciRegisters->AhciCmdTable, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (MaxCmdTableSize));
+
+  return EFI_SUCCESS;
+
+ErrorExit:
+  if (AhciRegisters->AhciRFisMap != NULL) {
+    IoMmuFreeBuffer (
+       EFI_SIZE_TO_PAGES (AhciRegisters->MaxRFisSize),
+       AhciRegisters->AhciRFis,
+       AhciRegisters->AhciRFisMap
+       );
+    AhciRegisters->AhciRFis = NULL;
+  }
+
+  if (AhciRegisters->AhciCmdListMap != NULL) {
+    IoMmuFreeBuffer (
+       EFI_SIZE_TO_PAGES (AhciRegisters->MaxCmdListSize),
+       AhciRegisters->AhciCmdList,
+       AhciRegisters->AhciCmdListMap
+       );
+    AhciRegisters->AhciCmdList = NULL;
+  }
+
+  return Status;
+}
+
+/**
+  Gets ATA device Capacity according to ATA 6.
+
+  This function returns the capacity of the ATA device if it follows
+  ATA 6 to support 48 bit addressing.
+
+  @param[in] IdentifyData    A pointer to ATA_IDENTIFY_DATA structure.
+
+  @return The capacity of the ATA device or 0 if the device does not support
+          48-bit addressing defined in ATA 6.
+
+**/
+EFI_LBA
+GetAtapi6Capacity (
+  IN ATA_IDENTIFY_DATA    *IdentifyData
+  )
+{
+  EFI_LBA                       Capacity;
+  EFI_LBA                       TmpLba;
+  UINTN                         Index;
+
+  if ((IdentifyData->command_set_supported_83 & BIT10) == 0) {
+    //
+    // The device doesn't support 48 bit addressing
+    //
+    return 0;
+  }
+
+  //
+  // 48 bit address feature set is supported, get maximum capacity
+  //
+  Capacity = 0;
+  for (Index = 0; Index < 4; Index++) {
+    //
+    // Lower byte goes first: word[100] is the lowest word, word[103] is highest
+    //
+    TmpLba = IdentifyData->maximum_lba_for_48bit_addressing[Index];
+    Capacity |= LShiftU64 (TmpLba, 16 * Index);
+  }
+
+  return Capacity;
+}
+
+/**
+  Identifies ATA device via the Identify data.
+
+  This function identifies the ATA device and initializes the media information.
+
+  @attention This is boundary function that may receive untrusted input.
+  @attention The input is from peripheral hardware device.
+
+  The Identify Drive command response data from an ATA device is the peripheral
+  hardware input, so this routine will do basic validation for the Identify Drive
+  command response data.
+
+  @param[in,out] DeviceData    A pointer to PEI_AHCI_ATA_DEVICE_DATA structure.
+
+  @retval EFI_SUCCESS        The device is successfully identified and media
+                             information is correctly initialized.
+  @retval EFI_UNSUPPORTED    The device is not a valid ATA device (hard disk).
+
+**/
+EFI_STATUS
+IdentifyAtaDevice (
+  IN OUT PEI_AHCI_ATA_DEVICE_DATA    *DeviceData
+  )
+{
+  ATA_IDENTIFY_DATA          *IdentifyData;
+  EFI_PEI_BLOCK_IO2_MEDIA    *Media;
+  EFI_LBA                    Capacity;
+  UINT32                     MaxSectorCount;
+  UINT16                     PhyLogicSectorSupport;
+
+  IdentifyData = DeviceData->IdentifyData;
+  Media        = &DeviceData->Media;
+
+  if ((IdentifyData->config & BIT15) != 0) {
+    DEBUG ((
+      DEBUG_ERROR, "%a: Not a hard disk device on Port 0x%x PortMultiplierPort 0x%x\n",
+      __FUNCTION__, DeviceData->Port, DeviceData->PortMultiplier
+      ));
+    return EFI_UNSUPPORTED;
+  }
+
+  DEBUG ((
+    DEBUG_INFO, "%a: Identify Device: Port 0x%x PortMultiplierPort 0x%x\n",
+    __FUNCTION__, DeviceData->Port, DeviceData->PortMultiplier
+    ));
+
+  //
+  // Skip checking whether the WORD 88 (supported UltraDMA by drive), since the
+  // driver only support PIO data transfer for now.
+  //
+
+  //
+  // Get the capacity information of the device.
+  //
+  Capacity = GetAtapi6Capacity (IdentifyData);
+  if (Capacity > MAX_28BIT_ADDRESSING_CAPACITY) {
+    //
+    // Capacity exceeds 120GB. 48-bit addressing is really needed
+    //
+    DeviceData->Lba48Bit = TRUE;
+  } else {
+    //
+    // This is a hard disk <= 120GB capacity, treat it as normal hard disk
+    //
+    Capacity = ((UINT32)IdentifyData->user_addressable_sectors_hi << 16) |
+                        IdentifyData->user_addressable_sectors_lo;
+    DeviceData->Lba48Bit = FALSE;
+  }
+
+  if (Capacity == 0) {
+    DEBUG ((DEBUG_ERROR, "%a: Invalid Capacity (0) for ATA device.\n", __FUNCTION__));
+    return EFI_UNSUPPORTED;
+  }
+  Media->LastBlock = (EFI_PEI_LBA) (Capacity - 1);
+
+  Media->BlockSize = 0x200;
+  //
+  // Check whether Long Physical Sector Feature is supported
+  //
+  PhyLogicSectorSupport = IdentifyData->phy_logic_sector_support;
+  DEBUG ((
+    DEBUG_INFO, "%a: PhyLogicSectorSupport = 0x%x\n",
+    __FUNCTION__, PhyLogicSectorSupport
+    ));
+  if ((PhyLogicSectorSupport & (BIT14 | BIT15)) == BIT14) {
+    //
+    // Check logical block size
+    //
+    if ((PhyLogicSectorSupport & BIT12) != 0) {
+      Media->BlockSize = (UINT32) (((IdentifyData->logic_sector_size_hi << 16) |
+                                     IdentifyData->logic_sector_size_lo) * sizeof (UINT16));
+    }
+  }
+
+  //
+  // Check BlockSize validity
+  //
+  MaxSectorCount = mMaxTransferBlockNumber[DeviceData->Lba48Bit];
+  if ((Media->BlockSize == 0) || (Media->BlockSize > MAX_UINT32 / MaxSectorCount)) {
+    DEBUG ((DEBUG_ERROR, "%a: Invalid BlockSize (0x%x).\n", __FUNCTION__, Media->BlockSize));
+    return EFI_UNSUPPORTED;
+  }
+
+  DEBUG ((
+    DEBUG_INFO, "%a: BlockSize = 0x%x, LastBlock = 0x%lx\n",
+    __FUNCTION__, Media->BlockSize, Media->LastBlock
+    ));
+
+  if ((IdentifyData->trusted_computing_support & BIT0) != 0) {
+    DEBUG ((DEBUG_INFO, "%a: Found Trust Computing feature support.\n", __FUNCTION__));
+    DeviceData->TrustComputing = TRUE;
+  }
+
+  Media->InterfaceType  = MSG_SATA_DP;
+  Media->RemovableMedia = FALSE;
+  Media->MediaPresent   = TRUE;
+  Media->ReadOnly       = FALSE;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Allocate device information data structure to contain device information.
+  And insert the data structure to the tail of device list for tracing.
+
+  @param[in,out] Private               A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA
+                                       instance.
+  @param[in]     DeviceIndex           The device index.
+  @param[in]     Port                  The port number of the ATA device to send
+                                       the command.
+  @param[in]     PortMultiplierPort    The port multiplier port number of the ATA
+                                       device to send the command.
+                                       If there is no port multiplier, then specify
+                                       0xFFFF.
+  @param[in]     FisIndex              The index of the FIS of the ATA device to
+                                       send the command.
+  @param[in]     IdentifyData          The data buffer to store the output of the
+                                       IDENTIFY command.
+
+  @retval EFI_SUCCESS                  Successfully insert the ATA device to the
+                                       tail of device list.
+  @retval EFI_OUT_OF_RESOURCES         Not enough resource.
+
+**/
+EFI_STATUS
+CreateNewDevice (
+  IN OUT PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private,
+  IN     UINTN                               DeviceIndex,
+  IN     UINT16                              Port,
+  IN     UINT16                              PortMultiplier,
+  IN     UINT8                               FisIndex,
+  IN     ATA_IDENTIFY_DATA                   *IdentifyData
+  )
+{
+  PEI_AHCI_ATA_DEVICE_DATA    *DeviceData;
+  EFI_STATUS                  Status;
+
+  DeviceData = AllocateZeroPool (sizeof (PEI_AHCI_ATA_DEVICE_DATA));
+  if (DeviceData == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  if (IdentifyData != NULL) {
+    DeviceData->IdentifyData = AllocateCopyPool (sizeof (ATA_IDENTIFY_DATA), IdentifyData);
+    if (DeviceData->IdentifyData == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  }
+
+  DeviceData->Signature      = AHCI_PEI_ATA_DEVICE_DATA_SIGNATURE;
+  DeviceData->Port           = Port;
+  DeviceData->PortMultiplier = PortMultiplier;
+  DeviceData->FisIndex       = FisIndex;
+  DeviceData->DeviceIndex    = DeviceIndex;
+  DeviceData->Private        = Private;
+
+  Status = IdentifyAtaDevice (DeviceData);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (DeviceData->TrustComputing) {
+    Private->TrustComputingDevices++;
+    DeviceData->TrustComputingDeviceIndex = Private->TrustComputingDevices;
+  }
+  Private->ActiveDevices++;
+  InsertTailList (&Private->DeviceList, &DeviceData->Link);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Initialize ATA host controller at AHCI mode.
+
+  The function is designed to initialize ATA host controller.
+
+  @param[in,out] Private    A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA instance.
+
+  @retval EFI_SUCCESS             The ATA AHCI controller is initialized successfully.
+  @retval EFI_OUT_OF_RESOURCES    Not enough resource to complete while initializing
+                                  the controller.
+  @retval Others                  A device error occurred while initializing the
+                                  controller.
+
+**/
+EFI_STATUS
+AhciModeInitialization (
+  IN OUT PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private
+  )
+{
+  EFI_STATUS            Status;
+  UINTN                 AhciBar;
+  UINT32                Capability;
+  UINT32                Value;
+  UINT8                 MaxPortNumber;
+  UINT32                PortImplementBitMap;
+  UINT32                PortInitializeBitMap;
+  EFI_AHCI_REGISTERS    *AhciRegisters;
+  UINT8                 PortIndex;
+  UINT8                 Port;
+  DATA_64               Data64;
+  UINT32                Data;
+  UINT32                Offset;
+  UINT32                PhyDetectDelay;
+  UINTN                 DeviceIndex;
+  ATA_IDENTIFY_DATA     IdentifyData;
+
+  AhciBar = Private->MmioBase;
+
+  Status = AhciReset (AhciBar, AHCI_PEI_RESET_TIMEOUT);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: AHCI HBA reset failed with %r.\n", __FUNCTION__, Status));
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Collect AHCI controller information
+  //
+  Capability = AhciReadReg (AhciBar, AHCI_CAPABILITY_OFFSET);
+
+  //
+  // Make sure that GHC.AE bit is set before accessing any AHCI registers.
+  //
+  Value = AhciReadReg (AhciBar, AHCI_GHC_OFFSET);
+  if ((Value & AHCI_GHC_ENABLE) == 0) {
+    AhciOrReg (AhciBar, AHCI_GHC_OFFSET, AHCI_GHC_ENABLE);
+  }
+
+  Status = AhciCreateTransferDescriptor (Private);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "%a: Transfer-related data allocation failed with %r.\n",
+      __FUNCTION__, Status
+      ));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Get the number of command slots per port supported by this HBA.
+  //
+  MaxPortNumber = (UINT8) ((Capability & 0x1F) + 1);
+
+  //
+  // Get the bit map of those ports exposed by this HBA.
+  // It indicates which ports that the HBA supports are available for software
+  // to use.
+  //
+  PortImplementBitMap = AhciReadReg (AhciBar, AHCI_PI_OFFSET);
+
+  //
+  // Get the number of ports that actually needed to be initialized.
+  //
+  MaxPortNumber = MIN (MaxPortNumber, (UINT8)(UINTN)(HighBitSet32(PortImplementBitMap) + 1));
+  MaxPortNumber = MIN (MaxPortNumber, AhciGetNumberOfPortsFromMap (Private->PortBitMap));
+
+  PortInitializeBitMap = Private->PortBitMap;
+  AhciRegisters        = &Private->AhciRegisters;
+  DeviceIndex          = 0;
+  //
+  // Enumerate ATA ports
+  //
+  for (PortIndex = 1; PortIndex <= MaxPortNumber; PortIndex ++) {
+    Status = AhciGetPortFromMap (PortInitializeBitMap, PortIndex, &Port);
+    if ((PortImplementBitMap & (BIT0 << Port)) != 0) {
+      //
+      // Initialize FIS Base Address Register and Command List Base Address
+      // Register for use.
+      //
+      Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis) +
+                      sizeof (EFI_AHCI_RECEIVED_FIS) * (PortIndex - 1);
+      Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_FB;
+      AhciWriteReg (AhciBar, Offset, Data64.Uint32.Lower32);
+      Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_FBU;
+      AhciWriteReg (AhciBar, Offset, Data64.Uint32.Upper32);
+
+      Data64.Uint64 = (UINTN) (AhciRegisters->AhciCmdList);
+      Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CLB;
+      AhciWriteReg (AhciBar, Offset, Data64.Uint32.Lower32);
+      Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CLBU;
+      AhciWriteReg (AhciBar, Offset, Data64.Uint32.Upper32);
+
+      Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CMD;
+      Data = AhciReadReg (AhciBar, Offset);
+      if ((Data & AHCI_PORT_CMD_CPD) != 0) {
+        AhciOrReg (AhciBar, Offset, AHCI_PORT_CMD_POD);
+      }
+
+      if ((Capability & AHCI_CAP_SSS) != 0) {
+        AhciOrReg (AhciBar, Offset, AHCI_PORT_CMD_SUD);
+      }
+
+      //
+      // Disable aggressive power management.
+      //
+      Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_SCTL;
+      AhciOrReg (AhciBar, Offset, AHCI_PORT_SCTL_IPM_INIT);
+      //
+      // Disable the reporting of the corresponding interrupt to system software.
+      //
+      Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_IE;
+      AhciAndReg (AhciBar, Offset, 0);
+
+      //
+      // Enable FIS Receive DMA engine for the first D2H FIS.
+      //
+      Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CMD;
+      AhciOrReg (AhciBar, Offset, AHCI_PORT_CMD_FRE);
+
+      //
+      // Wait no longer than 15 ms to wait the Phy to detect the presence of a device.
+      //
+      PhyDetectDelay = AHCI_BUS_PHY_DETECT_TIMEOUT;
+      Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_SSTS;
+      do {
+        Data = AhciReadReg (AhciBar, Offset) & AHCI_PORT_SSTS_DET_MASK;
+        if ((Data == AHCI_PORT_SSTS_DET_PCE) || (Data == AHCI_PORT_SSTS_DET)) {
+          break;
+        }
+
+        MicroSecondDelay (1000);
+        PhyDetectDelay--;
+      } while (PhyDetectDelay > 0);
+
+      if (PhyDetectDelay == 0) {
+        //
+        // No device detected at this port.
+        // Clear PxCMD.SUD for those ports at which there are no device present.
+        //
+        Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_CMD;
+        AhciAndReg (AhciBar, Offset, (UINT32) ~(AHCI_PORT_CMD_SUD));
+        DEBUG ((DEBUG_ERROR, "%a: No device detected at Port %d.\n", __FUNCTION__, Port));
+        continue;
+      }
+
+      //
+      // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ
+      // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.
+      //
+      PhyDetectDelay = 16 * 1000;
+      do {
+        Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_SERR;
+        if (AhciReadReg(AhciBar, Offset) != 0) {
+          AhciWriteReg (AhciBar, Offset, AhciReadReg (AhciBar, Offset));
+        }
+        Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_TFD;
+
+        Data = AhciReadReg (AhciBar, Offset) & AHCI_PORT_TFD_MASK;
+        if (Data == 0) {
+          break;
+        }
+
+        MicroSecondDelay (1000);
+        PhyDetectDelay--;
+      } while (PhyDetectDelay > 0);
+
+      if (PhyDetectDelay == 0) {
+        DEBUG ((
+          DEBUG_ERROR,
+          "%a: Port %d device presence detected but phy not ready (TFD=0x%x).\n",
+          __FUNCTION__, Port, Data
+          ));
+        continue;
+      }
+
+      //
+      // When the first D2H register FIS is received, the content of PxSIG register is updated.
+      //
+      Offset = AHCI_PORT_START + Port * AHCI_PORT_REG_WIDTH + AHCI_PORT_SIG;
+      Status = AhciWaitMmioSet (
+                 AhciBar,
+                 Offset,
+                 0x0000FFFF,
+                 0x00000101,
+                 160000000
+                 );
+      if (EFI_ERROR (Status)) {
+        DEBUG ((
+          DEBUG_ERROR,
+          "%a: Error occured when waiting for the first D2H register FIS - %r\n",
+          __FUNCTION__, Status
+          ));
+        continue;
+      }
+
+      Data = AhciReadReg (AhciBar, Offset);
+      if ((Data & AHCI_ATAPI_SIG_MASK) == AHCI_ATA_DEVICE_SIG) {
+        Status = AhciIdentify (Private, Port, 0, PortIndex - 1, &IdentifyData);
+        if (EFI_ERROR (Status)) {
+          DEBUG ((DEBUG_ERROR, "%a: AhciIdentify() failed with %r\n", __FUNCTION__, Status));
+          continue;
+        }
+        DEBUG ((DEBUG_INFO, "%a: ATA hard disk found on Port %d.\n", __FUNCTION__, Port));
+      } else {
+        continue;
+      }
+
+      //
+      // Found an ATA hard disk device, add it into the device list.
+      //
+      DeviceIndex++;
+      CreateNewDevice (
+        Private,
+        DeviceIndex,
+        Port,
+        0xFFFF,
+        PortIndex - 1,
+        &IdentifyData
+        );
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Trust transfer data from/to ATA device.
+
+  This function performs one ATA pass through transaction to do a trust transfer
+  from/to ATA device. It chooses the appropriate ATA command and protocol to invoke
+  PassThru interface of ATA pass through.
+
+  @param[in]     DeviceData     Pointer to PEI_AHCI_ATA_DEVICE_DATA structure.
+  @param[in,out] Buffer         The pointer to the current transaction buffer.
+  @param[in]     SecurityProtocolId
+                                The value of the "Security Protocol" parameter
+                                of the security protocol command to be sent.
+  @param[in]     SecurityProtocolSpecificData
+                                The value of the "Security Protocol Specific"
+                                parameter of the security protocol command to
+                                be sent.
+  @param[in]     TransferLength The block number or sector count of the transfer.
+  @param[in]     IsTrustSend    Indicates whether it is a trust send operation
+                                or not.
+  @param[in]     Timeout        The timeout, in 100ns units, to use for the execution
+                                of the security protocol command. A Timeout value
+                                of 0 means that this function will wait indefinitely
+                                for the security protocol command to execute. If
+                                Timeout is greater than zero, then this function
+                                will return EFI_TIMEOUT if the time required to
+                                execute the receive data command is greater than
+                                Timeout.
+  @param[out]    TransferLengthOut
+                                A pointer to a buffer to store the size in bytes
+                                of the data written to the buffer. Ignore it when
+                                IsTrustSend is TRUE.
+
+  @retval EFI_SUCCESS    The data transfer is complete successfully.
+  @return others         Some error occurs when transferring data.
+
+**/
+EFI_STATUS
+TrustTransferAtaDevice (
+  IN     PEI_AHCI_ATA_DEVICE_DATA    *DeviceData,
+  IN OUT VOID                        *Buffer,
+  IN     UINT8                       SecurityProtocolId,
+  IN     UINT16                      SecurityProtocolSpecificData,
+  IN     UINTN                       TransferLength,
+  IN     BOOLEAN                     IsTrustSend,
+  IN     UINT64                      Timeout,
+  OUT    UINTN                       *TransferLengthOut
+  )
+{
+  PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private;
+  EDKII_PEI_ATA_PASS_THRU_PPI         *AtaPassThru;
+  EFI_ATA_COMMAND_BLOCK               Acb;
+  EFI_ATA_PASS_THRU_COMMAND_PACKET    Packet;
+  EFI_STATUS                          Status;
+  VOID                                *NewBuffer;
+
+  Private     = DeviceData->Private;
+  AtaPassThru = &Private->AtaPassThruPpi;
+
+  //
+  // Ensure IsTrustSend are valid boolean values
+  //
+  ASSERT ((UINTN) IsTrustSend < 2);
+  if ((UINTN) IsTrustSend >= 2) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Prepare for ATA command block.
+  //
+  ZeroMem (&Acb, sizeof (EFI_ATA_COMMAND_BLOCK));
+  if (TransferLength == 0) {
+    Acb.AtaCommand    = ATA_CMD_TRUST_NON_DATA;
+  } else {
+    Acb.AtaCommand    = mAtaTrustCommands[IsTrustSend];
+  }
+  Acb.AtaFeatures      = SecurityProtocolId;
+  Acb.AtaSectorCount   = (UINT8) (TransferLength / 512);
+  Acb.AtaSectorNumber  = (UINT8) ((TransferLength / 512) >> 8);
+  //
+  // NOTE: ATA Spec has no explicitly definition for Security Protocol Specific layout.
+  // Here use big endian for Cylinder register.
+  //
+  Acb.AtaCylinderHigh  = (UINT8) SecurityProtocolSpecificData;
+  Acb.AtaCylinderLow   = (UINT8) (SecurityProtocolSpecificData >> 8);
+  Acb.AtaDeviceHead    = (UINT8) (BIT7 | BIT6 | BIT5 |
+                                  (DeviceData->PortMultiplier == 0xFFFF ?
+                                  0 : (DeviceData->PortMultiplier << 4)));
+
+  //
+  // Prepare for ATA pass through packet.
+  //
+  ZeroMem (&Packet, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));
+  if (TransferLength == 0) {
+    Packet.InTransferLength  = 0;
+    Packet.OutTransferLength = 0;
+    Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA;
+  } else if (IsTrustSend) {
+    //
+    // Check the alignment of the incoming buffer prior to invoking underlying
+    // ATA PassThru PPI.
+    //
+    if ((AtaPassThru->Mode->IoAlign > 1) &&
+        !IS_ALIGNED (Buffer, AtaPassThru->Mode->IoAlign)) {
+      NewBuffer = AllocateAlignedPages (
+                    EFI_SIZE_TO_PAGES (TransferLength),
+                    AtaPassThru->Mode->IoAlign
+                    );
+      if (NewBuffer == NULL) {
+        return EFI_OUT_OF_RESOURCES;
+      }
+
+      CopyMem (NewBuffer, Buffer, TransferLength);
+      Buffer = NewBuffer;
+    }
+    Packet.OutDataBuffer = Buffer;
+    Packet.OutTransferLength = (UINT32) TransferLength;
+    Packet.Protocol = mAtaPassThruCmdProtocols[IsTrustSend];
+  } else {
+    Packet.InDataBuffer = Buffer;
+    Packet.InTransferLength = (UINT32) TransferLength;
+    Packet.Protocol = mAtaPassThruCmdProtocols[IsTrustSend];
+  }
+  Packet.Asb      = NULL;
+  Packet.Acb      = &Acb;
+  Packet.Timeout  = Timeout;
+  Packet.Length   = EFI_ATA_PASS_THRU_LENGTH_BYTES;
+
+  Status = AtaPassThru->PassThru (
+                          AtaPassThru,
+                          DeviceData->Port,
+                          DeviceData->PortMultiplier,
+                          &Packet
+                          );
+  if (TransferLengthOut != NULL) {
+    if (!IsTrustSend) {
+      *TransferLengthOut = Packet.InTransferLength;
+    }
+  }
+  return Status;
+}
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.c b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.c
new file mode 100644
index 0000000000..82daa2ef29
--- /dev/null
+++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.c
@@ -0,0 +1,304 @@
+/** @file
+  The AhciPei driver is used to manage ATA hard disk device working under AHCI
+  mode at PEI phase.
+
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions
+  of the BSD License which accompanies this distribution.  The
+  full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "AhciPei.h"
+
+EFI_PEI_PPI_DESCRIPTOR  mAhciAtaPassThruPpiListTemplate = {
+  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+  &gEdkiiPeiAtaPassThruPpiGuid,
+  NULL
+};
+
+EFI_PEI_PPI_DESCRIPTOR  mAhciStorageSecurityPpiListTemplate = {
+  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+  &gEdkiiPeiStorageSecurityCommandPpiGuid,
+  NULL
+};
+
+EFI_PEI_NOTIFY_DESCRIPTOR  mAhciEndOfPeiNotifyListTemplate = {
+  (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+  &gEfiEndOfPeiSignalPpiGuid,
+  AhciPeimEndOfPei
+};
+
+
+/**
+  Free the DMA resources allocated by an ATA AHCI controller.
+
+  @param[in] Private    A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA data
+                        structure.
+
+**/
+VOID
+AhciFreeDmaResource (
+  IN PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private
+  )
+{
+  EFI_AHCI_REGISTERS    *AhciRegisters;
+
+  ASSERT (Private != NULL);
+
+  AhciRegisters = &Private->AhciRegisters;
+
+  if (AhciRegisters->AhciRFisMap != NULL) {
+    IoMmuFreeBuffer (
+       EFI_SIZE_TO_PAGES (AhciRegisters->MaxRFisSize),
+       AhciRegisters->AhciRFis,
+       AhciRegisters->AhciRFisMap
+       );
+  }
+
+  if (AhciRegisters->AhciCmdListMap != NULL) {
+    IoMmuFreeBuffer (
+       EFI_SIZE_TO_PAGES (AhciRegisters->MaxCmdListSize),
+       AhciRegisters->AhciCmdList,
+       AhciRegisters->AhciCmdListMap
+       );
+  }
+
+  if (AhciRegisters->AhciCmdTableMap != NULL) {
+    IoMmuFreeBuffer (
+      EFI_SIZE_TO_PAGES (AhciRegisters->MaxCmdTableSize),
+      AhciRegisters->AhciCmdTable,
+      AhciRegisters->AhciCmdTableMap
+      );
+  }
+
+}
+
+/**
+  One notified function to cleanup the allocated DMA buffers at EndOfPei.
+
+  @param[in] PeiServices         Pointer to PEI Services Table.
+  @param[in] NotifyDescriptor    Pointer to the descriptor for the Notification
+                                 event that caused this function to execute.
+  @param[in] Ppi                 Pointer to the PPI data associated with this function.
+
+  @retval EFI_SUCCESS    The function completes successfully
+
+**/
+EFI_STATUS
+EFIAPI
+AhciPeimEndOfPei (
+  IN EFI_PEI_SERVICES           **PeiServices,
+  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
+  IN VOID                       *Ppi
+  )
+{
+  PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private;
+
+  Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor);
+  AhciFreeDmaResource (Private);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Entry point of the PEIM.
+
+  @param[in] FileHandle     Handle of the file being invoked.
+  @param[in] PeiServices    Describes the list of possible PEI Services.
+
+  @retval EFI_SUCCESS    PPI successfully installed.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaAhciPeimEntry (
+  IN EFI_PEI_FILE_HANDLE       FileHandle,
+  IN CONST EFI_PEI_SERVICES    **PeiServices
+  )
+{
+  EFI_STATUS                            Status;
+  EFI_BOOT_MODE                         BootMode;
+  EDKII_ATA_AHCI_HOST_CONTROLLER_PPI    *AhciHcPpi;
+  UINT8                                 Controller;
+  UINTN                                 MmioBase;
+  UINTN                                 DevicePathLength;
+  EFI_DEVICE_PATH_PROTOCOL              *DevicePath;
+  UINT32                                PortBitMap;
+  PEI_AHCI_CONTROLLER_PRIVATE_DATA      *Private;
+  UINT8                                 NumberOfPorts;
+
+  DEBUG ((DEBUG_INFO, "%a: Enters.\n", __FUNCTION__));
+
+  //
+  // Get the current boot mode.
+  //
+  Status = PeiServicesGetBootMode (&BootMode);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Fail to get the current boot mode.\n", __FUNCTION__));
+    return Status;
+  }
+
+  //
+  // Locate the ATA AHCI host controller PPI.
+  //
+  Status = PeiServicesLocatePpi (
+             &gEdkiiPeiAtaAhciHostControllerPpiGuid,
+             0,
+             NULL,
+             (VOID **) &AhciHcPpi
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Failed to locate AtaAhciHostControllerPpi.\n", __FUNCTION__));
+    return EFI_UNSUPPORTED;
+  }
+
+  Controller = 0;
+  MmioBase   = 0;
+  while (TRUE) {
+    Status = AhciHcPpi->GetAhciHcMmioBar (
+                          AhciHcPpi,
+                          Controller,
+                          &MmioBase
+                          );
+    //
+    // When status is error, meant no controller is found.
+    //
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    Status = AhciHcPpi->GetAhciHcDevicePath (
+                          AhciHcPpi,
+                          Controller,
+                          &DevicePathLength,
+                          &DevicePath
+                          );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((
+        DEBUG_ERROR, "%a: Fail to allocate get the device path for Controller %d.\n",
+        __FUNCTION__, Controller
+        ));
+      return Status;
+    }
+
+    //
+    // Check validity of the device path of the ATA AHCI controller.
+    //
+    Status = AhciCheckHcDevicePath (DevicePath, DevicePathLength);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((
+        DEBUG_ERROR, "%a: The device path is invalid for Controller %d.\n",
+        __FUNCTION__, Controller
+        ));
+      Controller++;
+      continue;
+    }
+
+    if (BootMode == BOOT_ON_S3_RESUME) {
+      NumberOfPorts = AhciS3GetEumeratePorts (DevicePath, DevicePathLength, &PortBitMap);
+      if (NumberOfPorts == 0) {
+        //
+        // No ports need to be enumerated for this controller.
+        //
+        Controller++;
+        continue;
+      }
+    } else {
+      PortBitMap = MAX_UINT32;
+    }
+
+    //
+    // Memory allocation for controller private data.
+    //
+    Private = AllocateZeroPool (sizeof (PEI_AHCI_CONTROLLER_PRIVATE_DATA));
+    if (Private == NULL) {
+      DEBUG ((
+        DEBUG_ERROR, "%a: Fail to allocate private data for Controller %d.\n",
+        __FUNCTION__, Controller
+        ));
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    //
+    // Initialize controller private data.
+    //
+    Private->Signature        = AHCI_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE;
+    Private->MmioBase         = MmioBase;
+    Private->DevicePathLength = DevicePathLength;
+    Private->DevicePath       = DevicePath;
+    Private->PortBitMap       = PortBitMap;
+    InitializeListHead (&Private->DeviceList);
+
+    Status = AhciModeInitialization (Private);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "%a: Controller initialization fail for Controller %d with Status - %r.\n",
+        __FUNCTION__,
+        Controller,
+        Status
+        ));
+      Controller++;
+      continue;
+    }
+
+    Private->AtaPassThruMode.Attributes   = EFI_ATA_PASS_THRU_ATTRIBUTES_PHYSICAL |
+                                            EFI_ATA_PASS_THRU_ATTRIBUTES_LOGICAL;
+    Private->AtaPassThruMode.IoAlign      = sizeof (UINTN);
+    Private->AtaPassThruPpi.Revision      = EDKII_PEI_ATA_PASS_THRU_PPI_REVISION;
+    Private->AtaPassThruPpi.Mode          = &Private->AtaPassThruMode;
+    Private->AtaPassThruPpi.PassThru      = AhciAtaPassThruPassThru;
+    Private->AtaPassThruPpi.GetNextPort   = AhciAtaPassThruGetNextPort;
+    Private->AtaPassThruPpi.GetNextDevice = AhciAtaPassThruGetNextDevice;
+    Private->AtaPassThruPpi.GetDevicePath = AhciAtaPassThruGetDevicePath;
+    CopyMem (
+      &Private->AtaPassThruPpiList,
+      &mAhciAtaPassThruPpiListTemplate,
+      sizeof (EFI_PEI_PPI_DESCRIPTOR)
+      );
+    Private->AtaPassThruPpiList.Ppi       = &Private->AtaPassThruPpi;
+    PeiServicesInstallPpi (&Private->AtaPassThruPpiList);
+
+    if (Private->TrustComputingDevices != 0) {
+      DEBUG ((
+        DEBUG_INFO,
+        "%a: Security Security Command PPI will be produced for Controller %d.\n",
+        __FUNCTION__, Controller
+        ));
+      Private->StorageSecurityPpi.Revision           = EDKII_STORAGE_SECURITY_PPI_REVISION;
+      Private->StorageSecurityPpi.GetNumberofDevices = AhciStorageSecurityGetDeviceNo;
+      Private->StorageSecurityPpi.GetDevicePath      = AhciStorageSecurityGetDevicePath;
+      Private->StorageSecurityPpi.ReceiveData        = AhciStorageSecurityReceiveData;
+      Private->StorageSecurityPpi.SendData           = AhciStorageSecuritySendData;
+      CopyMem (
+        &Private->StorageSecurityPpiList,
+        &mAhciStorageSecurityPpiListTemplate,
+        sizeof (EFI_PEI_PPI_DESCRIPTOR)
+        );
+      Private->StorageSecurityPpiList.Ppi            = &Private->StorageSecurityPpi;
+      PeiServicesInstallPpi (&Private->StorageSecurityPpiList);
+    }
+
+    CopyMem (
+      &Private->EndOfPeiNotifyList,
+      &mAhciEndOfPeiNotifyListTemplate,
+      sizeof (EFI_PEI_NOTIFY_DESCRIPTOR)
+      );
+    PeiServicesNotifyPpi  (&Private->EndOfPeiNotifyList);
+
+    DEBUG ((
+      DEBUG_INFO, "%a: Controller %d has been successfully initialized.\n",
+      __FUNCTION__, Controller
+      ));
+    Controller++;
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.c b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.c
new file mode 100644
index 0000000000..394d6d98ad
--- /dev/null
+++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.c
@@ -0,0 +1,521 @@
+/** @file
+  The AhciPei driver is used to manage ATA hard disk device working under AHCI
+  mode at PEI phase.
+
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions
+  of the BSD License which accompanies this distribution.  The
+  full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "AhciPei.h"
+
+/**
+  Traverse the attached ATA devices list to find out the device with given Port
+  and PortMultiplierPort.
+
+  @param[in] Private               A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA
+                                   instance.
+  @param[in] Port                  The port number of the ATA device.
+  @param[in] PortMultiplierPort    The port multiplier port number of the ATA device.
+
+  @retval    The pointer to the PEI_AHCI_ATA_DEVICE_DATA structure of the device
+             info to access.
+
+**/
+PEI_AHCI_ATA_DEVICE_DATA *
+SearchDeviceByPort (
+  IN PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private,
+  IN UINT16                              Port,
+  IN UINT16                              PortMultiplierPort
+  )
+{
+  PEI_AHCI_ATA_DEVICE_DATA    *DeviceData;
+  LIST_ENTRY                  *Node;
+
+  Node = GetFirstNode (&Private->DeviceList);
+  while (!IsNull (&Private->DeviceList, Node)) {
+    DeviceData = AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS (Node);
+
+    if ((DeviceData->Port == Port) &&
+        (DeviceData->PortMultiplier == PortMultiplierPort)) {
+      return DeviceData;
+    }
+
+    Node = GetNextNode (&Private->DeviceList, Node);
+  }
+
+  return NULL;
+}
+
+/**
+  Sends an ATA command to an ATA device that is attached to the ATA controller.
+
+  @param[in]     Private               Pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA.
+  @param[in]     Port                  The port number of the ATA device.
+  @param[in]     PortMultiplierPort    The port multiplier port number of the ATA
+                                       device.
+  @param[in]     FisIndex              The index of the FIS.
+  @param[in,out] Packet                A pointer to the ATA command to send to
+                                       the ATA device specified by Port and
+                                       PortMultiplierPort.
+
+  @retval EFI_SUCCESS              The ATA command was sent by the host. For
+                                   bi-directional commands, InTransferLength bytes
+                                   were transferred from InDataBuffer. For write
+                                   and bi-directional commands, OutTransferLength
+                                   bytes were transferred by OutDataBuffer.
+  @retval EFI_BAD_BUFFER_SIZE      The ATA command was not executed. The number
+                                   of bytes that could be transferred is returned
+                                   in InTransferLength. For write and bi-directional
+                                   commands, OutTransferLength bytes were transferred
+                                   by OutDataBuffer.
+  @retval EFI_NOT_READY            The ATA command could not be sent because there
+                                   are too many ATA commands already queued. The
+                                   caller may retry again later.
+  @retval EFI_DEVICE_ERROR         A device error occurred while attempting to
+                                   send the ATA command.
+  @retval EFI_INVALID_PARAMETER    Port, PortMultiplierPort, or the contents of
+                                   Acb are invalid. The ATA command was not sent,
+                                   so no additional status information is available.
+
+**/
+EFI_STATUS
+AhciPassThruExecute (
+  IN     PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private,
+  IN     UINT16                              Port,
+  IN     UINT16                              PortMultiplierPort,
+  IN     UINT8                               FisIndex,
+  IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET    *Packet
+  )
+{
+  EFI_STATUS    Status;
+
+  switch (Packet->Protocol) {
+    case EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA:
+      Status = AhciNonDataTransfer (
+                 Private,
+                 (UINT8) Port,
+                 (UINT8) PortMultiplierPort,
+                 FisIndex,
+                 Packet->Acb,
+                 Packet->Asb,
+                 Packet->Timeout
+                 );
+      break;
+    case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN:
+      Status = AhciPioTransfer (
+                 Private,
+                 (UINT8) Port,
+                 (UINT8) PortMultiplierPort,
+                 FisIndex,
+                 TRUE,
+                 Packet->Acb,
+                 Packet->Asb,
+                 Packet->InDataBuffer,
+                 Packet->InTransferLength,
+                 Packet->Timeout
+                 );
+      break;
+    case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT:
+      Status = AhciPioTransfer (
+                 Private,
+                 (UINT8) Port,
+                 (UINT8) PortMultiplierPort,
+                 FisIndex,
+                 FALSE,
+                 Packet->Acb,
+                 Packet->Asb,
+                 Packet->OutDataBuffer,
+                 Packet->OutTransferLength,
+                 Packet->Timeout
+                 );
+      break;
+    default:
+      return EFI_UNSUPPORTED;
+  }
+
+  return Status;
+}
+
+/**
+  Sends an ATA command to an ATA device that is attached to the ATA controller.
+
+  @param[in]     This                  The PPI instance pointer.
+  @param[in]     Port                  The port number of the ATA device to send
+                                       the command.
+  @param[in]     PortMultiplierPort    The port multiplier port number of the ATA
+                                       device to send the command.
+                                       If there is no port multiplier, then specify
+                                       0xFFFF.
+  @param[in,out] Packet                A pointer to the ATA command to send to
+                                       the ATA device specified by Port and
+                                       PortMultiplierPort.
+
+  @retval EFI_SUCCESS              The ATA command was sent by the host. For
+                                   bi-directional commands, InTransferLength bytes
+                                   were transferred from InDataBuffer. For write
+                                   and bi-directional commands, OutTransferLength
+                                   bytes were transferred by OutDataBuffer.
+  @retval EFI_NOT_FOUND            The specified ATA device is not found.
+  @retval EFI_INVALID_PARAMETER    The contents of Acb are invalid. The ATA command
+                                   was not sent, so no additional status information
+                                   is available.
+  @retval EFI_BAD_BUFFER_SIZE      The ATA command was not executed. The number
+                                   of bytes that could be transferred is returned
+                                   in InTransferLength. For write and bi-directional
+                                   commands, OutTransferLength bytes were transferred
+                                   by OutDataBuffer.
+  @retval EFI_NOT_READY            The ATA command could not be sent because there
+                                   are too many ATA commands already queued. The
+                                   caller may retry again later.
+  @retval EFI_DEVICE_ERROR         A device error occurred while attempting to
+                                   send the ATA command.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciAtaPassThruPassThru (
+  IN     EDKII_PEI_ATA_PASS_THRU_PPI         *This,
+  IN     UINT16                              Port,
+  IN     UINT16                              PortMultiplierPort,
+  IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET    *Packet
+  )
+{
+  UINT32                              IoAlign;
+  PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private;
+  PEI_AHCI_ATA_DEVICE_DATA            *DeviceData;
+  UINT32                              MaxSectorCount;
+  UINT32                              BlockSize;
+
+  if (This == NULL || Packet == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  IoAlign = This->Mode->IoAlign;
+  if ((IoAlign > 1) && !IS_ALIGNED (Packet->InDataBuffer, IoAlign)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((IoAlign > 1) && !IS_ALIGNED (Packet->OutDataBuffer, IoAlign)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((IoAlign > 1) && !IS_ALIGNED (Packet->Asb, IoAlign)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_PASS_THRU (This);
+  DeviceData = SearchDeviceByPort (Private, Port, PortMultiplierPort);
+  if (DeviceData == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  MaxSectorCount = mMaxTransferBlockNumber[DeviceData->Lba48Bit];
+  BlockSize      = DeviceData->Media.BlockSize;
+
+  //
+  // Convert the transfer length from sector count to byte.
+  //
+  if (((Packet->Length & EFI_ATA_PASS_THRU_LENGTH_BYTES) == 0) &&
+       (Packet->InTransferLength != 0)) {
+    Packet->InTransferLength = Packet->InTransferLength * BlockSize;
+  }
+
+  //
+  // Convert the transfer length from sector count to byte.
+  //
+  if (((Packet->Length & EFI_ATA_PASS_THRU_LENGTH_BYTES) == 0) &&
+       (Packet->OutTransferLength != 0)) {
+    Packet->OutTransferLength = Packet->OutTransferLength * BlockSize;
+  }
+
+  //
+  // If the data buffer described by InDataBuffer/OutDataBuffer and
+  // InTransferLength/OutTransferLength is too big to be transferred in a single
+  // command, then no data is transferred and EFI_BAD_BUFFER_SIZE is returned.
+  //
+  if (((Packet->InTransferLength != 0) && (Packet->InTransferLength > MaxSectorCount * BlockSize)) ||
+      ((Packet->OutTransferLength != 0) && (Packet->OutTransferLength > MaxSectorCount * BlockSize))) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  return AhciPassThruExecute (
+           Private,
+           DeviceData->Port,
+           DeviceData->PortMultiplier,
+           DeviceData->FisIndex,
+           Packet
+           );
+}
+
+/**
+  Used to retrieve the list of legal port numbers for ATA devices on an ATA controller.
+  These can either be the list of ports where ATA devices are actually present or the
+  list of legal port numbers for the ATA controller. Regardless, the caller of this
+  function must probe the port number returned to see if an ATA device is actually
+  present at that location on the ATA controller.
+
+  The GetNextPort() function retrieves the port number on an ATA controller. If on
+  input Port is 0xFFFF, then the port number of the first port on the ATA controller
+  is returned in Port and EFI_SUCCESS is returned.
+
+  If Port is a port number that was returned on a previous call to GetNextPort(),
+  then the port number of the next port on the ATA controller is returned in Port,
+  and EFI_SUCCESS is returned. If Port is not 0xFFFF and Port was not returned on
+  a previous call to GetNextPort(), then EFI_INVALID_PARAMETER is returned.
+
+  If Port is the port number of the last port on the ATA controller, then EFI_NOT_FOUND
+  is returned.
+
+  @param[in]     This    The PPI instance pointer.
+  @param[in,out] Port    On input, a pointer to the port number on the ATA controller.
+                         On output, a pointer to the next port number on the ATA
+                         controller. An input value of 0xFFFF retrieves the first
+                         port number on the ATA controller.
+
+  @retval EFI_SUCCESS              The next port number on the ATA controller was
+                                   returned in Port.
+  @retval EFI_NOT_FOUND            There are no more ports on this ATA controller.
+  @retval EFI_INVALID_PARAMETER    Port is not 0xFFFF and Port was not returned
+                                   on a previous call to GetNextPort().
+
+**/
+EFI_STATUS
+EFIAPI
+AhciAtaPassThruGetNextPort (
+  IN     EDKII_PEI_ATA_PASS_THRU_PPI    *This,
+  IN OUT UINT16                         *Port
+  )
+{
+  PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private;
+  PEI_AHCI_ATA_DEVICE_DATA            *DeviceData;
+  LIST_ENTRY                          *Node;
+
+  if (This == NULL || Port == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_PASS_THRU (This);
+
+  if (*Port == 0xFFFF) {
+    //
+    // If the Port is all 0xFF's, start to traverse the device list from the
+    // beginning.
+    //
+    Node = GetFirstNode (&Private->DeviceList);
+    if (!IsNull (&Private->DeviceList, Node)) {
+      DeviceData = AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS (Node);
+
+      *Port = DeviceData->Port;
+      goto Exit;
+    }
+
+    return EFI_NOT_FOUND;
+  } else if (*Port == Private->PreviousPort) {
+    Node = GetFirstNode (&Private->DeviceList);
+
+    while (!IsNull (&Private->DeviceList, Node)) {
+      DeviceData = AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS (Node);
+
+      if (DeviceData->Port > *Port){
+        *Port = DeviceData->Port;
+        goto Exit;
+      }
+
+      Node = GetNextNode (&Private->DeviceList, Node);
+    }
+
+    return EFI_NOT_FOUND;
+  } else {
+    //
+    // Port is not equal to all 0xFF's and not equal to previous return value.
+    //
+    return EFI_INVALID_PARAMETER;
+  }
+
+Exit:
+  //
+  // Update the PreviousPort.
+  //
+  Private->PreviousPort = *Port;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Used to retrieve the list of legal port multiplier port numbers for ATA devices
+  on a port of an ATA controller. These can either be the list of port multiplier
+  ports where ATA devices are actually present on port or the list of legal port
+  multiplier ports on that port. Regardless, the caller of this function must probe
+  the port number and port multiplier port number returned to see if an ATA device
+  is actually present.
+
+  The GetNextDevice() function retrieves the port multiplier port number of an ATA
+  device present on a port of an ATA controller.
+
+  If PortMultiplierPort points to a port multiplier port number value that was
+  returned on a previous call to GetNextDevice(), then the port multiplier port
+  number of the next ATA device on the port of the ATA controller is returned in
+  PortMultiplierPort, and EFI_SUCCESS is returned.
+
+  If PortMultiplierPort points to 0xFFFF, then the port multiplier port number
+  of the first ATA device on port of the ATA controller is returned in PortMultiplierPort
+  and EFI_SUCCESS is returned.
+
+  If PortMultiplierPort is not 0xFFFF and the value pointed to by PortMultiplierPort
+  was not returned on a previous call to GetNextDevice(), then EFI_INVALID_PARAMETER
+  is returned.
+
+  If PortMultiplierPort is the port multiplier port number of the last ATA device
+  on the port of the ATA controller, then EFI_NOT_FOUND is returned.
+
+  @param[in]     This                  The PPI instance pointer.
+  @param[in]     Port                  The port number present on the ATA controller.
+  @param[in,out] PortMultiplierPort    On input, a pointer to the port multiplier
+                                       port number of an ATA device present on the
+                                       ATA controller. If on input a PortMultiplierPort
+                                       of 0xFFFF is specified, then the port multiplier
+                                       port number of the first ATA device is returned.
+                                       On output, a pointer to the port multiplier port
+                                       number of the next ATA device present on an ATA
+                                       controller.
+
+  @retval EFI_SUCCESS              The port multiplier port number of the next ATA
+                                   device on the port of the ATA controller was
+                                   returned in PortMultiplierPort.
+  @retval EFI_NOT_FOUND            There are no more ATA devices on this port of
+                                   the ATA controller.
+  @retval EFI_INVALID_PARAMETER    PortMultiplierPort is not 0xFFFF, and PortMultiplierPort
+                                   was not returned on a previous call to GetNextDevice().
+
+**/
+EFI_STATUS
+EFIAPI
+AhciAtaPassThruGetNextDevice (
+  IN     EDKII_PEI_ATA_PASS_THRU_PPI    *This,
+  IN     UINT16                         Port,
+  IN OUT UINT16                         *PortMultiplierPort
+  )
+{
+  PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private;
+  PEI_AHCI_ATA_DEVICE_DATA            *DeviceData;
+  LIST_ENTRY                          *Node;
+
+  if (This == NULL || PortMultiplierPort == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_PASS_THRU (This);
+
+  if (Private->PreviousPortMultiplier == 0xFFFF) {
+    //
+    // If a device is directly attached on a port, previous call to this
+    // function will return the value 0xFFFF for PortMultiplierPort. In
+    // this case, there should be no more device on the port multiplier.
+    //
+    Private->PreviousPortMultiplier = 0;
+    return EFI_NOT_FOUND;
+  }
+
+  if (*PortMultiplierPort == Private->PreviousPortMultiplier) {
+    Node = GetFirstNode (&Private->DeviceList);
+
+    while (!IsNull (&Private->DeviceList, Node)) {
+      DeviceData = AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS (Node);
+
+      if ((DeviceData->Port == Port) &&
+          (DeviceData->PortMultiplier > *PortMultiplierPort)){
+        *PortMultiplierPort = DeviceData->PortMultiplier;
+        goto Exit;
+      }
+
+      Node = GetNextNode (&Private->DeviceList, Node);
+    }
+
+    return EFI_NOT_FOUND;
+  } else if (*PortMultiplierPort == 0xFFFF) {
+    //
+    // If the PortMultiplierPort is all 0xFF's, start to traverse the device list
+    // from the beginning.
+    //
+    Node = GetFirstNode (&Private->DeviceList);
+
+    while (!IsNull (&Private->DeviceList, Node)) {
+      DeviceData = AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS (Node);
+
+      if (DeviceData->Port == Port){
+        *PortMultiplierPort = DeviceData->PortMultiplier;
+        goto Exit;
+      }
+
+      Node = GetNextNode (&Private->DeviceList, Node);
+    }
+
+    return EFI_NOT_FOUND;
+  } else {
+    //
+    // PortMultiplierPort is not equal to all 0xFF's and not equal to previous
+    // return value.
+    //
+    return EFI_INVALID_PARAMETER;
+  }
+
+Exit:
+  //
+  // Update the PreviousPortMultiplier.
+  //
+  Private->PreviousPortMultiplier = *PortMultiplierPort;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Gets the device path information of the underlying ATA host controller.
+
+  @param[in]  This                The PPI instance pointer.
+  @param[out] DevicePathLength    The length of the device path in bytes specified
+                                  by DevicePath.
+  @param[out] DevicePath          The device path of the underlying ATA host controller.
+                                  This field re-uses EFI Device Path Protocol as
+                                  defined by Section 10.2 EFI Device Path Protocol
+                                  of UEFI 2.7 Specification.
+
+  @retval EFI_SUCCESS              The device path of the ATA host controller has
+                                   been successfully returned.
+  @retval EFI_INVALID_PARAMETER    DevicePathLength or DevicePath is NULL.
+  @retval EFI_OUT_OF_RESOURCES     Not enough resource to return the device path.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciAtaPassThruGetDevicePath (
+  IN  EDKII_PEI_ATA_PASS_THRU_PPI    *This,
+  OUT UINTN                          *DevicePathLength,
+  OUT EFI_DEVICE_PATH_PROTOCOL       **DevicePath
+  )
+{
+  PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private;
+
+  if (This == NULL || DevicePathLength == NULL || DevicePath == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_PASS_THRU (This);
+
+  *DevicePathLength = Private->DevicePathLength;
+  *DevicePath       = AllocateCopyPool (Private->DevicePathLength, Private->DevicePath);
+  if (*DevicePath == NULL) {
+    *DevicePathLength = 0;
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiS3.c b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiS3.c
new file mode 100644
index 0000000000..3f77b979c1
--- /dev/null
+++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiS3.c
@@ -0,0 +1,139 @@
+/** @file
+  The AhciPei driver is used to manage ATA hard disk device working under AHCI
+  mode at PEI phase.
+
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions
+  of the BSD License which accompanies this distribution.  The
+  full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "AhciPei.h"
+
+#include <Guid/S3StorageDeviceInitList.h>
+
+#include <Library/LockBoxLib.h>
+
+/**
+  Collect the ports that need to be enumerated on a controller for S3 phase.
+
+  @param[in]  HcDevicePath          Device path of the controller.
+  @param[in]  HcDevicePathLength    Length of the device path specified by
+                                    HcDevicePath.
+  @param[out] PortBitMap            Bitmap that indicates the ports that need
+                                    to be enumerated on the controller.
+
+  @retval    The number of ports that need to be enumerated.
+
+**/
+UINT8
+AhciS3GetEumeratePorts (
+  IN  EFI_DEVICE_PATH_PROTOCOL    *HcDevicePath,
+  IN  UINTN                       HcDevicePathLength,
+  OUT UINT32                      *PortBitMap
+  )
+{
+  EFI_STATUS                  Status;
+  UINT8                       DummyData;
+  UINTN                       S3InitDevicesLength;
+  EFI_DEVICE_PATH_PROTOCOL    *S3InitDevices;
+  EFI_DEVICE_PATH_PROTOCOL    *DevicePathInst;
+  UINTN                       DevicePathInstLength;
+  BOOLEAN                     EntireEnd;
+  SATA_DEVICE_PATH            *SataDeviceNode;
+
+  *PortBitMap = 0;
+
+  //
+  // From the LockBox, get the list of device paths for devices need to be
+  // initialized in S3.
+  //
+  S3InitDevices       = NULL;
+  S3InitDevicesLength = sizeof (DummyData);
+  EntireEnd           = FALSE;
+  Status = RestoreLockBox (&gS3StorageDeviceInitListGuid, &DummyData, &S3InitDevicesLength);
+  if (Status != EFI_BUFFER_TOO_SMALL) {
+    return 0;
+  } else {
+    S3InitDevices = AllocatePool (S3InitDevicesLength);
+    if (S3InitDevices == NULL) {
+      return 0;
+    }
+
+    Status = RestoreLockBox (&gS3StorageDeviceInitListGuid, S3InitDevices, &S3InitDevicesLength);
+    if (EFI_ERROR (Status)) {
+      return 0;
+    }
+  }
+
+  if (S3InitDevices == NULL) {
+    return 0;
+  }
+
+  //
+  // Only enumerate the ports that exist in the device list.
+  //
+  do {
+    //
+    // Fetch the size of current device path instance.
+    //
+    Status = GetDevicePathInstanceSize (
+               S3InitDevices,
+               &DevicePathInstLength,
+               &EntireEnd
+               );
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    DevicePathInst = S3InitDevices;
+    S3InitDevices  = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN) S3InitDevices + DevicePathInstLength);
+
+    if (HcDevicePathLength >= DevicePathInstLength) {
+      continue;
+    }
+
+    //
+    // Compare the device paths to determine if the device is managed by this
+    // controller.
+    //
+    if (CompareMem (
+          DevicePathInst,
+          HcDevicePath,
+          HcDevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)
+          ) == 0) {
+      //
+      // Get the port number.
+      //
+      while (DevicePathInst->Type != END_DEVICE_PATH_TYPE) {
+        if ((DevicePathInst->Type == MESSAGING_DEVICE_PATH) &&
+            (DevicePathInst->SubType == MSG_SATA_DP)) {
+          SataDeviceNode = (SATA_DEVICE_PATH *) DevicePathInst;
+          //
+          // For now, the driver only support upto AHCI_MAX_PORTS ports and
+          // devices directly connected to a HBA.
+          //
+          if ((SataDeviceNode->HBAPortNumber >= AHCI_MAX_PORTS) ||
+              (SataDeviceNode->PortMultiplierPortNumber != 0xFFFF)) {
+            break;
+          }
+          *PortBitMap |= (UINT32)BIT0 << SataDeviceNode->HBAPortNumber;
+          break;
+        }
+        DevicePathInst = NextDevicePathNode (DevicePathInst);
+      }
+    }
+  } while (!EntireEnd);
+
+  //
+  // Return the number of ports need to be enumerated on this controller.
+  //
+  return AhciGetNumberOfPortsFromMap (*PortBitMap);
+}
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiStorageSecurity.c b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiStorageSecurity.c
new file mode 100644
index 0000000000..49c384cadd
--- /dev/null
+++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiStorageSecurity.c
@@ -0,0 +1,391 @@
+/** @file
+  The AhciPei driver is used to manage ATA hard disk device working under AHCI
+  mode at PEI phase.
+
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions
+  of the BSD License which accompanies this distribution.  The
+  full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "AhciPei.h"
+
+/**
+  Traverse the attached ATA devices list to find out the device with given trust
+  computing device index.
+
+  @param[in] Private                      A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA
+                                          instance.
+  @param[in] TrustComputingDeviceIndex    The trust computing device index.
+
+  @retval    The pointer to the PEI_AHCI_ATA_DEVICE_DATA structure of the device
+             info to access.
+
+**/
+PEI_AHCI_ATA_DEVICE_DATA *
+SearchTrustComputingDeviceByIndex (
+  IN PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private,
+  IN UINTN                               TrustComputingDeviceIndex
+  )
+{
+  PEI_AHCI_ATA_DEVICE_DATA    *DeviceData;
+  LIST_ENTRY                  *Node;
+
+  Node = GetFirstNode (&Private->DeviceList);
+  while (!IsNull (&Private->DeviceList, Node)) {
+    DeviceData = AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS (Node);
+
+    if (DeviceData->TrustComputingDeviceIndex == TrustComputingDeviceIndex) {
+      return DeviceData;
+    }
+
+    Node = GetNextNode (&Private->DeviceList, Node);
+  }
+
+  return NULL;
+}
+
+/**
+  Gets the count of storage security devices that one specific driver detects.
+
+  @param[in]  This               The PPI instance pointer.
+  @param[out] NumberofDevices    The number of storage security devices discovered.
+
+  @retval EFI_SUCCESS              The operation performed successfully.
+  @retval EFI_INVALID_PARAMETER    The parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStorageSecurityGetDeviceNo (
+  IN  EDKII_PEI_STORAGE_SECURITY_CMD_PPI    *This,
+  OUT UINTN                                 *NumberofDevices
+  )
+{
+  PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private;
+
+  if (This == NULL || NumberofDevices == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
+  *NumberofDevices = Private->TrustComputingDevices;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Gets the device path of a specific storage security device.
+
+  @param[in]  This                 The PPI instance pointer.
+  @param[in]  DeviceIndex          Specifies the storage security device to which
+                                   the function wants to talk. Because the driver
+                                   that implements Storage Security Command PPIs
+                                   will manage multiple storage devices, the PPIs
+                                   that want to talk to a single device must specify
+                                   the device index that was assigned during the
+                                   enumeration process. This index is a number from
+                                   one to NumberofDevices.
+  @param[out] DevicePathLength     The length of the device path in bytes specified
+                                   by DevicePath.
+  @param[out] DevicePath           The device path of storage security device.
+                                   This field re-uses EFI Device Path Protocol as
+                                   defined by Section 10.2 EFI Device Path Protocol
+                                   of UEFI 2.7 Specification.
+
+  @retval EFI_SUCCESS              The operation succeeds.
+  @retval EFI_INVALID_PARAMETER    DevicePathLength or DevicePath is NULL.
+  @retval EFI_NOT_FOUND            The specified storage security device not found.
+  @retval EFI_OUT_OF_RESOURCES     The operation fails due to lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStorageSecurityGetDevicePath (
+  IN  EDKII_PEI_STORAGE_SECURITY_CMD_PPI    *This,
+  IN  UINTN                                 DeviceIndex,
+  OUT UINTN                                 *DevicePathLength,
+  OUT EFI_DEVICE_PATH_PROTOCOL              **DevicePath
+  )
+{
+  PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private;
+  PEI_AHCI_ATA_DEVICE_DATA            *DeviceData;
+  EFI_STATUS                          Status;
+
+  if (This == NULL || DevicePathLength == NULL || DevicePath == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
+  if ((DeviceIndex == 0) || (DeviceIndex > Private->TrustComputingDevices)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DeviceData = SearchTrustComputingDeviceByIndex (Private, DeviceIndex);
+  if (DeviceData == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  Status = AhciBuildDevicePath (
+             Private,
+             DeviceData->Port,
+             DeviceData->PortMultiplier,
+             DevicePathLength,
+             DevicePath
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Send a security protocol command to a device that receives data and/or the result
+  of one or more commands sent by SendData.
+
+  The ReceiveData function sends a security protocol command to the given DeviceIndex.
+  The security protocol command sent is defined by SecurityProtocolId and contains
+  the security protocol specific data SecurityProtocolSpecificData. The function
+  returns the data from the security protocol command in PayloadBuffer.
+
+  For devices supporting the SCSI command set, the security protocol command is sent
+  using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+  For devices supporting the ATA command set, the security protocol command is sent
+  using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+  is non-zero.
+
+  If the PayloadBufferSize is zero, the security protocol command is sent using the
+  Trusted Non-Data command defined in ATA8-ACS.
+
+  If PayloadBufferSize is too small to store the available data from the security
+  protocol command, the function shall copy PayloadBufferSize bytes into the
+  PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+  If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+  the function shall return EFI_INVALID_PARAMETER.
+
+  If the given DeviceIndex does not support security protocol commands, the function
+  shall return EFI_UNSUPPORTED.
+
+  If the security protocol fails to complete within the Timeout period, the function
+  shall return EFI_TIMEOUT.
+
+  If the security protocol command completes without an error, the function shall
+  return EFI_SUCCESS. If the security protocol command completes with an error, the
+  function shall return EFI_DEVICE_ERROR.
+
+  @param[in]  This             The PPI instance pointer.
+  @param[in]  DeviceIndex      Specifies the storage security device to which the
+                               function wants to talk. Because the driver that
+                               implements Storage Security Command PPIs will manage
+                               multiple storage devices, the PPIs that want to talk
+                               to a single device must specify the device index
+                               that was assigned during the enumeration process.
+                               This index is a number from one to NumberofDevices.
+  @param[in]  Timeout          The timeout, in 100ns units, to use for the execution
+                               of the security protocol command. A Timeout value
+                               of 0 means that this function will wait indefinitely
+                               for the security protocol command to execute. If
+                               Timeout is greater than zero, then this function
+                               will return EFI_TIMEOUT if the time required to
+                               execute the receive data command is greater than
+                               Timeout.
+  @param[in]  SecurityProtocolId
+                               The value of the "Security Protocol" parameter of
+                               the security protocol command to be sent.
+  @param[in]  SecurityProtocolSpecificData
+                               The value of the "Security Protocol Specific"
+                               parameter of the security protocol command to be
+                               sent.
+  @param[in]  PayloadBufferSize
+                               Size in bytes of the payload data buffer.
+  @param[out] PayloadBuffer    A pointer to a destination buffer to store the
+                               security protocol command specific payload data
+                               for the security protocol command. The caller is
+                               responsible for having either implicit or explicit
+                               ownership of the buffer.
+  @param[out] PayloadTransferSize
+                               A pointer to a buffer to store the size in bytes
+                               of the data written to the payload data buffer.
+
+  @retval EFI_SUCCESS                  The security protocol command completed
+                                       successfully.
+  @retval EFI_WARN_BUFFER_TOO_SMALL    The PayloadBufferSize was too small to
+                                       store the available data from the device.
+                                       The PayloadBuffer contains the truncated
+                                       data.
+  @retval EFI_UNSUPPORTED              The given DeviceIndex does not support
+                                       security protocol commands.
+  @retval EFI_DEVICE_ERROR             The security protocol command completed
+                                       with an error.
+  @retval EFI_INVALID_PARAMETER        The PayloadBuffer or PayloadTransferSize
+                                       is NULL and PayloadBufferSize is non-zero.
+  @retval EFI_TIMEOUT                  A timeout occurred while waiting for the
+                                       security protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStorageSecurityReceiveData (
+  IN  EDKII_PEI_STORAGE_SECURITY_CMD_PPI    *This,
+  IN  UINTN                                 DeviceIndex,
+  IN  UINT64                                Timeout,
+  IN  UINT8                                 SecurityProtocolId,
+  IN  UINT16                                SecurityProtocolSpecificData,
+  IN  UINTN                                 PayloadBufferSize,
+  OUT VOID                                  *PayloadBuffer,
+  OUT UINTN                                 *PayloadTransferSize
+  )
+{
+  PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private;
+  PEI_AHCI_ATA_DEVICE_DATA            *DeviceData;
+
+  if ((PayloadBuffer == NULL) || (PayloadTransferSize == NULL) || (PayloadBufferSize == 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
+  if ((DeviceIndex == 0) || (DeviceIndex > Private->TrustComputingDevices)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DeviceData = SearchTrustComputingDeviceByIndex (Private, DeviceIndex);
+  if (DeviceData == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  ASSERT ((DeviceData->IdentifyData->trusted_computing_support & BIT0) != 0);
+  if ((DeviceData->IdentifyData->trusted_computing_support & BIT0) == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  return TrustTransferAtaDevice (
+           DeviceData,
+           PayloadBuffer,
+           SecurityProtocolId,
+           SecurityProtocolSpecificData,
+           PayloadBufferSize,
+           FALSE,
+           Timeout,
+           PayloadTransferSize
+           );
+}
+
+/**
+  Send a security protocol command to a device.
+
+  The SendData function sends a security protocol command containing the payload
+  PayloadBuffer to the given DeviceIndex. The security protocol command sent is
+  defined by SecurityProtocolId and contains the security protocol specific data
+  SecurityProtocolSpecificData. If the underlying protocol command requires a
+  specific padding for the command payload, the SendData function shall add padding
+  bytes to the command payload to satisfy the padding requirements.
+
+  For devices supporting the SCSI command set, the security protocol command is
+  sent using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+  For devices supporting the ATA command set, the security protocol command is
+  sent using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
+  is non-zero. If the PayloadBufferSize is zero, the security protocol command
+  is sent using the Trusted Non-Data command defined in ATA8-ACS.
+
+  If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
+  return EFI_INVALID_PARAMETER.
+
+  If the given DeviceIndex does not support security protocol commands, the function
+  shall return EFI_UNSUPPORTED.
+
+  If the security protocol fails to complete within the Timeout period, the function
+  shall return EFI_TIMEOUT.
+
+  If the security protocol command completes without an error, the function shall
+  return EFI_SUCCESS. If the security protocol command completes with an error,
+  the functio shall return EFI_DEVICE_ERROR.
+
+  @param[in] This              The PPI instance pointer.
+  @param[in] DeviceIndex       The ID of the device.
+  @param[in] Timeout           The timeout, in 100ns units, to use for the execution
+                               of the security protocol command. A Timeout value
+                               of 0 means that this function will wait indefinitely
+                               for the security protocol command to execute. If
+                               Timeout is greater than zero, then this function
+                               will return EFI_TIMEOUT if the time required to
+                               execute the receive data command is greater than
+                               Timeout.
+  @param[in] SecurityProtocolId
+                               The value of the "Security Protocol" parameter of
+                               the security protocol command to be sent.
+  @param[in] SecurityProtocolSpecificData
+                               The value of the "Security Protocol Specific"
+                               parameter of the security protocol command to be
+                               sent.
+  @param[in] PayloadBufferSize Size in bytes of the payload data buffer.
+  @param[in] PayloadBuffer     A pointer to a destination buffer to store the
+                               security protocol command specific payload data
+                               for the security protocol command.
+
+  @retval EFI_SUCCESS              The security protocol command completed successfully.
+  @retval EFI_UNSUPPORTED          The given DeviceIndex does not support security
+                                   protocol commands.
+  @retval EFI_DEVICE_ERROR         The security protocol command completed with
+                                   an error.
+  @retval EFI_INVALID_PARAMETER    The PayloadBuffer is NULL and PayloadBufferSize
+                                   is non-zero.
+  @retval EFI_TIMEOUT              A timeout occurred while waiting for the security
+                                   protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStorageSecuritySendData (
+  IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI  *This,
+  IN UINTN                               DeviceIndex,
+  IN UINT64                              Timeout,
+  IN UINT8                               SecurityProtocolId,
+  IN UINT16                              SecurityProtocolSpecificData,
+  IN UINTN                               PayloadBufferSize,
+  IN VOID                                *PayloadBuffer
+  )
+{
+  PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private;
+  PEI_AHCI_ATA_DEVICE_DATA            *DeviceData;
+
+  if ((PayloadBuffer == NULL) && (PayloadBufferSize != 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
+  if ((DeviceIndex == 0) || (DeviceIndex > Private->TrustComputingDevices)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DeviceData = SearchTrustComputingDeviceByIndex (Private, DeviceIndex);
+  if (DeviceData == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  ASSERT ((DeviceData->IdentifyData->trusted_computing_support & BIT0) != 0);
+  if ((DeviceData->IdentifyData->trusted_computing_support & BIT0) == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  return TrustTransferAtaDevice (
+           DeviceData,
+           PayloadBuffer,
+           SecurityProtocolId,
+           SecurityProtocolSpecificData,
+           PayloadBufferSize,
+           TRUE,
+           Timeout,
+           NULL
+           );
+}
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/DevicePath.c b/MdeModulePkg/Bus/Ata/AhciPei/DevicePath.c
new file mode 100644
index 0000000000..bdf8cc7780
--- /dev/null
+++ b/MdeModulePkg/Bus/Ata/AhciPei/DevicePath.c
@@ -0,0 +1,284 @@
+/** @file
+  The device path help function.
+
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions
+  of the BSD License which accompanies this distribution.  The
+  full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "AhciPei.h"
+
+//
+// Template for a SATA Device Path node
+//
+SATA_DEVICE_PATH  mAhciSataDevicePathNodeTemplate = {
+  {        // Header
+    MESSAGING_DEVICE_PATH,
+    MSG_SATA_DP,
+    {
+      (UINT8) (sizeof (SATA_DEVICE_PATH)),
+      (UINT8) ((sizeof (SATA_DEVICE_PATH)) >> 8)
+    }
+  },
+  0x0,     // HBAPortNumber
+  0xFFFF,  // PortMultiplierPortNumber
+  0x0      // Lun
+};
+
+//
+// Template for an End of entire Device Path node
+//
+EFI_DEVICE_PATH_PROTOCOL  mAhciEndDevicePathNodeTemplate = {
+  END_DEVICE_PATH_TYPE,
+  END_ENTIRE_DEVICE_PATH_SUBTYPE,
+  {
+    (UINT8) (sizeof (EFI_DEVICE_PATH_PROTOCOL)),
+    (UINT8) ((sizeof (EFI_DEVICE_PATH_PROTOCOL)) >> 8)
+  }
+};
+
+/**
+  Returns the 16-bit Length field of a device path node.
+
+  Returns the 16-bit Length field of the device path node specified by Node.
+  Node is not required to be aligned on a 16-bit boundary, so it is recommended
+  that a function such as ReadUnaligned16() be used to extract the contents of
+  the Length field.
+
+  If Node is NULL, then ASSERT().
+
+  @param  Node      A pointer to a device path node data structure.
+
+  @return The 16-bit Length field of the device path node specified by Node.
+
+**/
+UINTN
+DevicePathNodeLength (
+  IN CONST VOID  *Node
+  )
+{
+  ASSERT (Node != NULL);
+  return ReadUnaligned16 ((UINT16 *)&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0]);
+}
+
+/**
+  Returns a pointer to the next node in a device path.
+
+  If Node is NULL, then ASSERT().
+
+  @param  Node    A pointer to a device path node data structure.
+
+  @return a pointer to the device path node that follows the device path node
+  specified by Node.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+NextDevicePathNode (
+  IN CONST VOID  *Node
+  )
+{
+  ASSERT (Node != NULL);
+  return (EFI_DEVICE_PATH_PROTOCOL *)((UINT8 *)(Node) + DevicePathNodeLength(Node));
+}
+
+/**
+  Get the size of the current device path instance.
+
+  @param[in]  DevicePath             A pointer to the EFI_DEVICE_PATH_PROTOCOL
+                                     structure.
+  @param[out] InstanceSize           The size of the current device path instance.
+  @param[out] EntireDevicePathEnd    Indicate whether the instance is the last
+                                     one in the device path strucure.
+
+  @retval EFI_SUCCESS    The size of the current device path instance is fetched.
+  @retval Others         Fails to get the size of the current device path instance.
+
+**/
+EFI_STATUS
+GetDevicePathInstanceSize (
+  IN  EFI_DEVICE_PATH_PROTOCOL    *DevicePath,
+  OUT UINTN                       *InstanceSize,
+  OUT BOOLEAN                     *EntireDevicePathEnd
+  )
+{
+  EFI_DEVICE_PATH_PROTOCOL    *Walker;
+
+  if (DevicePath == NULL || InstanceSize == NULL || EntireDevicePathEnd == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Find the end of the device path instance
+  //
+  Walker = DevicePath;
+  while (Walker->Type != END_DEVICE_PATH_TYPE) {
+    Walker = NextDevicePathNode (Walker);
+  }
+
+  //
+  // Check if 'Walker' points to the end of an entire device path
+  //
+  if (Walker->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
+    *EntireDevicePathEnd = TRUE;
+  } else if (Walker->SubType == END_INSTANCE_DEVICE_PATH_SUBTYPE) {
+    *EntireDevicePathEnd = FALSE;
+  } else {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Compute the size of the device path instance
+  //
+  *InstanceSize = ((UINTN) Walker - (UINTN) (DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Check the validity of the device path of a ATA AHCI host controller.
+
+  @param[in] DevicePath          A pointer to the EFI_DEVICE_PATH_PROTOCOL
+                                 structure.
+  @param[in] DevicePathLength    The length of the device path.
+
+  @retval EFI_SUCCESS              The device path is valid.
+  @retval EFI_INVALID_PARAMETER    The device path is invalid.
+
+**/
+EFI_STATUS
+AhciCheckHcDevicePath (
+  IN EFI_DEVICE_PATH_PROTOCOL    *DevicePath,
+  IN UINTN                       DevicePathLength
+  )
+{
+  EFI_DEVICE_PATH_PROTOCOL    *Start;
+  UINTN                       Size;
+
+  if (DevicePath == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Validate the DevicePathLength is big enough to touch the first node.
+  //
+  if (DevicePathLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Start = DevicePath;
+  while (!(DevicePath->Type == END_DEVICE_PATH_TYPE &&
+           DevicePath->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE)) {
+    DevicePath = NextDevicePathNode (DevicePath);
+
+    //
+    // Prevent overflow and invalid zero in the 'Length' field of a device path
+    // node.
+    //
+    if ((UINTN) DevicePath <= (UINTN) Start) {
+      return EFI_INVALID_PARAMETER;
+    }
+
+    //
+    // Prevent touching memory beyond given DevicePathLength.
+    //
+    if ((UINTN) DevicePath - (UINTN) Start >
+        DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  //
+  // Check if the device path and its size match each other.
+  //
+  Size = ((UINTN) DevicePath - (UINTN) Start) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
+  if (Size != DevicePathLength) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Build the device path for an ATA device with given port and port multiplier number.
+
+  @param[in]  Private               A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA
+                                    data structure.
+  @param[in]  Port                  The given port number.
+  @param[in]  PortMultiplierPort    The given port multiplier number.
+  @param[out] DevicePathLength      The length of the device path in bytes specified
+                                    by DevicePath.
+  @param[out] DevicePath            The device path of ATA device.
+
+  @retval EFI_SUCCESS               The operation succeeds.
+  @retval EFI_INVALID_PARAMETER     The parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES      The operation fails due to lack of resources.
+
+**/
+EFI_STATUS
+AhciBuildDevicePath (
+  IN  PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private,
+  IN  UINT16                              Port,
+  IN  UINT16                              PortMultiplierPort,
+  OUT UINTN                               *DevicePathLength,
+  OUT EFI_DEVICE_PATH_PROTOCOL            **DevicePath
+  )
+{
+  EFI_DEVICE_PATH_PROTOCOL    *DevicePathWalker;
+  SATA_DEVICE_PATH            *SataDeviceNode;
+
+  if (DevicePathLength == NULL || DevicePath == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *DevicePathLength = Private->DevicePathLength + sizeof (SATA_DEVICE_PATH);
+  *DevicePath       = AllocatePool (*DevicePathLength);
+  if (*DevicePath == NULL) {
+    *DevicePathLength = 0;
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Construct the host controller part device nodes
+  //
+  DevicePathWalker = *DevicePath;
+  CopyMem (
+    DevicePathWalker,
+    Private->DevicePath,
+    Private->DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)
+    );
+
+  //
+  // Construct the SATA device node
+  //
+  DevicePathWalker = (EFI_DEVICE_PATH_PROTOCOL *) ((UINT8 *)DevicePathWalker +
+                     (Private->DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)));
+  CopyMem (
+    DevicePathWalker,
+    &mAhciSataDevicePathNodeTemplate,
+    sizeof (mAhciSataDevicePathNodeTemplate)
+    );
+  SataDeviceNode                           = (SATA_DEVICE_PATH *)DevicePathWalker;
+  SataDeviceNode->HBAPortNumber            = Port;
+  SataDeviceNode->PortMultiplierPortNumber = PortMultiplierPort;
+
+  //
+  // Construct the end device node
+  //
+  DevicePathWalker = (EFI_DEVICE_PATH_PROTOCOL *) ((UINT8 *)DevicePathWalker +
+                     sizeof (SATA_DEVICE_PATH));
+  CopyMem (
+    DevicePathWalker,
+    &mAhciEndDevicePathNodeTemplate,
+    sizeof (mAhciEndDevicePathNodeTemplate)
+    );
+
+  return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/DmaMem.c b/MdeModulePkg/Bus/Ata/AhciPei/DmaMem.c
new file mode 100644
index 0000000000..098b02c1a1
--- /dev/null
+++ b/MdeModulePkg/Bus/Ata/AhciPei/DmaMem.c
@@ -0,0 +1,270 @@
+/** @file
+  The DMA memory help function.
+
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions
+  of the BSD License which accompanies this distribution.  The
+  full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "AhciPei.h"
+
+/**
+  Get IOMMU PPI.
+
+  @return Pointer to IOMMU PPI.
+
+**/
+EDKII_IOMMU_PPI *
+GetIoMmu (
+  VOID
+  )
+{
+  EFI_STATUS         Status;
+  EDKII_IOMMU_PPI    *IoMmu;
+
+  IoMmu  = NULL;
+  Status = PeiServicesLocatePpi (
+             &gEdkiiIoMmuPpiGuid,
+             0,
+             NULL,
+             (VOID **) &IoMmu
+             );
+  if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
+    return IoMmu;
+  }
+
+  return NULL;
+}
+
+/**
+  Provides the controller-specific addresses required to access system memory from a
+  DMA bus master.
+
+  @param  Operation             Indicates if the bus master is going to read or write to system memory.
+  @param  HostAddress           The system memory address to map to the PCI controller.
+  @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes
+                                that were mapped.
+  @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to
+                                access the hosts HostAddress.
+  @param  Mapping               A resulting value to pass to Unmap().
+
+  @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.
+  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+IoMmuMap (
+  IN  EDKII_IOMMU_OPERATION Operation,
+  IN VOID                   *HostAddress,
+  IN  OUT UINTN             *NumberOfBytes,
+  OUT EFI_PHYSICAL_ADDRESS  *DeviceAddress,
+  OUT VOID                  **Mapping
+  )
+{
+  EFI_STATUS         Status;
+  UINT64             Attribute;
+  EDKII_IOMMU_PPI    *IoMmu;
+
+  IoMmu = GetIoMmu ();
+
+  if (IoMmu != NULL) {
+    Status = IoMmu->Map (
+                     IoMmu,
+                     Operation,
+                     HostAddress,
+                     NumberOfBytes,
+                     DeviceAddress,
+                     Mapping
+                     );
+    if (EFI_ERROR (Status)) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+    switch (Operation) {
+    case EdkiiIoMmuOperationBusMasterRead:
+    case EdkiiIoMmuOperationBusMasterRead64:
+      Attribute = EDKII_IOMMU_ACCESS_READ;
+      break;
+    case EdkiiIoMmuOperationBusMasterWrite:
+    case EdkiiIoMmuOperationBusMasterWrite64:
+      Attribute = EDKII_IOMMU_ACCESS_WRITE;
+      break;
+    case EdkiiIoMmuOperationBusMasterCommonBuffer:
+    case EdkiiIoMmuOperationBusMasterCommonBuffer64:
+      Attribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE;
+      break;
+    default:
+      ASSERT(FALSE);
+      return EFI_INVALID_PARAMETER;
+    }
+    Status = IoMmu->SetAttribute (
+                      IoMmu,
+                      *Mapping,
+                      Attribute
+                      );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  } else {
+    *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
+    *Mapping = NULL;
+    Status = EFI_SUCCESS;
+  }
+  return Status;
+}
+
+/**
+  Completes the Map() operation and releases any corresponding resources.
+
+  @param  Mapping               The mapping value returned from Map().
+
+  @retval EFI_SUCCESS           The range was unmapped.
+  @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+  @retval EFI_DEVICE_ERROR      The data was not committed to the target system memory.
+**/
+EFI_STATUS
+IoMmuUnmap (
+  IN VOID                  *Mapping
+  )
+{
+  EFI_STATUS         Status;
+  EDKII_IOMMU_PPI    *IoMmu;
+
+  IoMmu = GetIoMmu ();
+
+  if (IoMmu != NULL) {
+    Status = IoMmu->SetAttribute (IoMmu, Mapping, 0);
+    Status = IoMmu->Unmap (IoMmu, Mapping);
+  } else {
+    Status = EFI_SUCCESS;
+  }
+  return Status;
+}
+
+/**
+  Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+  OperationBusMasterCommonBuffer64 mapping.
+
+  @param  Pages                 The number of pages to allocate.
+  @param  HostAddress           A pointer to store the base system memory address of the
+                                allocated range.
+  @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to
+                                access the hosts HostAddress.
+  @param  Mapping               A resulting value to pass to Unmap().
+
+  @retval EFI_SUCCESS           The requested memory pages were allocated.
+  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are
+                                MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateBuffer (
+  IN UINTN                  Pages,
+  OUT VOID                  **HostAddress,
+  OUT EFI_PHYSICAL_ADDRESS  *DeviceAddress,
+  OUT VOID                  **Mapping
+  )
+{
+  EFI_STATUS            Status;
+  UINTN                 NumberOfBytes;
+  EFI_PHYSICAL_ADDRESS  HostPhyAddress;
+  EDKII_IOMMU_PPI       *IoMmu;
+
+  *HostAddress = NULL;
+  *DeviceAddress = 0;
+
+  IoMmu = GetIoMmu ();
+
+  if (IoMmu != NULL) {
+    Status = IoMmu->AllocateBuffer (
+                      IoMmu,
+                      EfiBootServicesData,
+                      Pages,
+                      HostAddress,
+                      0
+                      );
+    if (EFI_ERROR (Status)) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    NumberOfBytes = EFI_PAGES_TO_SIZE(Pages);
+    Status = IoMmu->Map (
+                      IoMmu,
+                      EdkiiIoMmuOperationBusMasterCommonBuffer,
+                      *HostAddress,
+                      &NumberOfBytes,
+                      DeviceAddress,
+                      Mapping
+                      );
+    if (EFI_ERROR (Status)) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+    Status = IoMmu->SetAttribute (
+                      IoMmu,
+                      *Mapping,
+                      EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
+                      );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  } else {
+    Status = PeiServicesAllocatePages (
+               EfiBootServicesData,
+               Pages,
+               &HostPhyAddress
+               );
+    if (EFI_ERROR (Status)) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+    *HostAddress = (VOID *)(UINTN)HostPhyAddress;
+    *DeviceAddress = HostPhyAddress;
+    *Mapping = NULL;
+  }
+  return Status;
+}
+
+/**
+  Frees memory that was allocated with AllocateBuffer().
+
+  @param  Pages                 The number of pages to free.
+  @param  HostAddress           The base system memory address of the allocated range.
+  @param  Mapping               The mapping value returned from Map().
+
+  @retval EFI_SUCCESS           The requested memory pages were freed.
+  @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+                                was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+IoMmuFreeBuffer (
+  IN UINTN                  Pages,
+  IN VOID                   *HostAddress,
+  IN VOID                   *Mapping
+  )
+{
+  EFI_STATUS         Status;
+  EDKII_IOMMU_PPI    *IoMmu;
+
+  IoMmu = GetIoMmu ();
+
+  if (IoMmu != NULL) {
+    Status = IoMmu->SetAttribute (IoMmu, Mapping, 0);
+    Status = IoMmu->Unmap (IoMmu, Mapping);
+    Status = IoMmu->FreeBuffer (IoMmu, Pages, HostAddress);
+  } else {
+    Status = EFI_SUCCESS;
+  }
+  return Status;
+}
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.uni b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.uni
new file mode 100644
index 0000000000..6dd3a74cc5
--- /dev/null
+++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.uni
@@ -0,0 +1,21 @@
+// /** @file
+// The AhciPei driver is used to manage ATA hard disk device working under AHCI
+// mode at PEI phase.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions
+// of the BSD License which accompanies this distribution.  The
+// full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "Manage AHCI mode ATA hard disk device at PEI phase"
+
+#string STR_MODULE_DESCRIPTION          #language en-US "The AhciPei driver is used to manage ATA hard disk device working under AHCI mode at PEI phase."
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiExtra.uni b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiExtra.uni
new file mode 100644
index 0000000000..295f426473
--- /dev/null
+++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// AhciPei Localized Strings and Content
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions
+// of the BSD License which accompanies this distribution.  The
+// full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"AHCI Bus Peim"
-- 
2.12.0.windows.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 09/12] MdeModulePkg/SmmLockBoxLib: Use 'DEBUG_' prefix instead of 'EFI_D_'
  2019-02-01  5:47 [PATCH v3 00/12] Split the S3 PEI phase HW init codes from Opal driver Hao Wu
                   ` (7 preceding siblings ...)
  2019-02-01  5:47 ` [PATCH v3 08/12] MdeModulePkg/AhciPei: Add AHCI mode ATA device support in PEI Hao Wu
@ 2019-02-01  5:47 ` Hao Wu
  2019-02-01  9:04   ` Laszlo Ersek
  2019-02-01  5:47 ` [PATCH v3 10/12] MdeModulePkg/SmmLockBox(PEI): Remove an ASSERT in RestoreLockBox() Hao Wu
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 19+ messages in thread
From: Hao Wu @ 2019-02-01  5:47 UTC (permalink / raw)
  To: edk2-devel; +Cc: Hao Wu, Jian J Wang, Star Zeng

This commit is out of the scope for BZ-1409. It is a coding style
refinement for the SmmLockBoxLib.

More specifically, the commit will remove all the debug message display
level macros starting with 'EFI_D_' and replace them with macros starting
with 'DEBUG_'.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Hao Wu <hao.a.wu@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
---
 MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c | 22 +++---
 MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c | 26 +++----
 MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c | 78 ++++++++++----------
 3 files changed, 63 insertions(+), 63 deletions(-)

diff --git a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c
index ac8bcd2ff7..0428decbac 100644
--- a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c
+++ b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c
@@ -1,6 +1,6 @@
 /** @file
 
-Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
 
 This program and the accompanying materials
 are licensed and made available under the terms and conditions
@@ -153,7 +153,7 @@ SaveLockBox (
   UINT8                           *CommBuffer;
   UINTN                           CommSize;
 
-  DEBUG ((EFI_D_INFO, "SmmLockBoxDxeLib SaveLockBox - Enter\n"));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib SaveLockBox - Enter\n"));
 
   //
   // Basic check
@@ -199,7 +199,7 @@ SaveLockBox (
 
   Status = (EFI_STATUS)LockBoxParameterSave->Header.ReturnStatus;
 
-  DEBUG ((EFI_D_INFO, "SmmLockBoxDxeLib SaveLockBox - Exit (%r)\n", Status));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib SaveLockBox - Exit (%r)\n", Status));
 
   //
   // Done
@@ -235,7 +235,7 @@ SetLockBoxAttributes (
   UINT8                                     *CommBuffer;
   UINTN                                     CommSize;
 
-  DEBUG ((EFI_D_INFO, "SmmLockBoxDxeLib SetLockBoxAttributes - Enter\n"));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib SetLockBoxAttributes - Enter\n"));
 
   //
   // Basic check
@@ -281,7 +281,7 @@ SetLockBoxAttributes (
 
   Status = (EFI_STATUS)LockBoxParameterSetAttributes->Header.ReturnStatus;
 
-  DEBUG ((EFI_D_INFO, "SmmLockBoxDxeLib SetLockBoxAttributes - Exit (%r)\n", Status));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib SetLockBoxAttributes - Exit (%r)\n", Status));
 
   //
   // Done
@@ -322,7 +322,7 @@ UpdateLockBox (
   UINT8                             *CommBuffer;
   UINTN                             CommSize;
 
-  DEBUG ((EFI_D_INFO, "SmmLockBoxDxeLib UpdateLockBox - Enter\n"));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib UpdateLockBox - Enter\n"));
 
   //
   // Basic check
@@ -369,7 +369,7 @@ UpdateLockBox (
 
   Status = (EFI_STATUS)LockBoxParameterUpdate->Header.ReturnStatus;
 
-  DEBUG ((EFI_D_INFO, "SmmLockBoxDxeLib UpdateLockBox - Exit (%r)\n", Status));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib UpdateLockBox - Exit (%r)\n", Status));
 
   //
   // Done
@@ -411,7 +411,7 @@ RestoreLockBox (
   UINT8                              *CommBuffer;
   UINTN                              CommSize;
 
-  DEBUG ((EFI_D_INFO, "SmmLockBoxDxeLib RestoreLockBox - Enter\n"));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib RestoreLockBox - Enter\n"));
 
   //
   // Basic check
@@ -467,7 +467,7 @@ RestoreLockBox (
 
   Status = (EFI_STATUS)LockBoxParameterRestore->Header.ReturnStatus;
 
-  DEBUG ((EFI_D_INFO, "SmmLockBoxDxeLib RestoreLockBox - Exit (%r)\n", Status));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib RestoreLockBox - Exit (%r)\n", Status));
 
   //
   // Done
@@ -496,7 +496,7 @@ RestoreAllLockBoxInPlace (
   UINT8                                           *CommBuffer;
   UINTN                                           CommSize;
 
-  DEBUG ((EFI_D_INFO, "SmmLockBoxDxeLib RestoreAllLockBoxInPlace - Enter\n"));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib RestoreAllLockBoxInPlace - Enter\n"));
 
   SmmCommunication = LockBoxGetSmmCommProtocol ();
   if (SmmCommunication == NULL) {
@@ -532,7 +532,7 @@ RestoreAllLockBoxInPlace (
 
   Status = (EFI_STATUS)LockBoxParameterRestoreAllInPlace->Header.ReturnStatus;
 
-  DEBUG ((EFI_D_INFO, "SmmLockBoxDxeLib RestoreAllLockBoxInPlace - Exit (%r)\n", Status));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxDxeLib RestoreAllLockBoxInPlace - Exit (%r)\n", Status));
 
   //
   // Done
diff --git a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
index 8a168663c4..9f73480070 100644
--- a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
+++ b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
@@ -1,6 +1,6 @@
 /** @file
 
-Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
 
 This program and the accompanying materials
 are licensed and made available under the terms and conditions
@@ -542,7 +542,7 @@ RestoreLockBox (
   // } EFI_SMM_COMMUNICATE_HEADER;
   //
 
-  DEBUG ((EFI_D_INFO, "SmmLockBoxPeiLib RestoreLockBox - Enter\n"));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib RestoreLockBox - Enter\n"));
 
   //
   // Basic check
@@ -563,9 +563,9 @@ RestoreLockBox (
              (VOID **)&SmmCommunicationPpi
              );
   if (EFI_ERROR (Status)) {
-    DEBUG ((EFI_D_INFO, "SmmLockBoxPeiLib LocatePpi - (%r)\n", Status));
+    DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib LocatePpi - (%r)\n", Status));
     Status = InternalRestoreLockBoxFromSmram (Guid, Buffer, Length);
-    DEBUG ((EFI_D_INFO, "SmmLockBoxPeiLib RestoreLockBox - Exit (%r)\n", Status));
+    DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib RestoreLockBox - Exit (%r)\n", Status));
     return Status;
   }
 
@@ -581,13 +581,13 @@ RestoreLockBox (
     CommHeader->MessageLength = sizeof(*LockBoxParameterRestore);
   }
 
-  DEBUG ((EFI_D_INFO, "SmmLockBoxPeiLib CommBuffer - %x\n", &CommBuffer[0]));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib CommBuffer - %x\n", &CommBuffer[0]));
   if ((sizeof(UINTN) == sizeof(UINT32)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) ) {
     LockBoxParameterRestore = (EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, MessageLength) + sizeof(UINT64)];
   } else {
     LockBoxParameterRestore = (EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, MessageLength) + sizeof(UINTN)];
   }
-  DEBUG ((EFI_D_INFO, "SmmLockBoxPeiLib LockBoxParameterRestore - %x\n", LockBoxParameterRestore));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib LockBoxParameterRestore - %x\n", LockBoxParameterRestore));
   LockBoxParameterRestore->Header.Command    = EFI_SMM_LOCK_BOX_COMMAND_RESTORE;
   LockBoxParameterRestore->Header.DataLength = sizeof(*LockBoxParameterRestore);
   LockBoxParameterRestore->Header.ReturnStatus = (UINT64)-1;
@@ -616,7 +616,7 @@ RestoreLockBox (
     //
     // Pei SMM communication not ready yet, so we access SMRAM directly
     //
-    DEBUG ((EFI_D_INFO, "SmmLockBoxPeiLib Communicate - (%r)\n", Status));
+    DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib Communicate - (%r)\n", Status));
     Status = InternalRestoreLockBoxFromSmram (Guid, Buffer, Length);
     LockBoxParameterRestore->Header.ReturnStatus = (UINT64)Status;
     if (Length != NULL) {
@@ -635,7 +635,7 @@ RestoreLockBox (
     Status |= MAX_BIT;
   }
 
-  DEBUG ((EFI_D_INFO, "SmmLockBoxPeiLib RestoreLockBox - Exit (%r)\n", Status));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib RestoreLockBox - Exit (%r)\n", Status));
 
   //
   // Done
@@ -673,7 +673,7 @@ RestoreAllLockBoxInPlace (
   // } EFI_SMM_COMMUNICATE_HEADER;
   //
 
-  DEBUG ((EFI_D_INFO, "SmmLockBoxPeiLib RestoreAllLockBoxInPlace - Enter\n"));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib RestoreAllLockBoxInPlace - Enter\n"));
 
   //
   // Get needed resource
@@ -685,9 +685,9 @@ RestoreAllLockBoxInPlace (
              (VOID **)&SmmCommunicationPpi
              );
   if (EFI_ERROR (Status)) {
-    DEBUG ((EFI_D_INFO, "SmmLockBoxPeiLib LocatePpi - (%r)\n", Status));
+    DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib LocatePpi - (%r)\n", Status));
     Status = InternalRestoreAllLockBoxInPlaceFromSmram ();
-    DEBUG ((EFI_D_INFO, "SmmLockBoxPeiLib RestoreAllLockBoxInPlace - Exit (%r)\n", Status));
+    DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib RestoreAllLockBoxInPlace - Exit (%r)\n", Status));
     return Status;
   }
 
@@ -725,7 +725,7 @@ RestoreAllLockBoxInPlace (
     //
     // Pei SMM communication not ready yet, so we access SMRAM directly
     //
-    DEBUG ((EFI_D_INFO, "SmmLockBoxPeiLib Communicate - (%r)\n", Status));
+    DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib Communicate - (%r)\n", Status));
     Status = InternalRestoreAllLockBoxInPlaceFromSmram ();
     LockBoxParameterRestoreAllInPlace->Header.ReturnStatus = (UINT64)Status;
   }
@@ -737,7 +737,7 @@ RestoreAllLockBoxInPlace (
     Status |= MAX_BIT;
   }
 
-  DEBUG ((EFI_D_INFO, "SmmLockBoxPeiLib RestoreAllLockBoxInPlace - Exit (%r)\n", Status));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib RestoreAllLockBoxInPlace - Exit (%r)\n", Status));
 
   //
   // Done
diff --git a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c
index 54a81d6521..c912d187a4 100644
--- a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c
+++ b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c
@@ -1,6 +1,6 @@
 /** @file
 
-Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
 
 This program and the accompanying materials
 are licensed and made available under the terms and conditions
@@ -214,7 +214,7 @@ SmmLockBoxSmmConstructor (
   EFI_STATUS           Status;
   SMM_LOCK_BOX_CONTEXT *SmmLockBoxContext;
 
-  DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmConstructor - Enter\n"));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmConstructor - Enter\n"));
 
   //
   // Register SmmReadyToLock notification.
@@ -255,8 +255,8 @@ SmmLockBoxSmmConstructor (
     // Find it. That means some other library instance is already run.
     // No need to install again, just return.
     //
-    DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxContext - already installed\n"));
-    DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmConstructor - Exit\n"));
+    DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SmmLockBoxContext - already installed\n"));
+    DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmConstructor - Exit\n"));
     return EFI_SUCCESS;
   }
 
@@ -279,9 +279,9 @@ SmmLockBoxSmmConstructor (
   ASSERT_EFI_ERROR (Status);
   mSmmConfigurationTableInstalled = TRUE;
 
-  DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxContext - %x\n", (UINTN)&mSmmLockBoxContext));
-  DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib LockBoxDataAddress - %x\n", (UINTN)&mLockBoxQueue));
-  DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmConstructor - Exit\n"));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SmmLockBoxContext - %x\n", (UINTN)&mSmmLockBoxContext));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib LockBoxDataAddress - %x\n", (UINTN)&mLockBoxQueue));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmConstructor - Exit\n"));
 
   return Status;
 }
@@ -306,7 +306,7 @@ SmmLockBoxSmmDestructor (
 {
   EFI_STATUS            Status;
 
-  DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmDestructor in %a module\n", gEfiCallerBaseName));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmDestructor in %a module\n", gEfiCallerBaseName));
 
   if (mSmmConfigurationTableInstalled) {
     Status = gSmst->SmmInstallConfigurationTable (
@@ -316,7 +316,7 @@ SmmLockBoxSmmDestructor (
                       0
                       );
     ASSERT_EFI_ERROR (Status);
-    DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib uninstall SmmLockBoxCommunication configuration table\n"));
+    DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib uninstall SmmLockBoxCommunication configuration table\n"));
   }
 
   if (mSmmLockBoxRegistrationSmmReadyToLock != NULL) {
@@ -438,13 +438,13 @@ SaveLockBox (
   EFI_STATUS                  Status;
   LIST_ENTRY                  *LockBoxQueue;
 
-  DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Enter\n"));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SaveLockBox - Enter\n"));
 
   //
   // Basic check
   //
   if ((Guid == NULL) || (Buffer == NULL) || (Length == 0)) {
-    DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_INVALID_PARAMETER));
+    DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_INVALID_PARAMETER));
     return EFI_INVALID_PARAMETER;
   }
 
@@ -453,7 +453,7 @@ SaveLockBox (
   //
   LockBox = InternalFindLockBoxByGuid (Guid);
   if (LockBox != NULL) {
-    DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_ALREADY_STARTED));
+    DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_ALREADY_STARTED));
     return EFI_ALREADY_STARTED;
   }
 
@@ -468,7 +468,7 @@ SaveLockBox (
                     );
   ASSERT_EFI_ERROR (Status);
   if (EFI_ERROR (Status)) {
-    DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_OUT_OF_RESOURCES));
+    DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_OUT_OF_RESOURCES));
     return EFI_OUT_OF_RESOURCES;
   }
 
@@ -483,7 +483,7 @@ SaveLockBox (
   ASSERT_EFI_ERROR (Status);
   if (EFI_ERROR (Status)) {
     gSmst->SmmFreePages (SmramBuffer, EFI_SIZE_TO_PAGES (Length));
-    DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_OUT_OF_RESOURCES));
+    DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_OUT_OF_RESOURCES));
     return EFI_OUT_OF_RESOURCES;
   }
 
@@ -503,7 +503,7 @@ SaveLockBox (
   LockBox->SmramBuffer = SmramBuffer;
 
   DEBUG ((
-    EFI_D_INFO,
+    DEBUG_INFO,
     "LockBoxGuid - %g, SmramBuffer - 0x%lx, Length - 0x%lx\n",
     &LockBox->Guid,
     LockBox->SmramBuffer,
@@ -517,7 +517,7 @@ SaveLockBox (
   //
   // Done
   //
-  DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_SUCCESS));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_SUCCESS));
   return EFI_SUCCESS;
 }
 
@@ -543,22 +543,22 @@ SetLockBoxAttributes (
 {
   SMM_LOCK_BOX_DATA              *LockBox;
 
-  DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Enter\n"));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Enter\n"));
 
   //
   // Basic check
   //
   if ((Guid == NULL) ||
       ((Attributes & ~(LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE | LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY)) != 0)) {
-    DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Exit (%r)\n", EFI_INVALID_PARAMETER));
+    DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Exit (%r)\n", EFI_INVALID_PARAMETER));
     return EFI_INVALID_PARAMETER;
   }
 
   if (((Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) != 0) &&
       ((Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY) != 0)) {
-    DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Exit (%r)\n", EFI_INVALID_PARAMETER));
-    DEBUG ((EFI_D_INFO, "  LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE and LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY\n\n"));
-    DEBUG ((EFI_D_INFO, "  can not be set together\n"));
+    DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Exit (%r)\n", EFI_INVALID_PARAMETER));
+    DEBUG ((DEBUG_INFO, "  LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE and LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY\n\n"));
+    DEBUG ((DEBUG_INFO, "  can not be set together\n"));
     return EFI_INVALID_PARAMETER;
   }
 
@@ -567,7 +567,7 @@ SetLockBoxAttributes (
   //
   LockBox = InternalFindLockBoxByGuid (Guid);
   if (LockBox == NULL) {
-    DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Exit (%r)\n", EFI_NOT_FOUND));
+    DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Exit (%r)\n", EFI_NOT_FOUND));
     return EFI_NOT_FOUND;
   }
 
@@ -575,9 +575,9 @@ SetLockBoxAttributes (
       ((LockBox->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY) != 0)) ||
       (((LockBox->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) != 0) &&
       ((Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY) != 0))) {
-    DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes 0x%lx 0x%lx - Exit (%r)\n", LockBox->Attributes, Attributes, EFI_INVALID_PARAMETER));
-    DEBUG ((EFI_D_INFO, "  LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE and LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY\n\n"));
-    DEBUG ((EFI_D_INFO, "  can not be set together\n"));
+    DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes 0x%lx 0x%lx - Exit (%r)\n", LockBox->Attributes, Attributes, EFI_INVALID_PARAMETER));
+    DEBUG ((DEBUG_INFO, "  LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE and LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY\n\n"));
+    DEBUG ((DEBUG_INFO, "  can not be set together\n"));
     return EFI_INVALID_PARAMETER;
   }
 
@@ -589,7 +589,7 @@ SetLockBoxAttributes (
   //
   // Done
   //
-  DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Exit (%r)\n", EFI_SUCCESS));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Exit (%r)\n", EFI_SUCCESS));
   return EFI_SUCCESS;
 }
 
@@ -620,13 +620,13 @@ UpdateLockBox (
 {
   SMM_LOCK_BOX_DATA             *LockBox;
 
-  DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Enter\n"));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Enter\n"));
 
   //
   // Basic check
   //
   if ((Guid == NULL) || (Buffer == NULL) || (Length == 0)) {
-    DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_INVALID_PARAMETER));
+    DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_INVALID_PARAMETER));
     return EFI_INVALID_PARAMETER;
   }
 
@@ -635,7 +635,7 @@ UpdateLockBox (
   //
   LockBox = InternalFindLockBoxByGuid (Guid);
   if (LockBox == NULL) {
-    DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_NOT_FOUND));
+    DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_NOT_FOUND));
     return EFI_NOT_FOUND;
   }
 
@@ -643,7 +643,7 @@ UpdateLockBox (
   // Update data
   //
   if (LockBox->Length < Offset + Length) {
-    DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_BUFFER_TOO_SMALL));
+    DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_BUFFER_TOO_SMALL));
     return EFI_BUFFER_TOO_SMALL;
   }
   ASSERT ((UINTN)LockBox->SmramBuffer <= (MAX_ADDRESS - Offset));
@@ -652,7 +652,7 @@ UpdateLockBox (
   //
   // Done
   //
-  DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_SUCCESS));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_SUCCESS));
   return EFI_SUCCESS;
 }
 
@@ -685,7 +685,7 @@ RestoreLockBox (
   SMM_LOCK_BOX_DATA              *LockBox;
   VOID                           *RestoreBuffer;
 
-  DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Enter\n"));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib RestoreLockBox - Enter\n"));
 
   //
   // Restore this, Buffer and Length MUST be both NULL or both non-NULL
@@ -693,7 +693,7 @@ RestoreLockBox (
   if ((Guid == NULL) ||
       ((Buffer == NULL) && (Length != NULL)) ||
       ((Buffer != NULL) && (Length == NULL))) {
-    DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_INVALID_PARAMETER));
+    DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_INVALID_PARAMETER));
     return EFI_INVALID_PARAMETER;
   }
 
@@ -705,7 +705,7 @@ RestoreLockBox (
     //
     // Not found
     //
-    DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_NOT_FOUND));
+    DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_NOT_FOUND));
     return EFI_NOT_FOUND;
   }
 
@@ -732,7 +732,7 @@ RestoreLockBox (
     // restore to original buffer
     //
     if ((LockBox->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) == 0) {
-      DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_WRITE_PROTECTED));
+      DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_WRITE_PROTECTED));
       return EFI_WRITE_PROTECTED;
     }
     RestoreBuffer = (VOID *)(UINTN)LockBox->Buffer;
@@ -747,7 +747,7 @@ RestoreLockBox (
       // Input buffer is too small to hold all data.
       //
       *Length = (UINTN)LockBox->Length;
-      DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_BUFFER_TOO_SMALL));
+      DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_BUFFER_TOO_SMALL));
       return EFI_BUFFER_TOO_SMALL;
     }
     *Length = (UINTN)LockBox->Length;
@@ -761,7 +761,7 @@ RestoreLockBox (
   //
   // Done
   //
-  DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_SUCCESS));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_SUCCESS));
   return EFI_SUCCESS;
 }
 
@@ -782,7 +782,7 @@ RestoreAllLockBoxInPlace (
   LIST_ENTRY                    *Link;
   LIST_ENTRY                    *LockBoxQueue;
 
-  DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreAllLockBoxInPlace - Enter\n"));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib RestoreAllLockBoxInPlace - Enter\n"));
 
   LockBoxQueue = InternalGetLockBoxQueue ();
   ASSERT (LockBoxQueue != NULL);
@@ -808,7 +808,7 @@ RestoreAllLockBoxInPlace (
   //
   // Done
   //
-  DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreAllLockBoxInPlace - Exit (%r)\n", EFI_SUCCESS));
+  DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib RestoreAllLockBoxInPlace - Exit (%r)\n", EFI_SUCCESS));
   return EFI_SUCCESS;
 }
 
-- 
2.12.0.windows.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 10/12] MdeModulePkg/SmmLockBox(PEI): Remove an ASSERT in RestoreLockBox()
  2019-02-01  5:47 [PATCH v3 00/12] Split the S3 PEI phase HW init codes from Opal driver Hao Wu
                   ` (8 preceding siblings ...)
  2019-02-01  5:47 ` [PATCH v3 09/12] MdeModulePkg/SmmLockBoxLib: Use 'DEBUG_' prefix instead of 'EFI_D_' Hao Wu
@ 2019-02-01  5:47 ` Hao Wu
  2019-02-01  9:17   ` Laszlo Ersek
  2019-02-01  5:47 ` [PATCH v3 11/12] MdeModulePkg/SmmLockBoxLib: Support LockBox enlarge in UpdateLockBox() Hao Wu
  2019-02-01  5:47 ` [PATCH v3 12/12] SecurityPkg/OpalPassword: Remove HW init codes and consume SSC PPI Hao Wu
  11 siblings, 1 reply; 19+ messages in thread
From: Hao Wu @ 2019-02-01  5:47 UTC (permalink / raw)
  To: edk2-devel; +Cc: Hao Wu, Jian J Wang, Star Zeng

This commit is out of the scope for BZ-1409. It is a refinement for the
PEI library instance within SmmLockBoxLib.

For the below ASSERT statement within function RestoreLockBox():
  Status = SmmCommunicationPpi->Communicate (
                                  SmmCommunicationPpi,
                                  &CommBuffer[0],
                                  &CommSize
                                  );
  if (Status == EFI_NOT_STARTED) {
    //
    // Pei SMM communication not ready yet, so we access SMRAM directly
    //
    DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib Communicate - (%r)\n", Status));
    Status = InternalRestoreLockBoxFromSmram (Guid, Buffer, Length);
    LockBoxParameterRestore->Header.ReturnStatus = (UINT64)Status;
    if (Length != NULL) {
      LockBoxParameterRestore->Length = (UINT64)*Length;
    }
  }
  ASSERT_EFI_ERROR (Status);

It is possible for previous codes to return an error status that is
possible for happen. One example is that, when the 'if' statement
'if (Status == EFI_NOT_STARTED) {' is entered, function
InternalRestoreLockBoxFromSmram() is possible to return 'BUFFER_TOO_SMALL'
if the caller of RestoreLockBox() provides a buffer that is too small to
hold the content of LockBox.

Thus, this commit will remove the ASSERT here.

Please note that the current implementation of RestoreLockBox() is
handling the above-mentioned error case properly, so no additional error
handling codes are needed here.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Hao Wu <hao.a.wu@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
---
 MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
index 9f73480070..8c3e65bc96 100644
--- a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
+++ b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
@@ -623,7 +623,6 @@ RestoreLockBox (
       LockBoxParameterRestore->Length = (UINT64)*Length;
     }
   }
-  ASSERT_EFI_ERROR (Status);
 
   if (Length != NULL) {
     *Length = (UINTN)LockBoxParameterRestore->Length;
-- 
2.12.0.windows.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 11/12] MdeModulePkg/SmmLockBoxLib: Support LockBox enlarge in UpdateLockBox()
  2019-02-01  5:47 [PATCH v3 00/12] Split the S3 PEI phase HW init codes from Opal driver Hao Wu
                   ` (9 preceding siblings ...)
  2019-02-01  5:47 ` [PATCH v3 10/12] MdeModulePkg/SmmLockBox(PEI): Remove an ASSERT in RestoreLockBox() Hao Wu
@ 2019-02-01  5:47 ` Hao Wu
  2019-02-01  7:52   ` Ni, Ray
  2019-02-01  9:39   ` Laszlo Ersek
  2019-02-01  5:47 ` [PATCH v3 12/12] SecurityPkg/OpalPassword: Remove HW init codes and consume SSC PPI Hao Wu
  11 siblings, 2 replies; 19+ messages in thread
From: Hao Wu @ 2019-02-01  5:47 UTC (permalink / raw)
  To: edk2-devel; +Cc: Hao Wu, Jian J Wang, Ray Ni, Star Zeng

REF:https://bugzilla.tianocore.org/show_bug.cgi?id=1409

This commit will add the support to enlarge a LockBox when using the
LockBoxLib API UpdateLockBox().

Please note that the new support will ONLY work for LockBox with attribute
LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY set.

The functional uni-test for the commit is available at:
https://github.com/hwu25/edk2/tree/lockbox_unitest

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Hao Wu <hao.a.wu@intel.com>
---
 MdeModulePkg/Include/Library/LockBoxLib.h             |  7 +-
 MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c  |  7 +-
 MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c |  5 +-
 MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c |  5 +-
 MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c | 72 ++++++++++++++++++--
 5 files changed, 86 insertions(+), 10 deletions(-)

diff --git a/MdeModulePkg/Include/Library/LockBoxLib.h b/MdeModulePkg/Include/Library/LockBoxLib.h
index 5921731419..addce3bd4a 100644
--- a/MdeModulePkg/Include/Library/LockBoxLib.h
+++ b/MdeModulePkg/Include/Library/LockBoxLib.h
@@ -2,7 +2,7 @@
   This library is only intended to be used by DXE modules that need save
   confidential information to LockBox and get it by PEI modules in S3 phase.
 
-Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
 
 This program and the accompanying materials
 are licensed and made available under the terms and conditions
@@ -85,7 +85,10 @@ SetLockBoxAttributes (
   @retval RETURN_SUCCESS            the information is saved successfully.
   @retval RETURN_INVALID_PARAMETER  the Guid is NULL, or Buffer is NULL, or Length is 0.
   @retval RETURN_NOT_FOUND          the requested GUID not found.
-  @retval RETURN_BUFFER_TOO_SMALL   the original buffer to too small to hold new information.
+  @retval RETURN_BUFFER_TOO_SMALL   for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE,
+                                    the original buffer to too small to hold new information.
+  @retval RETURN_OUT_OF_RESOURCES   for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
+                                    no enough resource to save the information.
   @retval RETURN_ACCESS_DENIED      it is too late to invoke this interface
   @retval RETURN_NOT_STARTED        it is too early to invoke this interface
   @retval RETURN_UNSUPPORTED        the service is not supported by implementaion.
diff --git a/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c b/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c
index c40dfea398..0adda1e2a9 100644
--- a/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c
+++ b/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c
@@ -1,6 +1,6 @@
 /** @file
 
-Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
 
 This program and the accompanying materials
 are licensed and made available under the terms and conditions
@@ -76,7 +76,10 @@ SetLockBoxAttributes (
   @retval RETURN_SUCCESS            the information is saved successfully.
   @retval RETURN_INVALID_PARAMETER  the Guid is NULL, or Buffer is NULL, or Length is 0.
   @retval RETURN_NOT_FOUND          the requested GUID not found.
-  @retval RETURN_BUFFER_TOO_SMALL   the original buffer to too small to hold new information.
+  @retval RETURN_BUFFER_TOO_SMALL   for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE,
+                                    the original buffer to too small to hold new information.
+  @retval RETURN_OUT_OF_RESOURCES   for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
+                                    no enough resource to save the information.
   @retval RETURN_ACCESS_DENIED      it is too late to invoke this interface
   @retval RETURN_NOT_STARTED        it is too early to invoke this interface
   @retval RETURN_UNSUPPORTED        the service is not supported by implementaion.
diff --git a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c
index 0428decbac..5ee563b71f 100644
--- a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c
+++ b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c
@@ -300,7 +300,10 @@ SetLockBoxAttributes (
   @retval RETURN_SUCCESS            the information is saved successfully.
   @retval RETURN_INVALID_PARAMETER  the Guid is NULL, or Buffer is NULL, or Length is 0.
   @retval RETURN_NOT_FOUND          the requested GUID not found.
-  @retval RETURN_BUFFER_TOO_SMALL   the original buffer to too small to hold new information.
+  @retval RETURN_BUFFER_TOO_SMALL   for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE,
+                                    the original buffer to too small to hold new information.
+  @retval RETURN_OUT_OF_RESOURCES   for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
+                                    no enough resource to save the information.
   @retval RETURN_ACCESS_DENIED      it is too late to invoke this interface
   @retval RETURN_NOT_STARTED        it is too early to invoke this interface
   @retval RETURN_UNSUPPORTED        the service is not supported by implementaion.
diff --git a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
index 8c3e65bc96..19fdd995c6 100644
--- a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
+++ b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
@@ -477,7 +477,10 @@ SetLockBoxAttributes (
   @retval RETURN_SUCCESS            the information is saved successfully.
   @retval RETURN_INVALID_PARAMETER  the Guid is NULL, or Buffer is NULL, or Length is 0.
   @retval RETURN_NOT_FOUND          the requested GUID not found.
-  @retval RETURN_BUFFER_TOO_SMALL   the original buffer to too small to hold new information.
+  @retval RETURN_BUFFER_TOO_SMALL   for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE,
+                                    the original buffer to too small to hold new information.
+  @retval RETURN_OUT_OF_RESOURCES   for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
+                                    no enough resource to save the information.
   @retval RETURN_ACCESS_DENIED      it is too late to invoke this interface
   @retval RETURN_NOT_STARTED        it is too early to invoke this interface
   @retval RETURN_UNSUPPORTED        the service is not supported by implementaion.
diff --git a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c
index c912d187a4..d1cff97ba1 100644
--- a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c
+++ b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c
@@ -604,7 +604,10 @@ SetLockBoxAttributes (
   @retval RETURN_SUCCESS            the information is saved successfully.
   @retval RETURN_INVALID_PARAMETER  the Guid is NULL, or Buffer is NULL, or Length is 0.
   @retval RETURN_NOT_FOUND          the requested GUID not found.
-  @retval RETURN_BUFFER_TOO_SMALL   the original buffer to too small to hold new information.
+  @retval RETURN_BUFFER_TOO_SMALL   for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE,
+                                    the original buffer to too small to hold new information.
+  @retval RETURN_OUT_OF_RESOURCES   for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
+                                    no enough resource to save the information.
   @retval RETURN_ACCESS_DENIED      it is too late to invoke this interface
   @retval RETURN_NOT_STARTED        it is too early to invoke this interface
   @retval RETURN_UNSUPPORTED        the service is not supported by implementaion.
@@ -619,13 +622,16 @@ UpdateLockBox (
   )
 {
   SMM_LOCK_BOX_DATA             *LockBox;
+  EFI_PHYSICAL_ADDRESS          SmramBuffer;
+  EFI_STATUS                    Status;
 
   DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Enter\n"));
 
   //
   // Basic check
   //
-  if ((Guid == NULL) || (Buffer == NULL) || (Length == 0)) {
+  if ((Guid == NULL) || (Buffer == NULL) || (Length == 0) ||
+      (Length > MAX_UINTN - Offset)) {
     DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_INVALID_PARAMETER));
     return EFI_INVALID_PARAMETER;
   }
@@ -643,8 +649,66 @@ UpdateLockBox (
   // Update data
   //
   if (LockBox->Length < Offset + Length) {
-    DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_BUFFER_TOO_SMALL));
-    return EFI_BUFFER_TOO_SMALL;
+    if ((LockBox->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY) != 0) {
+      //
+      // If 'LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY' attribute is set, enlarge the
+      // LockBox.
+      //
+      DEBUG ((
+        DEBUG_INFO,
+        "SmmLockBoxSmmLib UpdateLockBox - Origin LockBox too small, enlarge.\n"
+        ));
+
+      if (EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (LockBox->Length)) < Offset + Length) {
+        //
+        // In SaveLockBox(), the SMRAM buffer allocated for LockBox is of page
+        // granularity. Here, if the required size is larger than the origin size
+        // of the pages, allocate new buffer from SMRAM to enlarge the LockBox.
+        //
+        DEBUG ((
+          DEBUG_INFO,
+          "SmmLockBoxSmmLib UpdateLockBox - Allocate new buffer to enlarge.\n"
+          ));
+        Status = gSmst->SmmAllocatePages (
+                          AllocateAnyPages,
+                          EfiRuntimeServicesData,
+                          EFI_SIZE_TO_PAGES (Offset + Length),
+                          &SmramBuffer
+                          );
+        if (EFI_ERROR (Status)) {
+          DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_OUT_OF_RESOURCES));
+          return EFI_OUT_OF_RESOURCES;
+        }
+
+        //
+        // Copy origin data to the new SMRAM buffer and wipe the content in the
+        // origin SMRAM buffer.
+        //
+        CopyMem ((VOID *)(UINTN)SmramBuffer, (VOID *)(UINTN)LockBox->SmramBuffer, (UINTN)LockBox->Length);
+        ZeroMem ((VOID *)(UINTN)LockBox->SmramBuffer, (UINTN)LockBox->Length);
+        gSmst->SmmFreePages (LockBox->SmramBuffer, EFI_SIZE_TO_PAGES ((UINTN)LockBox->Length));
+
+        LockBox->SmramBuffer = SmramBuffer;
+      }
+
+      //
+      // Handle potential uninitialized content in the LockBox.
+      //
+      if (Offset > LockBox->Length) {
+        ZeroMem (
+          (VOID *)((UINTN)LockBox->SmramBuffer + (UINTN)LockBox->Length),
+          Offset - (UINTN)LockBox->Length
+          );
+      }
+      LockBox->Length = Offset + Length;
+    } else {
+      //
+      // If 'LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY' attribute is NOT set, return
+      // EFI_BUFFER_TOO_SMALL directly.
+      //
+      DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_BUFFER_TOO_SMALL));
+      return EFI_BUFFER_TOO_SMALL;
+    }
   }
   ASSERT ((UINTN)LockBox->SmramBuffer <= (MAX_ADDRESS - Offset));
   CopyMem ((VOID *)((UINTN)LockBox->SmramBuffer + Offset), Buffer, Length);
-- 
2.12.0.windows.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 12/12] SecurityPkg/OpalPassword: Remove HW init codes and consume SSC PPI
  2019-02-01  5:47 [PATCH v3 00/12] Split the S3 PEI phase HW init codes from Opal driver Hao Wu
                   ` (10 preceding siblings ...)
  2019-02-01  5:47 ` [PATCH v3 11/12] MdeModulePkg/SmmLockBoxLib: Support LockBox enlarge in UpdateLockBox() Hao Wu
@ 2019-02-01  5:47 ` Hao Wu
  11 siblings, 0 replies; 19+ messages in thread
From: Hao Wu @ 2019-02-01  5:47 UTC (permalink / raw)
  To: edk2-devel; +Cc: Hao Wu, Chao Zhang, Jiewen Yao, Ray Ni, Eric Dong

REF:https://bugzilla.tianocore.org/show_bug.cgi?id=1409

For the current implementation of OpalPassword drivers, it has a feature
to support devices being automatically unlocked in the S3 resume. For this
feature, two types of devices are supported:

* ATA hard disks working under AHCI mode
* NVM Express devices

The support of this feature requires the above 2 types of device to be
initialized at the PEI phase during S3 resume, which is done by the
co-work of the OpalPasswordDxe driver and the OpalPasswordPei driver.

More specifically, the OpalPasswordDxe will handle:

* Pre-allocate MMIO resource and save it in a driver internal LockBox for
  OpalPasswordPei to retrieve;
* Save the PCI configuration space of ATA controllers into boot script.

Meanwhile, the OpalPasswordPei will handle:

* Rely on the boot script for the PCI configuration space program of ATA
  controllers;
* Restore the driver internal LockBox to get the MMIO resource;
* Complete the PCI configuration space program for ATA and NVME
  controllers;
* Initialize ATA and NVME controllers and devices.

This commit will remove these hardware initialization related codes from
the OpalPassword drivers. The hardware initialization will be covered by
PEI storage device drivers (e.g. NvmExpressPei & AhciPei in the
MdeModulePkg).

After such codes removal, the OpalPasswordDxe will only handle:

* Construct/update the S3StorageDeviceInitList LockBox with the managing
  ATA and NVME devices.

And the OpalPasswordPei will only handle:

* Locate Storage Security Command PPI instances to perform the device
  automatic unlock during the S3 resume.

Cc: Chao Zhang <chao.b.zhang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Hao Wu <hao.a.wu@intel.com>
---
 SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordDxe.inf  |    6 +-
 SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.inf  |   12 +-
 SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.h       |  412 -----
 SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.h         |    4 +-
 SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.h       |  327 ----
 SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeReg.h        |  815 ---------
 SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordCommon.h |   45 +-
 SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.h    |  106 +-
 SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.c       | 1282 --------------
 SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c         |  408 ++---
 SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.c       | 1823 --------------------
 SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.c    |  757 ++------
 12 files changed, 355 insertions(+), 5642 deletions(-)

diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordDxe.inf b/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordDxe.inf
index 11e58b95cd..2e343a4707 100644
--- a/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordDxe.inf
+++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordDxe.inf
@@ -4,7 +4,7 @@
 #  This module is used to Management the Opal feature
 #  for Opal supported devices.
 #
-# Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
 # This program and the accompanying materials
 # are licensed and made available under the terms and conditions of the BSD License
 # which accompanies this distribution. The full text of the license may be found at
@@ -62,7 +62,6 @@
   TcgStorageOpalLib
   Tcg2PhysicalPresenceLib
   PciLib
-  S3BootScriptLib
   LockBoxLib
 
 [Protocols]
@@ -73,7 +72,8 @@
   gEfiBlockIoProtocolGuid                       ## CONSUMES
 
 [Guids]
-  gEfiEndOfDxeEventGroupGuid                    ## CONSUMES             ## Event
+  gEfiEndOfDxeEventGroupGuid                    ## CONSUMES ## Event
+  gS3StorageDeviceInitListGuid                  ## SOMETIMES_PRODUCES ## UNDEFINED
 
 [Pcd]
   gEfiSecurityPkgTokenSpaceGuid.PcdSkipOpalDxeUnlock  ## CONSUMES
diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.inf b/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.inf
index 482b7c25af..5abfc69e80 100644
--- a/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.inf
+++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.inf
@@ -1,7 +1,7 @@
 ## @file
 #  This is a Opal Password PEI driver.
 #
-# Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
 # This program and the accompanying materials
 # are licensed and made available under the terms and conditions of the BSD License
 # which accompanies this distribution. The full text of the license may be found at
@@ -29,11 +29,6 @@
   OpalPasswordPei.c
   OpalPasswordPei.h
   OpalPasswordCommon.h
-  OpalAhciMode.c
-  OpalAhciMode.h
-  OpalNvmeMode.c
-  OpalNvmeMode.h
-  OpalNvmeReg.h
 
 [Packages]
   MdePkg/MdePkg.dec
@@ -49,14 +44,13 @@
   BaseLib
   BaseMemoryLib
   MemoryAllocationLib
-  TimerLib
   LockBoxLib
   TcgStorageOpalLib
   Tcg2PhysicalPresenceLib
+  PeiServicesTablePointerLib
 
 [Ppis]
-  gEdkiiIoMmuPpiGuid                            ## SOMETIMES_CONSUMES
-  gEfiEndOfPeiSignalPpiGuid                     ## NOTIFY
+  gEdkiiPeiStorageSecurityCommandPpiGuid        ## NOTIFY
 
 [Depex]
   gEfiPeiMasterBootModePpiGuid
diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.h b/SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.h
deleted file mode 100644
index 2076b0411b..0000000000
--- a/SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.h
+++ /dev/null
@@ -1,412 +0,0 @@
-/** @file
-  Header file for AHCI mode of ATA host controller.
-
-Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution.  The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-
-#ifndef __OPAL_PASSWORD_AHCI_MODE_H__
-#define __OPAL_PASSWORD_AHCI_MODE_H__
-
-//
-// OPAL LIBRARY CALLBACKS
-//
-#define ATA_COMMAND_TRUSTED_RECEIVE            0x5C
-#define ATA_COMMAND_TRUSTED_SEND               0x5E
-
-//
-// ATA TRUSTED commands express transfer Length in 512 byte multiple
-//
-#define ATA_TRUSTED_TRANSFER_LENGTH_MULTIPLE   512
-#define ATA_DEVICE_LBA                         0x40    ///< Set for commands with LBA (rather than CHS) addresses
-
-
-#define EFI_AHCI_BAR_INDEX                     0x05
-
-#define EFI_AHCI_CAPABILITY_OFFSET             0x0000
-#define   EFI_AHCI_CAP_SAM                     BIT18
-#define EFI_AHCI_GHC_OFFSET                    0x0004
-#define   EFI_AHCI_GHC_RESET                   BIT0
-#define   EFI_AHCI_GHC_IE                      BIT1
-#define   EFI_AHCI_GHC_ENABLE                  BIT31
-#define EFI_AHCI_IS_OFFSET                     0x0008
-#define EFI_AHCI_PI_OFFSET                     0x000C
-
-typedef struct {
-  UINT32  Lower32;
-  UINT32  Upper32;
-} DATA_32;
-
-typedef union {
-  DATA_32   Uint32;
-  UINT64    Uint64;
-} DATA_64;
-
-//
-// Each PRDT entry can point to a memory block up to 4M byte
-//
-#define EFI_AHCI_MAX_DATA_PER_PRDT             0x400000
-
-#define EFI_AHCI_FIS_REGISTER_H2D              0x27      //Register FIS - Host to Device
-#define   EFI_AHCI_FIS_REGISTER_H2D_LENGTH     20
-#define EFI_AHCI_FIS_REGISTER_D2H              0x34      //Register FIS - Device to Host
-#define   EFI_AHCI_FIS_REGISTER_D2H_LENGTH     20
-#define EFI_AHCI_FIS_DMA_ACTIVATE              0x39      //DMA Activate FIS - Device to Host
-#define   EFI_AHCI_FIS_DMA_ACTIVATE_LENGTH     4
-#define EFI_AHCI_FIS_DMA_SETUP                 0x41      //DMA Setup FIS - Bi-directional
-#define   EFI_AHCI_FIS_DMA_SETUP_LENGTH        28
-#define EFI_AHCI_FIS_DATA                      0x46      //Data FIS - Bi-directional
-#define EFI_AHCI_FIS_BIST                      0x58      //BIST Activate FIS - Bi-directional
-#define   EFI_AHCI_FIS_BIST_LENGTH             12
-#define EFI_AHCI_FIS_PIO_SETUP                 0x5F      //PIO Setup FIS - Device to Host
-#define   EFI_AHCI_FIS_PIO_SETUP_LENGTH        20
-#define EFI_AHCI_FIS_SET_DEVICE                0xA1      //Set Device Bits FIS - Device to Host
-#define   EFI_AHCI_FIS_SET_DEVICE_LENGTH       8
-
-#define EFI_AHCI_D2H_FIS_OFFSET                0x40
-#define EFI_AHCI_DMA_FIS_OFFSET                0x00
-#define EFI_AHCI_PIO_FIS_OFFSET                0x20
-#define EFI_AHCI_SDB_FIS_OFFSET                0x58
-#define EFI_AHCI_FIS_TYPE_MASK                 0xFF
-#define EFI_AHCI_U_FIS_OFFSET                  0x60
-
-//
-// Port register
-//
-#define EFI_AHCI_PORT_START                    0x0100
-#define EFI_AHCI_PORT_REG_WIDTH                0x0080
-#define EFI_AHCI_PORT_CLB                      0x0000
-#define EFI_AHCI_PORT_CLBU                     0x0004
-#define EFI_AHCI_PORT_FB                       0x0008
-#define EFI_AHCI_PORT_FBU                      0x000C
-#define EFI_AHCI_PORT_IS                       0x0010
-#define   EFI_AHCI_PORT_IS_DHRS                BIT0
-#define   EFI_AHCI_PORT_IS_PSS                 BIT1
-#define   EFI_AHCI_PORT_IS_SSS                 BIT2
-#define   EFI_AHCI_PORT_IS_SDBS                BIT3
-#define   EFI_AHCI_PORT_IS_UFS                 BIT4
-#define   EFI_AHCI_PORT_IS_DPS                 BIT5
-#define   EFI_AHCI_PORT_IS_PCS                 BIT6
-#define   EFI_AHCI_PORT_IS_DIS                 BIT7
-#define   EFI_AHCI_PORT_IS_PRCS                BIT22
-#define   EFI_AHCI_PORT_IS_IPMS                BIT23
-#define   EFI_AHCI_PORT_IS_OFS                 BIT24
-#define   EFI_AHCI_PORT_IS_INFS                BIT26
-#define   EFI_AHCI_PORT_IS_IFS                 BIT27
-#define   EFI_AHCI_PORT_IS_HBDS                BIT28
-#define   EFI_AHCI_PORT_IS_HBFS                BIT29
-#define   EFI_AHCI_PORT_IS_TFES                BIT30
-#define   EFI_AHCI_PORT_IS_CPDS                BIT31
-#define   EFI_AHCI_PORT_IS_CLEAR               0xFFFFFFFF
-#define   EFI_AHCI_PORT_IS_FIS_CLEAR           0x0000000F
-
-#define EFI_AHCI_PORT_IE                       0x0014
-#define EFI_AHCI_PORT_CMD                      0x0018
-#define   EFI_AHCI_PORT_CMD_ST_MASK            0xFFFFFFFE
-#define   EFI_AHCI_PORT_CMD_ST                 BIT0
-#define   EFI_AHCI_PORT_CMD_SUD                BIT1
-#define   EFI_AHCI_PORT_CMD_POD                BIT2
-#define   EFI_AHCI_PORT_CMD_COL                BIT3
-#define   EFI_AHCI_PORT_CMD_CR                 BIT15
-#define   EFI_AHCI_PORT_CMD_FRE                BIT4
-#define   EFI_AHCI_PORT_CMD_FR                 BIT14
-#define   EFI_AHCI_PORT_CMD_MASK               ~(EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_FRE | EFI_AHCI_PORT_CMD_COL)
-#define   EFI_AHCI_PORT_CMD_PMA                BIT17
-#define   EFI_AHCI_PORT_CMD_HPCP               BIT18
-#define   EFI_AHCI_PORT_CMD_MPSP               BIT19
-#define   EFI_AHCI_PORT_CMD_CPD                BIT20
-#define   EFI_AHCI_PORT_CMD_ESP                BIT21
-#define   EFI_AHCI_PORT_CMD_ATAPI              BIT24
-#define   EFI_AHCI_PORT_CMD_DLAE               BIT25
-#define   EFI_AHCI_PORT_CMD_ALPE               BIT26
-#define   EFI_AHCI_PORT_CMD_ASP                BIT27
-#define   EFI_AHCI_PORT_CMD_ICC_MASK           (BIT28 | BIT29 | BIT30 | BIT31)
-#define   EFI_AHCI_PORT_CMD_ACTIVE             (1 << 28 )
-#define EFI_AHCI_PORT_TFD                      0x0020
-#define   EFI_AHCI_PORT_TFD_MASK               (BIT7 | BIT3 | BIT0)
-#define   EFI_AHCI_PORT_TFD_BSY                BIT7
-#define   EFI_AHCI_PORT_TFD_DRQ                BIT3
-#define   EFI_AHCI_PORT_TFD_ERR                BIT0
-#define   EFI_AHCI_PORT_TFD_ERR_MASK           0x00FF00
-#define EFI_AHCI_PORT_SIG                      0x0024
-#define EFI_AHCI_PORT_SSTS                     0x0028
-#define   EFI_AHCI_PORT_SSTS_DET_MASK          0x000F
-#define   EFI_AHCI_PORT_SSTS_DET               0x0001
-#define   EFI_AHCI_PORT_SSTS_DET_PCE           0x0003
-#define   EFI_AHCI_PORT_SSTS_SPD_MASK          0x00F0
-#define EFI_AHCI_PORT_SCTL                     0x002C
-#define   EFI_AHCI_PORT_SCTL_DET_MASK          0x000F
-#define   EFI_AHCI_PORT_SCTL_MASK              (~EFI_AHCI_PORT_SCTL_DET_MASK)
-#define   EFI_AHCI_PORT_SCTL_DET_INIT          0x0001
-#define   EFI_AHCI_PORT_SCTL_DET_PHYCOMM       0x0003
-#define   EFI_AHCI_PORT_SCTL_SPD_MASK          0x00F0
-#define   EFI_AHCI_PORT_SCTL_IPM_MASK          0x0F00
-#define   EFI_AHCI_PORT_SCTL_IPM_INIT          0x0300
-#define   EFI_AHCI_PORT_SCTL_IPM_PSD           0x0100
-#define   EFI_AHCI_PORT_SCTL_IPM_SSD           0x0200
-#define EFI_AHCI_PORT_SERR                     0x0030
-#define   EFI_AHCI_PORT_SERR_RDIE              BIT0
-#define   EFI_AHCI_PORT_SERR_RCE               BIT1
-#define   EFI_AHCI_PORT_SERR_TDIE              BIT8
-#define   EFI_AHCI_PORT_SERR_PCDIE             BIT9
-#define   EFI_AHCI_PORT_SERR_PE                BIT10
-#define   EFI_AHCI_PORT_SERR_IE                BIT11
-#define   EFI_AHCI_PORT_SERR_PRC               BIT16
-#define   EFI_AHCI_PORT_SERR_PIE               BIT17
-#define   EFI_AHCI_PORT_SERR_CW                BIT18
-#define   EFI_AHCI_PORT_SERR_BDE               BIT19
-#define   EFI_AHCI_PORT_SERR_DE                BIT20
-#define   EFI_AHCI_PORT_SERR_CRCE              BIT21
-#define   EFI_AHCI_PORT_SERR_HE                BIT22
-#define   EFI_AHCI_PORT_SERR_LSE               BIT23
-#define   EFI_AHCI_PORT_SERR_TSTE              BIT24
-#define   EFI_AHCI_PORT_SERR_UFT               BIT25
-#define   EFI_AHCI_PORT_SERR_EX                BIT26
-#define   EFI_AHCI_PORT_ERR_CLEAR              0xFFFFFFFF
-#define EFI_AHCI_PORT_SACT                     0x0034
-#define EFI_AHCI_PORT_CI                       0x0038
-#define EFI_AHCI_PORT_SNTF                     0x003C
-
-
-#pragma pack(1)
-//
-// Command List structure includes total 32 entries.
-// The entry Data structure is listed at the following.
-//
-typedef struct {
-  UINT32   AhciCmdCfl:5;      //Command FIS Length
-  UINT32   AhciCmdA:1;        //ATAPI
-  UINT32   AhciCmdW:1;        //Write
-  UINT32   AhciCmdP:1;        //Prefetchable
-  UINT32   AhciCmdR:1;        //Reset
-  UINT32   AhciCmdB:1;        //BIST
-  UINT32   AhciCmdC:1;        //Clear Busy upon R_OK
-  UINT32   AhciCmdRsvd:1;
-  UINT32   AhciCmdPmp:4;      //Port Multiplier Port
-  UINT32   AhciCmdPrdtl:16;   //Physical Region Descriptor Table Length
-  UINT32   AhciCmdPrdbc;      //Physical Region Descriptor Byte Count
-  UINT32   AhciCmdCtba;       //Command Table Descriptor Base Address
-  UINT32   AhciCmdCtbau;      //Command Table Descriptor Base Address Upper 32-BITs
-  UINT32   AhciCmdRsvd1[4];
-} EFI_AHCI_COMMAND_LIST;
-
-//
-// This is a software constructed FIS.
-// For Data transfer operations, this is the H2D Register FIS format as
-// specified in the Serial ATA Revision 2.6 specification.
-//
-typedef struct {
-  UINT8    AhciCFisType;
-  UINT8    AhciCFisPmNum:4;
-  UINT8    AhciCFisRsvd:1;
-  UINT8    AhciCFisRsvd1:1;
-  UINT8    AhciCFisRsvd2:1;
-  UINT8    AhciCFisCmdInd:1;
-  UINT8    AhciCFisCmd;
-  UINT8    AhciCFisFeature;
-  UINT8    AhciCFisSecNum;
-  UINT8    AhciCFisClyLow;
-  UINT8    AhciCFisClyHigh;
-  UINT8    AhciCFisDevHead;
-  UINT8    AhciCFisSecNumExp;
-  UINT8    AhciCFisClyLowExp;
-  UINT8    AhciCFisClyHighExp;
-  UINT8    AhciCFisFeatureExp;
-  UINT8    AhciCFisSecCount;
-  UINT8    AhciCFisSecCountExp;
-  UINT8    AhciCFisRsvd3;
-  UINT8    AhciCFisControl;
-  UINT8    AhciCFisRsvd4[4];
-  UINT8    AhciCFisRsvd5[44];
-} EFI_AHCI_COMMAND_FIS;
-
-//
-// ACMD: ATAPI command (12 or 16 bytes)
-//
-typedef struct {
-  UINT8    AtapiCmd[0x10];
-} EFI_AHCI_ATAPI_COMMAND;
-
-//
-// Physical Region Descriptor Table includes up to 65535 entries
-// The entry Data structure is listed at the following.
-// the actual entry number comes from the PRDTL field in the command
-// list entry for this command slot.
-//
-typedef struct {
-  UINT32   AhciPrdtDba;       //Data Base Address
-  UINT32   AhciPrdtDbau;      //Data Base Address Upper 32-BITs
-  UINT32   AhciPrdtRsvd;
-  UINT32   AhciPrdtDbc:22;    //Data Byte Count
-  UINT32   AhciPrdtRsvd1:9;
-  UINT32   AhciPrdtIoc:1;     //Interrupt on Completion
-} EFI_AHCI_COMMAND_PRDT;
-
-//
-// Command table Data strucute which is pointed to by the entry in the command list
-//
-typedef struct {
-  EFI_AHCI_COMMAND_FIS      CommandFis;       // A software constructed FIS.
-  EFI_AHCI_ATAPI_COMMAND    AtapiCmd;         // 12 or 16 bytes ATAPI cmd.
-  UINT8                     Reserved[0x30];
-  EFI_AHCI_COMMAND_PRDT     PrdtTable;    // The scatter/gather list for Data transfer
-} EFI_AHCI_COMMAND_TABLE;
-
-//
-// Received FIS structure
-//
-typedef struct {
-  UINT8    AhciDmaSetupFis[0x1C];         // Dma Setup Fis: offset 0x00
-  UINT8    AhciDmaSetupFisRsvd[0x04];
-  UINT8    AhciPioSetupFis[0x14];         // Pio Setup Fis: offset 0x20
-  UINT8    AhciPioSetupFisRsvd[0x0C];
-  UINT8    AhciD2HRegisterFis[0x14];      // D2H Register Fis: offset 0x40
-  UINT8    AhciD2HRegisterFisRsvd[0x04];
-  UINT64   AhciSetDeviceBitsFis;          // Set Device Bits Fix: offset 0x58
-  UINT8    AhciUnknownFis[0x40];          // Unkonwn Fis: offset 0x60
-  UINT8    AhciUnknownFisRsvd[0x60];
-} EFI_AHCI_RECEIVED_FIS;
-
-#pragma pack()
-
-typedef struct {
-  EFI_AHCI_RECEIVED_FIS     *AhciRFis;
-  VOID                      *AhciRFisMapping;
-  EFI_AHCI_COMMAND_LIST     *AhciCmdList;
-  VOID                      *AhciCmdListMapping;
-  EFI_AHCI_COMMAND_TABLE    *AhciCommandTable;
-  VOID                      *AhciCommandTableMapping;
-} EFI_AHCI_REGISTERS;
-
-typedef struct {
-  VOID                      *Buffer;
-  VOID                      *BufferMapping;
-  EFI_AHCI_REGISTERS        AhciRegisters;
-  UINT32                    AhciBar;
-} AHCI_CONTEXT;
-
-/**
-  Allocate transfer-related data struct which is used at AHCI mode.
-
-  @param[in, out] AhciContext   The pointer to the AHCI_CONTEXT.
-
-  @retval EFI_OUT_OF_RESOURCE   No enough resource.
-  @retval EFI_SUCCESS           Successful to allocate resource.
-
-**/
-EFI_STATUS
-EFIAPI
-AhciAllocateResource (
-  IN OUT AHCI_CONTEXT       *AhciContext
-  );
-
-/**
-  Free allocated transfer-related data struct which is used at AHCI mode.
-
-  @param[in, out] AhciContext   The pointer to the AHCI_CONTEXT.
-
-**/
-VOID
-EFIAPI
-AhciFreeResource (
-  IN OUT AHCI_CONTEXT       *AhciContext
-  );
-
-/**
-  Initialize ATA host controller at AHCI mode.
-
-  The function is designed to initialize ATA host controller.
-
-  @param[in]  AhciContext   The pointer to the AHCI_CONTEXT.
-  @param[in]  Port          The port number to do initialization.
-
-**/
-EFI_STATUS
-EFIAPI
-AhciModeInitialize (
-  IN AHCI_CONTEXT    *AhciContext,
-  IN UINT8           Port
-  );
-
-typedef struct _EFI_ATA_COMMAND_BLOCK {
-  UINT8 Reserved1[2];
-  UINT8 AtaCommand;
-  UINT8 AtaFeatures;
-  UINT8 AtaSectorNumber;
-  UINT8 AtaCylinderLow;
-  UINT8 AtaCylinderHigh;
-  UINT8 AtaDeviceHead;
-  UINT8 AtaSectorNumberExp;
-  UINT8 AtaCylinderLowExp;
-  UINT8 AtaCylinderHighExp;
-  UINT8 AtaFeaturesExp;
-  UINT8 AtaSectorCount;
-  UINT8 AtaSectorCountExp;
-  UINT8 Reserved2[6];
-} EFI_ATA_COMMAND_BLOCK;
-
-typedef struct _EFI_ATA_STATUS_BLOCK {
-  UINT8 Reserved1[2];
-  UINT8 AtaStatus;
-  UINT8 AtaError;
-  UINT8 AtaSectorNumber;
-  UINT8 AtaCylinderLow;
-  UINT8 AtaCylinderHigh;
-  UINT8 AtaDeviceHead;
-  UINT8 AtaSectorNumberExp;
-  UINT8 AtaCylinderLowExp;
-  UINT8 AtaCylinderHighExp;
-  UINT8 Reserved2;
-  UINT8 AtaSectorCount;
-  UINT8 AtaSectorCountExp;
-  UINT8 Reserved3[6];
-} EFI_ATA_STATUS_BLOCK;
-
-/**
-  Start a PIO Data transfer on specific port.
-
-  @param  AhciContext         The pointer to the AHCI_CONTEXT.
-  @param  Port                The number of port.
-  @param  PortMultiplier      The timeout Value of stop.
-  @param  AtapiCommand        The atapi command will be used for the transfer.
-  @param  AtapiCommandLength  The Length of the atapi command.
-  @param  Read                The transfer direction.
-  @param  AtaCommandBlock     The EFI_ATA_COMMAND_BLOCK Data.
-  @param  AtaStatusBlock      The EFI_ATA_STATUS_BLOCK Data.
-  @param  MemoryAddr          The pointer to the Data Buffer.
-  @param  DataCount           The Data count to be transferred.
-  @param  Timeout             The timeout Value of non Data transfer.
-
-  @retval EFI_DEVICE_ERROR    The PIO Data transfer abort with error occurs.
-  @retval EFI_TIMEOUT         The operation is time out.
-  @retval EFI_UNSUPPORTED     The device is not ready for transfer.
-  @retval EFI_SUCCESS         The PIO Data transfer executes successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-AhciPioTransfer (
-  IN     AHCI_CONTEXT               *AhciContext,
-  IN     UINT8                      Port,
-  IN     UINT8                      PortMultiplier,
-  IN     EFI_AHCI_ATAPI_COMMAND     *AtapiCommand OPTIONAL,
-  IN     UINT8                      AtapiCommandLength,
-  IN     BOOLEAN                    Read,
-  IN     EFI_ATA_COMMAND_BLOCK      *AtaCommandBlock,
-  IN OUT EFI_ATA_STATUS_BLOCK       *AtaStatusBlock,
-  IN OUT VOID                       *MemoryAddr,
-  IN     UINT32                     DataCount,
-  IN     UINT64                     Timeout
-  );
-
-
-#endif
-
diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.h b/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.h
index 2bca770620..1baa483e72 100644
--- a/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.h
+++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.h
@@ -1,7 +1,7 @@
 /** @file
   Values defined and used by the Opal UEFI Driver.
 
-Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
 This program and the accompanying materials
 are licensed and made available under the terms and conditions of the BSD License
 which accompanies this distribution.  The full text of the license may be found at
@@ -28,6 +28,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Protocol/StorageSecurityCommand.h>
 
 #include <Guid/EventGroup.h>
+#include <Guid/S3StorageDeviceInitList.h>
 
 #include <Library/UefiLib.h>
 #include <Library/UefiBootServicesTableLib.h>
@@ -42,7 +43,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Library/HiiLib.h>
 #include <Library/UefiHiiServicesLib.h>
 #include <Library/PciLib.h>
-#include <Library/S3BootScriptLib.h>
 #include <Library/LockBoxLib.h>
 #include <Library/TcgStorageOpalLib.h>
 #include <Library/Tcg2PhysicalPresenceLib.h>
diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.h b/SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.h
deleted file mode 100644
index bd2bd5239d..0000000000
--- a/SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.h
+++ /dev/null
@@ -1,327 +0,0 @@
-/** @file
-  Header file for NVMe function definitions
-
-Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution.  The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-#ifndef __OPAL_PASSWORD_NVME_MODE_H__
-#define __OPAL_PASSWORD_NVME_MODE_H__
-
-
-#include "OpalNvmeReg.h"
-
-#define NVME_MAX_SECTORS            0x10000
-//
-// QueueId
-//
-#define NVME_ADMIN_QUEUE            0x00
-#define NVME_IO_QUEUE               0x01
-
-typedef struct {
-  UINT8                             Opcode;
-  UINT8                             FusedOperation;
-    #define NORMAL_CMD              0x00
-    #define FUSED_FIRST_CMD         0x01
-    #define FUSED_SECOND_CMD        0x02
-  UINT16                            Cid;
-} NVME_CDW0;
-
-typedef struct {
-  NVME_CDW0                         Cdw0;
-  UINT8                             Flags;
-    #define CDW10_VALID             0x01
-    #define CDW11_VALID             0x02
-    #define CDW12_VALID             0x04
-    #define CDW13_VALID             0x08
-    #define CDW14_VALID             0x10
-    #define CDW15_VALID             0x20
-  UINT32                            Nsid;
-  UINT32                            Cdw10;
-  UINT32                            Cdw11;
-  UINT32                            Cdw12;
-  UINT32                            Cdw13;
-  UINT32                            Cdw14;
-  UINT32                            Cdw15;
-} NVM_EXPRESS_COMMAND;
-
-typedef struct {
-  UINT32                            Cdw0;
-  UINT32                            Cdw1;
-  UINT32                            Cdw2;
-  UINT32                            Cdw3;
-} NVM_EXPRESS_RESPONSE;
-
-typedef struct {
-  UINT64                            CommandTimeout;
-  UINT64                            TransferBuffer;
-  UINT32                            TransferLength;
-  UINT64                            MetadataBuffer;
-  UINT32                            MetadataLength;
-  UINT8                             QueueId;
-  NVM_EXPRESS_COMMAND               *NvmeCmd;
-  NVM_EXPRESS_RESPONSE              *NvmeResponse;
-} NVM_EXPRESS_PASS_THRU_COMMAND_PACKET;
-
-
-#pragma pack(1)
-
-// Internal fields
-typedef enum {
-  NvmeStatusUnknown,
-  NvmeStatusInit,
-  NvmeStatusInuse,
-  NvmeStatusMax,
-} NVME_STATUS;
-
-typedef struct {
-  UINT32                            Nbar;
-  VOID                              *BaseMem;
-  VOID                              *BaseMemMapping;
-  BOOLEAN                           PollCancellation;
-  UINT16                            NvmeInitWaitTime;
-
-  NVME_STATUS                       State;
-  UINT8                             BusID;
-  UINT8                             DeviceID;
-  UINT8                             FuncID;
-  UINTN                             PciBase;
-
-  UINT32                            Nsid;
-  UINT64                            Nsuuid;
-  UINT32                            BlockSize;
-  EFI_LBA                           LastBlock;
-
-  //
-  // Pointers to 4kB aligned submission & completion queues.
-  //
-  NVME_SQ                           *SqBuffer[NVME_MAX_IO_QUEUES];
-  NVME_CQ                           *CqBuffer[NVME_MAX_IO_QUEUES];
-  UINT16                            Cid[NVME_MAX_IO_QUEUES];
-
-  //
-  // Submission and completion queue indices.
-  //
-  NVME_SQTDBL                       SqTdbl[NVME_MAX_IO_QUEUES];
-  NVME_CQHDBL                       CqHdbl[NVME_MAX_IO_QUEUES];
-  UINT8                             Pt[NVME_MAX_IO_QUEUES];
-
-  UINTN                             SqeCount[NVME_MAX_IO_QUEUES];
-
-  //
-  // Nvme controller capabilities
-  //
-  NVME_CAP                          Cap;
-
-  //
-  // pointer to identify controller Data
-  //
-  NVME_ADMIN_CONTROLLER_DATA        *ControllerData;
-  NVME_ADMIN_NAMESPACE_DATA         *NamespaceData;
-} NVME_CONTEXT;
-
-#pragma pack()
-
-/**
-  Transfer MMIO Data to memory.
-
-  @param[in,out] MemBuffer - Destination: Memory address
-  @param[in] MmioAddr      - Source: MMIO address
-  @param[in] Size          - Size for read
-
-  @retval EFI_SUCCESS - MMIO read sucessfully
-**/
-EFI_STATUS
-NvmeMmioRead (
-  IN OUT VOID *MemBuffer,
-  IN     UINTN MmioAddr,
-  IN     UINTN Size
-  );
-
-/**
-  Transfer memory Data to MMIO.
-
-  @param[in,out] MmioAddr - Destination: MMIO address
-  @param[in] MemBuffer    - Source: Memory address
-  @param[in] Size         - Size for write
-
-  @retval EFI_SUCCESS - MMIO write sucessfully
-**/
-EFI_STATUS
-NvmeMmioWrite (
-  IN OUT UINTN MmioAddr,
-  IN     VOID *MemBuffer,
-  IN     UINTN Size
-  );
-
-/**
-  Transfer memory data to MMIO.
-
-  @param[in,out] MmioAddr - Destination: MMIO address
-  @param[in] MemBuffer    - Source: Memory address
-  @param[in] Size         - Size for write
-
-  @retval EFI_SUCCESS - MMIO write sucessfully
-**/
-EFI_STATUS
-OpalPciWrite (
-  IN OUT UINTN MmioAddr,
-  IN     VOID *MemBuffer,
-  IN     UINTN Size
-  );
-
-/**
-  Transfer MMIO data to memory.
-
-  @param[in,out] MemBuffer - Destination: Memory address
-  @param[in] MmioAddr      - Source: MMIO address
-  @param[in] Size          - Size for read
-
-  @retval EFI_SUCCESS - MMIO read sucessfully
-**/
-EFI_STATUS
-OpalPciRead (
-  IN OUT VOID *MemBuffer,
-  IN     UINTN MmioAddr,
-  IN     UINTN Size
-  );
-
-/**
-  Allocate transfer-related Data struct which is used at Nvme.
-
-  @param[in, out] Nvme          The pointer to the NVME_CONTEXT Data structure.
-
-  @retval EFI_OUT_OF_RESOURCE   No enough resource.
-  @retval EFI_SUCCESS           Successful to allocate resource.
-
-**/
-EFI_STATUS
-EFIAPI
-NvmeAllocateResource (
-  IN OUT NVME_CONTEXT       *Nvme
-  );
-
-/**
-  Free allocated transfer-related Data struct which is used at NVMe.
-
-  @param[in, out] Nvme          The pointer to the NVME_CONTEXT Data structure.
-
-**/
-VOID
-EFIAPI
-NvmeFreeResource (
-  IN OUT NVME_CONTEXT       *Nvme
-  );
-
-/**
-  Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function supports
-  both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the nonblocking
-  I/O functionality is optional.
-
-  @param[in] Nvme                   - The pointer to the NVME_CONTEXT Data structure.
-  @param[in] NamespaceId            - Is a 32 bit Namespace ID to which the Express HCI command packet will be sent.
-                                      A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in the namespace
-                                      ID specifies that the command packet should be sent to all valid namespaces.
-  @param[in] NamespaceUuid          - Is a 64 bit Namespace UUID to which the Express HCI command packet will be sent.
-                                      A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in the namespace
-                                      UUID specifies that the command packet should be sent to all valid namespaces.
-  @param[in,out] Packet             - A pointer to the NVM Express HCI Command Packet to send to the NVMe namespace specified
-                                      by NamespaceId.
-
-  @retval EFI_SUCCESS               - The NVM Express Command Packet was sent by the host. TransferLength bytes were transferred
-                                      to, or from DataBuffer.
-  @retval EFI_NOT_READY             - The NVM Express Command Packet could not be sent because the controller is not ready. The caller
-                                      may retry again later.
-  @retval EFI_DEVICE_ERROR          - A device error occurred while attempting to send the NVM Express Command Packet.
-  @retval EFI_INVALID_PARAMETER     - Namespace, or the contents of NVM_EXPRESS_PASS_THRU_COMMAND_PACKET are invalid. The NVM
-                                      Express Command Packet was not sent, so no additional status information is available.
-  @retval EFI_UNSUPPORTED           - The command described by the NVM Express Command Packet is not supported by the host adapter.
-                                      The NVM Express Command Packet was not sent, so no additional status information is available.
-  @retval EFI_TIMEOUT               - A timeout occurred while waiting for the NVM Express Command Packet to execute.
-
-**/
-EFI_STATUS
-NvmePassThru (
-  IN     NVME_CONTEXT                         *Nvme,
-  IN     UINT32                               NamespaceId,
-  IN     UINT64                               NamespaceUuid,
-  IN OUT NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet
-  );
-
-/**
-  Waits until all NVME commands completed.
-
-  @param[in] Nvme                   - The pointer to the NVME_CONTEXT Data structure.
-  @param[in] Qid                    - Queue index
-
-  @retval EFI_SUCCESS               - All NVME commands have completed
-  @retval EFI_TIMEOUT               - Timeout occured
-  @retval EFI_NOT_READY             - Not all NVME commands have completed
-  @retval others                    - Error occurred on device side.
-**/
-EFI_STATUS
-NvmeWaitAllComplete (
-  IN NVME_CONTEXT       *Nvme,
-  IN UINT8              Qid
-  );
-
-/**
-  Initialize the Nvm Express controller.
-
-  @param[in] Nvme                   - The pointer to the NVME_CONTEXT Data structure.
-
-  @retval EFI_SUCCESS               - The NVM Express Controller is initialized successfully.
-  @retval Others                    - A device error occurred while initializing the controller.
-
-**/
-EFI_STATUS
-NvmeControllerInit (
-  IN NVME_CONTEXT       *Nvme
-  );
-
-/**
-  Un-initialize the Nvm Express controller.
-
-  @param[in] Nvme                   - The pointer to the NVME_CONTEXT Data structure.
-
-  @retval EFI_SUCCESS               - The NVM Express Controller is un-initialized successfully.
-  @retval Others                    - A device error occurred while un-initializing the controller.
-
-**/
-EFI_STATUS
-NvmeControllerExit (
-  IN NVME_CONTEXT       *Nvme
-  );
-
-/**
-  Security send and receive commands.
-
-  @param[in]     Nvme                   - The pointer to the NVME_CONTEXT Data structure.
-  @param[in]     SendCommand            - The flag to indicate the command type, TRUE for Send command and FALSE for receive command
-  @param[in]     SecurityProtocol       - Security Protocol
-  @param[in]     SpSpecific             - Security Protocol Specific
-  @param[in]     TransferLength         - Transfer Length of Buffer (in bytes) - always a multiple of 512
-  @param[in,out] TransferBuffer         - Address of Data to transfer
-
-  @return EFI_SUCCESS               - Successfully create io submission queue.
-  @return others                    - Fail to send/receive commands.
-
-**/
-EFI_STATUS
-NvmeSecuritySendReceive (
-  IN NVME_CONTEXT                          *Nvme,
-  IN BOOLEAN                               SendCommand,
-  IN UINT8                                 SecurityProtocol,
-  IN UINT16                                SpSpecific,
-  IN UINTN                                 TransferLength,
-  IN OUT VOID                              *TransferBuffer
-  );
-
-#endif
diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeReg.h b/SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeReg.h
deleted file mode 100644
index 03376b9e6c..0000000000
--- a/SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeReg.h
+++ /dev/null
@@ -1,815 +0,0 @@
-/** @file
-  Header file for Registers and Structure definitions
-
-Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution.  The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-#ifndef __OPAL_PASSWORD_NVME_REG_H__
-#define __OPAL_PASSWORD_NVME_REG_H__
-
-//
-// PCI Header for PCIe root port configuration
-//
-#define NVME_PCIE_PCICMD                         0x04
-#define NVME_PCIE_BNUM                           0x18
-#define NVME_PCIE_SEC_BNUM                       0x19
-#define NVME_PCIE_IOBL                           0x1C
-#define NVME_PCIE_MBL                            0x20
-#define NVME_PCIE_PMBL                           0x24
-#define NVME_PCIE_PMBU32                         0x28
-#define NVME_PCIE_PMLU32                         0x2C
-#define NVME_PCIE_INTR                           0x3C
-
-//
-// NVMe related definitions
-//
-#define PCI_CLASS_MASS_STORAGE_NVM                0x08  // mass storage sub-class non-volatile memory.
-#define PCI_IF_NVMHCI                             0x02  // mass storage programming interface NVMHCI.
-
-#define NVME_ASQ_SIZE                                    1     // Number of admin submission queue entries, which is 0-based
-#define NVME_ACQ_SIZE                                    1     // Number of admin completion queue entries, which is 0-based
-
-#define NVME_CSQ_SIZE                                    63     // Number of I/O submission queue entries, which is 0-based
-#define NVME_CCQ_SIZE                                    63     // Number of I/O completion queue entries, which is 0-based
-
-#define NVME_MAX_IO_QUEUES                               2     // Number of I/O queues supported by the driver, 1 for AQ, 1 for CQ
-
-#define NVME_CSQ_DEPTH                                   (NVME_CSQ_SIZE+1)
-#define NVME_CCQ_DEPTH                                   (NVME_CCQ_SIZE+1)
-#define NVME_PRP_SIZE                                    (4)    // Pages of PRP list
-
-#define NVME_CONTROLLER_ID                               0
-
-//
-// Time out Value for Nvme transaction execution
-//
-#define NVME_GENERIC_TIMEOUT                             5000000   ///< us
-#define NVME_CMD_WAIT                                    100       ///< us
-#define NVME_CMD_TIMEOUT                                 20000000  ///< us
-
-
-
-#define NVME_MEM_MAX_SIZE \
-  (( \
-  1                                         /* Controller Data */ +  \
-  1                                         /* Identify Data */   +  \
-  1                                         /* ASQ */             +  \
-  1                                         /* ACQ */             +  \
-  1                                         /* SQs */             +  \
-  1                                         /* CQs */             +  \
-  NVME_PRP_SIZE * NVME_CSQ_DEPTH            /* PRPs */            +  \
-  1                                         /* SECURITY */           \
-  ) * EFI_PAGE_SIZE)
-
-
-//
-// controller register offsets
-//
-#define NVME_CAP_OFFSET          0x0000  // Controller Capabilities
-#define NVME_VER_OFFSET          0x0008  // Version
-#define NVME_INTMS_OFFSET        0x000c  // Interrupt Mask Set
-#define NVME_INTMC_OFFSET        0x0010  // Interrupt Mask Clear
-#define NVME_CC_OFFSET           0x0014  // Controller Configuration
-#define NVME_CSTS_OFFSET         0x001c  // Controller Status
-#define NVME_AQA_OFFSET          0x0024  // Admin Queue Attributes
-#define NVME_ASQ_OFFSET          0x0028  // Admin Submission Queue Base Address
-#define NVME_ACQ_OFFSET          0x0030  // Admin Completion Queue Base Address
-#define NVME_SQ0_OFFSET          0x1000  // Submission Queue 0 (admin) Tail Doorbell
-#define NVME_CQ0_OFFSET          0x1004  // Completion Queue 0 (admin) Head Doorbell
-
-//
-// These register offsets are defined as 0x1000 + (N * (4 << CAP.DSTRD))
-// Get the doorbell stride bit shift Value from the controller capabilities.
-//
-#define NVME_SQTDBL_OFFSET(QID, DSTRD)    0x1000 + ((2 * (QID)) * (4 << (DSTRD)))       // Submission Queue y (NVM) Tail Doorbell
-#define NVME_CQHDBL_OFFSET(QID, DSTRD)    0x1000 + (((2 * (QID)) + 1) * (4 << (DSTRD))) // Completion Queue y (NVM) Head Doorbell
-
-
-#pragma pack(1)
-
-//
-// 3.1.1 Offset 00h: CAP - Controller Capabilities
-//
-typedef struct {
-  UINT16 Mqes;      // Maximum Queue Entries Supported
-  UINT8  Cqr:1;     // Contiguous Queues Required
-  UINT8  Ams:2;     // Arbitration Mechanism Supported
-  UINT8  Rsvd1:5;
-  UINT8  To;        // Timeout
-  UINT16 Dstrd:4;
-  UINT16 Rsvd2:1;
-  UINT16 Css:4;     // Command Sets Supported
-  UINT16 Rsvd3:7;
-  UINT8  Mpsmin:4;
-  UINT8  Mpsmax:4;
-  UINT8  Rsvd4;
-} NVME_CAP;
-
-//
-// 3.1.2 Offset 08h: VS - Version
-//
-typedef struct {
-  UINT16 Mnr;       // Minor version number
-  UINT16 Mjr;       // Major version number
-} NVME_VER;
-
-//
-// 3.1.5 Offset 14h: CC - Controller Configuration
-//
-typedef struct {
-  UINT16 En:1;       // Enable
-  UINT16 Rsvd1:3;
-  UINT16 Css:3;      // Command Set Selected
-  UINT16 Mps:4;      // Memory Page Size
-  UINT16 Ams:3;      // Arbitration Mechanism Selected
-  UINT16 Shn:2;      // Shutdown Notification
-  UINT8  Iosqes:4;   // I/O Submission Queue Entry Size
-  UINT8  Iocqes:4;   // I/O Completion Queue Entry Size
-  UINT8  Rsvd2;
-} NVME_CC;
-
-//
-// 3.1.6 Offset 1Ch: CSTS - Controller Status
-//
-typedef struct {
-  UINT32 Rdy:1;      // Ready
-  UINT32 Cfs:1;      // Controller Fatal Status
-  UINT32 Shst:2;     // Shutdown Status
-  UINT32 Nssro:1;    // NVM Subsystem Reset Occurred
-  UINT32 Rsvd1:27;
-} NVME_CSTS;
-
-//
-// 3.1.8 Offset 24h: AQA - Admin Queue Attributes
-//
-typedef struct {
-  UINT16 Asqs:12;    // Submission Queue Size
-  UINT16 Rsvd1:4;
-  UINT16 Acqs:12;    // Completion Queue Size
-  UINT16 Rsvd2:4;
-} NVME_AQA;
-
-//
-// 3.1.9 Offset 28h: ASQ - Admin Submission Queue Base Address
-//
-#define NVME_ASQ      UINT64
-
-//
-// 3.1.10 Offset 30h: ACQ - Admin Completion Queue Base Address
-//
-#define NVME_ACQ      UINT64
-
-//
-// 3.1.11 Offset (1000h + ((2y) * (4 << CAP.DSTRD))): SQyTDBL - Submission Queue y Tail Doorbell
-//
-typedef struct {
-  UINT16 Sqt;
-  UINT16 Rsvd1;
-} NVME_SQTDBL;
-
-//
-// 3.1.12 Offset (1000h + ((2y + 1) * (4 << CAP.DSTRD))): CQyHDBL - Completion Queue y Head Doorbell
-//
-typedef struct {
-  UINT16 Cqh;
-  UINT16 Rsvd1;
-} NVME_CQHDBL;
-
-//
-// NVM command set structures
-//
-// Read Command
-//
-typedef struct {
-  //
-  // CDW 10, 11
-  //
-  UINT64 Slba;                /* Starting Sector Address */
-  //
-  // CDW 12
-  //
-  UINT16 Nlb;                 /* Number of Sectors */
-  UINT16 Rsvd1:10;
-  UINT16 Prinfo:4;            /* Protection Info Check */
-  UINT16 Fua:1;               /* Force Unit Access */
-  UINT16 Lr:1;                /* Limited Retry */
-  //
-  // CDW 13
-  //
-  UINT32 Af:4;                /* Access Frequency */
-  UINT32 Al:2;                /* Access Latency */
-  UINT32 Sr:1;                /* Sequential Request */
-  UINT32 In:1;                /* Incompressible */
-  UINT32 Rsvd2:24;
-  //
-  // CDW 14
-  //
-  UINT32 Eilbrt;              /* Expected Initial Logical Block Reference Tag */
-  //
-  // CDW 15
-  //
-  UINT16 Elbat;               /* Expected Logical Block Application Tag */
-  UINT16 Elbatm;              /* Expected Logical Block Application Tag Mask */
-} NVME_READ;
-
-//
-// Write Command
-//
-typedef struct {
-  //
-  // CDW 10, 11
-  //
-  UINT64 Slba;                /* Starting Sector Address */
-  //
-  // CDW 12
-  //
-  UINT16 Nlb;                 /* Number of Sectors */
-  UINT16 Rsvd1:10;
-  UINT16 Prinfo:4;            /* Protection Info Check */
-  UINT16 Fua:1;               /* Force Unit Access */
-  UINT16 Lr:1;                /* Limited Retry */
-  //
-  // CDW 13
-  //
-  UINT32 Af:4;                /* Access Frequency */
-  UINT32 Al:2;                /* Access Latency */
-  UINT32 Sr:1;                /* Sequential Request */
-  UINT32 In:1;                /* Incompressible */
-  UINT32 Rsvd2:24;
-  //
-  // CDW 14
-  //
-  UINT32 Ilbrt;               /* Initial Logical Block Reference Tag */
-  //
-  // CDW 15
-  //
-  UINT16 Lbat;                /* Logical Block Application Tag */
-  UINT16 Lbatm;               /* Logical Block Application Tag Mask */
-} NVME_WRITE;
-
-//
-// Flush
-//
-typedef struct {
-  //
-  // CDW 10
-  //
-  UINT32 Flush;               /* Flush */
-} NVME_FLUSH;
-
-//
-// Write Uncorrectable command
-//
-typedef struct {
-  //
-  // CDW 10, 11
-  //
-  UINT64 Slba;                /* Starting LBA */
-  //
-  // CDW 12
-  //
-  UINT32 Nlb:16;              /* Number of  Logical Blocks */
-  UINT32 Rsvd1:16;
-} NVME_WRITE_UNCORRECTABLE;
-
-//
-// Write Zeroes command
-//
-typedef struct {
-  //
-  // CDW 10, 11
-  //
-  UINT64 Slba;                /* Starting LBA */
-  //
-  // CDW 12
-  //
-  UINT16 Nlb;                 /* Number of Logical Blocks */
-  UINT16 Rsvd1:10;
-  UINT16 Prinfo:4;            /* Protection Info Check */
-  UINT16 Fua:1;               /* Force Unit Access */
-  UINT16 Lr:1;                /* Limited Retry */
-  //
-  // CDW 13
-  //
-  UINT32 Rsvd2;
-  //
-  // CDW 14
-  //
-  UINT32 Ilbrt;               /* Initial Logical Block Reference Tag */
-  //
-  // CDW 15
-  //
-  UINT16 Lbat;                /* Logical Block Application Tag */
-  UINT16 Lbatm;               /* Logical Block Application Tag Mask */
-} NVME_WRITE_ZEROES;
-
-//
-// Compare command
-//
-typedef struct {
-  //
-  // CDW 10, 11
-  //
-  UINT64 Slba;                /* Starting LBA */
-  //
-  // CDW 12
-  //
-  UINT16 Nlb;                 /* Number of Logical Blocks */
-  UINT16 Rsvd1:10;
-  UINT16 Prinfo:4;            /* Protection Info Check */
-  UINT16 Fua:1;               /* Force Unit Access */
-  UINT16 Lr:1;                /* Limited Retry */
-  //
-  // CDW 13
-  //
-  UINT32 Rsvd2;
-  //
-  // CDW 14
-  //
-  UINT32 Eilbrt;              /* Expected Initial Logical Block Reference Tag */
-  //
-  // CDW 15
-  //
-  UINT16 Elbat;               /* Expected Logical Block Application Tag */
-  UINT16 Elbatm;              /* Expected Logical Block Application Tag Mask */
-} NVME_COMPARE;
-
-typedef union {
-  NVME_READ                   Read;
-  NVME_WRITE                  Write;
-  NVME_FLUSH                  Flush;
-  NVME_WRITE_UNCORRECTABLE    WriteUncorrectable;
-  NVME_WRITE_ZEROES           WriteZeros;
-  NVME_COMPARE                Compare;
-} NVME_CMD;
-
-typedef struct {
-  UINT16 Mp;                /* Maximum Power */
-  UINT8  Rsvd1;             /* Reserved as of Nvm Express 1.1 Spec */
-  UINT8  Mps:1;             /* Max Power Scale */
-  UINT8  Nops:1;            /* Non-Operational State */
-  UINT8  Rsvd2:6;           /* Reserved as of Nvm Express 1.1 Spec */
-  UINT32 Enlat;             /* Entry Latency */
-  UINT32 Exlat;             /* Exit Latency */
-  UINT8  Rrt:5;             /* Relative Read Throughput */
-  UINT8  Rsvd3:3;           /* Reserved as of Nvm Express 1.1 Spec */
-  UINT8  Rrl:5;             /* Relative Read Leatency */
-  UINT8  Rsvd4:3;           /* Reserved as of Nvm Express 1.1 Spec */
-  UINT8  Rwt:5;             /* Relative Write Throughput */
-  UINT8  Rsvd5:3;           /* Reserved as of Nvm Express 1.1 Spec */
-  UINT8  Rwl:5;             /* Relative Write Leatency */
-  UINT8  Rsvd6:3;           /* Reserved as of Nvm Express 1.1 Spec */
-  UINT8  Rsvd7[16];         /* Reserved as of Nvm Express 1.1 Spec */
-} NVME_PSDESCRIPTOR;
-
-//
-//  Identify Controller Data
-//
-typedef struct {
-  //
-  // Controller Capabilities and Features 0-255
-  //
-  UINT16 Vid;                 /* PCI Vendor ID */
-  UINT16 Ssvid;               /* PCI sub-system vendor ID */
-  UINT8  Sn[20];              /* Produce serial number */
-
-  UINT8  Mn[40];              /* Proeduct model number */
-  UINT8  Fr[8];               /* Firmware Revision */
-  UINT8  Rab;                 /* Recommended Arbitration Burst */
-  UINT8  Ieee_oiu[3];         /* Organization Unique Identifier */
-  UINT8  Cmic;                /* Multi-interface Capabilities */
-  UINT8  Mdts;                /* Maximum Data Transfer Size */
-  UINT8  Cntlid[2];           /* Controller ID */
-  UINT8  Rsvd1[176];          /* Reserved as of Nvm Express 1.1 Spec */
-  //
-  // Admin Command Set Attributes
-  //
-  UINT16 Oacs;                /* Optional Admin Command Support */
-  UINT8  Acl;                 /* Abort Command Limit */
-  UINT8  Aerl;                /* Async Event Request Limit */
-  UINT8  Frmw;                /* Firmware updates */
-  UINT8  Lpa;                 /* Log Page Attributes */
-  UINT8  Elpe;                /* Error Log Page Entries */
-  UINT8  Npss;                /* Number of Power States Support */
-  UINT8  Avscc;               /* Admin Vendor Specific Command Configuration */
-  UINT8  Apsta;               /* Autonomous Power State Transition Attributes */
-  UINT8  Rsvd2[246];          /* Reserved as of Nvm Express 1.1 Spec */
-  //
-  // NVM Command Set Attributes
-  //
-  UINT8  Sqes;                /* Submission Queue Entry Size */
-  UINT8  Cqes;                /* Completion Queue Entry Size */
-  UINT16 Rsvd3;               /* Reserved as of Nvm Express 1.1 Spec */
-  UINT32 Nn;                  /* Number of Namespaces */
-  UINT16 Oncs;                /* Optional NVM Command Support */
-  UINT16 Fuses;               /* Fused Operation Support */
-  UINT8  Fna;                 /* Format NVM Attributes */
-  UINT8  Vwc;                 /* Volatile Write Cache */
-  UINT16 Awun;                /* Atomic Write Unit Normal */
-  UINT16 Awupf;               /* Atomic Write Unit Power Fail */
-  UINT8  Nvscc;               /* NVM Vendor Specific Command Configuration */
-  UINT8  Rsvd4;               /* Reserved as of Nvm Express 1.1 Spec */
-  UINT16 Acwu;                /* Atomic Compare & Write Unit */
-  UINT16 Rsvd5;               /* Reserved as of Nvm Express 1.1 Spec */
-  UINT32 Sgls;                /* SGL Support  */
-  UINT8  Rsvd6[164];          /* Reserved as of Nvm Express 1.1 Spec */
-  //
-  // I/O Command set Attributes
-  //
-  UINT8 Rsvd7[1344];          /* Reserved as of Nvm Express 1.1 Spec */
-  //
-  // Power State Descriptors
-  //
-  NVME_PSDESCRIPTOR PsDescriptor[32];
-
-  UINT8  VendorData[1024];    /* Vendor specific Data */
-} NVME_ADMIN_CONTROLLER_DATA;
-
-typedef struct {
-  UINT16        Security  : 1;    /* supports security send/receive commands */
-  UINT16        Format    : 1;    /* supports format nvm command */
-  UINT16        Firmware  : 1;    /* supports firmware activate/download commands */
-  UINT16        Oacs_rsvd : 13;
- } OACS; // optional admin command support: NVME_ADMIN_CONTROLLER_DATA.Oacs
-
-typedef struct {
-  UINT16 Ms;                /* Metadata Size */
-  UINT8  Lbads;             /* LBA Data Size */
-  UINT8  Rp:2;              /* Relative Performance */
-    #define LBAF_RP_BEST      00b
-    #define LBAF_RP_BETTER    01b
-    #define LBAF_RP_GOOD      10b
-    #define LBAF_RP_DEGRADED  11b
-  UINT8  Rsvd1:6;           /* Reserved as of Nvm Express 1.1 Spec */
-} NVME_LBAFORMAT;
-
-//
-// Identify Namespace Data
-//
-typedef struct {
-  //
-  // NVM Command Set Specific
-  //
-  UINT64 Nsze;                /* Namespace Size (total number of blocks in formatted namespace) */
-  UINT64 Ncap;                /* Namespace Capacity (max number of logical blocks) */
-  UINT64 Nuse;                /* Namespace Utilization */
-  UINT8  Nsfeat;              /* Namespace Features */
-  UINT8  Nlbaf;               /* Number of LBA Formats */
-  UINT8  Flbas;               /* Formatted LBA Size */
-  UINT8  Mc;                  /* Metadata Capabilities */
-  UINT8  Dpc;                 /* End-to-end Data Protection capabilities */
-  UINT8  Dps;                 /* End-to-end Data Protection Type Settings */
-  UINT8  Nmic;                /* Namespace Multi-path I/O and Namespace Sharing Capabilities */
-  UINT8  Rescap;              /* Reservation Capabilities */
-  UINT8  Rsvd1[88];           /* Reserved as of Nvm Express 1.1 Spec */
-  UINT64 Eui64;               /* IEEE Extended Unique Identifier */
-  //
-  // LBA Format
-  //
-  NVME_LBAFORMAT LbaFormat[16];
-
-  UINT8 Rsvd2[192];           /* Reserved as of Nvm Express 1.1 Spec */
-  UINT8 VendorData[3712];     /* Vendor specific Data */
-} NVME_ADMIN_NAMESPACE_DATA;
-
-//
-// NvmExpress Admin Identify Cmd
-//
-typedef struct {
-  //
-  // CDW 10
-  //
-  UINT32 Cns:2;
-  UINT32 Rsvd1:30;
-} NVME_ADMIN_IDENTIFY;
-
-//
-// NvmExpress Admin Create I/O Completion Queue
-//
-typedef struct {
-  //
-  // CDW 10
-  //
-  UINT32 Qid:16;              /* Queue Identifier */
-  UINT32 Qsize:16;            /* Queue Size */
-
-  //
-  // CDW 11
-  //
-  UINT32 Pc:1;                /* Physically Contiguous */
-  UINT32 Ien:1;               /* Interrupts Enabled */
-  UINT32 Rsvd1:14;            /* reserved as of Nvm Express 1.1 Spec */
-  UINT32 Iv:16;               /* Interrupt Vector */
-} NVME_ADMIN_CRIOCQ;
-
-//
-// NvmExpress Admin Create I/O Submission Queue
-//
-typedef struct {
-  //
-  // CDW 10
-  //
-  UINT32 Qid:16;              /* Queue Identifier */
-  UINT32 Qsize:16;            /* Queue Size */
-
-  //
-  // CDW 11
-  //
-  UINT32 Pc:1;                /* Physically Contiguous */
-  UINT32 Qprio:2;             /* Queue Priority */
-  UINT32 Rsvd1:13;            /* Reserved as of Nvm Express 1.1 Spec */
-  UINT32 Cqid:16;             /* Completion Queue ID */
-} NVME_ADMIN_CRIOSQ;
-
-//
-// NvmExpress Admin Delete I/O Completion Queue
-//
-typedef struct {
-  //
-  // CDW 10
-  //
-  UINT16 Qid;
-  UINT16 Rsvd1;
-} NVME_ADMIN_DEIOCQ;
-
-//
-// NvmExpress Admin Delete I/O Submission Queue
-//
-typedef struct {
-  //
-  // CDW 10
-  //
-  UINT16 Qid;
-  UINT16 Rsvd1;
-} NVME_ADMIN_DEIOSQ;
-
-//
-// NvmExpress Admin Security Send
-//
-typedef struct {
-  //
-  // CDW 10
-  //
-  UINT32 Resv:8;              /* Reserve */
-  UINT32 Spsp:16;             /* SP Specific */
-  UINT32 Secp:8;              /* Security Protocol */
-
-  //
-  // CDW 11
-  //
-  UINT32 Tl;                  /* Transfer Length */
-} NVME_ADMIN_SECSEND;
-
-//
-// NvmExpress Admin Abort Command
-//
-typedef struct {
-  //
-  // CDW 10
-  //
-  UINT32 Sqid:16;             /* Submission Queue identifier */
-  UINT32 Cid:16;              /* Command Identifier */
-} NVME_ADMIN_ABORT;
-
-//
-// NvmExpress Admin Firmware Activate Command
-//
-typedef struct {
-  //
-  // CDW 10
-  //
-  UINT32 Fs:3;                /* Submission Queue identifier */
-  UINT32 Aa:2;                /* Command Identifier */
-  UINT32 Rsvd1:27;
-} NVME_ADMIN_FIRMWARE_ACTIVATE;
-
-//
-// NvmExpress Admin Firmware Image Download Command
-//
-typedef struct {
-  //
-  // CDW 10
-  //
-  UINT32 Numd;                /* Number of Dwords */
-  //
-  // CDW 11
-  //
-  UINT32 Ofst;                /* Offset */
-} NVME_ADMIN_FIRMWARE_IMAGE_DOWNLOAD;
-
-//
-// NvmExpress Admin Get Features Command
-//
-typedef struct {
-  //
-  // CDW 10
-  //
-  UINT32 Fid:8;                /* Feature Identifier */
-  UINT32 Sel:3;                /* Select */
-  UINT32 Rsvd1:21;
-} NVME_ADMIN_GET_FEATURES;
-
-//
-// NvmExpress Admin Get Log Page Command
-//
-typedef struct {
-  //
-  // CDW 10
-  //
-  UINT32 Lid:8;               /* Log Page Identifier */
-    #define LID_ERROR_INFO
-    #define LID_SMART_INFO
-    #define LID_FW_SLOT_INFO
-  UINT32 Rsvd1:8;
-  UINT32 Numd:12;             /* Number of Dwords */
-  UINT32 Rsvd2:4;             /* Reserved as of Nvm Express 1.1 Spec */
-} NVME_ADMIN_GET_LOG_PAGE;
-
-//
-// NvmExpress Admin Set Features Command
-//
-typedef struct {
-  //
-  // CDW 10
-  //
-  UINT32 Fid:8;               /* Feature Identifier */
-  UINT32 Rsvd1:23;
-  UINT32 Sv:1;                /* Save */
-} NVME_ADMIN_SET_FEATURES;
-
-//
-// NvmExpress Admin Format NVM Command
-//
-typedef struct {
-  //
-  // CDW 10
-  //
-  UINT32 Lbaf:4;              /* LBA Format */
-  UINT32 Ms:1;                /* Metadata Settings */
-  UINT32 Pi:3;                /* Protection Information */
-  UINT32 Pil:1;               /* Protection Information Location */
-  UINT32 Ses:3;               /* Secure Erase Settings */
-  UINT32 Rsvd1:20;
-} NVME_ADMIN_FORMAT_NVM;
-
-//
-// NvmExpress Admin Security Receive Command
-//
-typedef struct {
-  //
-  // CDW 10
-  //
-  UINT32 Rsvd1:8;
-  UINT32 Spsp:16;             /* SP Specific */
-  UINT32 Secp:8;              /* Security Protocol */
-  //
-  // CDW 11
-  //
-  UINT32 Al;                  /* Allocation Length */
-} NVME_ADMIN_SECURITY_RECEIVE;
-
-//
-// NvmExpress Admin Security Send Command
-//
-typedef struct {
-  //
-  // CDW 10
-  //
-  UINT32 Rsvd1:8;
-  UINT32 Spsp:16;             /* SP Specific */
-  UINT32 Secp:8;              /* Security Protocol */
-  //
-  // CDW 11
-  //
-  UINT32 Tl;                  /* Transfer Length */
-} NVME_ADMIN_SECURITY_SEND;
-
-typedef union {
-  NVME_ADMIN_IDENTIFY                   Identify;
-  NVME_ADMIN_CRIOCQ                     CrIoCq;
-  NVME_ADMIN_CRIOSQ                     CrIoSq;
-  NVME_ADMIN_DEIOCQ                     DeIoCq;
-  NVME_ADMIN_DEIOSQ                     DeIoSq;
-  NVME_ADMIN_ABORT                      Abort;
-  NVME_ADMIN_FIRMWARE_ACTIVATE          Activate;
-  NVME_ADMIN_FIRMWARE_IMAGE_DOWNLOAD    FirmwareImageDownload;
-  NVME_ADMIN_GET_FEATURES               GetFeatures;
-  NVME_ADMIN_GET_LOG_PAGE               GetLogPage;
-  NVME_ADMIN_SET_FEATURES               SetFeatures;
-  NVME_ADMIN_FORMAT_NVM                 FormatNvm;
-  NVME_ADMIN_SECURITY_RECEIVE           SecurityReceive;
-  NVME_ADMIN_SECURITY_SEND              SecuritySend;
-} NVME_ADMIN_CMD;
-
-typedef struct {
-  UINT32 Cdw10;
-  UINT32 Cdw11;
-  UINT32 Cdw12;
-  UINT32 Cdw13;
-  UINT32 Cdw14;
-  UINT32 Cdw15;
-} NVME_RAW;
-
-typedef union {
-  NVME_ADMIN_CMD Admin;   // Union of Admin commands
-  NVME_CMD       Nvm;     // Union of Nvm commands
-  NVME_RAW       Raw;
-} NVME_PAYLOAD;
-
-//
-// Submission Queue
-//
-typedef struct {
-  //
-  // CDW 0, Common to all comnmands
-  //
-  UINT8  Opc;               // Opcode
-  UINT8  Fuse:2;            // Fused Operation
-  UINT8  Rsvd1:5;
-  UINT8  Psdt:1;            // PRP or SGL for Data Transfer
-  UINT16 Cid;               // Command Identifier
-
-  //
-  // CDW 1
-  //
-  UINT32 Nsid;              // Namespace Identifier
-
-  //
-  // CDW 2,3
-  //
-  UINT64 Rsvd2;
-
-  //
-  // CDW 4,5
-  //
-  UINT64 Mptr;              // Metadata Pointer
-
-  //
-  // CDW 6-9
-  //
-  UINT64 Prp[2];            // First and second PRP entries
-
-  NVME_PAYLOAD Payload;
-
-} NVME_SQ;
-
-//
-// Completion Queue
-//
-typedef struct {
-  //
-  // CDW 0
-  //
-  UINT32 Dword0;
-  //
-  // CDW 1
-  //
-  UINT32 Rsvd1;
-  //
-  // CDW 2
-  //
-  UINT16 Sqhd;              // Submission Queue Head Pointer
-  UINT16 Sqid;              // Submission Queue Identifier
-  //
-  // CDW 3
-  //
-  UINT16 Cid;               // Command Identifier
-  UINT16 Pt:1;              // Phase Tag
-  UINT16 Sc:8;              // Status Code
-  UINT16 Sct:3;             // Status Code Type
-  UINT16 Rsvd2:2;
-  UINT16 Mo:1;              // More
-  UINT16 Dnr:1;             // Retry
-} NVME_CQ;
-
-//
-// Nvm Express Admin cmd opcodes
-//
-#define NVME_ADMIN_DELIOSQ_OPC               0
-#define NVME_ADMIN_CRIOSQ_OPC                1
-#define NVME_ADMIN_DELIOCQ_OPC               4
-#define NVME_ADMIN_CRIOCQ_OPC                5
-#define NVME_ADMIN_IDENTIFY_OPC              6
-#define NVME_ADMIN_SECURITY_SEND_OPC         0x81
-#define NVME_ADMIN_SECURITY_RECV_OPC         0x82
-
-#define NVME_IO_FLUSH_OPC                    0
-#define NVME_IO_WRITE_OPC                    1
-#define NVME_IO_READ_OPC                     2
-
-//
-// Offset from the beginning of private Data queue Buffer
-//
-#define NVME_ASQ_BUF_OFFSET                  EFI_PAGE_SIZE
-
-#pragma pack()
-
-#endif
-
diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordCommon.h b/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordCommon.h
index e10146e466..54bdbaf9cb 100644
--- a/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordCommon.h
+++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordCommon.h
@@ -1,7 +1,7 @@
 /** @file
   Opal Password common header file.
 
-Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
 This program and the accompanying materials
 are licensed and made available under the terms and conditions of the BSD License
 which accompanies this distribution.  The full text of the license may be found at
@@ -30,38 +30,15 @@ typedef struct {
 } OPAL_PCI_DEVICE;
 
 typedef struct {
-  UINT16            Length;
-  OPAL_PCI_DEVICE   Device;
-  UINT8             PasswordLength;
-  UINT8             Password[OPAL_MAX_PASSWORD_SIZE];
-  UINT16            OpalBaseComId;
-  UINT32            BarAddr;
-} OPAL_DEVICE_COMMON;
-
-#define OPAL_DEVICE_ATA_GUID { 0xcb934fe1, 0xb8cd, 0x46b1, { 0xa0, 0x58, 0xdd, 0xcb, 0x7, 0xb7, 0xb4, 0x17 } }
-
-typedef struct {
-  UINT16            Length;
-  OPAL_PCI_DEVICE   Device;
-  UINT8             PasswordLength;
-  UINT8             Password[OPAL_MAX_PASSWORD_SIZE];
-  UINT16            OpalBaseComId;
-  UINT32            BarAddr;
-  UINT16            Port;
-  UINT16            PortMultiplierPort;
-} OPAL_DEVICE_ATA;
-
-#define OPAL_DEVICE_NVME_GUID { 0xde116925, 0xaf7f, 0x42d9, { 0x83, 0xc0, 0x7e, 0xd6, 0x26, 0x59, 0x0, 0xfb } }
-
-typedef struct {
-  UINT16            Length;
-  OPAL_PCI_DEVICE   Device;
-  UINT8             PasswordLength;
-  UINT8             Password[OPAL_MAX_PASSWORD_SIZE];
-  UINT16            OpalBaseComId;
-  UINT32            BarAddr;
-  UINT32            NvmeNamespaceId;
-  OPAL_PCI_DEVICE   PciBridgeNode[0];
-} OPAL_DEVICE_NVME;
+  UINT16                      Length;
+  OPAL_PCI_DEVICE             Device;
+  UINT8                       PasswordLength;
+  UINT8                       Password[OPAL_MAX_PASSWORD_SIZE];
+  UINT16                      OpalBaseComId;
+  UINT16                      DevicePathLength;
+  EFI_DEVICE_PATH_PROTOCOL    DevicePath[];
+} OPAL_DEVICE_LOCKBOX_DATA;
+
+#define OPAL_DEVICE_LOCKBOX_GUID  { 0x56a77f0d, 0x6f05, 0x4d47, { 0xb9, 0x11, 0x4f, 0xd, 0xec, 0x5c, 0x58, 0x61 } }
 
 #endif // _OPAL_PASSWORD_COMMON_H_
diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.h b/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.h
index 31aab37f5d..c86598f21c 100644
--- a/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.h
+++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.h
@@ -1,7 +1,7 @@
 /** @file
   Opal Password PEI driver which is used to unlock Opal Password for S3.
 
-Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
 This program and the accompanying materials
 are licensed and made available under the terms and conditions of the BSD License
 which accompanies this distribution.  The full text of the license may be found at
@@ -16,8 +16,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #define _OPAL_PASSWORD_PEI_H_
 
 #include <PiPei.h>
-#include <IndustryStandard/Atapi.h>
-#include <IndustryStandard/Pci.h>
 
 #include <Library/DebugLib.h>
 #include <Library/IoLib.h>
@@ -27,107 +25,63 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Library/MemoryAllocationLib.h>
 #include <Library/PeimEntryPoint.h>
 #include <Library/PeiServicesLib.h>
-#include <Library/HobLib.h>
-#include <Library/TimerLib.h>
 #include <Library/LockBoxLib.h>
 #include <Library/TcgStorageOpalLib.h>
 #include <Library/Tcg2PhysicalPresenceLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
 
 #include <Protocol/StorageSecurityCommand.h>
 
 #include <Ppi/IoMmu.h>
+#include <Ppi/StorageSecurityCommand.h>
 
 #include "OpalPasswordCommon.h"
-#include "OpalAhciMode.h"
-#include "OpalNvmeMode.h"
 
 //
-// Time out Value for ATA pass through protocol
+// The maximum number of Storage Security Command PPI instance supported
+// by the driver
 //
-#define ATA_TIMEOUT                      30000000
+#define OPAL_PEI_MAX_STORAGE_SECURITY_CMD_PPI    32
 
 //
-// The payload Length of HDD related ATA commands
+// The generic command timeout value (unit in us) for Storage Security Command
+// PPI ReceiveData/SendData services
 //
-#define HDD_PAYLOAD                      512
-//
-// According to ATA spec, the max Length of hdd password is 32 bytes
-//
-#define OPAL_PASSWORD_MAX_LENGTH         32
+#define SSC_PPI_GENERIC_TIMEOUT                  30000000
 
 #pragma pack(1)
 
-/**
-* Opal I/O Type utilized by the Trusted IO callback
-*
-* The type indicates if the I/O is a send or receive
-*/
-typedef enum {
-    //
-    // I/O is a TCG Trusted Send command
-    //
-    OpalSend,
-
-    //
-    // I/O is a TCG Trusted Receive command
-    //
-    OpalRecv
-} OPAL_IO_TYPE;
-
-#define OPAL_PEI_DEVICE_SIGNATURE SIGNATURE_32 ('o', 'p', 'd', 's')
+#define OPAL_PEI_DEVICE_SIGNATURE       SIGNATURE_32 ('o', 'p', 'd', 's')
 
 typedef struct {
-  UINTN                                     Signature;
-  EFI_STORAGE_SECURITY_COMMAND_PROTOCOL     Sscp;
-  UINT8                                     DeviceType;
-  OPAL_DEVICE_COMMON                        *Device;
-  VOID                                      *Context;
+  UINTN                                    Signature;
+  EFI_STORAGE_SECURITY_COMMAND_PROTOCOL    Sscp;
+  OPAL_DEVICE_LOCKBOX_DATA                 *Device;
+  VOID                                     *Context;
+  EDKII_PEI_STORAGE_SECURITY_CMD_PPI       *SscPpi;
+  UINTN                                    DeviceIndex;
 } OPAL_PEI_DEVICE;
 
-#define OPAL_PEI_DEVICE_FROM_THIS(a)  CR (a, OPAL_PEI_DEVICE, Sscp, OPAL_PEI_DEVICE_SIGNATURE)
+#define OPAL_PEI_DEVICE_FROM_THIS(a)    \
+  CR (a, OPAL_PEI_DEVICE, Sscp, OPAL_PEI_DEVICE_SIGNATURE)
 
 #pragma pack()
 
-/**
-  Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
-  OperationBusMasterCommonBuffer64 mapping.
-
-  @param Pages                  The number of pages to allocate.
-  @param HostAddress            A pointer to store the base system memory address of the
-                                allocated range.
-  @param DeviceAddress          The resulting map address for the bus master PCI controller to use to
-                                access the hosts HostAddress.
-  @param Mapping                A resulting value to pass to Unmap().
-
-  @retval EFI_SUCCESS           The requested memory pages were allocated.
-  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are
-                                MEMORY_WRITE_COMBINE and MEMORY_CACHED.
-  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
-  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
-
-**/
-EFI_STATUS
-IoMmuAllocateBuffer (
-  IN UINTN                  Pages,
-  OUT VOID                  **HostAddress,
-  OUT EFI_PHYSICAL_ADDRESS  *DeviceAddress,
-  OUT VOID                  **Mapping
-  );
+//
+// Private data structure for Opal PEI driver
+//
+#define OPAL_PEI_DRIVER_SIGNATURE       SIGNATURE_32 ('o', 'd', 'r', 'i')
 
-/**
-  Frees memory that was allocated with AllocateBuffer().
+typedef struct {
+  UINTN                        Signature;
+  EFI_PEI_NOTIFY_DESCRIPTOR    SscPpiNotifyList;
 
-  @param Pages              The number of pages to free.
-  @param HostAddress        The base system memory address of the allocated range.
-  @param Mapping            The mapping value returned from Map().
+  UINTN                        SscPpiInstanceNum;
+  UINTN                        SscPpiInstances[OPAL_PEI_MAX_STORAGE_SECURITY_CMD_PPI];
+} OPAL_PEI_DRIVER_PRIVATE_DATA;
 
-**/
-VOID
-IoMmuFreeBuffer (
-  IN UINTN                  Pages,
-  IN VOID                   *HostAddress,
-  IN VOID                   *Mapping
-  );
+#define OPAL_PEI_PRIVATE_DATA_FROM_THIS_NOTIFY(a)    \
+  CR (a, OPAL_PEI_DRIVER_PRIVATE_DATA, SscPpiNotifyList, OPAL_PEI_DRIVER_SIGNATURE)
 
 #endif // _OPAL_PASSWORD_PEI_H_
 
diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.c b/SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.c
deleted file mode 100644
index 0c4edd5346..0000000000
--- a/SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.c
+++ /dev/null
@@ -1,1282 +0,0 @@
-/** @file
-  This driver is used for Opal Password Feature support at AHCI mode.
-
-Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution.  The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-
-#include "OpalPasswordPei.h"
-
-/**
-  Start command for give slot on specific port.
-
-  @param  AhciBar            AHCI bar address.
-  @param  Port               The number of port.
-  @param  CommandSlot        The number of CommandSlot.
-  @param  Timeout            The timeout Value of start.
-
-  @retval EFI_DEVICE_ERROR   The command start unsuccessfully.
-  @retval EFI_TIMEOUT        The operation is time out.
-  @retval EFI_SUCCESS        The command start successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-AhciStartCommand (
-  IN  UINT32                    AhciBar,
-  IN  UINT8                     Port,
-  IN  UINT8                     CommandSlot,
-  IN  UINT64                    Timeout
-  );
-
-/**
-  Stop command running for giving port
-
-  @param  AhciBar            AHCI bar address.
-  @param  Port               The number of port.
-  @param  Timeout            The timeout Value of stop.
-
-  @retval EFI_DEVICE_ERROR   The command stop unsuccessfully.
-  @retval EFI_TIMEOUT        The operation is time out.
-  @retval EFI_SUCCESS        The command stop successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-AhciStopCommand (
-  IN  UINT32                    AhciBar,
-  IN  UINT8                     Port,
-  IN  UINT64                    Timeout
-  );
-
-/**
-  Read AHCI Operation register.
-
-  @param  AhciBar      AHCI bar address.
-  @param  Offset       The operation register offset.
-
-  @return The register content read.
-
-**/
-UINT32
-EFIAPI
-AhciReadReg (
-  IN  UINT32              AhciBar,
-  IN  UINT32              Offset
-  )
-{
-  UINT32   Data;
-
-  Data = 0;
-
-  Data = MmioRead32 (AhciBar + Offset);
-
-  return Data;
-}
-
-/**
-  Write AHCI Operation register.
-
-  @param  AhciBar      AHCI bar address.
-  @param  Offset       The operation register offset.
-  @param  Data         The Data used to write down.
-
-**/
-VOID
-EFIAPI
-AhciWriteReg (
-  IN UINT32               AhciBar,
-  IN UINT32               Offset,
-  IN UINT32               Data
-  )
-{
-  MmioWrite32 (AhciBar + Offset, Data);
-
-  return ;
-}
-
-/**
-  Do AND operation with the Value of AHCI Operation register.
-
-  @param  AhciBar      AHCI bar address.
-  @param  Offset       The operation register offset.
-  @param  AndData      The Data used to do AND operation.
-
-**/
-VOID
-EFIAPI
-AhciAndReg (
-  IN UINT32               AhciBar,
-  IN UINT32               Offset,
-  IN UINT32               AndData
-  )
-{
-  UINT32 Data;
-
-  Data  = AhciReadReg (AhciBar, Offset);
-
-  Data &= AndData;
-
-  AhciWriteReg (AhciBar, Offset, Data);
-}
-
-/**
-  Do OR operation with the Value of AHCI Operation register.
-
-  @param  AhciBar      AHCI bar address.
-  @param  Offset       The operation register offset.
-  @param  OrData       The Data used to do OR operation.
-
-**/
-VOID
-EFIAPI
-AhciOrReg (
-  IN UINT32               AhciBar,
-  IN UINT32               Offset,
-  IN UINT32               OrData
-  )
-{
-  UINT32 Data;
-
-  Data  = AhciReadReg (AhciBar, Offset);
-
-  Data |= OrData;
-
-  AhciWriteReg (AhciBar, Offset, Data);
-}
-
-/**
-  Wait for memory set to the test Value.
-
-  @param  AhciBar           AHCI bar address.
-  @param  Offset            The memory offset to test.
-  @param  MaskValue         The mask Value of memory.
-  @param  TestValue         The test Value of memory.
-  @param  Timeout           The time out Value for wait memory set.
-
-  @retval EFI_DEVICE_ERROR  The memory is not set.
-  @retval EFI_TIMEOUT       The memory setting is time out.
-  @retval EFI_SUCCESS       The memory is correct set.
-
-**/
-EFI_STATUS
-EFIAPI
-AhciWaitMmioSet (
-  IN  UINT32                    AhciBar,
-  IN  UINT32                    Offset,
-  IN  UINT32                    MaskValue,
-  IN  UINT32                    TestValue,
-  IN  UINT64                    Timeout
-  )
-{
-  UINT32     Value;
-  UINT32     Delay;
-
-  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
-
-  do {
-    Value = AhciReadReg (AhciBar, Offset) & MaskValue;
-
-    if (Value == TestValue) {
-      return EFI_SUCCESS;
-    }
-
-    //
-    // Stall for 100 microseconds.
-    //
-    MicroSecondDelay (100);
-
-    Delay--;
-
-  } while (Delay > 0);
-
-  return EFI_TIMEOUT;
-}
-/**
-  Wait for the Value of the specified system memory set to the test Value.
-
-  @param  Address           The system memory address to test.
-  @param  MaskValue         The mask Value of memory.
-  @param  TestValue         The test Value of memory.
-  @param  Timeout           The time out Value for wait memory set, uses 100ns as a unit.
-
-  @retval EFI_TIMEOUT       The system memory setting is time out.
-  @retval EFI_SUCCESS       The system memory is correct set.
-
-**/
-EFI_STATUS
-EFIAPI
-AhciWaitMemSet (
-  IN  EFI_PHYSICAL_ADDRESS      Address,
-  IN  UINT32                    MaskValue,
-  IN  UINT32                    TestValue,
-  IN  UINT64                    Timeout
-  )
-{
-  UINT32     Value;
-  UINT32     Delay;
-
-  Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);
-
-  do {
-    //
-    // Access sytem memory to see if the Value is the tested one.
-    //
-    // The system memory pointed by Address will be updated by the
-    // SATA Host Controller, "volatile" is introduced to prevent
-    // compiler from optimizing the access to the memory address
-    // to only read once.
-    //
-    Value  = *(volatile UINT32 *) (UINTN) Address;
-    Value &= MaskValue;
-
-    if (Value == TestValue) {
-      return EFI_SUCCESS;
-    }
-
-    //
-    // Stall for 100 microseconds.
-    //
-    MicroSecondDelay (100);
-
-    Delay--;
-
-  } while (Delay > 0);
-
-  return EFI_TIMEOUT;
-}
-
-/**
-  Check the memory status to the test Value.
-
-  @param[in]       Address           The memory address to test.
-  @param[in]       MaskValue         The mask Value of memory.
-  @param[in]       TestValue         The test Value of memory.
-  @param[in, out]  RetryTimes        The retry times Value for waitting memory set. If 0, then just try once.
-
-  @retval EFI_NOTREADY      The memory is not set.
-  @retval EFI_TIMEOUT       The memory setting retry times out.
-  @retval EFI_SUCCESS       The memory is correct set.
-
-**/
-EFI_STATUS
-EFIAPI
-AhciCheckMemSet (
-  IN     UINTN                     Address,
-  IN     UINT32                    MaskValue,
-  IN     UINT32                    TestValue,
-  IN OUT UINTN                     *RetryTimes OPTIONAL
-  )
-{
-  UINT32     Value;
-
-  if (RetryTimes != NULL) {
-    (*RetryTimes)--;
-  }
-
-  Value  = *(volatile UINT32 *) Address;
-  Value &= MaskValue;
-
-  if (Value == TestValue) {
-    return EFI_SUCCESS;
-  }
-
-  if ((RetryTimes != NULL) && (*RetryTimes == 0)) {
-    return EFI_TIMEOUT;
-  } else {
-    return EFI_NOT_READY;
-  }
-}
-
-/**
-  Clear the port interrupt and error status. It will also clear
-  HBA interrupt status.
-
-  @param      AhciBar        AHCI bar address.
-  @param      Port           The number of port.
-
-**/
-VOID
-EFIAPI
-AhciClearPortStatus (
-  IN  UINT32                 AhciBar,
-  IN  UINT8                  Port
-  )
-{
-  UINT32 Offset;
-
-  //
-  // Clear any error status
-  //
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;
-  AhciWriteReg (AhciBar, Offset, AhciReadReg (AhciBar, Offset));
-
-  //
-  // Clear any port interrupt status
-  //
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;
-  AhciWriteReg (AhciBar, Offset, AhciReadReg (AhciBar, Offset));
-
-  //
-  // Clear any HBA interrupt status
-  //
-  AhciWriteReg (AhciBar, EFI_AHCI_IS_OFFSET, AhciReadReg (AhciBar, EFI_AHCI_IS_OFFSET));
-}
-
-/**
-  Enable the FIS running for giving port.
-
-  @param      AhciBar        AHCI bar address.
-  @param      Port           The number of port.
-  @param      Timeout        The timeout Value of enabling FIS.
-
-  @retval EFI_DEVICE_ERROR   The FIS enable setting fails.
-  @retval EFI_TIMEOUT        The FIS enable setting is time out.
-  @retval EFI_SUCCESS        The FIS enable successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-AhciEnableFisReceive (
-  IN  UINT32                    AhciBar,
-  IN  UINT8                     Port,
-  IN  UINT64                    Timeout
-  )
-{
-  UINT32 Offset;
-
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
-  AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_FRE);
-
-  return AhciWaitMmioSet (
-           AhciBar,
-           Offset,
-           EFI_AHCI_PORT_CMD_FR,
-           EFI_AHCI_PORT_CMD_FR,
-           Timeout
-           );
-}
-
-/**
-  Disable the FIS running for giving port.
-
-  @param      AhciBar        AHCI bar address.
-  @param      Port           The number of port.
-  @param      Timeout        The timeout Value of disabling FIS.
-
-  @retval EFI_DEVICE_ERROR   The FIS disable setting fails.
-  @retval EFI_TIMEOUT        The FIS disable setting is time out.
-  @retval EFI_UNSUPPORTED    The port is in running state.
-  @retval EFI_SUCCESS        The FIS disable successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-AhciDisableFisReceive (
-  IN  UINT32                    AhciBar,
-  IN  UINT8                     Port,
-  IN  UINT64                    Timeout
-  )
-{
-  UINT32 Offset;
-  UINT32 Data;
-
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
-  Data   = AhciReadReg (AhciBar, Offset);
-
-  //
-  // Before disabling Fis receive, the DMA engine of the port should NOT be in running status.
-  //
-  if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) != 0) {
-    return EFI_UNSUPPORTED;
-  }
-
-  //
-  // Check if the Fis receive DMA engine for the port is running.
-  //
-  if ((Data & EFI_AHCI_PORT_CMD_FR) != EFI_AHCI_PORT_CMD_FR) {
-    return EFI_SUCCESS;
-  }
-
-  AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE));
-
-  return AhciWaitMmioSet (
-           AhciBar,
-           Offset,
-           EFI_AHCI_PORT_CMD_FR,
-           0,
-           Timeout
-           );
-}
-
-/**
-  Build the command list, command table and prepare the fis receiver.
-
-  @param    AhciContext           The pointer to the AHCI_CONTEXT.
-  @param    Port                  The number of port.
-  @param    PortMultiplier        The timeout Value of stop.
-  @param    CommandFis            The control fis will be used for the transfer.
-  @param    CommandList           The command list will be used for the transfer.
-  @param    AtapiCommand          The atapi command will be used for the transfer.
-  @param    AtapiCommandLength    The Length of the atapi command.
-  @param    CommandSlotNumber     The command slot will be used for the transfer.
-  @param    DataPhysicalAddr      The pointer to the Data Buffer pci bus master address.
-  @param    DataLength            The Data count to be transferred.
-
-**/
-VOID
-EFIAPI
-AhciBuildCommand (
-  IN     AHCI_CONTEXT               *AhciContext,
-  IN     UINT8                      Port,
-  IN     UINT8                      PortMultiplier,
-  IN     EFI_AHCI_COMMAND_FIS       *CommandFis,
-  IN     EFI_AHCI_COMMAND_LIST      *CommandList,
-  IN     EFI_AHCI_ATAPI_COMMAND     *AtapiCommand OPTIONAL,
-  IN     UINT8                      AtapiCommandLength,
-  IN     UINT8                      CommandSlotNumber,
-  IN OUT VOID                       *DataPhysicalAddr,
-  IN     UINT64                     DataLength
-  )
-{
-  EFI_AHCI_REGISTERS    *AhciRegisters;
-  UINT32                AhciBar;
-  UINT64                BaseAddr;
-  UINT64                PrdtNumber;
-  UINTN                 RemainedData;
-  UINTN                 MemAddr;
-  DATA_64               Data64;
-  UINT32                Offset;
-
-  AhciRegisters = &AhciContext->AhciRegisters;
-  AhciBar = AhciContext->AhciBar;
-
-  //
-  // Filling the PRDT
-  //
-  PrdtNumber = DivU64x32 (DataLength + EFI_AHCI_MAX_DATA_PER_PRDT - 1, EFI_AHCI_MAX_DATA_PER_PRDT);
-
-  //
-  // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB Data block.
-  // It also limits that the maximum amount of the PRDT entry in the command table
-  // is 65535.
-  //
-  ASSERT (PrdtNumber <= 1);
-
-  Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis);
-
-  BaseAddr = Data64.Uint64;
-
-  ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));
-
-  ZeroMem (AhciRegisters->AhciCommandTable, sizeof (EFI_AHCI_COMMAND_TABLE));
-
-  CommandFis->AhciCFisPmNum = PortMultiplier;
-
-  CopyMem (&AhciRegisters->AhciCommandTable->CommandFis, CommandFis, sizeof (EFI_AHCI_COMMAND_FIS));
-
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
-  if (AtapiCommand != NULL) {
-    CopyMem (
-      &AhciRegisters->AhciCommandTable->AtapiCmd,
-      AtapiCommand,
-      AtapiCommandLength
-      );
-
-    CommandList->AhciCmdA = 1;
-    CommandList->AhciCmdP = 1;
-
-    AhciOrReg (AhciBar, Offset, (EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));
-  } else {
-    AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));
-  }
-
-  RemainedData = (UINTN) DataLength;
-  MemAddr      = (UINTN) DataPhysicalAddr;
-  CommandList->AhciCmdPrdtl = (UINT32)PrdtNumber;
-
-  AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDbc = (UINT32)RemainedData - 1;
-
-  Data64.Uint64 = (UINT64)MemAddr;
-  AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDba  = Data64.Uint32.Lower32;
-  AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDbau = Data64.Uint32.Upper32;
-
-  //
-  // Set the last PRDT to Interrupt On Complete
-  //
-  AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtIoc = 1;
-
-  CopyMem (
-    (VOID *) ((UINTN) AhciRegisters->AhciCmdList + (UINTN) CommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST)),
-    CommandList,
-    sizeof (EFI_AHCI_COMMAND_LIST)
-    );
-
-  Data64.Uint64 = (UINT64)(UINTN) AhciRegisters->AhciCommandTable;
-  AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtba  = Data64.Uint32.Lower32;
-  AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtbau = Data64.Uint32.Upper32;
-  AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdPmp   = PortMultiplier;
-
-}
-
-/**
-  Buid a command FIS.
-
-  @param  CmdFis            A pointer to the EFI_AHCI_COMMAND_FIS Data structure.
-  @param  AtaCommandBlock   A pointer to the AhciBuildCommandFis Data structure.
-
-**/
-VOID
-EFIAPI
-AhciBuildCommandFis (
-  IN OUT EFI_AHCI_COMMAND_FIS    *CmdFis,
-  IN     EFI_ATA_COMMAND_BLOCK   *AtaCommandBlock
-  )
-{
-  ZeroMem (CmdFis, sizeof (EFI_AHCI_COMMAND_FIS));
-
-  CmdFis->AhciCFisType = EFI_AHCI_FIS_REGISTER_H2D;
-  //
-  // Indicator it's a command
-  //
-  CmdFis->AhciCFisCmdInd      = 0x1;
-  CmdFis->AhciCFisCmd         = AtaCommandBlock->AtaCommand;
-
-  CmdFis->AhciCFisFeature     = AtaCommandBlock->AtaFeatures;
-  CmdFis->AhciCFisFeatureExp  = AtaCommandBlock->AtaFeaturesExp;
-
-  CmdFis->AhciCFisSecNum      = AtaCommandBlock->AtaSectorNumber;
-  CmdFis->AhciCFisSecNumExp   = AtaCommandBlock->AtaSectorNumberExp;
-
-  CmdFis->AhciCFisClyLow      = AtaCommandBlock->AtaCylinderLow;
-  CmdFis->AhciCFisClyLowExp   = AtaCommandBlock->AtaCylinderLowExp;
-
-  CmdFis->AhciCFisClyHigh     = AtaCommandBlock->AtaCylinderHigh;
-  CmdFis->AhciCFisClyHighExp  = AtaCommandBlock->AtaCylinderHighExp;
-
-  CmdFis->AhciCFisSecCount    = AtaCommandBlock->AtaSectorCount;
-  CmdFis->AhciCFisSecCountExp = AtaCommandBlock->AtaSectorCountExp;
-
-  CmdFis->AhciCFisDevHead     = (UINT8) (AtaCommandBlock->AtaDeviceHead | 0xE0);
-}
-
-/**
-  Start a PIO Data transfer on specific port.
-
-  @param  AhciContext         The pointer to the AHCI_CONTEXT.
-  @param  Port                The number of port.
-  @param  PortMultiplier      The timeout Value of stop.
-  @param  AtapiCommand        The atapi command will be used for the transfer.
-  @param  AtapiCommandLength  The Length of the atapi command.
-  @param  Read                The transfer direction.
-  @param  AtaCommandBlock     The EFI_ATA_COMMAND_BLOCK Data.
-  @param  AtaStatusBlock      The EFI_ATA_STATUS_BLOCK Data.
-  @param  MemoryAddr          The pointer to the Data Buffer.
-  @param  DataCount           The Data count to be transferred.
-  @param  Timeout             The timeout Value of non Data transfer.
-
-  @retval EFI_DEVICE_ERROR    The PIO Data transfer abort with error occurs.
-  @retval EFI_TIMEOUT         The operation is time out.
-  @retval EFI_UNSUPPORTED     The device is not ready for transfer.
-  @retval EFI_SUCCESS         The PIO Data transfer executes successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-AhciPioTransfer (
-  IN     AHCI_CONTEXT               *AhciContext,
-  IN     UINT8                      Port,
-  IN     UINT8                      PortMultiplier,
-  IN     EFI_AHCI_ATAPI_COMMAND     *AtapiCommand OPTIONAL,
-  IN     UINT8                      AtapiCommandLength,
-  IN     BOOLEAN                    Read,
-  IN     EFI_ATA_COMMAND_BLOCK      *AtaCommandBlock,
-  IN OUT EFI_ATA_STATUS_BLOCK       *AtaStatusBlock,
-  IN OUT VOID                       *MemoryAddr,
-  IN     UINT32                     DataCount,
-  IN     UINT64                     Timeout
-  )
-{
-  EFI_STATUS                    Status;
-  EFI_AHCI_REGISTERS            *AhciRegisters;
-  UINT32                        AhciBar;
-  UINT32                        FisBaseAddr;
-  UINT32                        Offset;
-  UINT32                        Delay;
-  EFI_AHCI_COMMAND_FIS          CFis;
-  EFI_AHCI_COMMAND_LIST         CmdList;
-  UINT32                        PortTfd;
-  UINT32                        PrdCount;
-  UINT32                        OldRfisLo;
-  UINT32                        OldRfisHi;
-  UINT32                        OldCmdListLo;
-  UINT32                        OldCmdListHi;
-
-  AhciRegisters = &AhciContext->AhciRegisters;
-  AhciBar = AhciContext->AhciBar;
-
-  Offset    = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;
-  OldRfisLo = AhciReadReg (AhciBar, Offset);
-  Offset    = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;
-  OldRfisHi = AhciReadReg (AhciBar, Offset);
-  Offset    = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;
-  AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciRFis);
-  Offset    = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;
-  AhciWriteReg (AhciBar, Offset, 0);
-
-  //
-  // Single task envrionment, we only use one command table for all port
-  //
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;
-  OldCmdListLo = AhciReadReg (AhciBar, Offset);
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;
-  OldCmdListHi = AhciReadReg (AhciBar, Offset);
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;
-  AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciCmdList);
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;
-  AhciWriteReg (AhciBar, Offset, 0);
-
-  //
-  // Package read needed
-  //
-  AhciBuildCommandFis (&CFis, AtaCommandBlock);
-
-  ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));
-
-  CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;
-  CmdList.AhciCmdW   = Read ? 0 : 1;
-
-  AhciBuildCommand (
-    AhciContext,
-    Port,
-    PortMultiplier,
-    &CFis,
-    &CmdList,
-    AtapiCommand,
-    AtapiCommandLength,
-    0,
-    MemoryAddr,
-    DataCount
-    );
-
-  Status = AhciStartCommand (
-             AhciBar,
-             Port,
-             0,
-             Timeout
-             );
-  if (EFI_ERROR (Status)) {
-    goto Exit;
-  }
-
-  //
-  // Checking the status and wait the driver sending Data
-  //
-  FisBaseAddr = (UINT32)(UINTN)AhciRegisters->AhciRFis;
-  if (Read && (AtapiCommand == 0)) {
-    //
-    // Wait device sends the PIO setup fis before Data transfer
-    //
-    Status = EFI_TIMEOUT;
-    Delay  = (UINT32) (DivU64x32 (Timeout, 1000) + 1);
-    do {
-      Offset = FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET;
-
-      Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_PIO_SETUP, 0);
-      if (!EFI_ERROR (Status)) {
-        Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
-        PortTfd = AhciReadReg (AhciBar, (UINT32) Offset);
-        //
-        // PxTFD will be updated if there is a D2H or SetupFIS received.
-        // For PIO IN transfer, D2H means a device error. Therefore we only need to check the TFD after receiving a SetupFIS.
-        //
-        if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {
-          Status = EFI_DEVICE_ERROR;
-          break;
-        }
-
-        PrdCount = *(volatile UINT32 *) (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));
-        if (PrdCount == DataCount) {
-          break;
-        }
-      }
-
-      Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
-      Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, 0);
-      if (!EFI_ERROR (Status)) {
-        Status = EFI_DEVICE_ERROR;
-        break;
-      }
-
-      //
-      // Stall for 100 microseconds.
-      //
-      MicroSecondDelay(100);
-
-      Delay--;
-    } while (Delay > 0);
-  } else {
-    //
-    // Wait for D2H Fis is received
-    //
-    Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
-    Status = AhciWaitMemSet (
-               Offset,
-               EFI_AHCI_FIS_TYPE_MASK,
-               EFI_AHCI_FIS_REGISTER_D2H,
-               Timeout
-               );
-
-    if (EFI_ERROR (Status)) {
-      goto Exit;
-    }
-
-    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
-    PortTfd = AhciReadReg (AhciBar, (UINT32) Offset);
-    if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {
-      Status = EFI_DEVICE_ERROR;
-    }
-  }
-
-Exit:
-  AhciStopCommand (
-    AhciBar,
-    Port,
-    Timeout
-    );
-
-  AhciDisableFisReceive (
-    AhciBar,
-    Port,
-    Timeout
-    );
-
-  Offset    = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;
-  AhciWriteReg (AhciBar, Offset, OldRfisLo);
-  Offset    = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;
-  AhciWriteReg (AhciBar, Offset, OldRfisHi);
-
-  Offset    = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;
-  AhciWriteReg (AhciBar, Offset, OldCmdListLo);
-  Offset    = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;
-  AhciWriteReg (AhciBar, Offset, OldCmdListHi);
-
-  return Status;
-}
-
-/**
-  Stop command running for giving port
-
-  @param  AhciBar            AHCI bar address.
-  @param  Port               The number of port.
-  @param  Timeout            The timeout Value of stop.
-
-  @retval EFI_DEVICE_ERROR   The command stop unsuccessfully.
-  @retval EFI_TIMEOUT        The operation is time out.
-  @retval EFI_SUCCESS        The command stop successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-AhciStopCommand (
-  IN  UINT32                    AhciBar,
-  IN  UINT8                     Port,
-  IN  UINT64                    Timeout
-  )
-{
-  UINT32 Offset;
-  UINT32 Data;
-
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
-  Data   = AhciReadReg (AhciBar, Offset);
-
-  if ((Data & (EFI_AHCI_PORT_CMD_ST |  EFI_AHCI_PORT_CMD_CR)) == 0) {
-    return EFI_SUCCESS;
-  }
-
-  if ((Data & EFI_AHCI_PORT_CMD_ST) != 0) {
-    AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_ST));
-  }
-
-  return AhciWaitMmioSet (
-           AhciBar,
-           Offset,
-           EFI_AHCI_PORT_CMD_CR,
-           0,
-           Timeout
-           );
-}
-
-/**
-  Start command for give slot on specific port.
-
-  @param  AhciBar            AHCI bar address.
-  @param  Port               The number of port.
-  @param  CommandSlot        The number of CommandSlot.
-  @param  Timeout            The timeout Value of start.
-
-  @retval EFI_DEVICE_ERROR   The command start unsuccessfully.
-  @retval EFI_TIMEOUT        The operation is time out.
-  @retval EFI_SUCCESS        The command start successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-AhciStartCommand (
-  IN  UINT32                    AhciBar,
-  IN  UINT8                     Port,
-  IN  UINT8                     CommandSlot,
-  IN  UINT64                    Timeout
-  )
-{
-  UINT32                        CmdSlotBit;
-  EFI_STATUS                    Status;
-  UINT32                        PortStatus;
-  UINT32                        StartCmd;
-  UINT32                        PortTfd;
-  UINT32                        Offset;
-  UINT32                        Capability;
-
-  //
-  // Collect AHCI controller information
-  //
-  Capability = AhciReadReg(AhciBar, EFI_AHCI_CAPABILITY_OFFSET);
-
-  CmdSlotBit = (UINT32) (1 << CommandSlot);
-
-  AhciClearPortStatus (
-    AhciBar,
-    Port
-    );
-
-  Status = AhciEnableFisReceive (
-             AhciBar,
-             Port,
-             Timeout
-             );
-
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
-  PortStatus = AhciReadReg (AhciBar, Offset);
-
-  StartCmd = 0;
-  if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) != 0) {
-    StartCmd = AhciReadReg (AhciBar, Offset);
-    StartCmd &= ~EFI_AHCI_PORT_CMD_ICC_MASK;
-    StartCmd |= EFI_AHCI_PORT_CMD_ACTIVE;
-  }
-
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
-  PortTfd = AhciReadReg (AhciBar, Offset);
-
-  if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) != 0) {
-    if ((Capability & BIT24) != 0) {
-      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
-      AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_COL);
-
-      AhciWaitMmioSet (
-        AhciBar,
-        Offset,
-        EFI_AHCI_PORT_CMD_COL,
-        0,
-        Timeout
-        );
-    }
-  }
-
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
-  AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_ST | StartCmd);
-
-  //
-  // Setting the command
-  //
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SACT;
-  AhciAndReg (AhciBar, Offset, 0);
-  AhciOrReg (AhciBar, Offset, CmdSlotBit);
-
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;
-  AhciAndReg (AhciBar, Offset, 0);
-  AhciOrReg (AhciBar, Offset, CmdSlotBit);
-  return EFI_SUCCESS;
-}
-
-
-/**
-  Do AHCI HBA reset.
-
-  @param[in]  AhciBar        AHCI bar address.
-  @param[in]  Timeout        The timeout Value of reset.
-
-  @retval EFI_DEVICE_ERROR   AHCI controller is failed to complete hardware reset.
-  @retval EFI_TIMEOUT        The reset operation is time out.
-  @retval EFI_SUCCESS        AHCI controller is reset successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-AhciReset (
-  IN  UINT32                    AhciBar,
-  IN  UINT64                    Timeout
-  )
-{
-  UINT32                 Delay;
-  UINT32                 Value;
-  UINT32                 Capability;
-
-  //
-  // Collect AHCI controller information
-  //
-  Capability = AhciReadReg (AhciBar, EFI_AHCI_CAPABILITY_OFFSET);
-
-  //
-  // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only is not set
-  //
-  if ((Capability & EFI_AHCI_CAP_SAM) == 0) {
-    AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);
-  }
-
-  AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);
-
-  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
-
-  do {
-    Value = AhciReadReg(AhciBar, EFI_AHCI_GHC_OFFSET);
-    if ((Value & EFI_AHCI_GHC_RESET) == 0) {
-      return EFI_SUCCESS;
-    }
-
-    //
-    // Stall for 100 microseconds.
-    //
-    MicroSecondDelay(100);
-
-    Delay--;
-  } while (Delay > 0);
-
-  return EFI_TIMEOUT;
-
-
-}
-
-/**
-  Allocate transfer-related data struct which is used at AHCI mode.
-
-  @param[in, out] AhciContext   The pointer to the AHCI_CONTEXT.
-
-  @retval EFI_OUT_OF_RESOURCE   No enough resource.
-  @retval EFI_SUCCESS           Successful to allocate resource.
-
-**/
-EFI_STATUS
-EFIAPI
-AhciAllocateResource (
-  IN OUT AHCI_CONTEXT       *AhciContext
-  )
-{
-  EFI_STATUS                Status;
-  EFI_AHCI_REGISTERS        *AhciRegisters;
-  EFI_PHYSICAL_ADDRESS      DeviceAddress;
-  VOID                      *Base;
-  VOID                      *Mapping;
-
-  AhciRegisters = &AhciContext->AhciRegisters;
-
-  //
-  // Allocate resources required by AHCI host controller.
-  //
-  Status = IoMmuAllocateBuffer (
-             EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
-             &Base,
-             &DeviceAddress,
-             &Mapping
-             );
-  if (EFI_ERROR (Status)) {
-    return EFI_OUT_OF_RESOURCES;
-  }
-  ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
-  AhciRegisters->AhciRFisMapping = Mapping;
-  AhciRegisters->AhciRFis = Base;
-  ZeroMem (AhciRegisters->AhciRFis, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)));
-
-  Status = IoMmuAllocateBuffer (
-             EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),
-             &Base,
-             &DeviceAddress,
-             &Mapping
-             );
-  if (EFI_ERROR (Status)) {
-    IoMmuFreeBuffer (
-       EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
-       AhciRegisters->AhciRFis,
-       AhciRegisters->AhciRFisMapping
-       );
-    AhciRegisters->AhciRFis = NULL;
-    return EFI_OUT_OF_RESOURCES;
-  }
-  ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
-  AhciRegisters->AhciCmdListMapping = Mapping;
-  AhciRegisters->AhciCmdList = Base;
-  ZeroMem (AhciRegisters->AhciCmdList, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)));
-
-  Status = IoMmuAllocateBuffer (
-             EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)),
-             &Base,
-             &DeviceAddress,
-             &Mapping
-             );
-  if (EFI_ERROR (Status)) {
-    IoMmuFreeBuffer (
-       EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),
-       AhciRegisters->AhciCmdList,
-       AhciRegisters->AhciCmdListMapping
-       );
-    AhciRegisters->AhciCmdList = NULL;
-    IoMmuFreeBuffer (
-       EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
-       AhciRegisters->AhciRFis,
-       AhciRegisters->AhciRFisMapping
-       );
-    AhciRegisters->AhciRFis = NULL;
-    return EFI_OUT_OF_RESOURCES;
-  }
-  ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
-  AhciRegisters->AhciCommandTableMapping = Mapping;
-  AhciRegisters->AhciCommandTable = Base;
-  ZeroMem (AhciRegisters->AhciCommandTable, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)));
-
-  //
-  // Allocate resources for data transfer.
-  //
-  Status = IoMmuAllocateBuffer (
-             EFI_SIZE_TO_PAGES (HDD_PAYLOAD),
-             &Base,
-             &DeviceAddress,
-             &Mapping
-             );
-  if (EFI_ERROR (Status)) {
-    IoMmuFreeBuffer (
-       EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
-       AhciRegisters->AhciCommandTable,
-       AhciRegisters->AhciCommandTableMapping
-       );
-    AhciRegisters->AhciCommandTable = NULL;
-    IoMmuFreeBuffer (
-       EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),
-       AhciRegisters->AhciCmdList,
-       AhciRegisters->AhciCmdListMapping
-       );
-    AhciRegisters->AhciCmdList = NULL;
-    IoMmuFreeBuffer (
-       EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
-       AhciRegisters->AhciRFis,
-       AhciRegisters->AhciRFisMapping
-       );
-    AhciRegisters->AhciRFis = NULL;
-    return EFI_OUT_OF_RESOURCES;
-  }
-  ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
-  AhciContext->BufferMapping = Mapping;
-  AhciContext->Buffer = Base;
-  ZeroMem (AhciContext->Buffer, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (HDD_PAYLOAD));
-
-  DEBUG ((
-    DEBUG_INFO,
-    "%a() AhciContext 0x%x 0x%x 0x%x 0x%x\n",
-    __FUNCTION__,
-    AhciContext->Buffer,
-    AhciRegisters->AhciRFis,
-    AhciRegisters->AhciCmdList,
-    AhciRegisters->AhciCommandTable
-    ));
-  return EFI_SUCCESS;
-}
-
-/**
-  Free allocated transfer-related data struct which is used at AHCI mode.
-
-  @param[in, out] AhciContext   The pointer to the AHCI_CONTEXT.
-
-**/
-VOID
-EFIAPI
-AhciFreeResource (
-  IN OUT AHCI_CONTEXT       *AhciContext
-  )
-{
-  EFI_AHCI_REGISTERS        *AhciRegisters;
-
-  AhciRegisters = &AhciContext->AhciRegisters;
-
-  if (AhciContext->Buffer != NULL) {
-    IoMmuFreeBuffer (
-       EFI_SIZE_TO_PAGES (HDD_PAYLOAD),
-       AhciContext->Buffer,
-       AhciContext->BufferMapping
-       );
-    AhciContext->Buffer = NULL;
-  }
-
-  if (AhciRegisters->AhciCommandTable != NULL) {
-    IoMmuFreeBuffer (
-       EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)),
-       AhciRegisters->AhciCommandTable,
-       AhciRegisters->AhciCommandTableMapping
-       );
-    AhciRegisters->AhciCommandTable = NULL;
-  }
-
-  if (AhciRegisters->AhciCmdList != NULL) {
-    IoMmuFreeBuffer (
-       EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),
-       AhciRegisters->AhciCmdList,
-       AhciRegisters->AhciCmdListMapping
-       );
-    AhciRegisters->AhciCmdList = NULL;
-  }
-
-  if (AhciRegisters->AhciRFis != NULL) {
-    IoMmuFreeBuffer (
-       EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
-       AhciRegisters->AhciRFis,
-       AhciRegisters->AhciRFisMapping
-       );
-    AhciRegisters->AhciRFis = NULL;
-  }
-}
-
-/**
-  Initialize ATA host controller at AHCI mode.
-
-  The function is designed to initialize ATA host controller.
-
-  @param[in]  AhciContext   The pointer to the AHCI_CONTEXT.
-  @param[in]  Port          The port number to do initialization.
-
-**/
-EFI_STATUS
-EFIAPI
-AhciModeInitialize (
-  IN AHCI_CONTEXT    *AhciContext,
-  IN UINT8           Port
-  )
-{
-  EFI_STATUS         Status;
-  EFI_AHCI_REGISTERS *AhciRegisters;
-  UINT32             AhciBar;
-  UINT32             Capability;
-  UINT32             Offset;
-  UINT32             Data;
-  UINT32             PhyDetectDelay;
-
-  AhciRegisters = &AhciContext->AhciRegisters;
-  AhciBar = AhciContext->AhciBar;
-
-  Status = AhciReset (AhciBar, ATA_TIMEOUT);
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  //
-  // Collect AHCI controller information
-  //
-  Capability = AhciReadReg (AhciBar, EFI_AHCI_CAPABILITY_OFFSET);
-
-  //
-  // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only is not set
-  //
-  if ((Capability & EFI_AHCI_CAP_SAM) == 0) {
-    AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);
-  }
-
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;
-  AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciRFis);
-
-  //
-  // Single task envrionment, we only use one command table for all port
-  //
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;
-  AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciCmdList);
-
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
-  Data = AhciReadReg (AhciBar, Offset);
-  if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) {
-    AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_POD);
-  }
-
-  if ((Capability & BIT27) != 0) {
-    AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_SUD);
-  }
-
-  //
-  // Disable aggressive power management.
-  //
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;
-  AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_SCTL_IPM_INIT);
-  //
-  // Disable the reporting of the corresponding interrupt to system software.
-  //
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;
-  AhciAndReg (AhciBar, Offset, 0);
-
-  Status = AhciEnableFisReceive (
-             AhciBar,
-             Port,
-             5000000
-             );
-  ASSERT_EFI_ERROR (Status);
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  //
-  // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ
-  // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.
-  //
-  PhyDetectDelay = 16 * 1000;
-  do {
-    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;
-    if (AhciReadReg(AhciBar, Offset) != 0) {
-      AhciWriteReg (AhciBar, Offset, AhciReadReg(AhciBar, Offset));
-    }
-    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
-
-    Data = AhciReadReg (AhciBar, Offset) & EFI_AHCI_PORT_TFD_MASK;
-    if (Data == 0) {
-      break;
-    }
-
-    MicroSecondDelay (1000);
-    PhyDetectDelay--;
-  } while (PhyDetectDelay > 0);
-
-  if (PhyDetectDelay == 0) {
-    return EFI_NOT_FOUND;
-  }
-
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;
-  Status = AhciWaitMmioSet (
-             AhciBar,
-             Offset,
-             0x0000FFFF,
-             0x00000101,
-             160000000
-             );
-
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  return Status;
-}
-
diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c b/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c
index 734c5f06ff..5433638cca 100644
--- a/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c
+++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c
@@ -2,7 +2,7 @@
   Entrypoint of Opal UEFI Driver and contains all the logic to
   register for new Opal device instances.
 
-Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
 This program and the accompanying materials
 are licensed and made available under the terms and conditions of the BSD License
 which accompanies this distribution.  The full text of the license may be found at
@@ -21,40 +21,13 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include "OpalDriver.h"
 #include "OpalHii.h"
 
-EFI_GUID mOpalDeviceAtaGuid = OPAL_DEVICE_ATA_GUID;
-EFI_GUID mOpalDeviceNvmeGuid = OPAL_DEVICE_NVME_GUID;
+EFI_GUID mOpalDeviceLockBoxGuid = OPAL_DEVICE_LOCKBOX_GUID;
 
 BOOLEAN                 mOpalEndOfDxe = FALSE;
 OPAL_REQUEST_VARIABLE   *mOpalRequestVariable = NULL;
 UINTN                   mOpalRequestVariableSize = 0;
 CHAR16                  mPopUpString[100];
 
-typedef struct {
-  UINT32                   Address;
-  S3_BOOT_SCRIPT_LIB_WIDTH Width;
-} OPAL_HC_PCI_REGISTER_SAVE;
-
-//
-// To unlock the Intel SATA controller at S3 Resume, restored the following registers.
-//
-const OPAL_HC_PCI_REGISTER_SAVE mSataHcRegisterSaveTemplate[] = {
-  {0x9,  S3BootScriptWidthUint8},
-  {0x10, S3BootScriptWidthUint32},
-  {0x14, S3BootScriptWidthUint32},
-  {0x18, S3BootScriptWidthUint32},
-  {0x1C, S3BootScriptWidthUint32},
-  {0x20, S3BootScriptWidthUint32},
-  {0x24, S3BootScriptWidthUint32},
-  {0x3c, S3BootScriptWidthUint8},
-  {0x3d, S3BootScriptWidthUint8},
-  {0x40, S3BootScriptWidthUint16},
-  {0x42, S3BootScriptWidthUint16},
-  {0x92, S3BootScriptWidthUint16},
-  {0x94, S3BootScriptWidthUint32},
-  {0x9C, S3BootScriptWidthUint32},
-  {0x4,  S3BootScriptWidthUint16},
-};
-
 OPAL_DRIVER mOpalDriver;
 
 //
@@ -233,14 +206,12 @@ OpalSupportUpdatePassword (
   @param[out] DevInfoLength     Device information length needed.
   @param[out] DevInfo           Device information extracted.
 
-  @return Device type.
-
 **/
-UINT8
+VOID
 ExtractDeviceInfoFromDevicePath (
   IN  EFI_DEVICE_PATH_PROTOCOL  *DevicePath,
   OUT UINT16                    *DevInfoLength,
-  OUT OPAL_DEVICE_COMMON        *DevInfo OPTIONAL
+  OUT OPAL_DEVICE_LOCKBOX_DATA  *DevInfo OPTIONAL
   )
 {
   EFI_DEVICE_PATH_PROTOCOL      *TmpDevPath;
@@ -249,10 +220,6 @@ ExtractDeviceInfoFromDevicePath (
   UINT8                         DeviceType;
   UINT8                         BusNum;
   OPAL_PCI_DEVICE               *PciDevice;
-  OPAL_DEVICE_ATA               *DevInfoAta;
-  OPAL_DEVICE_NVME              *DevInfoNvme;
-  SATA_DEVICE_PATH              *SataDevPath;
-  NVME_NAMESPACE_DEVICE_PATH    *NvmeDevPath;
 
   ASSERT (DevicePath != NULL);
   ASSERT (DevInfoLength != NULL);
@@ -266,30 +233,15 @@ ExtractDeviceInfoFromDevicePath (
   // Get device type.
   //
   while (!IsDevicePathEnd (TmpDevPath)) {
-    if (TmpDevPath->Type == MESSAGING_DEVICE_PATH && TmpDevPath->SubType == MSG_SATA_DP) {
-      //
-      // SATA
-      //
-      if (DevInfo != NULL) {
-        SataDevPath = (SATA_DEVICE_PATH *) TmpDevPath;
-        DevInfoAta = (OPAL_DEVICE_ATA *) DevInfo;
-        DevInfoAta->Port = SataDevPath->HBAPortNumber;
-        DevInfoAta->PortMultiplierPort = SataDevPath->PortMultiplierPortNumber;
-      }
-      DeviceType = OPAL_DEVICE_TYPE_ATA;
-      *DevInfoLength = sizeof (OPAL_DEVICE_ATA);
-      break;
-    } else if (TmpDevPath->Type == MESSAGING_DEVICE_PATH && TmpDevPath->SubType == MSG_NVME_NAMESPACE_DP) {
-      //
-      // NVMe
-      //
+    if ((TmpDevPath->Type == MESSAGING_DEVICE_PATH) &&
+        (TmpDevPath->SubType == MSG_SATA_DP || TmpDevPath->SubType == MSG_NVME_NAMESPACE_DP)) {
       if (DevInfo != NULL) {
-        NvmeDevPath = (NVME_NAMESPACE_DEVICE_PATH *) TmpDevPath;
-        DevInfoNvme = (OPAL_DEVICE_NVME *) DevInfo;
-        DevInfoNvme->NvmeNamespaceId = NvmeDevPath->NamespaceId;
+        DevInfo->DevicePathLength = (UINT16) GetDevicePathSize (DevicePath);
+        CopyMem (DevInfo->DevicePath, DevicePath, DevInfo->DevicePathLength);
       }
-      DeviceType = OPAL_DEVICE_TYPE_NVME;
-      *DevInfoLength = sizeof (OPAL_DEVICE_NVME);
+
+      DeviceType = (TmpDevPath->SubType == MSG_SATA_DP) ? OPAL_DEVICE_TYPE_ATA : OPAL_DEVICE_TYPE_NVME;
+      *DevInfoLength = sizeof (OPAL_DEVICE_LOCKBOX_DATA) + (UINT16) GetDevicePathSize (DevicePath);
       break;
     }
     TmpDevPath = NextDevicePathNode (TmpDevPath);
@@ -304,8 +256,8 @@ ExtractDeviceInfoFromDevicePath (
   while (!IsDevicePathEnd (TmpDevPath2)) {
     if (TmpDevPath->Type == HARDWARE_DEVICE_PATH && TmpDevPath->SubType == HW_PCI_DP) {
       PciDevPath = (PCI_DEVICE_PATH *) TmpDevPath;
-      if ((TmpDevPath2->Type == MESSAGING_DEVICE_PATH && TmpDevPath2->SubType == MSG_NVME_NAMESPACE_DP)||
-          (TmpDevPath2->Type == MESSAGING_DEVICE_PATH && TmpDevPath2->SubType == MSG_SATA_DP)) {
+      if ((TmpDevPath2->Type == MESSAGING_DEVICE_PATH) &&
+          (TmpDevPath2->SubType == MSG_SATA_DP || TmpDevPath2->SubType == MSG_NVME_NAMESPACE_DP)) {
         if (DevInfo != NULL) {
           PciDevice = &DevInfo->Device;
           PciDevice->Segment = 0;
@@ -314,14 +266,6 @@ ExtractDeviceInfoFromDevicePath (
           PciDevice->Function = PciDevPath->Function;
         }
       } else {
-        if (DevInfo != NULL) {
-          PciDevice = (OPAL_PCI_DEVICE *) ((UINTN) DevInfo + *DevInfoLength);
-          PciDevice->Segment = 0;
-          PciDevice->Bus = BusNum;
-          PciDevice->Device = PciDevPath->Device;
-          PciDevice->Function = PciDevPath->Function;
-        }
-        *DevInfoLength += sizeof (OPAL_PCI_DEVICE);
         if (TmpDevPath2->Type == HARDWARE_DEVICE_PATH && TmpDevPath2->SubType == HW_PCI_DP) {
           BusNum = PciRead8 (PCI_LIB_ADDRESS (BusNum, PciDevPath->Device, PciDevPath->Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));
         }
@@ -333,245 +277,149 @@ ExtractDeviceInfoFromDevicePath (
   }
 
   ASSERT (DeviceType != OPAL_DEVICE_TYPE_UNKNOWN);
-  return DeviceType;
+  return;
 }
 
 /**
-  Save boot script for ATA OPAL device.
-
-  @param[in] DevInfo    Pointer to ATA Opal device information.
+  Build OPAL device info and save them to LockBox.
 
  **/
 VOID
-OpalDeviceAtaSaveBootScript (
-  IN OPAL_DEVICE_ATA    *DevInfo
-  )
-{
-  UINTN                         Bus;
-  UINTN                         Device;
-  UINTN                         Function;
-  UINTN                         Index;
-  EFI_STATUS                    Status;
-  UINTN                         Offset;
-  UINT64                        Address;
-  S3_BOOT_SCRIPT_LIB_WIDTH      Width;
-  UINT32                        Data;
-  OPAL_HC_PCI_REGISTER_SAVE     *HcRegisterSaveListPtr;
-  UINTN                         Count;
-
-  Data = 0;
-
-  Bus        = DevInfo->Device.Bus;
-  Device     = DevInfo->Device.Device;
-  Function   = DevInfo->Device.Function;
-
-  HcRegisterSaveListPtr = (OPAL_HC_PCI_REGISTER_SAVE *) mSataHcRegisterSaveTemplate;
-  Count = sizeof (mSataHcRegisterSaveTemplate) / sizeof (OPAL_HC_PCI_REGISTER_SAVE);
-
-  for (Index = 0; Index < Count; Index++) {
-    Offset  = HcRegisterSaveListPtr[Index].Address;
-    Width   = HcRegisterSaveListPtr[Index].Width;
-
-    switch (Width) {
-      case S3BootScriptWidthUint8:
-        Data = (UINT32)PciRead8 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));
-        break;
-      case S3BootScriptWidthUint16:
-        Data = (UINT32)PciRead16 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));
-        break;
-      case S3BootScriptWidthUint32:
-        Data = PciRead32 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));
-        break;
-      default:
-        ASSERT (FALSE);
-        break;
-    }
-
-    Address = S3_BOOT_SCRIPT_LIB_PCI_ADDRESS (Bus, Device, Function, Offset);
-    Status  = S3BootScriptSavePciCfgWrite (Width, Address, 1, &Data);
-    ASSERT_EFI_ERROR (Status);
-  }
-}
-
-/**
-  Build ATA OPAL device info and save them to LockBox.
-
-  @param[in] BarAddr    Bar address allocated.
-
- **/
-VOID
-BuildOpalDeviceInfoAta (
-  IN UINT32     BarAddr
+BuildOpalDeviceInfo (
+  VOID
   )
 {
-  EFI_STATUS            Status;
-  UINT8                 DeviceType;
-  OPAL_DEVICE_ATA       *DevInfoAta;
-  OPAL_DEVICE_ATA       *TempDevInfoAta;
-  UINTN                 DevInfoLengthAta;
-  UINT16                DevInfoLength;
-  OPAL_DRIVER_DEVICE    *TmpDev;
+  EFI_STATUS                  Status;
+  OPAL_DEVICE_LOCKBOX_DATA    *DevInfo;
+  OPAL_DEVICE_LOCKBOX_DATA    *TempDevInfo;
+  UINTN                       TotalDevInfoLength;
+  UINT16                      DevInfoLength;
+  OPAL_DRIVER_DEVICE          *TmpDev;
+  UINT8                       DummyData;
+  BOOLEAN                     S3InitDevicesExist;
+  UINTN                       S3InitDevicesLength;
+  EFI_DEVICE_PATH_PROTOCOL    *S3InitDevices;
+  EFI_DEVICE_PATH_PROTOCOL    *S3InitDevicesBak;
 
   //
-  // Build ATA OPAL device info and save them to LockBox.
+  // Build OPAL device info and save them to LockBox.
   //
-  DevInfoLengthAta = 0;
+  TotalDevInfoLength = 0;
   TmpDev = mOpalDriver.DeviceList;
   while (TmpDev != NULL) {
-    DeviceType = ExtractDeviceInfoFromDevicePath (
-                   TmpDev->OpalDisk.OpalDevicePath,
-                   &DevInfoLength,
-                   NULL
-                   );
-    if (DeviceType == OPAL_DEVICE_TYPE_ATA) {
-      DevInfoLengthAta += DevInfoLength;
-    }
-
+    ExtractDeviceInfoFromDevicePath (
+      TmpDev->OpalDisk.OpalDevicePath,
+      &DevInfoLength,
+      NULL
+      );
+    TotalDevInfoLength += DevInfoLength;
     TmpDev = TmpDev->Next;
   }
 
-  if (DevInfoLengthAta == 0) {
+  if (TotalDevInfoLength == 0) {
     return;
   }
 
-  DevInfoAta = AllocateZeroPool (DevInfoLengthAta);
-  ASSERT (DevInfoAta != NULL);
-
-  TempDevInfoAta = DevInfoAta;
-  TmpDev = mOpalDriver.DeviceList;
-  while (TmpDev != NULL) {
-    DeviceType = ExtractDeviceInfoFromDevicePath (
-                   TmpDev->OpalDisk.OpalDevicePath,
-                   &DevInfoLength,
-                   NULL
-                   );
-    if (DeviceType == OPAL_DEVICE_TYPE_ATA) {
-      ExtractDeviceInfoFromDevicePath (
-        TmpDev->OpalDisk.OpalDevicePath,
-        &DevInfoLength,
-        (OPAL_DEVICE_COMMON *) TempDevInfoAta
-        );
-      TempDevInfoAta->Length = DevInfoLength;
-      TempDevInfoAta->OpalBaseComId = TmpDev->OpalDisk.OpalBaseComId;
-      TempDevInfoAta->BarAddr = BarAddr;
-      CopyMem (
-        TempDevInfoAta->Password,
-        TmpDev->OpalDisk.Password,
-        TmpDev->OpalDisk.PasswordLength
-        );
-      TempDevInfoAta->PasswordLength = TmpDev->OpalDisk.PasswordLength;
-      OpalDeviceAtaSaveBootScript (TempDevInfoAta);
-      TempDevInfoAta = (OPAL_DEVICE_ATA *) ((UINTN) TempDevInfoAta + DevInfoLength);
-    }
-
-    TmpDev = TmpDev->Next;
-  }
-
-  Status = SaveLockBox (
-             &mOpalDeviceAtaGuid,
-             DevInfoAta,
-             DevInfoLengthAta
+  S3InitDevicesLength = sizeof (DummyData);
+  Status = RestoreLockBox (
+             &gS3StorageDeviceInitListGuid,
+             &DummyData,
+             &S3InitDevicesLength
              );
-  ASSERT_EFI_ERROR (Status);
-
-  Status = SetLockBoxAttributes (
-             &mOpalDeviceAtaGuid,
-             LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY
-             );
-  ASSERT_EFI_ERROR (Status);
-
-  ZeroMem (DevInfoAta, DevInfoLengthAta);
-  FreePool (DevInfoAta);
-}
-
-/**
-  Build NVMe OPAL device info and save them to LockBox.
-
-  @param[in] BarAddr    Bar address allocated.
-
- **/
-VOID
-BuildOpalDeviceInfoNvme (
-  IN UINT32     BarAddr
-  )
-{
-  EFI_STATUS            Status;
-  UINT8                 DeviceType;
-  OPAL_DEVICE_NVME      *DevInfoNvme;
-  OPAL_DEVICE_NVME      *TempDevInfoNvme;
-  UINTN                 DevInfoLengthNvme;
-  UINT16                DevInfoLength;
-  OPAL_DRIVER_DEVICE    *TmpDev;
-
-  //
-  // Build NVMe OPAL device info and save them to LockBox.
-  //
-  DevInfoLengthNvme = 0;
-  TmpDev = mOpalDriver.DeviceList;
-  while (TmpDev != NULL) {
-    DeviceType = ExtractDeviceInfoFromDevicePath (
-                   TmpDev->OpalDisk.OpalDevicePath,
-                   &DevInfoLength,
-                   NULL
-                   );
-    if (DeviceType == OPAL_DEVICE_TYPE_NVME) {
-      DevInfoLengthNvme += DevInfoLength;
-    }
-
-    TmpDev = TmpDev->Next;
-  }
-
-  if (DevInfoLengthNvme == 0) {
+  ASSERT ((Status == EFI_NOT_FOUND) || (Status == EFI_BUFFER_TOO_SMALL));
+  if (Status == EFI_NOT_FOUND) {
+    S3InitDevices      = NULL;
+    S3InitDevicesExist = FALSE;
+  } else if (Status == EFI_BUFFER_TOO_SMALL) {
+    S3InitDevices = AllocatePool (S3InitDevicesLength);
+    ASSERT (S3InitDevices != NULL);
+
+    Status = RestoreLockBox (
+               &gS3StorageDeviceInitListGuid,
+               S3InitDevices,
+               &S3InitDevicesLength
+               );
+    ASSERT_EFI_ERROR (Status);
+    S3InitDevicesExist = TRUE;
+  } else {
     return;
   }
 
-  DevInfoNvme = AllocateZeroPool (DevInfoLengthNvme);
-  ASSERT (DevInfoNvme != NULL);
+  DevInfo = AllocateZeroPool (TotalDevInfoLength);
+  ASSERT (DevInfo != NULL);
 
-  TempDevInfoNvme = DevInfoNvme;
-  TmpDev = mOpalDriver.DeviceList;
+  TempDevInfo = DevInfo;
+  TmpDev      = mOpalDriver.DeviceList;
   while (TmpDev != NULL) {
-    DeviceType = ExtractDeviceInfoFromDevicePath (
-                   TmpDev->OpalDisk.OpalDevicePath,
-                   &DevInfoLength,
-                   NULL
-                   );
-    if (DeviceType == OPAL_DEVICE_TYPE_NVME) {
-      ExtractDeviceInfoFromDevicePath (
-        TmpDev->OpalDisk.OpalDevicePath,
-        &DevInfoLength,
-        (OPAL_DEVICE_COMMON *) TempDevInfoNvme
-        );
-      TempDevInfoNvme->Length = DevInfoLength;
-      TempDevInfoNvme->OpalBaseComId = TmpDev->OpalDisk.OpalBaseComId;
-      TempDevInfoNvme->BarAddr = BarAddr;
-      CopyMem (
-        TempDevInfoNvme->Password,
-        TmpDev->OpalDisk.Password,
-        TmpDev->OpalDisk.PasswordLength
-        );
-      TempDevInfoNvme->PasswordLength = TmpDev->OpalDisk.PasswordLength;
-      TempDevInfoNvme = (OPAL_DEVICE_NVME *) ((UINTN) TempDevInfoNvme + DevInfoLength);
+    ExtractDeviceInfoFromDevicePath (
+      TmpDev->OpalDisk.OpalDevicePath,
+      &DevInfoLength,
+      TempDevInfo
+      );
+    TempDevInfo->Length = DevInfoLength;
+    TempDevInfo->OpalBaseComId = TmpDev->OpalDisk.OpalBaseComId;
+    CopyMem (
+      TempDevInfo->Password,
+      TmpDev->OpalDisk.Password,
+      TmpDev->OpalDisk.PasswordLength
+      );
+    TempDevInfo->PasswordLength = TmpDev->OpalDisk.PasswordLength;
+
+    S3InitDevicesBak = S3InitDevices;
+    S3InitDevices    = AppendDevicePathInstance (
+                         S3InitDevicesBak,
+                         TmpDev->OpalDisk.OpalDevicePath
+                         );
+    if (S3InitDevicesBak != NULL) {
+      FreePool (S3InitDevicesBak);
     }
+    ASSERT (S3InitDevices != NULL);
 
+    TempDevInfo = (OPAL_DEVICE_LOCKBOX_DATA *) ((UINTN) TempDevInfo + DevInfoLength);
     TmpDev = TmpDev->Next;
   }
 
   Status = SaveLockBox (
-             &mOpalDeviceNvmeGuid,
-             DevInfoNvme,
-             DevInfoLengthNvme
+             &mOpalDeviceLockBoxGuid,
+             DevInfo,
+             TotalDevInfoLength
              );
   ASSERT_EFI_ERROR (Status);
 
   Status = SetLockBoxAttributes (
-             &mOpalDeviceNvmeGuid,
+             &mOpalDeviceLockBoxGuid,
              LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY
              );
   ASSERT_EFI_ERROR (Status);
 
-  ZeroMem (DevInfoNvme, DevInfoLengthNvme);
-  FreePool (DevInfoNvme);
+  S3InitDevicesLength = GetDevicePathSize (S3InitDevices);
+  if (S3InitDevicesExist) {
+    Status = UpdateLockBox (
+               &gS3StorageDeviceInitListGuid,
+               0,
+               S3InitDevices,
+               S3InitDevicesLength
+               );
+    ASSERT_EFI_ERROR (Status);
+  } else {
+    Status = SaveLockBox (
+               &gS3StorageDeviceInitListGuid,
+               S3InitDevices,
+               S3InitDevicesLength
+               );
+    ASSERT_EFI_ERROR (Status);
+
+    Status = SetLockBoxAttributes (
+               &gS3StorageDeviceInitListGuid,
+               LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY
+               );
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  ZeroMem (DevInfo, TotalDevInfoLength);
+  FreePool (DevInfo);
+  ZeroMem (S3InitDevices, S3InitDevicesLength);
+  FreePool (S3InitDevices);
 }
 
 /**
@@ -590,9 +438,6 @@ OpalEndOfDxeEventNotify (
   VOID                                    *Context
   )
 {
-  EFI_STATUS            Status;
-  EFI_PHYSICAL_ADDRESS  Address;
-  UINT64                Length;
   OPAL_DRIVER_DEVICE    *TmpDev;
 
   DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));
@@ -617,24 +462,7 @@ OpalEndOfDxeEventNotify (
     return;
   }
 
-  //
-  // Assume 64K size and alignment are enough.
-  //
-  Length = 0x10000;
-  Address = 0xFFFFFFFF;
-  Status = gDS->AllocateMemorySpace (
-                  EfiGcdAllocateMaxAddressSearchBottomUp,
-                  EfiGcdMemoryTypeMemoryMappedIo,
-                  16,                             // 2^16: 64K Alignment
-                  Length,
-                  &Address,
-                  gImageHandle,
-                  NULL
-                  );
-  ASSERT_EFI_ERROR (Status);
-
-  BuildOpalDeviceInfoAta ((UINT32) Address);
-  BuildOpalDeviceInfoNvme ((UINT32) Address);
+  BuildOpalDeviceInfo ();
 
   //
   // Zero passsword.
diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.c b/SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.c
deleted file mode 100644
index 01c316d597..0000000000
--- a/SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.c
+++ /dev/null
@@ -1,1823 +0,0 @@
-/** @file
-  Provide functions to initialize NVME controller and perform NVME commands
-
-Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution.  The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-#include "OpalPasswordPei.h"
-
-
-#define ALIGN(v, a)                         (UINTN)((((v) - 1) | ((a) - 1)) + 1)
-
-///
-/// NVME Host controller registers operation
-///
-#define NVME_GET_CAP(Nvme, Cap)             NvmeMmioRead  (Cap, Nvme->Nbar + NVME_CAP_OFFSET, sizeof (NVME_CAP))
-#define NVME_GET_CC(Nvme, Cc)               NvmeMmioRead  (Cc, Nvme->Nbar + NVME_CC_OFFSET, sizeof (NVME_CC))
-#define NVME_SET_CC(Nvme, Cc)               NvmeMmioWrite (Nvme->Nbar + NVME_CC_OFFSET, Cc, sizeof (NVME_CC))
-#define NVME_GET_CSTS(Nvme, Csts)           NvmeMmioRead  (Csts, Nvme->Nbar + NVME_CSTS_OFFSET, sizeof (NVME_CSTS))
-#define NVME_GET_AQA(Nvme, Aqa)             NvmeMmioRead  (Aqa, Nvme->Nbar + NVME_AQA_OFFSET, sizeof (NVME_AQA))
-#define NVME_SET_AQA(Nvme, Aqa)             NvmeMmioWrite (Nvme->Nbar + NVME_AQA_OFFSET, Aqa, sizeof (NVME_AQA))
-#define NVME_GET_ASQ(Nvme, Asq)             NvmeMmioRead  (Asq, Nvme->Nbar + NVME_ASQ_OFFSET, sizeof (NVME_ASQ))
-#define NVME_SET_ASQ(Nvme, Asq)             NvmeMmioWrite (Nvme->Nbar + NVME_ASQ_OFFSET, Asq, sizeof (NVME_ASQ))
-#define NVME_GET_ACQ(Nvme, Acq)             NvmeMmioRead  (Acq, Nvme->Nbar + NVME_ACQ_OFFSET, sizeof (NVME_ACQ))
-#define NVME_SET_ACQ(Nvme, Acq)             NvmeMmioWrite (Nvme->Nbar + NVME_ACQ_OFFSET, Acq, sizeof (NVME_ACQ))
-#define NVME_GET_VER(Nvme, Ver)             NvmeMmioRead  (Ver, Nvme->Nbar + NVME_VER_OFFSET, sizeof (NVME_VER))
-#define NVME_SET_SQTDBL(Nvme, Qid, Sqtdbl)  NvmeMmioWrite (Nvme->Nbar + NVME_SQTDBL_OFFSET(Qid, Nvme->Cap.Dstrd), Sqtdbl, sizeof (NVME_SQTDBL))
-#define NVME_SET_CQHDBL(Nvme, Qid, Cqhdbl)  NvmeMmioWrite (Nvme->Nbar + NVME_CQHDBL_OFFSET(Qid, Nvme->Cap.Dstrd), Cqhdbl, sizeof (NVME_CQHDBL))
-
-///
-/// Base memory address
-///
-enum {
-  BASEMEM_CONTROLLER_DATA,
-  BASEMEM_IDENTIFY_DATA,
-  BASEMEM_ASQ,
-  BASEMEM_ACQ,
-  BASEMEM_SQ,
-  BASEMEM_CQ,
-  BASEMEM_PRP,
-  BASEMEM_SECURITY,
-  MAX_BASEMEM_COUNT
-};
-
-///
-/// All of base memories are 4K(0x1000) alignment
-///
-#define NVME_MEM_BASE(Nvme)                 ((UINTN)(Nvme->BaseMem))
-#define NVME_CONTROL_DATA_BASE(Nvme)        (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_CONTROLLER_DATA))                        * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
-#define NVME_NAMESPACE_DATA_BASE(Nvme)      (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_IDENTIFY_DATA))                          * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
-#define NVME_ASQ_BASE(Nvme)                 (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_ASQ))                                    * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
-#define NVME_ACQ_BASE(Nvme)                 (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_ACQ))                                    * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
-#define NVME_SQ_BASE(Nvme, index)           (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_SQ) + ((index)*(NVME_MAX_IO_QUEUES-1)))  * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
-#define NVME_CQ_BASE(Nvme, index)           (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_CQ) + ((index)*(NVME_MAX_IO_QUEUES-1)))  * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
-#define NVME_PRP_BASE(Nvme, index)          (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_PRP) + ((index)*NVME_PRP_SIZE))          * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
-#define NVME_SEC_BASE(Nvme)                 (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_SECURITY))                               * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
-
-/**
-  Transfer MMIO Data to memory.
-
-  @param[in,out] MemBuffer - Destination: Memory address
-  @param[in] MmioAddr      - Source: MMIO address
-  @param[in] Size          - Size for read
-
-  @retval EFI_SUCCESS - MMIO read sucessfully
-**/
-EFI_STATUS
-NvmeMmioRead (
-  IN OUT VOID *MemBuffer,
-  IN     UINTN MmioAddr,
-  IN     UINTN Size
-  )
-{
-  UINTN  Offset;
-  UINT8  Data;
-  UINT8  *Ptr;
-
-  // priority has adjusted
-  switch (Size) {
-    case 4:
-      *((UINT32 *)MemBuffer) = MmioRead32 (MmioAddr);
-      break;
-
-    case 8:
-      *((UINT64 *)MemBuffer) = MmioRead64 (MmioAddr);
-      break;
-
-    case 2:
-      *((UINT16 *)MemBuffer) = MmioRead16 (MmioAddr);
-      break;
-
-    case 1:
-      *((UINT8 *)MemBuffer) = MmioRead8 (MmioAddr);
-      break;
-
-    default:
-      Ptr = (UINT8 *)MemBuffer;
-      for (Offset = 0; Offset < Size; Offset += 1) {
-        Data = MmioRead8 (MmioAddr + Offset);
-        Ptr[Offset] = Data;
-      }
-      break;
-  }
-
-  return EFI_SUCCESS;
-}
-
-/**
-  Transfer memory data to MMIO.
-
-  @param[in,out] MmioAddr - Destination: MMIO address
-  @param[in] MemBuffer    - Source: Memory address
-  @param[in] Size         - Size for write
-
-  @retval EFI_SUCCESS - MMIO write sucessfully
-**/
-EFI_STATUS
-NvmeMmioWrite (
-  IN OUT UINTN MmioAddr,
-  IN     VOID *MemBuffer,
-  IN     UINTN Size
-  )
-{
-  UINTN  Offset;
-  UINT8  Data;
-  UINT8  *Ptr;
-
-  // priority has adjusted
-  switch (Size) {
-    case 4:
-      MmioWrite32 (MmioAddr, *((UINT32 *)MemBuffer));
-      break;
-
-    case 8:
-      MmioWrite64 (MmioAddr, *((UINT64 *)MemBuffer));
-      break;
-
-    case 2:
-      MmioWrite16 (MmioAddr, *((UINT16 *)MemBuffer));
-      break;
-
-    case 1:
-      MmioWrite8 (MmioAddr, *((UINT8 *)MemBuffer));
-      break;
-
-    default:
-      Ptr = (UINT8 *)MemBuffer;
-      for (Offset = 0; Offset < Size; Offset += 1) {
-        Data = Ptr[Offset];
-        MmioWrite8 (MmioAddr + Offset, Data);
-      }
-      break;
-  }
-
-  return EFI_SUCCESS;
-}
-
-/**
-  Transfer MMIO data to memory.
-
-  @param[in,out] MemBuffer - Destination: Memory address
-  @param[in] MmioAddr      - Source: MMIO address
-  @param[in] Size          - Size for read
-
-  @retval EFI_SUCCESS - MMIO read sucessfully
-**/
-EFI_STATUS
-OpalPciRead (
-  IN OUT VOID *MemBuffer,
-  IN     UINTN MmioAddr,
-  IN     UINTN Size
-  )
-{
-  UINTN  Offset;
-  UINT8  Data;
-  UINT8  *Ptr;
-
-  // priority has adjusted
-  switch (Size) {
-    case 4:
-      *((UINT32 *)MemBuffer) = PciRead32 (MmioAddr);
-      break;
-
-    case 2:
-      *((UINT16 *)MemBuffer) = PciRead16 (MmioAddr);
-      break;
-
-    case 1:
-      *((UINT8 *)MemBuffer) = PciRead8 (MmioAddr);
-      break;
-
-    default:
-      Ptr = (UINT8 *)MemBuffer;
-      for (Offset = 0; Offset < Size; Offset += 1) {
-        Data = PciRead8 (MmioAddr + Offset);
-        Ptr[Offset] = Data;
-      }
-      break;
-  }
-
-  return EFI_SUCCESS;
-}
-
-/**
-  Transfer memory data to MMIO.
-
-  @param[in,out] MmioAddr - Destination: MMIO address
-  @param[in] MemBuffer    - Source: Memory address
-  @param[in] Size         - Size for write
-
-  @retval EFI_SUCCESS - MMIO write sucessfully
-**/
-EFI_STATUS
-OpalPciWrite (
-  IN OUT UINTN MmioAddr,
-  IN     VOID *MemBuffer,
-  IN     UINTN Size
-  )
-{
-  UINTN  Offset;
-  UINT8  Data;
-  UINT8  *Ptr;
-
-  // priority has adjusted
-  switch (Size) {
-    case 4:
-      PciWrite32 (MmioAddr, *((UINT32 *)MemBuffer));
-      break;
-
-    case 2:
-      PciWrite16 (MmioAddr, *((UINT16 *)MemBuffer));
-      break;
-
-    case 1:
-      PciWrite8 (MmioAddr, *((UINT8 *)MemBuffer));
-      break;
-
-    default:
-      Ptr = (UINT8 *)MemBuffer;
-      for (Offset = 0; Offset < Size; Offset += 1) {
-        Data = Ptr[Offset];
-        PciWrite8 (MmioAddr + Offset, Data);
-      }
-      break;
-  }
-
-  return EFI_SUCCESS;
-}
-
-/**
-  Get total pages for specific NVME based memory.
-
-  @param[in] BaseMemIndex           - The Index of BaseMem (0-based).
-
-  @retval - The page count for specific BaseMem Index
-
-**/
-UINT32
-NvmeGetBaseMemPages (
-  IN UINTN              BaseMemIndex
-  )
-{
-  UINT32                Pages;
-  UINTN                 Index;
-  UINT32                PageSizeList[8];
-
-  PageSizeList[0] = 1;  /* Controller Data */
-  PageSizeList[1] = 1;  /* Identify Data */
-  PageSizeList[2] = 1;  /* ASQ */
-  PageSizeList[3] = 1;  /* ACQ */
-  PageSizeList[4] = 1;  /* SQs */
-  PageSizeList[5] = 1;  /* CQs */
-  PageSizeList[6] = NVME_PRP_SIZE * NVME_CSQ_DEPTH;  /* PRPs */
-  PageSizeList[7] = 1;  /* Security Commands */
-
-  if (BaseMemIndex > MAX_BASEMEM_COUNT) {
-    ASSERT (FALSE);
-    return 0;
-  }
-
-  Pages = 0;
-  for (Index = 0; Index < BaseMemIndex; Index++) {
-    Pages += PageSizeList[Index];
-  }
-
-  return Pages;
-}
-
-/**
-  Wait for NVME controller status to be ready or not.
-
-  @param[in] Nvme                   - The pointer to the NVME_CONTEXT Data structure.
-  @param[in] WaitReady              - Flag for waitting status ready or not
-
-  @return EFI_SUCCESS               - Successfully to wait specific status.
-  @return others                    - Fail to wait for specific controller status.
-
-**/
-STATIC
-EFI_STATUS
-NvmeWaitController (
-  IN NVME_CONTEXT       *Nvme,
-  IN BOOLEAN            WaitReady
-  )
-{
-  NVME_CSTS              Csts;
-  EFI_STATUS             Status;
-  UINT32                 Index;
-  UINT8                  Timeout;
-
-  //
-  // Cap.To specifies max delay time in 500ms increments for Csts.Rdy to set after
-  // Cc.Enable. Loop produces a 1 millisecond delay per itteration, up to 500 * Cap.To.
-  //
-  if (Nvme->Cap.To == 0) {
-    Timeout = 1;
-  } else {
-    Timeout = Nvme->Cap.To;
-  }
-
-  Status = EFI_SUCCESS;
-  for(Index = (Timeout * 500); Index != 0; --Index) {
-    MicroSecondDelay (1000);
-
-    //
-    // Check if the controller is initialized
-    //
-    Status = NVME_GET_CSTS (Nvme, &Csts);
-    if (EFI_ERROR(Status)) {
-      DEBUG ((DEBUG_ERROR, "NVME_GET_CSTS fail, Status = %r\n", Status));
-      return Status;
-    }
-
-    if ((BOOLEAN) Csts.Rdy == WaitReady) {
-      break;
-    }
-  }
-
-  if (Index == 0) {
-    Status = EFI_TIMEOUT;
-  }
-
-  return Status;
-}
-
-/**
-  Disable the Nvm Express controller.
-
-  @param[in] Nvme                   - The pointer to the NVME_CONTEXT Data structure.
-
-  @return EFI_SUCCESS               - Successfully disable the controller.
-  @return others                    - Fail to disable the controller.
-
-**/
-STATIC
-EFI_STATUS
-NvmeDisableController (
-  IN NVME_CONTEXT       *Nvme
-  )
-{
-  NVME_CC                Cc;
-  NVME_CSTS              Csts;
-  EFI_STATUS             Status;
-
-  Status = NVME_GET_CSTS (Nvme, &Csts);
-
-  ///
-  /// Read Controller Configuration Register.
-  ///
-  Status = NVME_GET_CC (Nvme, &Cc);
-  if (EFI_ERROR(Status)) {
-    DEBUG ((DEBUG_ERROR, "NVME_GET_CC fail, Status = %r\n", Status));
-    goto Done;
-  }
-
-  if (Cc.En == 1) {
-    Cc.En = 0;
-    ///
-    /// Disable the controller.
-    ///
-    Status = NVME_SET_CC (Nvme, &Cc);
-    if (EFI_ERROR(Status)) {
-      DEBUG ((DEBUG_ERROR, "NVME_SET_CC fail, Status = %r\n", Status));
-      goto Done;
-    }
-  }
-
-  Status = NvmeWaitController (Nvme, FALSE);
-  if (EFI_ERROR(Status)) {
-    DEBUG ((DEBUG_ERROR, "NvmeWaitController fail, Status = %r\n", Status));
-    goto Done;
-  }
-
-  return EFI_SUCCESS;
-
-Done:
-  DEBUG ((DEBUG_INFO, "NvmeDisableController fail, Status: %r\n", Status));
-  return Status;
-}
-
-/**
-  Enable the Nvm Express controller.
-
-  @param[in] Nvme                   - The pointer to the NVME_CONTEXT Data structure.
-
-  @return EFI_SUCCESS               - Successfully enable the controller.
-  @return EFI_DEVICE_ERROR          - Fail to enable the controller.
-  @return EFI_TIMEOUT               - Fail to enable the controller in given time slot.
-
-**/
-STATIC
-EFI_STATUS
-NvmeEnableController (
-  IN NVME_CONTEXT       *Nvme
-  )
-{
-  NVME_CC                Cc;
-  EFI_STATUS             Status;
-
-  //
-  // Enable the controller
-  //
-  ZeroMem (&Cc, sizeof (NVME_CC));
-  Cc.En     = 1;
-  Cc.Iosqes = 6;
-  Cc.Iocqes = 4;
-  Status    = NVME_SET_CC (Nvme, &Cc);
-  if (EFI_ERROR(Status)) {
-    DEBUG ((DEBUG_ERROR, "NVME_SET_CC fail, Status = %r\n", Status));
-    goto Done;
-  }
-
-  Status = NvmeWaitController (Nvme, TRUE);
-  if (EFI_ERROR(Status)) {
-    DEBUG ((DEBUG_ERROR, "NvmeWaitController fail, Status = %r\n", Status));
-    goto Done;
-  }
-
-  return EFI_SUCCESS;
-
-Done:
-  DEBUG ((DEBUG_INFO, "NvmeEnableController fail, Status: %r\n", Status));
-  return Status;
-}
-
-/**
-  Shutdown the Nvm Express controller.
-
-  @param[in] Nvme                   - The pointer to the NVME_CONTEXT Data structure.
-
-  @return EFI_SUCCESS               - Successfully shutdown the controller.
-  @return EFI_DEVICE_ERROR          - Fail to shutdown the controller.
-  @return EFI_TIMEOUT               - Fail to shutdown the controller in given time slot.
-
-**/
-STATIC
-EFI_STATUS
-NvmeShutdownController (
-  IN NVME_CONTEXT       *Nvme
-  )
-{
-  NVME_CC                Cc;
-  NVME_CSTS              Csts;
-  EFI_STATUS             Status;
-  UINT32                 Index;
-  UINTN                  Timeout;
-
-  Status    = NVME_GET_CC (Nvme, &Cc);
-  if (EFI_ERROR(Status)) {
-    DEBUG ((DEBUG_ERROR, "NVME_GET_CC fail, Status = %r\n", Status));
-    return Status;
-  }
-
-  Cc.Shn     = 1; // Normal shutdown
-
-  Status    = NVME_SET_CC (Nvme, &Cc);
-  if (EFI_ERROR(Status)) {
-    DEBUG ((DEBUG_ERROR, "NVME_SET_CC fail, Status = %r\n", Status));
-    return Status;
-  }
-
-  Timeout = NVME_GENERIC_TIMEOUT/1000; // ms
-  for(Index = (UINT32)(Timeout); Index != 0; --Index) {
-    MicroSecondDelay (1000);
-
-    Status = NVME_GET_CSTS (Nvme, &Csts);
-    if (EFI_ERROR(Status)) {
-      DEBUG ((DEBUG_ERROR, "NVME_GET_CSTS fail, Status = %r\n", Status));
-      return Status;
-    }
-
-    if (Csts.Shst == 2) { // Shutdown processing complete
-      break;
-    }
-  }
-
-  if (Index == 0) {
-    Status = EFI_TIMEOUT;
-  }
-
-  return Status;
-}
-
-/**
-  Check the execution status from a given completion queue entry.
-
-  @param[in]     Cq                 - A pointer to the NVME_CQ item.
-
-**/
-EFI_STATUS
-NvmeCheckCqStatus (
-  IN NVME_CQ             *Cq
-  )
-{
-  if (Cq->Sct == 0x0 && Cq->Sc == 0x0) {
-    return EFI_SUCCESS;
-  }
-
-  DEBUG ((DEBUG_INFO, "Dump NVMe Completion Entry Status from [0x%x]:\n", (UINTN)Cq));
-  DEBUG ((DEBUG_INFO, "  SQ Identifier : [0x%x], Phase Tag : [%d], Cmd Identifier : [0x%x]\n", Cq->Sqid, Cq->Pt, Cq->Cid));
-  DEBUG ((DEBUG_INFO, "  NVMe Cmd Execution Result - "));
-
-  switch (Cq->Sct) {
-    case 0x0:
-      switch (Cq->Sc) {
-        case 0x0:
-          DEBUG ((DEBUG_INFO, "Successful Completion\n"));
-          return EFI_SUCCESS;
-        case 0x1:
-          DEBUG ((DEBUG_INFO, "Invalid Command Opcode\n"));
-          break;
-        case 0x2:
-          DEBUG ((DEBUG_INFO, "Invalid Field in Command\n"));
-          break;
-        case 0x3:
-          DEBUG ((DEBUG_INFO, "Command ID Conflict\n"));
-          break;
-        case 0x4:
-          DEBUG ((DEBUG_INFO, "Data Transfer Error\n"));
-          break;
-        case 0x5:
-          DEBUG ((DEBUG_INFO, "Commands Aborted due to Power Loss Notification\n"));
-          break;
-        case 0x6:
-          DEBUG ((DEBUG_INFO, "Internal Device Error\n"));
-          break;
-        case 0x7:
-          DEBUG ((DEBUG_INFO, "Command Abort Requested\n"));
-          break;
-        case 0x8:
-          DEBUG ((DEBUG_INFO, "Command Aborted due to SQ Deletion\n"));
-          break;
-        case 0x9:
-          DEBUG ((DEBUG_INFO, "Command Aborted due to Failed Fused Command\n"));
-          break;
-        case 0xA:
-          DEBUG ((DEBUG_INFO, "Command Aborted due to Missing Fused Command\n"));
-          break;
-        case 0xB:
-          DEBUG ((DEBUG_INFO, "Invalid Namespace or Format\n"));
-          break;
-        case 0xC:
-          DEBUG ((DEBUG_INFO, "Command Sequence Error\n"));
-          break;
-        case 0xD:
-          DEBUG ((DEBUG_INFO, "Invalid SGL Last Segment Descriptor\n"));
-          break;
-        case 0xE:
-          DEBUG ((DEBUG_INFO, "Invalid Number of SGL Descriptors\n"));
-          break;
-        case 0xF:
-          DEBUG ((DEBUG_INFO, "Data SGL Length Invalid\n"));
-          break;
-        case 0x10:
-          DEBUG ((DEBUG_INFO, "Metadata SGL Length Invalid\n"));
-          break;
-        case 0x11:
-          DEBUG ((DEBUG_INFO, "SGL Descriptor Type Invalid\n"));
-          break;
-        case 0x80:
-          DEBUG ((DEBUG_INFO, "LBA Out of Range\n"));
-          break;
-        case 0x81:
-          DEBUG ((DEBUG_INFO, "Capacity Exceeded\n"));
-          break;
-        case 0x82:
-          DEBUG ((DEBUG_INFO, "Namespace Not Ready\n"));
-          break;
-        case 0x83:
-          DEBUG ((DEBUG_INFO, "Reservation Conflict\n"));
-          break;
-      }
-      break;
-
-    case 0x1:
-      switch (Cq->Sc) {
-        case 0x0:
-          DEBUG ((DEBUG_INFO, "Completion Queue Invalid\n"));
-          break;
-        case 0x1:
-          DEBUG ((DEBUG_INFO, "Invalid Queue Identifier\n"));
-          break;
-        case 0x2:
-          DEBUG ((DEBUG_INFO, "Maximum Queue Size Exceeded\n"));
-          break;
-        case 0x3:
-          DEBUG ((DEBUG_INFO, "Abort Command Limit Exceeded\n"));
-          break;
-        case 0x5:
-          DEBUG ((DEBUG_INFO, "Asynchronous Event Request Limit Exceeded\n"));
-          break;
-        case 0x6:
-          DEBUG ((DEBUG_INFO, "Invalid Firmware Slot\n"));
-          break;
-        case 0x7:
-          DEBUG ((DEBUG_INFO, "Invalid Firmware Image\n"));
-          break;
-        case 0x8:
-          DEBUG ((DEBUG_INFO, "Invalid Interrupt Vector\n"));
-          break;
-        case 0x9:
-          DEBUG ((DEBUG_INFO, "Invalid Log Page\n"));
-          break;
-        case 0xA:
-          DEBUG ((DEBUG_INFO, "Invalid Format\n"));
-          break;
-        case 0xB:
-          DEBUG ((DEBUG_INFO, "Firmware Application Requires Conventional Reset\n"));
-          break;
-        case 0xC:
-          DEBUG ((DEBUG_INFO, "Invalid Queue Deletion\n"));
-          break;
-        case 0xD:
-          DEBUG ((DEBUG_INFO, "Feature Identifier Not Saveable\n"));
-          break;
-        case 0xE:
-          DEBUG ((DEBUG_INFO, "Feature Not Changeable\n"));
-          break;
-        case 0xF:
-          DEBUG ((DEBUG_INFO, "Feature Not Namespace Specific\n"));
-          break;
-        case 0x10:
-          DEBUG ((DEBUG_INFO, "Firmware Application Requires NVM Subsystem Reset\n"));
-          break;
-        case 0x80:
-          DEBUG ((DEBUG_INFO, "Conflicting Attributes\n"));
-          break;
-        case 0x81:
-          DEBUG ((DEBUG_INFO, "Invalid Protection Information\n"));
-          break;
-        case 0x82:
-          DEBUG ((DEBUG_INFO, "Attempted Write to Read Only Range\n"));
-          break;
-      }
-      break;
-
-    case 0x2:
-      switch (Cq->Sc) {
-        case 0x80:
-          DEBUG ((DEBUG_INFO, "Write Fault\n"));
-          break;
-        case 0x81:
-          DEBUG ((DEBUG_INFO, "Unrecovered Read Error\n"));
-          break;
-        case 0x82:
-          DEBUG ((DEBUG_INFO, "End-to-end Guard Check Error\n"));
-          break;
-        case 0x83:
-          DEBUG ((DEBUG_INFO, "End-to-end Application Tag Check Error\n"));
-          break;
-        case 0x84:
-          DEBUG ((DEBUG_INFO, "End-to-end Reference Tag Check Error\n"));
-          break;
-        case 0x85:
-          DEBUG ((DEBUG_INFO, "Compare Failure\n"));
-          break;
-        case 0x86:
-          DEBUG ((DEBUG_INFO, "Access Denied\n"));
-          break;
-      }
-      break;
-
-    default:
-      DEBUG ((DEBUG_INFO, "Unknown error\n"));
-      break;
-  }
-
-  return EFI_DEVICE_ERROR;
-}
-
-/**
-  Create PRP lists for Data transfer which is larger than 2 memory pages.
-  Note here we calcuate the number of required PRP lists and allocate them at one time.
-
-  @param[in] Nvme                   - The pointer to the NVME_CONTEXT Data structure.
-  @param[in] SqId                   - The SQ index for this PRP
-  @param[in] PhysicalAddr           - The physical base address of Data Buffer.
-  @param[in] Pages                  - The number of pages to be transfered.
-  @param[out] PrpListHost           - The host base address of PRP lists.
-  @param[in,out] PrpListNo          - The number of PRP List.
-
-  @retval The pointer Value to the first PRP List of the PRP lists.
-
-**/
-STATIC
-UINT64
-NvmeCreatePrpList (
-  IN     NVME_CONTEXT                 *Nvme,
-  IN     UINT16                       SqId,
-  IN     EFI_PHYSICAL_ADDRESS         PhysicalAddr,
-  IN     UINTN                        Pages,
-     OUT VOID                         **PrpListHost,
-  IN OUT UINTN                        *PrpListNo
-  )
-{
-  UINTN                       PrpEntryNo;
-  UINT64                      PrpListBase;
-  UINTN                       PrpListIndex;
-  UINTN                       PrpEntryIndex;
-  UINT64                      Remainder;
-  EFI_PHYSICAL_ADDRESS        PrpListPhyAddr;
-  UINTN                       Bytes;
-  UINT8                       *PrpEntry;
-  EFI_PHYSICAL_ADDRESS        NewPhyAddr;
-
-  ///
-  /// The number of Prp Entry in a memory page.
-  ///
-  PrpEntryNo = EFI_PAGE_SIZE / sizeof (UINT64);
-
-  ///
-  /// Calculate total PrpList number.
-  ///
-  *PrpListNo = (UINTN) DivU64x64Remainder ((UINT64)Pages, (UINT64)PrpEntryNo, &Remainder);
-  if (Remainder != 0) {
-    *PrpListNo += 1;
-  }
-
-  if (*PrpListNo > NVME_PRP_SIZE) {
-    DEBUG ((DEBUG_INFO, "NvmeCreatePrpList (PhysicalAddr: %lx, Pages: %x) PrpEntryNo: %x\n",
-      PhysicalAddr, Pages, PrpEntryNo));
-    DEBUG ((DEBUG_INFO, "*PrpListNo: %x, Remainder: %lx", *PrpListNo, Remainder));
-    ASSERT (FALSE);
-  }
-  *PrpListHost = (VOID *)(UINTN) NVME_PRP_BASE (Nvme, SqId);
-
-  Bytes = EFI_PAGES_TO_SIZE (*PrpListNo);
-  PrpListPhyAddr = (UINT64)(UINTN)(*PrpListHost);
-
-  ///
-  /// Fill all PRP lists except of last one.
-  ///
-  ZeroMem (*PrpListHost, Bytes);
-  for (PrpListIndex = 0; PrpListIndex < *PrpListNo - 1; ++PrpListIndex) {
-    PrpListBase = *(UINT64*)PrpListHost + PrpListIndex * EFI_PAGE_SIZE;
-
-    for (PrpEntryIndex = 0; PrpEntryIndex < PrpEntryNo; ++PrpEntryIndex) {
-      PrpEntry = (UINT8 *)(UINTN) (PrpListBase + PrpEntryIndex * sizeof(UINT64));
-      if (PrpEntryIndex != PrpEntryNo - 1) {
-        ///
-        /// Fill all PRP entries except of last one.
-        ///
-        CopyMem (PrpEntry, (VOID *)(UINTN) (&PhysicalAddr), sizeof (UINT64));
-        PhysicalAddr += EFI_PAGE_SIZE;
-      } else {
-        ///
-        /// Fill last PRP entries with next PRP List pointer.
-        ///
-        NewPhyAddr = (PrpListPhyAddr + (PrpListIndex + 1) * EFI_PAGE_SIZE);
-        CopyMem (PrpEntry, (VOID *)(UINTN) (&NewPhyAddr), sizeof (UINT64));
-      }
-    }
-  }
-
-  ///
-  /// Fill last PRP list.
-  ///
-  PrpListBase = *(UINT64*)PrpListHost + PrpListIndex * EFI_PAGE_SIZE;
-  for (PrpEntryIndex = 0; PrpEntryIndex < ((Remainder != 0) ? Remainder : PrpEntryNo); ++PrpEntryIndex) {
-    PrpEntry = (UINT8 *)(UINTN) (PrpListBase + PrpEntryIndex * sizeof(UINT64));
-    CopyMem (PrpEntry, (VOID *)(UINTN) (&PhysicalAddr), sizeof (UINT64));
-
-    PhysicalAddr += EFI_PAGE_SIZE;
-  }
-
-  return PrpListPhyAddr;
-}
-
-/**
-  Waits until all NVME commands completed.
-
-  @param[in] Nvme                   - The pointer to the NVME_CONTEXT Data structure.
-  @param[in] Qid                    - Queue index
-
-  @retval EFI_SUCCESS               - All NVME commands have completed
-  @retval EFI_TIMEOUT               - Timeout occured
-  @retval EFI_NOT_READY             - Not all NVME commands have completed
-  @retval others                    - Error occurred on device side.
-**/
-EFI_STATUS
-NvmeWaitAllComplete (
-  IN NVME_CONTEXT       *Nvme,
-  IN UINT8              Qid
-  )
-{
-  return EFI_SUCCESS;
-}
-
-/**
-  Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function supports
-  both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the nonblocking
-  I/O functionality is optional.
-
-  @param[in] Nvme                   - The pointer to the NVME_CONTEXT Data structure.
-  @param[in] NamespaceId            - Is a 32 bit Namespace ID to which the Express HCI command packet will be sent.
-                                      A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in the namespace
-                                      ID specifies that the command packet should be sent to all valid namespaces.
-  @param[in] NamespaceUuid          - Is a 64 bit Namespace UUID to which the Express HCI command packet will be sent.
-                                      A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in the namespace
-                                      UUID specifies that the command packet should be sent to all valid namespaces.
-  @param[in,out] Packet             - A pointer to the NVM Express HCI Command Packet to send to the NVMe namespace specified
-                                      by NamespaceId.
-
-  @retval EFI_SUCCESS               - The NVM Express Command Packet was sent by the host. TransferLength bytes were transferred
-                                      to, or from DataBuffer.
-  @retval EFI_NOT_READY             - The NVM Express Command Packet could not be sent because the controller is not ready. The caller
-                                      may retry again later.
-  @retval EFI_DEVICE_ERROR          - A device error occurred while attempting to send the NVM Express Command Packet.
-  @retval EFI_INVALID_PARAMETER     - Namespace, or the contents of NVM_EXPRESS_PASS_THRU_COMMAND_PACKET are invalid. The NVM
-                                      Express Command Packet was not sent, so no additional status information is available.
-  @retval EFI_UNSUPPORTED           - The command described by the NVM Express Command Packet is not supported by the host adapter.
-                                      The NVM Express Command Packet was not sent, so no additional status information is available.
-  @retval EFI_TIMEOUT               - A timeout occurred while waiting for the NVM Express Command Packet to execute.
-
-**/
-EFI_STATUS
-NvmePassThru (
-  IN     NVME_CONTEXT                         *Nvme,
-  IN     UINT32                               NamespaceId,
-  IN     UINT64                               NamespaceUuid,
-  IN OUT NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet
-  )
-{
-  EFI_STATUS                    Status;
-  NVME_SQ                       *Sq;
-  NVME_CQ                       *Cq;
-  UINT8                         Qid;
-  UINT32                        Bytes;
-  UINT32                        Offset;
-  EFI_PHYSICAL_ADDRESS          PhyAddr;
-  VOID                          *PrpListHost;
-  UINTN                         PrpListNo;
-  UINT32                        Timer;
-  UINTN SqSize;
-  UINTN CqSize;
-
-  ///
-  /// check the Data fields in Packet parameter.
-  ///
-  if ((Nvme == NULL) || (Packet == NULL)) {
-    DEBUG ((DEBUG_ERROR, "NvmePassThru, invalid parameter: Nvme(%x)/Packet(%x)\n",
-      (UINTN)Nvme, (UINTN)Packet));
-    return EFI_INVALID_PARAMETER;
-  }
-
-  if ((Packet->NvmeCmd == NULL) || (Packet->NvmeResponse == NULL)) {
-    DEBUG ((DEBUG_ERROR, "NvmePassThru, invalid parameter: NvmeCmd(%x)/NvmeResponse(%x)\n",
-      (UINTN)Packet->NvmeCmd, (UINTN)Packet->NvmeResponse));
-    return EFI_INVALID_PARAMETER;
-  }
-
-  if (Packet->QueueId != NVME_ADMIN_QUEUE && Packet->QueueId != NVME_IO_QUEUE) {
-    DEBUG ((DEBUG_ERROR, "NvmePassThru, invalid parameter: QueueId(%x)\n",
-      Packet->QueueId));
-    return EFI_INVALID_PARAMETER;
-  }
-
-  PrpListHost = NULL;
-  PrpListNo   = 0;
-  Status      = EFI_SUCCESS;
-
-  Qid = Packet->QueueId;
-  Sq  = Nvme->SqBuffer[Qid] + Nvme->SqTdbl[Qid].Sqt;
-  Cq  = Nvme->CqBuffer[Qid] + Nvme->CqHdbl[Qid].Cqh;
-  if (Qid == NVME_ADMIN_QUEUE) {
-    SqSize = NVME_ASQ_SIZE + 1;
-    CqSize = NVME_ACQ_SIZE + 1;
-  } else {
-    SqSize = NVME_CSQ_DEPTH;
-    CqSize = NVME_CCQ_DEPTH;
-  }
-
-  if (Packet->NvmeCmd->Nsid != NamespaceId) {
-    DEBUG ((DEBUG_ERROR, "NvmePassThru: Nsid mismatch (%x, %x)\n",
-      Packet->NvmeCmd->Nsid, NamespaceId));
-    return EFI_INVALID_PARAMETER;
-  }
-
-  ZeroMem (Sq, sizeof (NVME_SQ));
-  Sq->Opc  = Packet->NvmeCmd->Cdw0.Opcode;
-  Sq->Fuse = Packet->NvmeCmd->Cdw0.FusedOperation;
-  Sq->Cid  = Packet->NvmeCmd->Cdw0.Cid;
-  Sq->Nsid = Packet->NvmeCmd->Nsid;
-
-  ///
-  /// Currently we only support PRP for Data transfer, SGL is NOT supported.
-  ///
-  ASSERT (Sq->Psdt == 0);
-  if (Sq->Psdt != 0) {
-    DEBUG ((DEBUG_ERROR, "NvmePassThru: doesn't support SGL mechanism\n"));
-    return EFI_UNSUPPORTED;
-  }
-
-  Sq->Prp[0] = Packet->TransferBuffer;
-  Sq->Prp[1] = 0;
-
-  if(Packet->MetadataBuffer != (UINT64)(UINTN)NULL) {
-    Sq->Mptr = Packet->MetadataBuffer;
-  }
-
-  ///
-  /// If the Buffer Size spans more than two memory pages (page Size as defined in CC.Mps),
-  /// then build a PRP list in the second PRP submission queue entry.
-  ///
-  Offset = ((UINT32)Sq->Prp[0]) & (EFI_PAGE_SIZE - 1);
-  Bytes  = Packet->TransferLength;
-
-  if ((Offset + Bytes) > (EFI_PAGE_SIZE * 2)) {
-    ///
-    /// Create PrpList for remaining Data Buffer.
-    ///
-    PhyAddr = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1);
-    Sq->Prp[1] = NvmeCreatePrpList (Nvme, Nvme->SqTdbl[Qid].Sqt, PhyAddr, EFI_SIZE_TO_PAGES(Offset + Bytes) - 1, &PrpListHost, &PrpListNo);
-    if (Sq->Prp[1] == 0) {
-      Status = EFI_OUT_OF_RESOURCES;
-      DEBUG ((DEBUG_ERROR, "NvmeCreatePrpList fail, Status: %r\n", Status));
-      goto EXIT;
-    }
-
-  } else if ((Offset + Bytes) > EFI_PAGE_SIZE) {
-    Sq->Prp[1] = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1);
-  }
-
-  if(Packet->NvmeCmd->Flags & CDW10_VALID) {
-    Sq->Payload.Raw.Cdw10 = Packet->NvmeCmd->Cdw10;
-  }
-  if(Packet->NvmeCmd->Flags & CDW11_VALID) {
-    Sq->Payload.Raw.Cdw11 = Packet->NvmeCmd->Cdw11;
-  }
-  if(Packet->NvmeCmd->Flags & CDW12_VALID) {
-    Sq->Payload.Raw.Cdw12 = Packet->NvmeCmd->Cdw12;
-  }
-  if(Packet->NvmeCmd->Flags & CDW13_VALID) {
-    Sq->Payload.Raw.Cdw13 = Packet->NvmeCmd->Cdw13;
-  }
-  if(Packet->NvmeCmd->Flags & CDW14_VALID) {
-    Sq->Payload.Raw.Cdw14 = Packet->NvmeCmd->Cdw14;
-  }
-  if(Packet->NvmeCmd->Flags & CDW15_VALID) {
-    Sq->Payload.Raw.Cdw15 = Packet->NvmeCmd->Cdw15;
-  }
-
-  ///
-  /// Ring the submission queue doorbell.
-  ///
-  Nvme->SqTdbl[Qid].Sqt++;
-  if(Nvme->SqTdbl[Qid].Sqt == SqSize) {
-    Nvme->SqTdbl[Qid].Sqt = 0;
-  }
-  Status = NVME_SET_SQTDBL (Nvme, Qid, &Nvme->SqTdbl[Qid]);
-  if (EFI_ERROR(Status)) {
-    DEBUG ((DEBUG_ERROR, "NVME_SET_SQTDBL fail, Status: %r\n", Status));
-    goto EXIT;
-  }
-
-  ///
-  /// Wait for completion queue to get filled in.
-  ///
-  Status = EFI_TIMEOUT;
-  Timer   = 0;
-  while (Timer < NVME_CMD_TIMEOUT) {
-    //DEBUG ((DEBUG_VERBOSE, "Timer: %x, Cq:\n", Timer));
-    //DumpMem (Cq, sizeof (NVME_CQ));
-    if (Cq->Pt != Nvme->Pt[Qid]) {
-      Status = EFI_SUCCESS;
-      break;
-    }
-
-    MicroSecondDelay (NVME_CMD_WAIT);
-    Timer += NVME_CMD_WAIT;
-  }
-
-  Nvme->CqHdbl[Qid].Cqh++;
-  if (Nvme->CqHdbl[Qid].Cqh == CqSize) {
-    Nvme->CqHdbl[Qid].Cqh = 0;
-    Nvme->Pt[Qid] ^= 1;
-  }
-
-  ///
-  /// Copy the Respose Queue entry for this command to the callers response Buffer
-  ///
-  CopyMem (Packet->NvmeResponse, Cq, sizeof(NVM_EXPRESS_RESPONSE));
-
-  if (!EFI_ERROR(Status)) { // We still need to check CQ status if no timeout error occured
-    Status = NvmeCheckCqStatus (Cq);
-  }
-  NVME_SET_CQHDBL (Nvme, Qid, &Nvme->CqHdbl[Qid]);
-
-EXIT:
-  return Status;
-}
-
-/**
-  Get identify controller Data.
-
-  @param[in] Nvme                   - The pointer to the NVME_CONTEXT Data structure.
-  @param[in] Buffer                 - The Buffer used to store the identify controller Data.
-
-  @return EFI_SUCCESS               - Successfully get the identify controller Data.
-  @return others                    - Fail to get the identify controller Data.
-
-**/
-STATIC
-EFI_STATUS
-NvmeIdentifyController (
-  IN NVME_CONTEXT                          *Nvme,
-  IN VOID                                  *Buffer
-  )
-{
-  NVM_EXPRESS_PASS_THRU_COMMAND_PACKET     CommandPacket;
-  NVM_EXPRESS_COMMAND                      Command;
-  NVM_EXPRESS_RESPONSE                     Response;
-  EFI_STATUS                               Status;
-
-  ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
-  ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
-  ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
-
-  Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_OPC;
-  Command.Cdw0.Cid    = Nvme->Cid[NVME_ADMIN_QUEUE]++;
-  //
-  // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.
-  // For the Identify command, the Namespace Identifier is only used for the Namespace Data structure.
-  //
-  Command.Nsid        = 0;
-
-  CommandPacket.NvmeCmd        = &Command;
-  CommandPacket.NvmeResponse   = &Response;
-  CommandPacket.TransferBuffer = (UINT64)(UINTN)Buffer;
-  CommandPacket.TransferLength = sizeof (NVME_ADMIN_CONTROLLER_DATA);
-  CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
-  CommandPacket.QueueId        = NVME_ADMIN_QUEUE;
-  //
-  // Set bit 0 (Cns bit) to 1 to identify a controller
-  //
-  Command.Cdw10                = 1;
-  Command.Flags                = CDW10_VALID;
-
-  Status = NvmePassThru (
-              Nvme,
-              NVME_CONTROLLER_ID,
-              0,
-              &CommandPacket
-              );
-  if (!EFI_ERROR (Status)) {
-    Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);
-  }
-
-  return Status;
-}
-
-/**
-  Get specified identify namespace Data.
-
-  @param[in] Nvme                   - The pointer to the NVME_CONTEXT Data structure.
-  @param[in] NamespaceId            - The specified namespace identifier.
-  @param[in] Buffer                 - The Buffer used to store the identify namespace Data.
-
-  @return EFI_SUCCESS               - Successfully get the identify namespace Data.
-  @return others                    - Fail to get the identify namespace Data.
-
-**/
-STATIC
-EFI_STATUS
-NvmeIdentifyNamespace (
-  IN NVME_CONTEXT                          *Nvme,
-  IN UINT32                                NamespaceId,
-  IN VOID                                  *Buffer
-  )
-{
-  NVM_EXPRESS_PASS_THRU_COMMAND_PACKET     CommandPacket;
-  NVM_EXPRESS_COMMAND                      Command;
-  NVM_EXPRESS_RESPONSE                     Response;
-  EFI_STATUS                               Status;
-
-  ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
-  ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
-  ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
-
-  CommandPacket.NvmeCmd      = &Command;
-  CommandPacket.NvmeResponse = &Response;
-
-  Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_OPC;
-  Command.Cdw0.Cid    = Nvme->Cid[NVME_ADMIN_QUEUE]++;
-  Command.Nsid        = NamespaceId;
-  CommandPacket.TransferBuffer = (UINT64)(UINTN)Buffer;
-  CommandPacket.TransferLength = sizeof (NVME_ADMIN_NAMESPACE_DATA);
-  CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
-  CommandPacket.QueueId        = NVME_ADMIN_QUEUE;
-  //
-  // Set bit 0 (Cns bit) to 1 to identify a namespace
-  //
-  CommandPacket.NvmeCmd->Cdw10 = 0;
-  CommandPacket.NvmeCmd->Flags = CDW10_VALID;
-
-  Status = NvmePassThru (
-              Nvme,
-              NamespaceId,
-              0,
-              &CommandPacket
-              );
-  if (!EFI_ERROR (Status)) {
-    Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);
-  }
-
-  return Status;
-}
-
-/**
-  Get Block Size for specific namespace of NVME.
-
-  @param[in] Nvme                   - The pointer to the NVME_CONTEXT Data structure.
-
-  @return                           - Block Size in bytes
-
-**/
-STATIC
-UINT32
-NvmeGetBlockSize (
-  IN NVME_CONTEXT       *Nvme
-  )
-{
-  UINT32                BlockSize;
-  UINT32                Lbads;
-  UINT32                Flbas;
-  UINT32                LbaFmtIdx;
-
-  Flbas     = Nvme->NamespaceData->Flbas;
-  LbaFmtIdx = Flbas & 3;
-  Lbads     = Nvme->NamespaceData->LbaFormat[LbaFmtIdx].Lbads;
-
-  BlockSize = (UINT32)1 << Lbads;
-  return BlockSize;
-}
-
-/**
-  Get last LBA for specific namespace of NVME.
-
-  @param[in] Nvme                   - The pointer to the NVME_CONTEXT Data structure.
-
-  @return                           - Last LBA address
-
-**/
-STATIC
-EFI_LBA
-NvmeGetLastLba (
-  IN NVME_CONTEXT       *Nvme
-  )
-{
-  EFI_LBA               LastBlock;
-  LastBlock = Nvme->NamespaceData->Nsze - 1;
-  return LastBlock;
-}
-
-/**
-  Create io completion queue.
-
-  @param[in] Nvme                   - The pointer to the NVME_CONTEXT Data structure.
-
-  @return EFI_SUCCESS               - Successfully create io completion queue.
-  @return others                    - Fail to create io completion queue.
-
-**/
-STATIC
-EFI_STATUS
-NvmeCreateIoCompletionQueue (
-  IN     NVME_CONTEXT                      *Nvme
-  )
-{
-  NVM_EXPRESS_PASS_THRU_COMMAND_PACKET     CommandPacket;
-  NVM_EXPRESS_COMMAND                      Command;
-  NVM_EXPRESS_RESPONSE                     Response;
-  EFI_STATUS                               Status;
-  NVME_ADMIN_CRIOCQ                        CrIoCq;
-
-  ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
-  ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
-  ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
-  ZeroMem (&CrIoCq, sizeof(NVME_ADMIN_CRIOCQ));
-
-  CommandPacket.NvmeCmd      = &Command;
-  CommandPacket.NvmeResponse = &Response;
-
-  Command.Cdw0.Opcode = NVME_ADMIN_CRIOCQ_OPC;
-  Command.Cdw0.Cid    = Nvme->Cid[NVME_ADMIN_QUEUE]++;
-  CommandPacket.TransferBuffer = (UINT64)(UINTN)Nvme->CqBuffer[NVME_IO_QUEUE];
-  CommandPacket.TransferLength = EFI_PAGE_SIZE;
-  CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
-  CommandPacket.QueueId        = NVME_ADMIN_QUEUE;
-
-  CrIoCq.Qid   = NVME_IO_QUEUE;
-  CrIoCq.Qsize = NVME_CCQ_SIZE;
-  CrIoCq.Pc    = 1;
-  CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoCq, sizeof (NVME_ADMIN_CRIOCQ));
-  CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
-
-  Status = NvmePassThru (
-              Nvme,
-              NVME_CONTROLLER_ID,
-              0,
-              &CommandPacket
-              );
-  if (!EFI_ERROR (Status)) {
-    Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);
-  }
-
-  return Status;
-}
-
-/**
-  Create io submission queue.
-
-  @param[in] Nvme                   - The pointer to the NVME_CONTEXT Data structure.
-
-  @return EFI_SUCCESS               - Successfully create io submission queue.
-  @return others                    - Fail to create io submission queue.
-
-**/
-STATIC
-EFI_STATUS
-NvmeCreateIoSubmissionQueue (
-  IN NVME_CONTEXT                          *Nvme
-  )
-{
-  NVM_EXPRESS_PASS_THRU_COMMAND_PACKET     CommandPacket;
-  NVM_EXPRESS_COMMAND                      Command;
-  NVM_EXPRESS_RESPONSE                     Response;
-  EFI_STATUS                               Status;
-  NVME_ADMIN_CRIOSQ                        CrIoSq;
-
-  ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
-  ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
-  ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
-  ZeroMem (&CrIoSq, sizeof(NVME_ADMIN_CRIOSQ));
-
-  CommandPacket.NvmeCmd      = &Command;
-  CommandPacket.NvmeResponse = &Response;
-
-  Command.Cdw0.Opcode = NVME_ADMIN_CRIOSQ_OPC;
-  Command.Cdw0.Cid    = Nvme->Cid[NVME_ADMIN_QUEUE]++;
-  CommandPacket.TransferBuffer = (UINT64)(UINTN)Nvme->SqBuffer[NVME_IO_QUEUE];
-  CommandPacket.TransferLength = EFI_PAGE_SIZE;
-  CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
-  CommandPacket.QueueId        = NVME_ADMIN_QUEUE;
-
-  CrIoSq.Qid   = NVME_IO_QUEUE;
-  CrIoSq.Qsize = NVME_CSQ_SIZE;
-  CrIoSq.Pc    = 1;
-  CrIoSq.Cqid  = NVME_IO_QUEUE;
-  CrIoSq.Qprio = 0;
-  CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoSq, sizeof (NVME_ADMIN_CRIOSQ));
-  CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
-
-  Status = NvmePassThru (
-              Nvme,
-              NVME_CONTROLLER_ID,
-              0,
-              &CommandPacket
-              );
-  if (!EFI_ERROR (Status)) {
-    Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);
-  }
-
-  return Status;
-}
-
-/**
-  Security send and receive commands.
-
-  @param[in]     Nvme                   - The pointer to the NVME_CONTEXT Data structure.
-  @param[in]     SendCommand            - The flag to indicate the command type, TRUE for Send command and FALSE for receive command
-  @param[in]     SecurityProtocol       - Security Protocol
-  @param[in]     SpSpecific             - Security Protocol Specific
-  @param[in]     TransferLength         - Transfer Length of Buffer (in bytes) - always a multiple of 512
-  @param[in,out] TransferBuffer         - Address of Data to transfer
-
-  @return EFI_SUCCESS               - Successfully create io submission queue.
-  @return others                    - Fail to send/receive commands.
-
-**/
-EFI_STATUS
-NvmeSecuritySendReceive (
-  IN NVME_CONTEXT                          *Nvme,
-  IN BOOLEAN                               SendCommand,
-  IN UINT8                                 SecurityProtocol,
-  IN UINT16                                SpSpecific,
-  IN UINTN                                 TransferLength,
-  IN OUT VOID                              *TransferBuffer
-  )
-{
-  NVM_EXPRESS_PASS_THRU_COMMAND_PACKET     CommandPacket;
-  NVM_EXPRESS_COMMAND                      Command;
-  NVM_EXPRESS_RESPONSE                     Response;
-  EFI_STATUS                               Status;
-  NVME_ADMIN_SECSEND                       SecSend;
-  OACS                                     *Oacs;
-  UINT8                                    Opcode;
-  VOID*                                    *SecBuff;
-
-  Oacs = (OACS *)&Nvme->ControllerData->Oacs;
-
-  //
-  // Verify security bit for Security Send/Receive commands
-  //
-  if (Oacs->Security == 0) {
-    DEBUG ((DEBUG_ERROR, "Security command doesn't support.\n"));
-    return EFI_NOT_READY;
-  }
-
-  SecBuff = (VOID *)(UINTN) NVME_SEC_BASE (Nvme);
-
-  //
-  // Actions for sending security command
-  //
-  if (SendCommand) {
-    CopyMem (SecBuff, TransferBuffer, TransferLength);
-  }
-
-  ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
-  ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
-  ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
-  ZeroMem (&SecSend, sizeof(NVME_ADMIN_SECSEND));
-
-  CommandPacket.NvmeCmd      = &Command;
-  CommandPacket.NvmeResponse = &Response;
-
-  Opcode = (UINT8)(SendCommand ? NVME_ADMIN_SECURITY_SEND_OPC : NVME_ADMIN_SECURITY_RECV_OPC);
-  Command.Cdw0.Opcode = Opcode;
-  Command.Cdw0.Cid    = Nvme->Cid[NVME_ADMIN_QUEUE]++;
-  CommandPacket.TransferBuffer = (UINT64)(UINTN)SecBuff;
-  CommandPacket.TransferLength = (UINT32)TransferLength;
-  CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
-  CommandPacket.QueueId        = NVME_ADMIN_QUEUE;
-
-  SecSend.Spsp = SpSpecific;
-  SecSend.Secp = SecurityProtocol;
-  SecSend.Tl   = (UINT32)TransferLength;
-
-  CopyMem (&CommandPacket.NvmeCmd->Cdw10, &SecSend, sizeof (NVME_ADMIN_SECSEND));
-  CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
-
-  Status = NvmePassThru (
-              Nvme,
-              NVME_CONTROLLER_ID,
-              0,
-              &CommandPacket
-              );
-  if (!EFI_ERROR (Status)) {
-    Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);
-  }
-
-  //
-  // Actions for receiving security command
-  //
-  if (!SendCommand) {
-    CopyMem (TransferBuffer, SecBuff, TransferLength);
-  }
-
-  return Status;
-}
-
-/**
-  Destroy io completion queue.
-
-  @param[in] Nvme                   - The pointer to the NVME_CONTEXT Data structure.
-
-  @return EFI_SUCCESS               - Successfully destroy io completion queue.
-  @return others                    - Fail to destroy io completion queue.
-
-**/
-STATIC
-EFI_STATUS
-NvmeDestroyIoCompletionQueue (
-  IN     NVME_CONTEXT                      *Nvme
-  )
-{
-  NVM_EXPRESS_PASS_THRU_COMMAND_PACKET     CommandPacket;
-  NVM_EXPRESS_COMMAND                      Command;
-  NVM_EXPRESS_RESPONSE                     Response;
-  EFI_STATUS                               Status;
-  NVME_ADMIN_DEIOCQ                        DelIoCq;
-
-  ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
-  ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
-  ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
-  ZeroMem (&DelIoCq, sizeof(NVME_ADMIN_DEIOCQ));
-
-  CommandPacket.NvmeCmd      = &Command;
-  CommandPacket.NvmeResponse = &Response;
-
-  Command.Cdw0.Opcode = NVME_ADMIN_DELIOCQ_OPC;
-  Command.Cdw0.Cid    = Nvme->Cid[NVME_ADMIN_QUEUE]++;
-  CommandPacket.TransferBuffer = (UINT64)(UINTN)Nvme->CqBuffer[NVME_IO_QUEUE];
-  CommandPacket.TransferLength = EFI_PAGE_SIZE;
-  CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
-  CommandPacket.QueueId        = NVME_ADMIN_QUEUE;
-
-  DelIoCq.Qid   = NVME_IO_QUEUE;
-  CopyMem (&CommandPacket.NvmeCmd->Cdw10, &DelIoCq, sizeof (NVME_ADMIN_DEIOCQ));
-  CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
-
-  Status = NvmePassThru (
-              Nvme,
-              NVME_CONTROLLER_ID,
-              0,
-              &CommandPacket
-              );
-  if (!EFI_ERROR (Status)) {
-    Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);
-  }
-
-  return Status;
-}
-
-/**
-  Destroy io submission queue.
-
-  @param[in] Nvme                   - The pointer to the NVME_CONTEXT Data structure.
-
-  @return EFI_SUCCESS               - Successfully destroy io submission queue.
-  @return others                    - Fail to destroy io submission queue.
-
-**/
-STATIC
-EFI_STATUS
-NvmeDestroyIoSubmissionQueue (
-  IN NVME_CONTEXT                          *Nvme
-  )
-{
-  NVM_EXPRESS_PASS_THRU_COMMAND_PACKET     CommandPacket;
-  NVM_EXPRESS_COMMAND                      Command;
-  NVM_EXPRESS_RESPONSE                     Response;
-  EFI_STATUS                               Status;
-  NVME_ADMIN_DEIOSQ                        DelIoSq;
-
-  ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
-  ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
-  ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
-  ZeroMem (&DelIoSq, sizeof(NVME_ADMIN_DEIOSQ));
-
-  CommandPacket.NvmeCmd      = &Command;
-  CommandPacket.NvmeResponse = &Response;
-
-  Command.Cdw0.Opcode = NVME_ADMIN_DELIOSQ_OPC;
-  Command.Cdw0.Cid    = Nvme->Cid[NVME_ADMIN_QUEUE]++;
-  CommandPacket.TransferBuffer = (UINT64)(UINTN)Nvme->SqBuffer[NVME_IO_QUEUE];
-  CommandPacket.TransferLength = EFI_PAGE_SIZE;
-  CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
-  CommandPacket.QueueId        = NVME_ADMIN_QUEUE;
-
-  DelIoSq.Qid   = NVME_IO_QUEUE;
-  CopyMem (&CommandPacket.NvmeCmd->Cdw10, &DelIoSq, sizeof (NVME_ADMIN_DEIOSQ));
-  CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
-
-  Status = NvmePassThru (
-              Nvme,
-              NVME_CONTROLLER_ID,
-              0,
-              &CommandPacket
-              );
-  if (!EFI_ERROR (Status)) {
-    Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);
-  }
-
-  return Status;
-}
-
-/**
-  Allocate transfer-related Data struct which is used at Nvme.
-
-  @param[in, out] Nvme          The pointer to the NVME_CONTEXT Data structure.
-
-  @retval EFI_OUT_OF_RESOURCE   No enough resource.
-  @retval EFI_SUCCESS           Successful to allocate resource.
-
-**/
-EFI_STATUS
-EFIAPI
-NvmeAllocateResource (
-  IN OUT NVME_CONTEXT       *Nvme
-  )
-{
-  EFI_STATUS                Status;
-  EFI_PHYSICAL_ADDRESS      DeviceAddress;
-  VOID                      *Base;
-  VOID                      *Mapping;
-
-  //
-  // Allocate resources for DMA.
-  //
-  Status = IoMmuAllocateBuffer (
-             EFI_SIZE_TO_PAGES (NVME_MEM_MAX_SIZE),
-             &Base,
-             &DeviceAddress,
-             &Mapping
-             );
-  if (EFI_ERROR (Status)) {
-    return EFI_OUT_OF_RESOURCES;
-  }
-  ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
-  Nvme->BaseMemMapping = Mapping;
-  Nvme->BaseMem = Base;
-  ZeroMem (Nvme->BaseMem, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (NVME_MEM_MAX_SIZE));
-
-  DEBUG ((
-    DEBUG_INFO,
-    "%a() NvmeContext 0x%x\n",
-    __FUNCTION__,
-    Nvme->BaseMem
-    ));
-
-  return EFI_SUCCESS;
-}
-
-/**
-  Free allocated transfer-related Data struct which is used at NVMe.
-
-  @param[in, out] Nvme          The pointer to the NVME_CONTEXT Data structure.
-
-**/
-VOID
-EFIAPI
-NvmeFreeResource (
-  IN OUT NVME_CONTEXT       *Nvme
-  )
-{
-  if (Nvme->BaseMem != NULL) {
-    IoMmuFreeBuffer (
-       EFI_SIZE_TO_PAGES (NVME_MEM_MAX_SIZE),
-       Nvme->BaseMem,
-       Nvme->BaseMemMapping
-       );
-    Nvme->BaseMem = NULL;
-  }
-}
-
-/**
-  Initialize the Nvm Express controller.
-
-  @param[in] Nvme                   - The pointer to the NVME_CONTEXT Data structure.
-
-  @retval EFI_SUCCESS               - The NVM Express Controller is initialized successfully.
-  @retval Others                    - A device error occurred while initializing the controller.
-
-**/
-EFI_STATUS
-NvmeControllerInit (
-  IN NVME_CONTEXT       *Nvme
-  )
-{
-  EFI_STATUS            Status;
-  NVME_AQA              Aqa;
-  NVME_ASQ              Asq;
-  NVME_ACQ              Acq;
-  NVME_VER              Ver;
-
-  UINT32                MlBAR;
-  UINT32                MuBAR;
-
-  ///
-  /// Update PCIE BAR0/1 for NVME device
-  ///
-  MlBAR = Nvme->Nbar;
-  MuBAR = 0;
-  PciWrite32 (Nvme->PciBase + 0x10, MlBAR); // MLBAR (BAR0)
-  PciWrite32 (Nvme->PciBase + 0x14, MuBAR); // MUBAR (BAR1)
-
-  ///
-  /// Enable PCIE decode
-  ///
-  PciWrite8 (Nvme->PciBase + NVME_PCIE_PCICMD, 0x6);
-
-  // Version
-  NVME_GET_VER (Nvme, &Ver);
-  if (!(Ver.Mjr == 0x0001) && (Ver.Mnr == 0x0000)) {
-    DEBUG ((DEBUG_INFO, "\n!!!\n!!! NVME Version mismatch for the implementation !!!\n!!!\n"));
-  }
-
-  ///
-  /// Read the Controller Capabilities register and verify that the NVM command set is supported
-  ///
-  Status = NVME_GET_CAP (Nvme, &Nvme->Cap);
-  if (EFI_ERROR (Status)) {
-    DEBUG ((DEBUG_ERROR, "NVME_GET_CAP fail, Status: %r\n", Status));
-    goto Done;
-  }
-
-  if (Nvme->Cap.Css != 0x01) {
-    DEBUG ((DEBUG_ERROR, "NvmeControllerInit fail: the controller doesn't support NVMe command set\n"));
-    Status = EFI_UNSUPPORTED;
-    goto Done;
-  }
-
-  ///
-  /// Currently the driver only supports 4k page Size.
-  ///
-  if ((Nvme->Cap.Mpsmin + 12) > EFI_PAGE_SHIFT) {
-    DEBUG ((DEBUG_ERROR, "NvmeControllerInit fail: only supports 4k page Size\n"));
-    ASSERT (FALSE);
-    Status = EFI_UNSUPPORTED;
-    goto Done;
-  }
-
-  Nvme->Cid[0] = 0;
-  Nvme->Cid[1] = 0;
-
-  Nvme->Pt[0]  = 0;
-  Nvme->Pt[1]  = 0;
-
-  ZeroMem ((VOID *)(UINTN)(&(Nvme->SqTdbl[0])), sizeof (NVME_SQTDBL) * NVME_MAX_IO_QUEUES);
-  ZeroMem ((VOID *)(UINTN)(&(Nvme->CqHdbl[0])), sizeof (NVME_CQHDBL) * NVME_MAX_IO_QUEUES);
-
-  ZeroMem (Nvme->BaseMem, NVME_MEM_MAX_SIZE);
-
-  Status = NvmeDisableController (Nvme);
-  if (EFI_ERROR(Status)) {
-    DEBUG ((DEBUG_ERROR, "NvmeDisableController fail, Status: %r\n", Status));
-    goto Done;
-  }
-
-  ///
-  /// set number of entries admin submission & completion queues.
-  ///
-  Aqa.Asqs  = NVME_ASQ_SIZE;
-  Aqa.Rsvd1 = 0;
-  Aqa.Acqs  = NVME_ACQ_SIZE;
-  Aqa.Rsvd2 = 0;
-
-  ///
-  /// Address of admin submission queue.
-  ///
-  Asq = (UINT64)(UINTN)(NVME_ASQ_BASE (Nvme) & ~0xFFF);
-
-  ///
-  /// Address of admin completion queue.
-  ///
-  Acq = (UINT64)(UINTN)(NVME_ACQ_BASE (Nvme) & ~0xFFF);
-
-  ///
-  /// Address of I/O submission & completion queue.
-  ///
-  Nvme->SqBuffer[0] = (NVME_SQ *)(UINTN)NVME_ASQ_BASE (Nvme);   // NVME_ADMIN_QUEUE
-  Nvme->CqBuffer[0] = (NVME_CQ *)(UINTN)NVME_ACQ_BASE (Nvme);   // NVME_ADMIN_QUEUE
-  Nvme->SqBuffer[1] = (NVME_SQ *)(UINTN)NVME_SQ_BASE (Nvme, 0); // NVME_IO_QUEUE
-  Nvme->CqBuffer[1] = (NVME_CQ *)(UINTN)NVME_CQ_BASE (Nvme, 0); // NVME_IO_QUEUE
-
-  DEBUG ((DEBUG_INFO, "Admin Submission Queue Size (Aqa.Asqs) = [%08X]\n", Aqa.Asqs));
-  DEBUG ((DEBUG_INFO, "Admin Completion Queue Size (Aqa.Acqs) = [%08X]\n", Aqa.Acqs));
-  DEBUG ((DEBUG_INFO, "Admin Submission Queue (SqBuffer[0]) =   [%08X]\n", Nvme->SqBuffer[0]));
-  DEBUG ((DEBUG_INFO, "Admin Completion Queue (CqBuffer[0]) =   [%08X]\n", Nvme->CqBuffer[0]));
-  DEBUG ((DEBUG_INFO, "I/O   Submission Queue (SqBuffer[1]) =   [%08X]\n", Nvme->SqBuffer[1]));
-  DEBUG ((DEBUG_INFO, "I/O   Completion Queue (CqBuffer[1]) =   [%08X]\n", Nvme->CqBuffer[1]));
-
-  ///
-  /// Program admin queue attributes.
-  ///
-  Status = NVME_SET_AQA (Nvme, &Aqa);
-  if (EFI_ERROR(Status)) {
-    goto Done;
-  }
-
-  ///
-  /// Program admin submission queue address.
-  ///
-  Status = NVME_SET_ASQ (Nvme, &Asq);
-  if (EFI_ERROR(Status)) {
-    goto Done;
-  }
-
-  ///
-  /// Program admin completion queue address.
-  ///
-  Status = NVME_SET_ACQ (Nvme, &Acq);
-  if (EFI_ERROR(Status)) {
-    goto Done;
-  }
-
-  Status = NvmeEnableController (Nvme);
-  if (EFI_ERROR(Status)) {
-    goto Done;
-  }
-
-  ///
-  /// Create one I/O completion queue.
-  ///
-  Status = NvmeCreateIoCompletionQueue (Nvme);
-  if (EFI_ERROR(Status)) {
-    goto Done;
-  }
-
-  ///
-  /// Create one I/O Submission queue.
-  ///
-  Status = NvmeCreateIoSubmissionQueue (Nvme);
-  if (EFI_ERROR(Status)) {
-    goto Done;
-  }
-
-  ///
-  /// Get current Identify Controller Data
-  ///
-  Nvme->ControllerData = (NVME_ADMIN_CONTROLLER_DATA *)(UINTN) NVME_CONTROL_DATA_BASE (Nvme);
-  Status = NvmeIdentifyController (Nvme, Nvme->ControllerData);
-  if (EFI_ERROR(Status)) {
-    goto Done;
-  }
-
-  ///
-  /// Dump NvmExpress Identify Controller Data
-  ///
-  Nvme->ControllerData->Sn[19] = 0;
-  Nvme->ControllerData->Mn[39] = 0;
-  //NvmeDumpIdentifyController (Nvme->ControllerData);
-
-  ///
-  /// Get current Identify Namespace Data
-  ///
-  Nvme->NamespaceData = (NVME_ADMIN_NAMESPACE_DATA *)NVME_NAMESPACE_DATA_BASE (Nvme);
-  Status = NvmeIdentifyNamespace (Nvme, Nvme->Nsid, Nvme->NamespaceData);
-  if (EFI_ERROR(Status)) {
-    DEBUG ((DEBUG_ERROR, "NvmeIdentifyNamespace fail, Status = %r\n", Status));
-    goto Done;
-  }
-
-  ///
-  /// Dump NvmExpress Identify Namespace Data
-  ///
-  if (Nvme->NamespaceData->Ncap == 0) {
-    DEBUG ((DEBUG_ERROR, "Invalid Namespace, Ncap: %lx\n", Nvme->NamespaceData->Ncap));
-    Status = EFI_DEVICE_ERROR;
-    goto Done;
-  }
-
-  Nvme->BlockSize = NvmeGetBlockSize (Nvme);
-  Nvme->LastBlock = NvmeGetLastLba (Nvme);
-
-  Nvme->State    = NvmeStatusInit;
-
-  return EFI_SUCCESS;
-
-Done:
-  return Status;
-}
-
-/**
-  Un-initialize the Nvm Express controller.
-
-  @param[in] Nvme                   - The pointer to the NVME_CONTEXT Data structure.
-
-  @retval EFI_SUCCESS               - The NVM Express Controller is un-initialized successfully.
-  @retval Others                    - A device error occurred while un-initializing the controller.
-
-**/
-EFI_STATUS
-NvmeControllerExit (
-  IN NVME_CONTEXT       *Nvme
-  )
-{
-  EFI_STATUS            Status;
-
-  Status = EFI_SUCCESS;
-  if (Nvme->State == NvmeStatusInit || Nvme->State == NvmeStatusMax) {
-    ///
-    /// Destroy I/O Submission queue.
-    ///
-    Status = NvmeDestroyIoSubmissionQueue (Nvme);
-    if (EFI_ERROR(Status)) {
-      DEBUG ((DEBUG_ERROR, "NvmeDestroyIoSubmissionQueue fail, Status = %r\n", Status));
-      return Status;
-    }
-
-    ///
-    /// Destroy I/O completion queue.
-    ///
-    Status = NvmeDestroyIoCompletionQueue (Nvme);
-    if (EFI_ERROR(Status)) {
-      DEBUG ((DEBUG_ERROR, "NvmeDestroyIoCompletionQueue fail, Status = %r\n", Status));
-      return Status;
-    }
-
-    Status = NvmeShutdownController (Nvme);
-    if (EFI_ERROR(Status)) {
-      DEBUG ((DEBUG_ERROR, "NvmeShutdownController fail, Status: %r\n", Status));
-    }
-  }
-
-  ///
-  /// Disable PCIE decode
-  ///
-  PciWrite8  (Nvme->PciBase + NVME_PCIE_PCICMD, 0x0);
-  PciWrite32 (Nvme->PciBase + 0x10, 0); // MLBAR (BAR0)
-  PciWrite32 (Nvme->PciBase + 0x14, 0); // MUBAR (BAR1)
-
-  Nvme->State = NvmeStatusUnknown;
-  return Status;
-}
diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.c b/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.c
index edb47ca8bc..4d78a6a4ed 100644
--- a/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.c
+++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.c
@@ -1,7 +1,7 @@
 /** @file
   Opal Password PEI driver which is used to unlock Opal Password for S3.
 
-Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
 This program and the accompanying materials
 are licensed and made available under the terms and conditions of the BSD License
 which accompanies this distribution.  The full text of the license may be found at
@@ -14,249 +14,34 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 
 #include "OpalPasswordPei.h"
 
-EFI_GUID mOpalDeviceAtaGuid = OPAL_DEVICE_ATA_GUID;
-EFI_GUID mOpalDeviceNvmeGuid = OPAL_DEVICE_NVME_GUID;
-
-#define OPAL_PCIE_ROOTPORT_SAVESIZE               (0x40)
-#define STORE_INVALID_ROOTPORT_INDEX              ((UINT8) -1)
+EFI_GUID mOpalDeviceLockBoxGuid = OPAL_DEVICE_LOCKBOX_GUID;
 
 /**
-  Get IOMMU PPI.
+  Tell whether the input EDKII_PEI_STORAGE_SECURITY_CMD_PPI instance has already
+  been handled by the Opal PEI driver.
 
-  @return Pointer to IOMMU PPI.
+  @param[in] Private        Pointer to the Opal PEI driver private data.
+  @param[in] SscInstance    Pointer to the EDKII_PEI_STORAGE_SECURITY_CMD_PPI.
 
-**/
-EDKII_IOMMU_PPI *
-GetIoMmu (
-  VOID
-  )
-{
-  EFI_STATUS                Status;
-  EDKII_IOMMU_PPI           *IoMmu;
-
-  IoMmu = NULL;
-  Status = PeiServicesLocatePpi (
-             &gEdkiiIoMmuPpiGuid,
-             0,
-             NULL,
-             (VOID **) &IoMmu
-             );
-  if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
-    return IoMmu;
-  }
-
-  return NULL;
-}
-
-/**
-  Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
-  OperationBusMasterCommonBuffer64 mapping.
-
-  @param Pages                  The number of pages to allocate.
-  @param HostAddress            A pointer to store the base system memory address of the
-                                allocated range.
-  @param DeviceAddress          The resulting map address for the bus master PCI controller to use to
-                                access the hosts HostAddress.
-  @param Mapping                A resulting value to pass to Unmap().
-
-  @retval EFI_SUCCESS           The requested memory pages were allocated.
-  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are
-                                MEMORY_WRITE_COMBINE and MEMORY_CACHED.
-  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
-  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
+  @retval TRUE     The PPI instance has already been handled.
+  @retval FALSE    The PPI instance has not been handled before.
 
 **/
-EFI_STATUS
-IoMmuAllocateBuffer (
-  IN UINTN                  Pages,
-  OUT VOID                  **HostAddress,
-  OUT EFI_PHYSICAL_ADDRESS  *DeviceAddress,
-  OUT VOID                  **Mapping
-  )
-{
-  EFI_STATUS            Status;
-  UINTN                 NumberOfBytes;
-  EFI_PHYSICAL_ADDRESS  HostPhyAddress;
-  EDKII_IOMMU_PPI       *IoMmu;
-
-  *HostAddress = NULL;
-  *DeviceAddress = 0;
-  *Mapping = NULL;
-
-  IoMmu = GetIoMmu ();
-
-  if (IoMmu != NULL) {
-    Status = IoMmu->AllocateBuffer (
-                      IoMmu,
-                      EfiBootServicesData,
-                      Pages,
-                      HostAddress,
-                      0
-                      );
-    if (EFI_ERROR (Status)) {
-      return EFI_OUT_OF_RESOURCES;
-    }
-
-    NumberOfBytes = EFI_PAGES_TO_SIZE (Pages);
-    Status = IoMmu->Map (
-                      IoMmu,
-                      EdkiiIoMmuOperationBusMasterCommonBuffer,
-                      *HostAddress,
-                      &NumberOfBytes,
-                      DeviceAddress,
-                      Mapping
-                      );
-    if (EFI_ERROR (Status)) {
-      IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
-      *HostAddress = NULL;
-      return EFI_OUT_OF_RESOURCES;
-    }
-    Status = IoMmu->SetAttribute (
-                      IoMmu,
-                      *Mapping,
-                      EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
-                      );
-    if (EFI_ERROR (Status)) {
-      IoMmu->Unmap (IoMmu, *Mapping);
-      IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
-      *Mapping = NULL;
-      *HostAddress = NULL;
-      return Status;
-    }
-  } else {
-    Status = PeiServicesAllocatePages (
-               EfiBootServicesData,
-               Pages,
-               &HostPhyAddress
-               );
-    if (EFI_ERROR (Status)) {
-      return EFI_OUT_OF_RESOURCES;
-    }
-    *HostAddress = (VOID *) (UINTN) HostPhyAddress;
-    *DeviceAddress = HostPhyAddress;
-    *Mapping = NULL;
-  }
-  return Status;
-}
-
-/**
-  Frees memory that was allocated with AllocateBuffer().
-
-  @param Pages              The number of pages to free.
-  @param HostAddress        The base system memory address of the allocated range.
-  @param Mapping            The mapping value returned from Map().
-
-**/
-VOID
-IoMmuFreeBuffer (
-  IN UINTN                  Pages,
-  IN VOID                   *HostAddress,
-  IN VOID                   *Mapping
-  )
-{
-  EDKII_IOMMU_PPI       *IoMmu;
-
-  IoMmu = GetIoMmu ();
-
-  if (IoMmu != NULL) {
-    IoMmu->SetAttribute (IoMmu, Mapping, 0);
-    IoMmu->Unmap (IoMmu, Mapping);
-    IoMmu->FreeBuffer (IoMmu, Pages, HostAddress);
-  } else {
-    PeiServicesFreePages (
-      (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress,
-      Pages
-      );
-  }
-}
-
-/**
-  Provide IO action support.
-
-  @param[in]     PeiDev             The opal device need to perform trusted IO.
-  @param[in]     IoType             OPAL_IO_TYPE indicating whether to perform a Trusted Send or Trusted Receive.
-  @param[in]     SecurityProtocol   Security Protocol
-  @param[in]     SpSpecific         Security Protocol Specific
-  @param[in]     TransferLength     Transfer Length of Buffer (in bytes) - always a multiple of 512
-  @param[in]     Buffer             Address of Data to transfer
-
-  @retval        EFI_SUCCESS        Perform the IO action success.
-  @retval        Others             Perform the IO action failed.
-
-**/
-EFI_STATUS
-PerformTrustedIo (
-  OPAL_PEI_DEVICE  *PeiDev,
-  OPAL_IO_TYPE     IoType,
-  UINT8            SecurityProtocol,
-  UINT16           SpSpecific,
-  UINTN            TransferLength,
-  VOID             *Buffer
+BOOLEAN
+IsSscInstanceHandled (
+  IN OPAL_PEI_DRIVER_PRIVATE_DATA          *Private,
+  IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI    *SscInstance
   )
 {
-  EFI_STATUS                    Status;
-  UINTN                         BufferSizeBlocks;
-  EFI_ATA_COMMAND_BLOCK         AtaCommandBlock;
-  OPAL_DEVICE_ATA               *DevInfoAta;
-  AHCI_CONTEXT                  *AhciContext;
-  NVME_CONTEXT                  *NvmeContext;
-
-  Status = EFI_DEVICE_ERROR;
-  if (PeiDev->DeviceType == OPAL_DEVICE_TYPE_ATA) {
-    DevInfoAta = (OPAL_DEVICE_ATA *) PeiDev->Device;
-    AhciContext = (AHCI_CONTEXT *) PeiDev->Context;
-
-    BufferSizeBlocks = TransferLength / 512;
-
-    ZeroMem( &AtaCommandBlock, sizeof( EFI_ATA_COMMAND_BLOCK ) );
-    AtaCommandBlock.AtaCommand = ( IoType == OpalSend ) ? ATA_COMMAND_TRUSTED_SEND : ATA_COMMAND_TRUSTED_RECEIVE;
-    AtaCommandBlock.AtaSectorCount = ( UINT8 )BufferSizeBlocks;
-    AtaCommandBlock.AtaSectorNumber = ( UINT8 )( BufferSizeBlocks >> 8 );
-    AtaCommandBlock.AtaFeatures = SecurityProtocol;
-    AtaCommandBlock.AtaCylinderLow = ( UINT8 )( SpSpecific >> 8 );
-    AtaCommandBlock.AtaCylinderHigh = ( UINT8 )( SpSpecific );
-    AtaCommandBlock.AtaDeviceHead = ATA_DEVICE_LBA;
-
-
-    ZeroMem( AhciContext->Buffer, HDD_PAYLOAD );
-    ASSERT( TransferLength <= HDD_PAYLOAD );
-
-    if (IoType == OpalSend) {
-      CopyMem( AhciContext->Buffer, Buffer, TransferLength );
-    }
+  UINTN    Index;
 
-    Status = AhciPioTransfer(
-                AhciContext,
-                (UINT8) DevInfoAta->Port,
-                (UINT8) DevInfoAta->PortMultiplierPort,
-                NULL,
-                0,
-                ( IoType == OpalSend ) ? FALSE : TRUE,   // i/o direction
-                &AtaCommandBlock,
-                NULL,
-                AhciContext->Buffer,
-                (UINT32)TransferLength,
-                ATA_TIMEOUT
-                );
-
-    if (IoType == OpalRecv) {
-      CopyMem( Buffer, AhciContext->Buffer, TransferLength );
+  for (Index = 0; Index < Private->SscPpiInstanceNum; Index++) {
+    if ((UINTN)SscInstance == Private->SscPpiInstances[Index]) {
+      return TRUE;
     }
-  } else if (PeiDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
-    NvmeContext = (NVME_CONTEXT *) PeiDev->Context;
-    Status = NvmeSecuritySendReceive (
-                NvmeContext,
-                IoType == OpalSend,
-                SecurityProtocol,
-                SwapBytes16(SpSpecific),
-                TransferLength,
-                Buffer
-              );
-  } else {
-    DEBUG((DEBUG_ERROR, "DeviceType(%x) not support.\n", PeiDev->DeviceType));
   }
 
-  return Status;
+  return FALSE;
 }
 
 /**
@@ -351,14 +136,16 @@ SecurityReceiveData (
     return EFI_DEVICE_ERROR;
   }
 
-  return PerformTrustedIo (
-                        PeiDev,
-                        OpalRecv,
-                        SecurityProtocolId,
-                        SecurityProtocolSpecificData,
-                        PayloadBufferSize,
-                        PayloadBuffer
-                        );
+  return PeiDev->SscPpi->ReceiveData (
+                           PeiDev->SscPpi,
+                           PeiDev->DeviceIndex,
+                           SSC_PPI_GENERIC_TIMEOUT,
+                           SecurityProtocolId,
+                           SecurityProtocolSpecificData,
+                           PayloadBufferSize,
+                           PayloadBuffer,
+                           PayloadTransferSize
+                           );
 }
 
 /**
@@ -441,111 +228,15 @@ SecuritySendData (
     return EFI_DEVICE_ERROR;
   }
 
-  return PerformTrustedIo (
-                          PeiDev,
-                          OpalSend,
-                          SecurityProtocolId,
-                          SecurityProtocolSpecificData,
-                          PayloadBufferSize,
-                          PayloadBuffer
-                          );
-
-}
-
-/**
-  Save/Restore RootPort configuration space.
-
-  @param[in]     DevInfoNvme            Pointer to NVMe device info.
-  @param[in]     SaveAction             TRUE: Save, FALSE: Restore
-  @param[in,out] PcieConfBufferList    Configuration space data buffer for save/restore
-
-  @return PCIE base address of this RootPort
-**/
-UINTN
-SaveRestoreRootportConfSpace (
-  IN     OPAL_DEVICE_NVME               *DevInfoNvme,
-  IN     BOOLEAN                        SaveAction,
-  IN OUT UINT8                          **PcieConfBufferList
-  )
-{
-  UINTN             RpBase;
-  UINTN             Length;
-  OPAL_PCI_DEVICE   *DevNode;
-  UINT8             *StorePcieConfData;
-  UINTN             Index;
-
-  Length = 0;
-  Index  = 0;
-  RpBase = 0;
-
-  while (sizeof (OPAL_DEVICE_NVME) + Length < DevInfoNvme->Length) {
-    DevNode = (OPAL_PCI_DEVICE *)((UINT8*)DevInfoNvme->PciBridgeNode + Length);
-    RpBase = PCI_LIB_ADDRESS (DevNode->Bus, DevNode->Device, DevNode->Function, 0x0);
-
-    if (PcieConfBufferList != NULL) {
-      if (SaveAction) {
-        StorePcieConfData = (UINT8 *) AllocateZeroPool (OPAL_PCIE_ROOTPORT_SAVESIZE);
-        ASSERT (StorePcieConfData != NULL);
-        OpalPciRead (StorePcieConfData, RpBase, OPAL_PCIE_ROOTPORT_SAVESIZE);
-        PcieConfBufferList[Index] = StorePcieConfData;
-      } else {
-        // Skip PCIe Command & Status registers
-        StorePcieConfData = PcieConfBufferList[Index];
-        OpalPciWrite (RpBase, StorePcieConfData, 4);
-        OpalPciWrite (RpBase + 8, StorePcieConfData + 8, OPAL_PCIE_ROOTPORT_SAVESIZE - 8);
-
-        FreePool (StorePcieConfData);
-      }
-    }
-
-    Length += sizeof (OPAL_PCI_DEVICE);
-    Index ++;
-  }
-
-  return RpBase;
-}
-
-/**
-  Configure RootPort for downstream PCIe NAND devices.
-
-  @param[in] RpBase             - PCIe configuration space address of this RootPort
-  @param[in] BusNumber          - Bus number
-  @param[in] MemoryBase         - Memory base address
-  @param[in] MemoryLength       - Memory size
-
-**/
-VOID
-ConfigureRootPortForPcieNand (
-  IN UINTN   RpBase,
-  IN UINTN   BusNumber,
-  IN UINT32  MemoryBase,
-  IN UINT32  MemoryLength
-  )
-{
-  UINT32  MemoryLimit;
-
-  DEBUG ((DEBUG_INFO, "ConfigureRootPortForPcieNand, BusNumber: %x, MemoryBase: %x, MemoryLength: %x\n",
-    BusNumber, MemoryBase, MemoryLength));
-
-  if (MemoryLength == 0) {
-    MemoryLimit = MemoryBase;
-  } else {
-    MemoryLimit = MemoryBase + MemoryLength + 0xFFFFF; // 1M
-  }
-
-  ///
-  /// Configue PCIE configuration space for RootPort
-  ///
-  PciWrite8  (RpBase + NVME_PCIE_BNUM + 1,  (UINT8) BusNumber);           // Secondary Bus Number registers
-  PciWrite8  (RpBase + NVME_PCIE_BNUM + 2,  (UINT8) BusNumber);           // Subordinate Bus Number registers
-  PciWrite8  (RpBase + NVME_PCIE_IOBL,      0xFF);                        // I/O Base registers
-  PciWrite8  (RpBase + NVME_PCIE_IOBL + 1,  0x00);                        // I/O Limit registers
-  PciWrite16 (RpBase + NVME_PCIE_MBL,       (UINT16) RShiftU64 ((UINTN)MemoryBase, 16));  // Memory Base register
-  PciWrite16 (RpBase + NVME_PCIE_MBL + 2,   (UINT16) RShiftU64 ((UINTN)MemoryLimit, 16)); // Memory Limit register
-  PciWrite16 (RpBase + NVME_PCIE_PMBL,      0xFFFF);                      // Prefetchable Memory Base registers
-  PciWrite16 (RpBase + NVME_PCIE_PMBL + 2,  0x0000);                      // Prefetchable Memory Limit registers
-  PciWrite32 (RpBase + NVME_PCIE_PMBU32,    0xFFFFFFFF);                  // Prefetchable Memory Upper Base registers
-  PciWrite32 (RpBase + NVME_PCIE_PMLU32,    0x00000000);                  // Prefetchable Memory Upper Limit registers
+  return PeiDev->SscPpi->SendData (
+                           PeiDev->SscPpi,
+                           PeiDev->DeviceIndex,
+                           SSC_PPI_GENERIC_TIMEOUT,
+                           SecurityProtocolId,
+                           SecurityProtocolSpecificData,
+                           PayloadBufferSize,
+                           PayloadBuffer
+                           );
 }
 
 /**
@@ -651,272 +342,178 @@ UnlockOpalPassword (
 }
 
 /**
-  Unlock ATA OPAL password for S3.
+  Unlock the OPAL NVM Express and ATA devices for S3.
+
+  @param[in] Private    Pointer to the Opal PEI driver private data.
 
 **/
 VOID
-UnlockOpalPasswordAta (
-  VOID
+UnlockOpalPasswordDevices (
+  IN OPAL_PEI_DRIVER_PRIVATE_DATA    *Private
   )
 {
-  EFI_STATUS                    Status;
-  UINT8                         *DevInfo;
-  OPAL_DEVICE_ATA               TempDevInfoAta;
-  OPAL_DEVICE_ATA               *DevInfoAta;
-  UINTN                         DevInfoLengthAta;
-  UINT8                         Bus;
-  UINT8                         Device;
-  UINT8                         Function;
-  OPAL_PEI_DEVICE               OpalDev;
-  UINT8                         BaseClassCode;
-  UINT8                         SubClassCode;
-  UINT8                         SataCmdSt;
-  AHCI_CONTEXT                  AhciContext;
-  UINT32                        AhciBar;
-
-  DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));
+  EFI_STATUS                            Status;
+  UINT8                                 *DevInfoBuffer;
+  UINT8                                 DummyData;
+  OPAL_DEVICE_LOCKBOX_DATA              *DevInfo;
+  UINTN                                 DevInfoLength;
+  EFI_PEI_PPI_DESCRIPTOR                *TempPpiDescriptor;
+  UINTN                                 SscPpiInstance;
+  EDKII_PEI_STORAGE_SECURITY_CMD_PPI    *SscPpi;
+  EFI_DEVICE_PATH_PROTOCOL              *SscDevicePath;
+  UINTN                                 SscDevicePathLength;
+  UINTN                                 SscDeviceNum;
+  UINTN                                 SscDeviceIndex;
+  OPAL_PEI_DEVICE                       OpalDev;
 
   //
-  // Get ATA OPAL device info from LockBox.
+  // Get OPAL devices info from LockBox.
   //
-  DevInfo = (UINT8 *) &TempDevInfoAta;
-  DevInfoLengthAta = sizeof (OPAL_DEVICE_ATA);
-  Status = RestoreLockBox (&mOpalDeviceAtaGuid, DevInfo, &DevInfoLengthAta);
+  DevInfoBuffer = &DummyData;
+  DevInfoLength = sizeof (DummyData);
+  Status = RestoreLockBox (&mOpalDeviceLockBoxGuid, DevInfoBuffer, &DevInfoLength);
   if (Status == EFI_BUFFER_TOO_SMALL) {
-    DevInfo = AllocatePages (EFI_SIZE_TO_PAGES (DevInfoLengthAta));
-    if (DevInfo != NULL) {
-      Status = RestoreLockBox (&mOpalDeviceAtaGuid, DevInfo, &DevInfoLengthAta);
+    DevInfoBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DevInfoLength));
+    if (DevInfoBuffer != NULL) {
+      Status = RestoreLockBox (&mOpalDeviceLockBoxGuid, DevInfoBuffer, &DevInfoLength);
     }
   }
-  if (EFI_ERROR (Status) || (DevInfo == NULL)) {
+  if (DevInfoBuffer == NULL || DevInfoBuffer == &DummyData) {
+    return;
+  } else if (EFI_ERROR (Status)) {
+    FreePages (DevInfoBuffer, EFI_SIZE_TO_PAGES (DevInfoLength));
     return;
   }
 
-  for (DevInfoAta = (OPAL_DEVICE_ATA *) DevInfo;
-       (UINTN) DevInfoAta < ((UINTN) DevInfo + DevInfoLengthAta);
-       DevInfoAta = (OPAL_DEVICE_ATA *) ((UINTN) DevInfoAta + DevInfoAta->Length)) {
-    Bus = DevInfoAta->Device.Bus;
-    Device = DevInfoAta->Device.Device;
-    Function = DevInfoAta->Device.Function;
-
-    SataCmdSt = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET));
-    PciWrite8 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), 0x6);
-
-    BaseClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0B));
-    SubClassCode  = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0A));
-    if ((BaseClassCode != PCI_CLASS_MASS_STORAGE) ||
-        ((SubClassCode != PCI_CLASS_MASS_STORAGE_SATADPA) && (SubClassCode != PCI_CLASS_MASS_STORAGE_RAID))) {
-      DEBUG ((DEBUG_ERROR, "%a() ClassCode/SubClassCode are not supported\n", __FUNCTION__));
-    } else {
-      AhciBar = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24));
-      PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24), DevInfoAta->BarAddr);
-
-      ZeroMem (&AhciContext, sizeof (AHCI_CONTEXT));
-      AhciContext.AhciBar = DevInfoAta->BarAddr;
-      AhciAllocateResource (&AhciContext);
-      Status = AhciModeInitialize (&AhciContext, (UINT8)DevInfoAta->Port);
-      ASSERT_EFI_ERROR (Status);
-      if (EFI_ERROR (Status)) {
-        DEBUG ((DEBUG_ERROR, "%a() AhciModeInitialize() error, Status: %r\n", __FUNCTION__, Status));
-      } else {
-        OpalDev.Signature = OPAL_PEI_DEVICE_SIGNATURE;
-        OpalDev.Sscp.ReceiveData = SecurityReceiveData;
-        OpalDev.Sscp.SendData = SecuritySendData;
-        OpalDev.DeviceType = OPAL_DEVICE_TYPE_ATA;
-        OpalDev.Device = (OPAL_DEVICE_COMMON *) DevInfoAta;
-        OpalDev.Context = &AhciContext;
-
-        UnlockOpalPassword (&OpalDev);
-      }
-      AhciFreeResource (&AhciContext);
-      PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24), AhciBar);
-    }
-    PciWrite8 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), SataCmdSt);
-  }
-
-  ZeroMem (DevInfo, DevInfoLengthAta);
-  if ((UINTN) DevInfo != (UINTN) &TempDevInfoAta) {
-    FreePages (DevInfo, EFI_SIZE_TO_PAGES (DevInfoLengthAta));
-  }
-
-  DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));
-}
-
-/**
-  Unlock NVMe OPAL password for S3.
-
-**/
-VOID
-UnlockOpalPasswordNvme (
-  VOID
-  )
-{
-  EFI_STATUS                    Status;
-  UINT8                         *DevInfo;
-  OPAL_DEVICE_NVME              TempDevInfoNvme;
-  OPAL_DEVICE_NVME              *DevInfoNvme;
-  UINTN                         DevInfoLengthNvme;
-  UINT8                         Bus;
-  UINT8                         Device;
-  UINT8                         Function;
-  OPAL_PEI_DEVICE               OpalDev;
-  UINT8                         BaseClassCode;
-  UINT8                         SubClassCode;
-  UINT8                         ProgInt;
-  UINT8                         NvmeCmdSt;
-  UINT8                         *StorePcieConfDataList[16];
-  UINTN                         RpBase;
-  UINTN                         MemoryBase;
-  UINTN                         MemoryLength;
-  NVME_CONTEXT                  NvmeContext;
-
-  DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));
-
   //
-  // Get NVMe OPAL device info from LockBox.
+  // Go through the Storage Security Command PPI instances within system.
   //
-  DevInfo = (UINT8 *) &TempDevInfoNvme;
-  DevInfoLengthNvme = sizeof (OPAL_DEVICE_NVME);
-  Status = RestoreLockBox (&mOpalDeviceNvmeGuid, DevInfo, &DevInfoLengthNvme);
-  if (Status == EFI_BUFFER_TOO_SMALL) {
-    DevInfo = AllocatePages (EFI_SIZE_TO_PAGES (DevInfoLengthNvme));
-    if (DevInfo != NULL) {
-      Status = RestoreLockBox (&mOpalDeviceNvmeGuid, DevInfo, &DevInfoLengthNvme);
+  for (SscPpiInstance = 0;
+       SscPpiInstance < OPAL_PEI_MAX_STORAGE_SECURITY_CMD_PPI;
+       SscPpiInstance++) {
+    Status = PeiServicesLocatePpi (
+               &gEdkiiPeiStorageSecurityCommandPpiGuid,
+               SscPpiInstance,
+               &TempPpiDescriptor,
+               (VOID **) &SscPpi
+               );
+    if (EFI_ERROR (Status)) {
+      break;
     }
-  }
-  if (EFI_ERROR (Status) || (DevInfo == NULL)) {
-    return;
-  }
 
-  for (DevInfoNvme = (OPAL_DEVICE_NVME *) DevInfo;
-       (UINTN) DevInfoNvme < ((UINTN) DevInfo + DevInfoLengthNvme);
-       DevInfoNvme = (OPAL_DEVICE_NVME *) ((UINTN) DevInfoNvme + DevInfoNvme->Length)) {
-    Bus = DevInfoNvme->Device.Bus;
-    Device = DevInfoNvme->Device.Device;
-    Function = DevInfoNvme->Device.Function;
-
-    RpBase    = 0;
-    NvmeCmdSt = 0;
-
-    ///
-    /// Save original RootPort configuration space to heap
-    ///
-    RpBase = SaveRestoreRootportConfSpace (
-                DevInfoNvme,
-                TRUE, // save
-                StorePcieConfDataList
-                );
-    MemoryBase = DevInfoNvme->BarAddr;
-    MemoryLength = 0;
-    ConfigureRootPortForPcieNand (RpBase, Bus, (UINT32) MemoryBase, (UINT32) MemoryLength);
-
-    ///
-    /// Enable PCIE decode for RootPort
-    ///
-    NvmeCmdSt = PciRead8 (RpBase + NVME_PCIE_PCICMD);
-    PciWrite8  (RpBase + NVME_PCIE_PCICMD,  0x6);
-
-    BaseClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0B));
-    SubClassCode  = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0A));
-    ProgInt       = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x09));
-    if ((BaseClassCode != PCI_CLASS_MASS_STORAGE) ||
-        (SubClassCode != PCI_CLASS_MASS_STORAGE_NVM) ||
-        (ProgInt != PCI_IF_NVMHCI)) {
-      DEBUG ((DEBUG_ERROR, "%a() ClassCode/SubClassCode/PI are not supported\n", __FUNCTION__));
+    //
+    // Check whether this PPI instance has been handled previously.
+    //
+    if (IsSscInstanceHandled (Private, SscPpi)) {
+      DEBUG ((
+        DEBUG_INFO, "%a: Ssc PPI instance (0x%p) already handled.\n",
+        __FUNCTION__, (UINTN)SscPpi
+        ));
+      continue;
     } else {
-      ZeroMem (&NvmeContext, sizeof (NVME_CONTEXT));
-      NvmeContext.Nbar = DevInfoNvme->BarAddr;
-      NvmeContext.PciBase = PCI_LIB_ADDRESS (Bus, Device, Function, 0x0);
-      NvmeContext.NvmeInitWaitTime = 0;
-      NvmeContext.Nsid = DevInfoNvme->NvmeNamespaceId;
-      NvmeAllocateResource (&NvmeContext);
-      Status = NvmeControllerInit (&NvmeContext);
-
-      OpalDev.Signature = OPAL_PEI_DEVICE_SIGNATURE;
-      OpalDev.Sscp.ReceiveData = SecurityReceiveData;
-      OpalDev.Sscp.SendData = SecuritySendData;
-      OpalDev.DeviceType = OPAL_DEVICE_TYPE_NVME;
-      OpalDev.Device = (OPAL_DEVICE_COMMON *) DevInfoNvme;
-      OpalDev.Context = &NvmeContext;
-
-      UnlockOpalPassword (&OpalDev);
-
-      Status = NvmeControllerExit (&NvmeContext);
-      NvmeFreeResource (&NvmeContext);
+      DEBUG ((
+        DEBUG_INFO, "%a: New Ssc PPI instance (0x%p) found.\n",
+        __FUNCTION__, (UINTN)SscPpi
+        ));
+      Private->SscPpiInstances[Private->SscPpiInstanceNum] = (UINTN)SscPpi;
+      Private->SscPpiInstanceNum++;
     }
 
-    ASSERT (RpBase != 0);
-    PciWrite8  (RpBase + NVME_PCIE_PCICMD, 0);
-    RpBase = SaveRestoreRootportConfSpace (
-                DevInfoNvme,
-                FALSE,  // restore
-                StorePcieConfDataList
-                );
-    PciWrite8  (RpBase + NVME_PCIE_PCICMD, NvmeCmdSt);
-  }
+    //
+    // Go through all the devices managed by this PPI instance.
+    //
+    Status = SscPpi->GetNumberofDevices (SscPpi, &SscDeviceNum);
+    if (EFI_ERROR (Status)) {
+      continue;
+    }
+    for (SscDeviceIndex = 1; SscDeviceIndex <= SscDeviceNum; SscDeviceIndex++) {
+      Status = SscPpi->GetDevicePath (
+                         SscPpi,
+                         SscDeviceIndex,
+                         &SscDevicePathLength,
+                         &SscDevicePath
+                         );
+      if (SscDevicePathLength <= sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
+        //
+        // Device path validity check.
+        //
+        continue;
+      }
 
-  ZeroMem (DevInfo, DevInfoLengthNvme);
-  if ((UINTN) DevInfo != (UINTN) &TempDevInfoNvme) {
-    FreePages (DevInfo, EFI_SIZE_TO_PAGES (DevInfoLengthNvme));
+      //
+      // Search the device in the restored LockBox.
+      //
+      for (DevInfo = (OPAL_DEVICE_LOCKBOX_DATA *) DevInfoBuffer;
+           (UINTN) DevInfo < ((UINTN) DevInfoBuffer + DevInfoLength);
+           DevInfo = (OPAL_DEVICE_LOCKBOX_DATA *) ((UINTN) DevInfo + DevInfo->Length)) {
+        //
+        // Find the matching device.
+        //
+        if ((DevInfo->DevicePathLength >= SscDevicePathLength) &&
+            (CompareMem (
+               DevInfo->DevicePath,
+               SscDevicePath,
+               SscDevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)) == 0)) {
+          OpalDev.Signature        = OPAL_PEI_DEVICE_SIGNATURE;
+          OpalDev.Sscp.ReceiveData = SecurityReceiveData;
+          OpalDev.Sscp.SendData    = SecuritySendData;
+          OpalDev.Device           = DevInfo;
+          OpalDev.Context          = NULL;
+          OpalDev.SscPpi           = SscPpi;
+          OpalDev.DeviceIndex      = SscDeviceIndex;
+          UnlockOpalPassword (&OpalDev);
+          break;
+        }
+      }
+    }
   }
 
-  DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));
-}
-
-/**
-  Unlock OPAL password for S3.
+  ZeroMem (DevInfoBuffer, DevInfoLength);
+  FreePages (DevInfoBuffer, EFI_SIZE_TO_PAGES (DevInfoLength));
 
-**/
-VOID
-OpalPasswordS3 (
-  VOID
-  )
-{
-  UnlockOpalPasswordAta ();
-  UnlockOpalPasswordNvme ();
 }
 
 /**
-  Entry point of the notification callback function itself within the PEIM.
+  One notified function at the installation of EDKII_PEI_STORAGE_SECURITY_CMD_PPI.
   It is to unlock OPAL password for S3.
 
-  @param  PeiServices      Indirect reference to the PEI Services Table.
-  @param  NotifyDescriptor Address of the notification descriptor data structure.
-  @param  Ppi              Address of the PPI that was installed.
+  @param[in] PeiServices         Indirect reference to the PEI Services Table.
+  @param[in] NotifyDescriptor    Address of the notification descriptor data structure.
+  @param[in] Ppi                 Address of the PPI that was installed.
 
   @return Status of the notification.
           The status code returned from this function is ignored.
+
 **/
 EFI_STATUS
 EFIAPI
-OpalPasswordEndOfPeiNotify(
-  IN EFI_PEI_SERVICES          **PeiServices,
-  IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
-  IN VOID                      *Ppi
+OpalPasswordStorageSecurityPpiNotify (
+  IN EFI_PEI_SERVICES             **PeiServices,
+  IN EFI_PEI_NOTIFY_DESCRIPTOR    *NotifyDesc,
+  IN VOID                         *Ppi
   )
 {
-  EFI_STATUS                        Status;
-  EFI_BOOT_MODE                     BootMode;
+  OPAL_PEI_DRIVER_PRIVATE_DATA    *Private;
 
-  Status = PeiServicesGetBootMode (&BootMode);
-  ASSERT_EFI_ERROR (Status);
-  if (BootMode != BOOT_ON_S3_RESUME) {
-    return EFI_UNSUPPORTED;
-  }
+  DEBUG ((DEBUG_INFO, "%a entered at S3 resume!\n", __FUNCTION__));
 
-  DEBUG ((DEBUG_INFO, "%a() - enter at S3 resume\n", __FUNCTION__));
+  Private = OPAL_PEI_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDesc);
+  UnlockOpalPasswordDevices (Private);
 
-  OpalPasswordS3 ();
-
-  DEBUG ((DEBUG_INFO, "%a() - exit at S3 resume\n", __FUNCTION__));
+  DEBUG ((DEBUG_INFO, "%a exit at S3 resume!\n", __FUNCTION__));
 
   return EFI_SUCCESS;
 }
 
-EFI_PEI_NOTIFY_DESCRIPTOR mOpalPasswordEndOfPeiNotifyDesc = {
-  (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
-  &gEfiEndOfPeiSignalPpiGuid,
-  OpalPasswordEndOfPeiNotify
+OPAL_PEI_DRIVER_PRIVATE_DATA mOpalPeiDriverPrivateTemplate = {
+  OPAL_PEI_DRIVER_SIGNATURE,    // Signature
+  {                             // SscPpiNotifyList
+    (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+    &gEdkiiPeiStorageSecurityCommandPpiGuid,
+    OpalPasswordStorageSecurityPpiNotify
+  },
+  0,                            // SscPpiInstanceNum
+  {0}                           // SscPpiInstances
 };
 
 /**
@@ -935,10 +532,32 @@ OpalPasswordPeiInit (
   IN CONST EFI_PEI_SERVICES     **PeiServices
   )
 {
-  EFI_STATUS                    Status;
+  EFI_STATUS                      Status;
+  EFI_BOOT_MODE                   BootMode;
+  OPAL_PEI_DRIVER_PRIVATE_DATA    *Private;
 
-  Status = PeiServicesNotifyPpi (&mOpalPasswordEndOfPeiNotifyDesc);
+  Status = PeiServicesGetBootMode (&BootMode);
+  if ((EFI_ERROR (Status)) || (BootMode != BOOT_ON_S3_RESUME)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  DEBUG ((DEBUG_INFO, "%a: Enters in S3 path.\n", __FUNCTION__));
+
+  Private = (OPAL_PEI_DRIVER_PRIVATE_DATA *)
+              AllocateCopyPool (
+                sizeof (OPAL_PEI_DRIVER_PRIVATE_DATA),
+                &mOpalPeiDriverPrivateTemplate
+                );
+  if (Private == NULL) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "%a: Failed to allocate memory for OPAL_PEI_DRIVER_PRIVATE_DATA.\n",
+      __FUNCTION__
+      ));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = PeiServicesNotifyPpi (&Private->SscPpiNotifyList);
   ASSERT_EFI_ERROR (Status);
   return Status;
 }
-
-- 
2.12.0.windows.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 11/12] MdeModulePkg/SmmLockBoxLib: Support LockBox enlarge in UpdateLockBox()
  2019-02-01  5:47 ` [PATCH v3 11/12] MdeModulePkg/SmmLockBoxLib: Support LockBox enlarge in UpdateLockBox() Hao Wu
@ 2019-02-01  7:52   ` Ni, Ray
  2019-02-01  9:39   ` Laszlo Ersek
  1 sibling, 0 replies; 19+ messages in thread
From: Ni, Ray @ 2019-02-01  7:52 UTC (permalink / raw)
  To: Hao Wu, edk2-devel; +Cc: Jian J Wang, Star Zeng

Reviewed-by: Ray Ni <ray.ni@intel.com>

-- 
Thanks,
Ray


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 09/12] MdeModulePkg/SmmLockBoxLib: Use 'DEBUG_' prefix instead of 'EFI_D_'
  2019-02-01  5:47 ` [PATCH v3 09/12] MdeModulePkg/SmmLockBoxLib: Use 'DEBUG_' prefix instead of 'EFI_D_' Hao Wu
@ 2019-02-01  9:04   ` Laszlo Ersek
  0 siblings, 0 replies; 19+ messages in thread
From: Laszlo Ersek @ 2019-02-01  9:04 UTC (permalink / raw)
  To: Hao Wu, edk2-devel; +Cc: Star Zeng

On 02/01/19 06:47, Hao Wu wrote:
> This commit is out of the scope for BZ-1409. It is a coding style
> refinement for the SmmLockBoxLib.
> 
> More specifically, the commit will remove all the debug message display
> level macros starting with 'EFI_D_' and replace them with macros starting
> with 'DEBUG_'.
> 
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Star Zeng <star.zeng@intel.com>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Hao Wu <hao.a.wu@intel.com>
> Reviewed-by: Ray Ni <ray.ni@intel.com>
> ---
>  MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c | 22 +++---
>  MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c | 26 +++----
>  MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c | 78 ++++++++++----------
>  3 files changed, 63 insertions(+), 63 deletions(-)

Reviewed-by: Laszlo Ersek <lersek@redhat.com>



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 10/12] MdeModulePkg/SmmLockBox(PEI): Remove an ASSERT in RestoreLockBox()
  2019-02-01  5:47 ` [PATCH v3 10/12] MdeModulePkg/SmmLockBox(PEI): Remove an ASSERT in RestoreLockBox() Hao Wu
@ 2019-02-01  9:17   ` Laszlo Ersek
  2019-02-01 10:54     ` Wu, Hao A
  0 siblings, 1 reply; 19+ messages in thread
From: Laszlo Ersek @ 2019-02-01  9:17 UTC (permalink / raw)
  To: Hao Wu, edk2-devel; +Cc: Star Zeng

On 02/01/19 06:47, Hao Wu wrote:
> This commit is out of the scope for BZ-1409. It is a refinement for the
> PEI library instance within SmmLockBoxLib.
> 
> For the below ASSERT statement within function RestoreLockBox():
>   Status = SmmCommunicationPpi->Communicate (
>                                   SmmCommunicationPpi,
>                                   &CommBuffer[0],
>                                   &CommSize
>                                   );
>   if (Status == EFI_NOT_STARTED) {
>     //
>     // Pei SMM communication not ready yet, so we access SMRAM directly
>     //
>     DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib Communicate - (%r)\n", Status));
>     Status = InternalRestoreLockBoxFromSmram (Guid, Buffer, Length);
>     LockBoxParameterRestore->Header.ReturnStatus = (UINT64)Status;
>     if (Length != NULL) {
>       LockBoxParameterRestore->Length = (UINT64)*Length;
>     }
>   }
>   ASSERT_EFI_ERROR (Status);
> 
> It is possible for previous codes to return an error status that is
> possible for happen. One example is that, when the 'if' statement
> 'if (Status == EFI_NOT_STARTED) {' is entered, function
> InternalRestoreLockBoxFromSmram() is possible to return 'BUFFER_TOO_SMALL'
> if the caller of RestoreLockBox() provides a buffer that is too small to
> hold the content of LockBox.
> 
> Thus, this commit will remove the ASSERT here.
> 
> Please note that the current implementation of RestoreLockBox() is
> handling the above-mentioned error case properly, so no additional error
> handling codes are needed here.
> 
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Star Zeng <star.zeng@intel.com>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Hao Wu <hao.a.wu@intel.com>
> Reviewed-by: Ray Ni <ray.ni@intel.com>
> ---
>  MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c | 1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
> index 9f73480070..8c3e65bc96 100644
> --- a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
> +++ b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
> @@ -623,7 +623,6 @@ RestoreLockBox (
>        LockBoxParameterRestore->Length = (UINT64)*Length;
>      }
>    }
> -  ASSERT_EFI_ERROR (Status);
>  
>    if (Length != NULL) {
>      *Length = (UINTN)LockBoxParameterRestore->Length;
> 

OVMF never reaches this code path because it doesn't include an
EFI_PEI_SMM_COMMUNICATION_PPI instance. Therefore OVMF always goes
through InternalRestoreLockBoxFromSmram().

See commit bd3afeb1d62c ("MdeModulePkg: SmmLockBoxPeiLib: work without
EFI_PEI_SMM_COMMUNICATION_PPI", 2015-11-16).

In that regard, I'm OK with this patch; this alone would suffice for me
to give an Acked-by.

However, having re-reviewed bd3afeb1d62c now, I see that this patch is
actually technically correct. So I believe I can give an R-b too,
despite OVMF not using the affected code path.

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

Other than that, you might want to review existing callers of this
function, to ensure they don't rely on any such failure being caught
internally to the function (via the ASSERT that's now being removed).
Again, this would only be relevant for platforms that produce an
EFI_PEI_SMM_COMMUNICATION_PPI instance.

Thanks
Laszlo


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 11/12] MdeModulePkg/SmmLockBoxLib: Support LockBox enlarge in UpdateLockBox()
  2019-02-01  5:47 ` [PATCH v3 11/12] MdeModulePkg/SmmLockBoxLib: Support LockBox enlarge in UpdateLockBox() Hao Wu
  2019-02-01  7:52   ` Ni, Ray
@ 2019-02-01  9:39   ` Laszlo Ersek
  2019-02-01 11:03     ` Wu, Hao A
  1 sibling, 1 reply; 19+ messages in thread
From: Laszlo Ersek @ 2019-02-01  9:39 UTC (permalink / raw)
  To: Hao Wu, edk2-devel; +Cc: Star Zeng

Hi Hao,

On 02/01/19 06:47, Hao Wu wrote:
> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=1409
>
> This commit will add the support to enlarge a LockBox when using the
> LockBoxLib API UpdateLockBox().
>
> Please note that the new support will ONLY work for LockBox with attribute
> LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY set.
>
> The functional uni-test for the commit is available at:
> https://github.com/hwu25/edk2/tree/lockbox_unitest
>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Star Zeng <star.zeng@intel.com>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Hao Wu <hao.a.wu@intel.com>
> ---
>  MdeModulePkg/Include/Library/LockBoxLib.h             |  7 +-
>  MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c  |  7 +-
>  MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c |  5 +-
>  MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c |  5 +-
>  MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c | 72 ++++++++++++++++++--
>  5 files changed, 86 insertions(+), 10 deletions(-)
>
> diff --git a/MdeModulePkg/Include/Library/LockBoxLib.h b/MdeModulePkg/Include/Library/LockBoxLib.h
> index 5921731419..addce3bd4a 100644
> --- a/MdeModulePkg/Include/Library/LockBoxLib.h
> +++ b/MdeModulePkg/Include/Library/LockBoxLib.h
> @@ -2,7 +2,7 @@
>    This library is only intended to be used by DXE modules that need save
>    confidential information to LockBox and get it by PEI modules in S3 phase.
>
> -Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
>
>  This program and the accompanying materials
>  are licensed and made available under the terms and conditions
> @@ -85,7 +85,10 @@ SetLockBoxAttributes (
>    @retval RETURN_SUCCESS            the information is saved successfully.
>    @retval RETURN_INVALID_PARAMETER  the Guid is NULL, or Buffer is NULL, or Length is 0.
>    @retval RETURN_NOT_FOUND          the requested GUID not found.
> -  @retval RETURN_BUFFER_TOO_SMALL   the original buffer to too small to hold new information.
> +  @retval RETURN_BUFFER_TOO_SMALL   for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE,
> +                                    the original buffer to too small to hold new information.
> +  @retval RETURN_OUT_OF_RESOURCES   for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
> +                                    no enough resource to save the information.
>    @retval RETURN_ACCESS_DENIED      it is too late to invoke this interface
>    @retval RETURN_NOT_STARTED        it is too early to invoke this interface
>    @retval RETURN_UNSUPPORTED        the service is not supported by implementaion.
> diff --git a/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c b/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c
> index c40dfea398..0adda1e2a9 100644
> --- a/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c
> +++ b/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c
> @@ -1,6 +1,6 @@
>  /** @file
>
> -Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
>
>  This program and the accompanying materials
>  are licensed and made available under the terms and conditions
> @@ -76,7 +76,10 @@ SetLockBoxAttributes (
>    @retval RETURN_SUCCESS            the information is saved successfully.
>    @retval RETURN_INVALID_PARAMETER  the Guid is NULL, or Buffer is NULL, or Length is 0.
>    @retval RETURN_NOT_FOUND          the requested GUID not found.
> -  @retval RETURN_BUFFER_TOO_SMALL   the original buffer to too small to hold new information.
> +  @retval RETURN_BUFFER_TOO_SMALL   for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE,
> +                                    the original buffer to too small to hold new information.
> +  @retval RETURN_OUT_OF_RESOURCES   for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
> +                                    no enough resource to save the information.
>    @retval RETURN_ACCESS_DENIED      it is too late to invoke this interface
>    @retval RETURN_NOT_STARTED        it is too early to invoke this interface
>    @retval RETURN_UNSUPPORTED        the service is not supported by implementaion.
> diff --git a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c
> index 0428decbac..5ee563b71f 100644
> --- a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c
> +++ b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c
> @@ -300,7 +300,10 @@ SetLockBoxAttributes (
>    @retval RETURN_SUCCESS            the information is saved successfully.
>    @retval RETURN_INVALID_PARAMETER  the Guid is NULL, or Buffer is NULL, or Length is 0.
>    @retval RETURN_NOT_FOUND          the requested GUID not found.
> -  @retval RETURN_BUFFER_TOO_SMALL   the original buffer to too small to hold new information.
> +  @retval RETURN_BUFFER_TOO_SMALL   for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE,
> +                                    the original buffer to too small to hold new information.
> +  @retval RETURN_OUT_OF_RESOURCES   for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
> +                                    no enough resource to save the information.
>    @retval RETURN_ACCESS_DENIED      it is too late to invoke this interface
>    @retval RETURN_NOT_STARTED        it is too early to invoke this interface
>    @retval RETURN_UNSUPPORTED        the service is not supported by implementaion.
> diff --git a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
> index 8c3e65bc96..19fdd995c6 100644
> --- a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
> +++ b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
> @@ -477,7 +477,10 @@ SetLockBoxAttributes (
>    @retval RETURN_SUCCESS            the information is saved successfully.
>    @retval RETURN_INVALID_PARAMETER  the Guid is NULL, or Buffer is NULL, or Length is 0.
>    @retval RETURN_NOT_FOUND          the requested GUID not found.
> -  @retval RETURN_BUFFER_TOO_SMALL   the original buffer to too small to hold new information.
> +  @retval RETURN_BUFFER_TOO_SMALL   for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE,
> +                                    the original buffer to too small to hold new information.
> +  @retval RETURN_OUT_OF_RESOURCES   for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
> +                                    no enough resource to save the information.
>    @retval RETURN_ACCESS_DENIED      it is too late to invoke this interface
>    @retval RETURN_NOT_STARTED        it is too early to invoke this interface
>    @retval RETURN_UNSUPPORTED        the service is not supported by implementaion.
> diff --git a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c
> index c912d187a4..d1cff97ba1 100644
> --- a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c
> +++ b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c
> @@ -604,7 +604,10 @@ SetLockBoxAttributes (
>    @retval RETURN_SUCCESS            the information is saved successfully.
>    @retval RETURN_INVALID_PARAMETER  the Guid is NULL, or Buffer is NULL, or Length is 0.
>    @retval RETURN_NOT_FOUND          the requested GUID not found.
> -  @retval RETURN_BUFFER_TOO_SMALL   the original buffer to too small to hold new information.
> +  @retval RETURN_BUFFER_TOO_SMALL   for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE,
> +                                    the original buffer to too small to hold new information.
> +  @retval RETURN_OUT_OF_RESOURCES   for lockbox with attribute LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
> +                                    no enough resource to save the information.
>    @retval RETURN_ACCESS_DENIED      it is too late to invoke this interface
>    @retval RETURN_NOT_STARTED        it is too early to invoke this interface
>    @retval RETURN_UNSUPPORTED        the service is not supported by implementaion.
> @@ -619,13 +622,16 @@ UpdateLockBox (
>    )
>  {
>    SMM_LOCK_BOX_DATA             *LockBox;
> +  EFI_PHYSICAL_ADDRESS          SmramBuffer;
> +  EFI_STATUS                    Status;
>
>    DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Enter\n"));
>
>    //
>    // Basic check
>    //
> -  if ((Guid == NULL) || (Buffer == NULL) || (Length == 0)) {
> +  if ((Guid == NULL) || (Buffer == NULL) || (Length == 0) ||
> +      (Length > MAX_UINTN - Offset)) {
>      DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_INVALID_PARAMETER));
>      return EFI_INVALID_PARAMETER;
>    }
> @@ -643,8 +649,66 @@ UpdateLockBox (
>    // Update data
>    //
>    if (LockBox->Length < Offset + Length) {
> -    DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_BUFFER_TOO_SMALL));
> -    return EFI_BUFFER_TOO_SMALL;
> +    if ((LockBox->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY) != 0) {
> +      //
> +      // If 'LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY' attribute is set, enlarge the
> +      // LockBox.
> +      //
> +      DEBUG ((
> +        DEBUG_INFO,
> +        "SmmLockBoxSmmLib UpdateLockBox - Origin LockBox too small, enlarge.\n"
> +        ));
> +
> +      if (EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (LockBox->Length)) < Offset + Length) {
> +        //
> +        // In SaveLockBox(), the SMRAM buffer allocated for LockBox is of page
> +        // granularity. Here, if the required size is larger than the origin size
> +        // of the pages, allocate new buffer from SMRAM to enlarge the LockBox.
> +        //
> +        DEBUG ((
> +          DEBUG_INFO,
> +          "SmmLockBoxSmmLib UpdateLockBox - Allocate new buffer to enlarge.\n"
> +          ));
> +        Status = gSmst->SmmAllocatePages (
> +                          AllocateAnyPages,
> +                          EfiRuntimeServicesData,
> +                          EFI_SIZE_TO_PAGES (Offset + Length),
> +                          &SmramBuffer
> +                          );
> +        if (EFI_ERROR (Status)) {
> +          DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_OUT_OF_RESOURCES));
> +          return EFI_OUT_OF_RESOURCES;
> +        }
> +
> +        //
> +        // Copy origin data to the new SMRAM buffer and wipe the content in the
> +        // origin SMRAM buffer.
> +        //
> +        CopyMem ((VOID *)(UINTN)SmramBuffer, (VOID *)(UINTN)LockBox->SmramBuffer, (UINTN)LockBox->Length);
> +        ZeroMem ((VOID *)(UINTN)LockBox->SmramBuffer, (UINTN)LockBox->Length);
> +        gSmst->SmmFreePages (LockBox->SmramBuffer, EFI_SIZE_TO_PAGES ((UINTN)LockBox->Length));
> +
> +        LockBox->SmramBuffer = SmramBuffer;
> +      }
> +
> +      //
> +      // Handle potential uninitialized content in the LockBox.
> +      //
> +      if (Offset > LockBox->Length) {
> +        ZeroMem (
> +          (VOID *)((UINTN)LockBox->SmramBuffer + (UINTN)LockBox->Length),
> +          Offset - (UINTN)LockBox->Length
> +          );
> +      }
> +      LockBox->Length = Offset + Length;
> +    } else {
> +      //
> +      // If 'LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY' attribute is NOT set, return
> +      // EFI_BUFFER_TOO_SMALL directly.
> +      //
> +      DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_BUFFER_TOO_SMALL));
> +      return EFI_BUFFER_TOO_SMALL;
> +    }
>    }
>    ASSERT ((UINTN)LockBox->SmramBuffer <= (MAX_ADDRESS - Offset));
>    CopyMem ((VOID *)((UINTN)LockBox->SmramBuffer + Offset), Buffer, Length);
>

(1) The change is a no-op if LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY is
not set.

As far as I can see, only the "SecurityPkg/Tcg/Opal/OpalPassword" driver
sets this attribute (both before, and after, patch v3 12/12 in this
series). So that's fine with me; OVMF does not include OpalPassword,
therefore this patch is a no-op even for the SMM_REQUIRE build of OVMF.

Acked-by: Laszlo Ersek <lersek@redhat.com>


(2) In this patch, you modify the library class header, and then you
update some lockbox library instances as well -- just the documentation
-- whose behavior doesn't change. For example, the Null instance (where
no lockbox exists actually), and also the lib instances for PEIMs and
DXE+ drivers when the lockbox exists in SMRAM.

That's great. However, the edk2 tree contains three more LockBoxLib
instances:

  OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
  OvmfPkg/Library/LockBoxLib/LockBoxDxeLib.inf
  Vlv2TbltDevicePkg/Library/I2CLibPei/I2CLibPei.inf

Can you please do two more steps:

(a) extend the UpdateLockBox() comments in
"OvmfPkg/Library/LockBoxLib/LockBoxLib.c", in a spearate patch. It can
be posted separately; no need to hold up this series just because of
that.

(b) the LIBRARY_CLASS in
"Vlv2TbltDevicePkg/Library/I2CLibPei/I2CLibPei.inf" is in fact bogus.
The lib instance has nothing to do with the lockbox. Can you please post
a patch for fixing that define, or else file a BZ so that the
maintainers fix it?


My apologies that I'm only commenting on v3 -- I haven't noticed the
series earlier. In the future, please CC me on patches that are somehow
related to SMM.

Thanks!
Laszlo


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 10/12] MdeModulePkg/SmmLockBox(PEI): Remove an ASSERT in RestoreLockBox()
  2019-02-01  9:17   ` Laszlo Ersek
@ 2019-02-01 10:54     ` Wu, Hao A
  0 siblings, 0 replies; 19+ messages in thread
From: Wu, Hao A @ 2019-02-01 10:54 UTC (permalink / raw)
  To: Laszlo Ersek, edk2-devel@lists.01.org; +Cc: Zeng, Star

> -----Original Message-----
> From: Laszlo Ersek [mailto:lersek@redhat.com]
> Sent: Friday, February 01, 2019 5:18 PM
> To: Wu, Hao A; edk2-devel@lists.01.org
> Cc: Zeng, Star
> Subject: Re: [edk2] [PATCH v3 10/12] MdeModulePkg/SmmLockBox(PEI):
> Remove an ASSERT in RestoreLockBox()
> 
> On 02/01/19 06:47, Hao Wu wrote:
> > This commit is out of the scope for BZ-1409. It is a refinement for the
> > PEI library instance within SmmLockBoxLib.
> >
> > For the below ASSERT statement within function RestoreLockBox():
> >   Status = SmmCommunicationPpi->Communicate (
> >                                   SmmCommunicationPpi,
> >                                   &CommBuffer[0],
> >                                   &CommSize
> >                                   );
> >   if (Status == EFI_NOT_STARTED) {
> >     //
> >     // Pei SMM communication not ready yet, so we access SMRAM directly
> >     //
> >     DEBUG ((DEBUG_INFO, "SmmLockBoxPeiLib Communicate - (%r)\n",
> Status));
> >     Status = InternalRestoreLockBoxFromSmram (Guid, Buffer, Length);
> >     LockBoxParameterRestore->Header.ReturnStatus = (UINT64)Status;
> >     if (Length != NULL) {
> >       LockBoxParameterRestore->Length = (UINT64)*Length;
> >     }
> >   }
> >   ASSERT_EFI_ERROR (Status);
> >
> > It is possible for previous codes to return an error status that is
> > possible for happen. One example is that, when the 'if' statement
> > 'if (Status == EFI_NOT_STARTED) {' is entered, function
> > InternalRestoreLockBoxFromSmram() is possible to return
> 'BUFFER_TOO_SMALL'
> > if the caller of RestoreLockBox() provides a buffer that is too small to
> > hold the content of LockBox.
> >
> > Thus, this commit will remove the ASSERT here.
> >
> > Please note that the current implementation of RestoreLockBox() is
> > handling the above-mentioned error case properly, so no additional error
> > handling codes are needed here.
> >
> > Cc: Jian J Wang <jian.j.wang@intel.com>
> > Cc: Star Zeng <star.zeng@intel.com>
> > Contributed-under: TianoCore Contribution Agreement 1.1
> > Signed-off-by: Hao Wu <hao.a.wu@intel.com>
> > Reviewed-by: Ray Ni <ray.ni@intel.com>
> > ---
> >  MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c | 1 -
> >  1 file changed, 1 deletion(-)
> >
> > diff --git a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
> b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
> > index 9f73480070..8c3e65bc96 100644
> > --- a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
> > +++ b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
> > @@ -623,7 +623,6 @@ RestoreLockBox (
> >        LockBoxParameterRestore->Length = (UINT64)*Length;
> >      }
> >    }
> > -  ASSERT_EFI_ERROR (Status);
> >
> >    if (Length != NULL) {
> >      *Length = (UINTN)LockBoxParameterRestore->Length;
> >
> 
> OVMF never reaches this code path because it doesn't include an
> EFI_PEI_SMM_COMMUNICATION_PPI instance. Therefore OVMF always goes
> through InternalRestoreLockBoxFromSmram().
> 
> See commit bd3afeb1d62c ("MdeModulePkg: SmmLockBoxPeiLib: work without
> EFI_PEI_SMM_COMMUNICATION_PPI", 2015-11-16).
> 
> In that regard, I'm OK with this patch; this alone would suffice for me
> to give an Acked-by.
> 
> However, having re-reviewed bd3afeb1d62c now, I see that this patch is
> actually technically correct. So I believe I can give an R-b too,
> despite OVMF not using the affected code path.
> 
> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
> 
> Other than that, you might want to review existing callers of this
> function, to ensure they don't rely on any such failure being caught
> internally to the function (via the ASSERT that's now being removed).
> Again, this would only be relevant for platforms that produce an
> EFI_PEI_SMM_COMMUNICATION_PPI instance.

Sure. Thanks for the reminder.
I will check those callers before pushing this change.

Best Regards,
Hao Wu

> 
> Thanks
> Laszlo

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 11/12] MdeModulePkg/SmmLockBoxLib: Support LockBox enlarge in UpdateLockBox()
  2019-02-01  9:39   ` Laszlo Ersek
@ 2019-02-01 11:03     ` Wu, Hao A
  0 siblings, 0 replies; 19+ messages in thread
From: Wu, Hao A @ 2019-02-01 11:03 UTC (permalink / raw)
  To: Laszlo Ersek, edk2-devel@lists.01.org; +Cc: Zeng, Star

> -----Original Message-----
> From: Laszlo Ersek [mailto:lersek@redhat.com]
> Sent: Friday, February 01, 2019 5:40 PM
> To: Wu, Hao A; edk2-devel@lists.01.org
> Cc: Zeng, Star
> Subject: Re: [edk2] [PATCH v3 11/12] MdeModulePkg/SmmLockBoxLib: Support
> LockBox enlarge in UpdateLockBox()
> 
> Hi Hao,
> 
> On 02/01/19 06:47, Hao Wu wrote:
> > REF:https://bugzilla.tianocore.org/show_bug.cgi?id=1409
> >
> > This commit will add the support to enlarge a LockBox when using the
> > LockBoxLib API UpdateLockBox().
> >
> > Please note that the new support will ONLY work for LockBox with attribute
> > LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY set.
> >
> > The functional uni-test for the commit is available at:
> > https://github.com/hwu25/edk2/tree/lockbox_unitest
> >
> > Cc: Jian J Wang <jian.j.wang@intel.com>
> > Cc: Ray Ni <ray.ni@intel.com>
> > Cc: Star Zeng <star.zeng@intel.com>
> > Contributed-under: TianoCore Contribution Agreement 1.1
> > Signed-off-by: Hao Wu <hao.a.wu@intel.com>
> > ---
> >  MdeModulePkg/Include/Library/LockBoxLib.h             |  7 +-
> >  MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c  |  7 +-
> >  MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c |  5 +-
> >  MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c |  5 +-
> >  MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c | 72
> ++++++++++++++++++--
> >  5 files changed, 86 insertions(+), 10 deletions(-)
> >
> > diff --git a/MdeModulePkg/Include/Library/LockBoxLib.h
> b/MdeModulePkg/Include/Library/LockBoxLib.h
> > index 5921731419..addce3bd4a 100644
> > --- a/MdeModulePkg/Include/Library/LockBoxLib.h
> > +++ b/MdeModulePkg/Include/Library/LockBoxLib.h
> > @@ -2,7 +2,7 @@
> >    This library is only intended to be used by DXE modules that need save
> >    confidential information to LockBox and get it by PEI modules in S3 phase.
> >
> > -Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
> > +Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
> >
> >  This program and the accompanying materials
> >  are licensed and made available under the terms and conditions
> > @@ -85,7 +85,10 @@ SetLockBoxAttributes (
> >    @retval RETURN_SUCCESS            the information is saved successfully.
> >    @retval RETURN_INVALID_PARAMETER  the Guid is NULL, or Buffer is NULL,
> or Length is 0.
> >    @retval RETURN_NOT_FOUND          the requested GUID not found.
> > -  @retval RETURN_BUFFER_TOO_SMALL   the original buffer to too small to
> hold new information.
> > +  @retval RETURN_BUFFER_TOO_SMALL   for lockbox with attribute
> LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE,
> > +                                    the original buffer to too small to hold new
> information.
> > +  @retval RETURN_OUT_OF_RESOURCES   for lockbox with attribute
> LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
> > +                                    no enough resource to save the information.
> >    @retval RETURN_ACCESS_DENIED      it is too late to invoke this interface
> >    @retval RETURN_NOT_STARTED        it is too early to invoke this interface
> >    @retval RETURN_UNSUPPORTED        the service is not supported by
> implementaion.
> > diff --git a/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c
> b/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c
> > index c40dfea398..0adda1e2a9 100644
> > --- a/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c
> > +++ b/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c
> > @@ -1,6 +1,6 @@
> >  /** @file
> >
> > -Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
> > +Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
> >
> >  This program and the accompanying materials
> >  are licensed and made available under the terms and conditions
> > @@ -76,7 +76,10 @@ SetLockBoxAttributes (
> >    @retval RETURN_SUCCESS            the information is saved successfully.
> >    @retval RETURN_INVALID_PARAMETER  the Guid is NULL, or Buffer is NULL,
> or Length is 0.
> >    @retval RETURN_NOT_FOUND          the requested GUID not found.
> > -  @retval RETURN_BUFFER_TOO_SMALL   the original buffer to too small to
> hold new information.
> > +  @retval RETURN_BUFFER_TOO_SMALL   for lockbox with attribute
> LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE,
> > +                                    the original buffer to too small to hold new
> information.
> > +  @retval RETURN_OUT_OF_RESOURCES   for lockbox with attribute
> LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
> > +                                    no enough resource to save the information.
> >    @retval RETURN_ACCESS_DENIED      it is too late to invoke this interface
> >    @retval RETURN_NOT_STARTED        it is too early to invoke this interface
> >    @retval RETURN_UNSUPPORTED        the service is not supported by
> implementaion.
> > diff --git a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c
> b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c
> > index 0428decbac..5ee563b71f 100644
> > --- a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c
> > +++ b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c
> > @@ -300,7 +300,10 @@ SetLockBoxAttributes (
> >    @retval RETURN_SUCCESS            the information is saved successfully.
> >    @retval RETURN_INVALID_PARAMETER  the Guid is NULL, or Buffer is NULL,
> or Length is 0.
> >    @retval RETURN_NOT_FOUND          the requested GUID not found.
> > -  @retval RETURN_BUFFER_TOO_SMALL   the original buffer to too small to
> hold new information.
> > +  @retval RETURN_BUFFER_TOO_SMALL   for lockbox with attribute
> LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE,
> > +                                    the original buffer to too small to hold new
> information.
> > +  @retval RETURN_OUT_OF_RESOURCES   for lockbox with attribute
> LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
> > +                                    no enough resource to save the information.
> >    @retval RETURN_ACCESS_DENIED      it is too late to invoke this interface
> >    @retval RETURN_NOT_STARTED        it is too early to invoke this interface
> >    @retval RETURN_UNSUPPORTED        the service is not supported by
> implementaion.
> > diff --git a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
> b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
> > index 8c3e65bc96..19fdd995c6 100644
> > --- a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
> > +++ b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
> > @@ -477,7 +477,10 @@ SetLockBoxAttributes (
> >    @retval RETURN_SUCCESS            the information is saved successfully.
> >    @retval RETURN_INVALID_PARAMETER  the Guid is NULL, or Buffer is NULL,
> or Length is 0.
> >    @retval RETURN_NOT_FOUND          the requested GUID not found.
> > -  @retval RETURN_BUFFER_TOO_SMALL   the original buffer to too small to
> hold new information.
> > +  @retval RETURN_BUFFER_TOO_SMALL   for lockbox with attribute
> LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE,
> > +                                    the original buffer to too small to hold new
> information.
> > +  @retval RETURN_OUT_OF_RESOURCES   for lockbox with attribute
> LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
> > +                                    no enough resource to save the information.
> >    @retval RETURN_ACCESS_DENIED      it is too late to invoke this interface
> >    @retval RETURN_NOT_STARTED        it is too early to invoke this interface
> >    @retval RETURN_UNSUPPORTED        the service is not supported by
> implementaion.
> > diff --git a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c
> b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c
> > index c912d187a4..d1cff97ba1 100644
> > --- a/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c
> > +++ b/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c
> > @@ -604,7 +604,10 @@ SetLockBoxAttributes (
> >    @retval RETURN_SUCCESS            the information is saved successfully.
> >    @retval RETURN_INVALID_PARAMETER  the Guid is NULL, or Buffer is NULL,
> or Length is 0.
> >    @retval RETURN_NOT_FOUND          the requested GUID not found.
> > -  @retval RETURN_BUFFER_TOO_SMALL   the original buffer to too small to
> hold new information.
> > +  @retval RETURN_BUFFER_TOO_SMALL   for lockbox with attribute
> LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE,
> > +                                    the original buffer to too small to hold new
> information.
> > +  @retval RETURN_OUT_OF_RESOURCES   for lockbox with attribute
> LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY,
> > +                                    no enough resource to save the information.
> >    @retval RETURN_ACCESS_DENIED      it is too late to invoke this interface
> >    @retval RETURN_NOT_STARTED        it is too early to invoke this interface
> >    @retval RETURN_UNSUPPORTED        the service is not supported by
> implementaion.
> > @@ -619,13 +622,16 @@ UpdateLockBox (
> >    )
> >  {
> >    SMM_LOCK_BOX_DATA             *LockBox;
> > +  EFI_PHYSICAL_ADDRESS          SmramBuffer;
> > +  EFI_STATUS                    Status;
> >
> >    DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Enter\n"));
> >
> >    //
> >    // Basic check
> >    //
> > -  if ((Guid == NULL) || (Buffer == NULL) || (Length == 0)) {
> > +  if ((Guid == NULL) || (Buffer == NULL) || (Length == 0) ||
> > +      (Length > MAX_UINTN - Offset)) {
> >      DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n",
> EFI_INVALID_PARAMETER));
> >      return EFI_INVALID_PARAMETER;
> >    }
> > @@ -643,8 +649,66 @@ UpdateLockBox (
> >    // Update data
> >    //
> >    if (LockBox->Length < Offset + Length) {
> > -    DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit
> (%r)\n", EFI_BUFFER_TOO_SMALL));
> > -    return EFI_BUFFER_TOO_SMALL;
> > +    if ((LockBox->Attributes &
> LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY) != 0) {
> > +      //
> > +      // If 'LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY' attribute is set,
> enlarge the
> > +      // LockBox.
> > +      //
> > +      DEBUG ((
> > +        DEBUG_INFO,
> > +        "SmmLockBoxSmmLib UpdateLockBox - Origin LockBox too small,
> enlarge.\n"
> > +        ));
> > +
> > +      if (EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (LockBox->Length)) < Offset
> + Length) {
> > +        //
> > +        // In SaveLockBox(), the SMRAM buffer allocated for LockBox is of page
> > +        // granularity. Here, if the required size is larger than the origin size
> > +        // of the pages, allocate new buffer from SMRAM to enlarge the
> LockBox.
> > +        //
> > +        DEBUG ((
> > +          DEBUG_INFO,
> > +          "SmmLockBoxSmmLib UpdateLockBox - Allocate new buffer to
> enlarge.\n"
> > +          ));
> > +        Status = gSmst->SmmAllocatePages (
> > +                          AllocateAnyPages,
> > +                          EfiRuntimeServicesData,
> > +                          EFI_SIZE_TO_PAGES (Offset + Length),
> > +                          &SmramBuffer
> > +                          );
> > +        if (EFI_ERROR (Status)) {
> > +          DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit
> (%r)\n", EFI_OUT_OF_RESOURCES));
> > +          return EFI_OUT_OF_RESOURCES;
> > +        }
> > +
> > +        //
> > +        // Copy origin data to the new SMRAM buffer and wipe the content in
> the
> > +        // origin SMRAM buffer.
> > +        //
> > +        CopyMem ((VOID *)(UINTN)SmramBuffer, (VOID *)(UINTN)LockBox-
> >SmramBuffer, (UINTN)LockBox->Length);
> > +        ZeroMem ((VOID *)(UINTN)LockBox->SmramBuffer, (UINTN)LockBox-
> >Length);
> > +        gSmst->SmmFreePages (LockBox->SmramBuffer, EFI_SIZE_TO_PAGES
> ((UINTN)LockBox->Length));
> > +
> > +        LockBox->SmramBuffer = SmramBuffer;
> > +      }
> > +
> > +      //
> > +      // Handle potential uninitialized content in the LockBox.
> > +      //
> > +      if (Offset > LockBox->Length) {
> > +        ZeroMem (
> > +          (VOID *)((UINTN)LockBox->SmramBuffer + (UINTN)LockBox->Length),
> > +          Offset - (UINTN)LockBox->Length
> > +          );
> > +      }
> > +      LockBox->Length = Offset + Length;
> > +    } else {
> > +      //
> > +      // If 'LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY' attribute is NOT
> set, return
> > +      // EFI_BUFFER_TOO_SMALL directly.
> > +      //
> > +      DEBUG ((DEBUG_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit
> (%r)\n", EFI_BUFFER_TOO_SMALL));
> > +      return EFI_BUFFER_TOO_SMALL;
> > +    }
> >    }
> >    ASSERT ((UINTN)LockBox->SmramBuffer <= (MAX_ADDRESS - Offset));
> >    CopyMem ((VOID *)((UINTN)LockBox->SmramBuffer + Offset), Buffer,
> Length);
> >
> 
> (1) The change is a no-op if LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY is
> not set.
> 
> As far as I can see, only the "SecurityPkg/Tcg/Opal/OpalPassword" driver
> sets this attribute (both before, and after, patch v3 12/12 in this
> series). So that's fine with me; OVMF does not include OpalPassword,
> therefore this patch is a no-op even for the SMM_REQUIRE build of OVMF.
> 
> Acked-by: Laszlo Ersek <lersek@redhat.com>
> 
> 
> (2) In this patch, you modify the library class header, and then you
> update some lockbox library instances as well -- just the documentation
> -- whose behavior doesn't change. For example, the Null instance (where
> no lockbox exists actually), and also the lib instances for PEIMs and
> DXE+ drivers when the lockbox exists in SMRAM.
> 
> That's great. However, the edk2 tree contains three more LockBoxLib
> instances:
> 
>   OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
>   OvmfPkg/Library/LockBoxLib/LockBoxDxeLib.inf
>   Vlv2TbltDevicePkg/Library/I2CLibPei/I2CLibPei.inf
> 
> Can you please do two more steps:
> 
> (a) extend the UpdateLockBox() comments in
> "OvmfPkg/Library/LockBoxLib/LockBoxLib.c", in a spearate patch. It can
> be posted separately; no need to hold up this series just because of
> that.

OK. If this series goes to v4, I will add another patch to address this.
Otherwise, I will send a separate patch for this.

> 
> (b) the LIBRARY_CLASS in
> "Vlv2TbltDevicePkg/Library/I2CLibPei/I2CLibPei.inf" is in fact bogus.
> The lib instance has nothing to do with the lockbox. Can you please post
> a patch for fixing that define, or else file a BZ so that the
> maintainers fix it?

BZ filed first:
https://bugzilla.tianocore.org/show_bug.cgi?id=1507

> 
> 
> My apologies that I'm only commenting on v3 -- I haven't noticed the
> series earlier. In the future, please CC me on patches that are somehow
> related to SMM.

Sure. Sorry for missing you in the CC list.

Best Regards,
Hao Wu

> 
> Thanks!
> Laszlo

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2019-02-01 11:04 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-02-01  5:47 [PATCH v3 00/12] Split the S3 PEI phase HW init codes from Opal driver Hao Wu
2019-02-01  5:47 ` [PATCH v3 01/12] MdeModulePkg: Add definitions for ATA AHCI host controller PPI Hao Wu
2019-02-01  5:47 ` [PATCH v3 02/12] MdeModulePkg: Add definitions for EDKII PEI ATA PassThru PPI Hao Wu
2019-02-01  5:47 ` [PATCH v3 03/12] MdeModulePkg: Add definitions for Storage Security Command PPI Hao Wu
2019-02-01  5:47 ` [PATCH v3 04/12] MdeModulePkg: Add GUID for LockBox to save storage dev to init in S3 Hao Wu
2019-02-01  5:47 ` [PATCH v3 05/12] MdeModulePkg/NvmExpressPei: Avoid updating the module-level variable Hao Wu
2019-02-01  5:47 ` [PATCH v3 06/12] MdeModulePkg/NvmExpressPei: Add logic to produce SSC PPI Hao Wu
2019-02-01  5:47 ` [PATCH v3 07/12] MdeModulePkg/NvmExpressPei: Consume S3StorageDeviceInitList LockBox Hao Wu
2019-02-01  5:47 ` [PATCH v3 08/12] MdeModulePkg/AhciPei: Add AHCI mode ATA device support in PEI Hao Wu
2019-02-01  5:47 ` [PATCH v3 09/12] MdeModulePkg/SmmLockBoxLib: Use 'DEBUG_' prefix instead of 'EFI_D_' Hao Wu
2019-02-01  9:04   ` Laszlo Ersek
2019-02-01  5:47 ` [PATCH v3 10/12] MdeModulePkg/SmmLockBox(PEI): Remove an ASSERT in RestoreLockBox() Hao Wu
2019-02-01  9:17   ` Laszlo Ersek
2019-02-01 10:54     ` Wu, Hao A
2019-02-01  5:47 ` [PATCH v3 11/12] MdeModulePkg/SmmLockBoxLib: Support LockBox enlarge in UpdateLockBox() Hao Wu
2019-02-01  7:52   ` Ni, Ray
2019-02-01  9:39   ` Laszlo Ersek
2019-02-01 11:03     ` Wu, Hao A
2019-02-01  5:47 ` [PATCH v3 12/12] SecurityPkg/OpalPassword: Remove HW init codes and consume SSC PPI Hao Wu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox