SecurityPkg OpalPassword: Add solution without SMM device code
authorStar Zeng <star.zeng@intel.com>
Sun, 11 Feb 2018 03:00:44 +0000 (11:00 +0800)
committerStar Zeng <star.zeng@intel.com>
Thu, 8 Mar 2018 13:33:50 +0000 (21:33 +0800)
After IOMMU is enabled in S3, original solution with SMM device
code (OpalPasswordSmm) to unlock OPAL device for S3 will not work
as the DMA operation will be aborted without granted DMA buffer.
Instead, this solution is to add OpalPasswordPei to eliminate
SMM device code, and OPAL setup UI produced by OpalPasswordDxe
will be updated to send requests (set password, update password,
and etc), and then the requests will be processed in next boot
before SmmReadyToLock, password and device info will be saved to
lock box used by OpalPasswordPei to unlock OPAL device for S3.

Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Chao Zhang <chao.b.zhang@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Star Zeng <star.zeng@intel.com>
Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
20 files changed:
SecurityPkg/SecurityPkg.dsc
SecurityPkg/Tcg/Opal/OpalPassword/ComponentName.c [new file with mode: 0644]
SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.c [new file with mode: 0644]
SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.h [new file with mode: 0644]
SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c [new file with mode: 0644]
SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.h [new file with mode: 0644]
SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.c [new file with mode: 0644]
SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.h [new file with mode: 0644]
SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiCallbacks.c [new file with mode: 0644]
SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormStrings.uni [new file with mode: 0644]
SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormValues.h [new file with mode: 0644]
SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.c [new file with mode: 0644]
SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.h [new file with mode: 0644]
SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeReg.h [new file with mode: 0644]
SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordCommon.h [new file with mode: 0644]
SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordDxe.inf [new file with mode: 0644]
SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordForm.vfr [new file with mode: 0644]
SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.c [new file with mode: 0644]
SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.h [new file with mode: 0644]
SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.inf [new file with mode: 0644]

index 65a2fe3d796763768ac4880e53a4aabc34d49724..f82703a17b8283fc1431bc52ec160cea73cf4f2b 100644 (file)
   #\r
   SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordDxe.inf\r
   SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.inf\r
+  SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordDxe.inf\r
+  SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.inf\r
 \r
 [Components.IPF]\r
   SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.inf\r
diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/ComponentName.c b/SecurityPkg/Tcg/Opal/OpalPassword/ComponentName.c
new file mode 100644 (file)
index 0000000..ef963d0
--- /dev/null
@@ -0,0 +1,398 @@
+/** @file\r
+  UEFI Component Name(2) protocol implementation for Opal driver.\r
+\r
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "OpalDriver.h"\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gOpalComponentName = {\r
+  OpalEfiDriverComponentNameGetDriverName,\r
+  OpalEfiDriverComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gOpalComponentName2 = {\r
+  OpalEfiDriverComponentName2GetDriverName,\r
+  OpalEfiDriverComponentName2GetControllerName,\r
+  "en"\r
+};\r
+\r
+\r
+/// The name of the driver in all the languages we support.\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mOpalDriverNameTable[] = {\r
+    { LANGUAGE_RFC_3066_ENGLISH, (CHAR16*)EFI_DRIVER_NAME_UNICODE },\r
+    { LANGUAGE_ISO_639_2_ENGLISH, (CHAR16*)EFI_DRIVER_NAME_UNICODE },\r
+    { 0, 0 }\r
+};\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverComponentNameGetDriverName(\r
+  EFI_COMPONENT_NAME_PROTOCOL*    This,\r
+  CHAR8*                          Language,\r
+  CHAR16**                        DriverName\r
+  )\r
+{\r
+  return LookupUnicodeString2(\r
+    Language,\r
+    This->SupportedLanguages,\r
+    mOpalDriverNameTable,\r
+    DriverName,\r
+    TRUE\r
+    );\r
+}\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverComponentName2GetDriverName(\r
+  EFI_COMPONENT_NAME2_PROTOCOL*   This,\r
+  CHAR8*                          Language,\r
+  CHAR16**                        DriverName\r
+  )\r
+{\r
+  return LookupUnicodeString2(\r
+    Language,\r
+    This->SupportedLanguages,\r
+    mOpalDriverNameTable,\r
+    DriverName,\r
+    FALSE\r
+    );\r
+}\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+GetControllerName(\r
+  EFI_HANDLE  ControllerHandle,\r
+  EFI_HANDLE  ChildHandle,\r
+  CHAR8*      Language,\r
+  CHAR16**    ControllerName\r
+  )\r
+{\r
+  if (Language == NULL || ControllerName == NULL || ControllerHandle == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  // don't support any controller or children names\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverComponentNameGetControllerName(\r
+  EFI_COMPONENT_NAME_PROTOCOL*    This,\r
+  EFI_HANDLE                      ControllerHandle,\r
+  EFI_HANDLE                      ChildHandle,\r
+  CHAR8*                          Language,\r
+  CHAR16**                        ControllerName\r
+  )\r
+{\r
+  return (GetControllerName( ControllerHandle, ChildHandle, Language, ControllerName));\r
+}\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverComponentName2GetControllerName(\r
+  EFI_COMPONENT_NAME2_PROTOCOL*   This,\r
+  EFI_HANDLE                      ControllerHandle,\r
+  EFI_HANDLE                      ChildHandle,\r
+  CHAR8*                          Language,\r
+  CHAR16**                        ControllerName\r
+  )\r
+{\r
+  return (GetControllerName(ControllerHandle, ChildHandle, Language, ControllerName));\r
+}\r
+\r
diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.c b/SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.c
new file mode 100644 (file)
index 0000000..d518653
--- /dev/null
@@ -0,0 +1,1334 @@
+/** @file\r
+  This driver is used for Opal Password Feature support at AHCI mode.\r
+\r
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#include "OpalPasswordPei.h"\r
+\r
+/**\r
+  Start command for give slot on specific port.\r
+\r
+  @param  AhciBar            AHCI bar address.\r
+  @param  Port               The number of port.\r
+  @param  CommandSlot        The number of CommandSlot.\r
+  @param  Timeout            The timeout Value of start.\r
+\r
+  @retval EFI_DEVICE_ERROR   The command start unsuccessfully.\r
+  @retval EFI_TIMEOUT        The operation is time out.\r
+  @retval EFI_SUCCESS        The command start successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciStartCommand (\r
+  IN  UINT32                    AhciBar,\r
+  IN  UINT8                     Port,\r
+  IN  UINT8                     CommandSlot,\r
+  IN  UINT64                    Timeout\r
+  );\r
+\r
+/**\r
+  Stop command running for giving port\r
+\r
+  @param  AhciBar            AHCI bar address.\r
+  @param  Port               The number of port.\r
+  @param  Timeout            The timeout Value of stop.\r
+\r
+  @retval EFI_DEVICE_ERROR   The command stop unsuccessfully.\r
+  @retval EFI_TIMEOUT        The operation is time out.\r
+  @retval EFI_SUCCESS        The command stop successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciStopCommand (\r
+  IN  UINT32                    AhciBar,\r
+  IN  UINT8                     Port,\r
+  IN  UINT64                    Timeout\r
+  );\r
+\r
+/**\r
+  Read AHCI Operation register.\r
+\r
+  @param  AhciBar      AHCI bar address.\r
+  @param  Offset       The operation register offset.\r
+\r
+  @return The register content read.\r
+\r
+**/\r
+UINT32\r
+EFIAPI\r
+AhciReadReg (\r
+  IN  UINT32              AhciBar,\r
+  IN  UINT32              Offset\r
+  )\r
+{\r
+  UINT32   Data;\r
+\r
+  Data = 0;\r
+\r
+  Data = MmioRead32 (AhciBar + Offset);\r
+\r
+  return Data;\r
+}\r
+\r
+/**\r
+  Write AHCI Operation register.\r
+\r
+  @param  AhciBar      AHCI bar address.\r
+  @param  Offset       The operation register offset.\r
+  @param  Data         The Data used to write down.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciWriteReg (\r
+  IN UINT32               AhciBar,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Data\r
+  )\r
+{\r
+  MmioWrite32 (AhciBar + Offset, Data);\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  Do AND operation with the Value of AHCI Operation register.\r
+\r
+  @param  AhciBar      AHCI bar address.\r
+  @param  Offset       The operation register offset.\r
+  @param  AndData      The Data used to do AND operation.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciAndReg (\r
+  IN UINT32               AhciBar,\r
+  IN UINT32               Offset,\r
+  IN UINT32               AndData\r
+  )\r
+{\r
+  UINT32 Data;\r
+\r
+  Data  = AhciReadReg (AhciBar, Offset);\r
+\r
+  Data &= AndData;\r
+\r
+  AhciWriteReg (AhciBar, Offset, Data);\r
+}\r
+\r
+/**\r
+  Do OR operation with the Value of AHCI Operation register.\r
+\r
+  @param  AhciBar      AHCI bar address.\r
+  @param  Offset       The operation register offset.\r
+  @param  OrData       The Data used to do OR operation.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciOrReg (\r
+  IN UINT32               AhciBar,\r
+  IN UINT32               Offset,\r
+  IN UINT32               OrData\r
+  )\r
+{\r
+  UINT32 Data;\r
+\r
+  Data  = AhciReadReg (AhciBar, Offset);\r
+\r
+  Data |= OrData;\r
+\r
+  AhciWriteReg (AhciBar, Offset, Data);\r
+}\r
+\r
+/**\r
+  Wait for memory set to the test Value.\r
+\r
+  @param  AhciBar           AHCI bar address.\r
+  @param  Offset            The memory offset to test.\r
+  @param  MaskValue         The mask Value of memory.\r
+  @param  TestValue         The test Value of memory.\r
+  @param  Timeout           The time out Value for wait memory set.\r
+\r
+  @retval EFI_DEVICE_ERROR  The memory is not set.\r
+  @retval EFI_TIMEOUT       The memory setting is time out.\r
+  @retval EFI_SUCCESS       The memory is correct set.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciWaitMmioSet (\r
+  IN  UINT32                    AhciBar,\r
+  IN  UINT32                    Offset,\r
+  IN  UINT32                    MaskValue,\r
+  IN  UINT32                    TestValue,\r
+  IN  UINT64                    Timeout\r
+  )\r
+{\r
+  UINT32     Value;\r
+  UINT32     Delay;\r
+\r
+  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+\r
+  do {\r
+    Value = AhciReadReg (AhciBar, Offset) & MaskValue;\r
+\r
+    if (Value == TestValue) {\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    //\r
+    // Stall for 100 microseconds.\r
+    //\r
+    MicroSecondDelay (100);\r
+\r
+    Delay--;\r
+\r
+  } while (Delay > 0);\r
+\r
+  return EFI_TIMEOUT;\r
+}\r
+/**\r
+  Wait for the Value of the specified system memory set to the test Value.\r
+\r
+  @param  Address           The system memory address to test.\r
+  @param  MaskValue         The mask Value of memory.\r
+  @param  TestValue         The test Value of memory.\r
+  @param  Timeout           The time out Value for wait memory set, uses 100ns as a unit.\r
+\r
+  @retval EFI_TIMEOUT       The system memory setting is time out.\r
+  @retval EFI_SUCCESS       The system memory is correct set.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciWaitMemSet (\r
+  IN  EFI_PHYSICAL_ADDRESS      Address,\r
+  IN  UINT32                    MaskValue,\r
+  IN  UINT32                    TestValue,\r
+  IN  UINT64                    Timeout\r
+  )\r
+{\r
+  UINT32     Value;\r
+  UINT32     Delay;\r
+\r
+  Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);\r
+\r
+  do {\r
+    //\r
+    // Access sytem memory to see if the Value is the tested one.\r
+    //\r
+    // The system memory pointed by Address will be updated by the\r
+    // SATA Host Controller, "volatile" is introduced to prevent\r
+    // compiler from optimizing the access to the memory address\r
+    // to only read once.\r
+    //\r
+    Value  = *(volatile UINT32 *) (UINTN) Address;\r
+    Value &= MaskValue;\r
+\r
+    if (Value == TestValue) {\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    //\r
+    // Stall for 100 microseconds.\r
+    //\r
+    MicroSecondDelay (100);\r
+\r
+    Delay--;\r
+\r
+  } while (Delay > 0);\r
+\r
+  return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+  Check the memory status to the test Value.\r
+\r
+  @param[in]       Address           The memory address to test.\r
+  @param[in]       MaskValue         The mask Value of memory.\r
+  @param[in]       TestValue         The test Value of memory.\r
+  @param[in, out]  RetryTimes        The retry times Value for waitting memory set. If 0, then just try once.\r
+\r
+  @retval EFI_NOTREADY      The memory is not set.\r
+  @retval EFI_TIMEOUT       The memory setting retry times out.\r
+  @retval EFI_SUCCESS       The memory is correct set.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciCheckMemSet (\r
+  IN     UINTN                     Address,\r
+  IN     UINT32                    MaskValue,\r
+  IN     UINT32                    TestValue,\r
+  IN OUT UINTN                     *RetryTimes OPTIONAL\r
+  )\r
+{\r
+  UINT32     Value;\r
+\r
+  if (RetryTimes != NULL) {\r
+    (*RetryTimes)--;\r
+  }\r
+\r
+  Value  = *(volatile UINT32 *) Address;\r
+  Value &= MaskValue;\r
+\r
+  if (Value == TestValue) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if ((RetryTimes != NULL) && (*RetryTimes == 0)) {\r
+    return EFI_TIMEOUT;\r
+  } else {\r
+    return EFI_NOT_READY;\r
+  }\r
+}\r
+\r
+/**\r
+  Clear the port interrupt and error status. It will also clear\r
+  HBA interrupt status.\r
+\r
+  @param      AhciBar        AHCI bar address.\r
+  @param      Port           The number of port.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciClearPortStatus (\r
+  IN  UINT32                 AhciBar,\r
+  IN  UINT8                  Port\r
+  )\r
+{\r
+  UINT32 Offset;\r
+\r
+  //\r
+  // Clear any error status\r
+  //\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
+  AhciWriteReg (AhciBar, Offset, AhciReadReg (AhciBar, Offset));\r
+\r
+  //\r
+  // Clear any port interrupt status\r
+  //\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;\r
+  AhciWriteReg (AhciBar, Offset, AhciReadReg (AhciBar, Offset));\r
+\r
+  //\r
+  // Clear any HBA interrupt status\r
+  //\r
+  AhciWriteReg (AhciBar, EFI_AHCI_IS_OFFSET, AhciReadReg (AhciBar, EFI_AHCI_IS_OFFSET));\r
+}\r
+\r
+/**\r
+  Enable the FIS running for giving port.\r
+\r
+  @param      AhciBar        AHCI bar address.\r
+  @param      Port           The number of port.\r
+  @param      Timeout        The timeout Value of enabling FIS.\r
+\r
+  @retval EFI_DEVICE_ERROR   The FIS enable setting fails.\r
+  @retval EFI_TIMEOUT        The FIS enable setting is time out.\r
+  @retval EFI_SUCCESS        The FIS enable successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciEnableFisReceive (\r
+  IN  UINT32                    AhciBar,\r
+  IN  UINT8                     Port,\r
+  IN  UINT64                    Timeout\r
+  )\r
+{\r
+  UINT32 Offset;\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+  AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_FRE);\r
+\r
+  return AhciWaitMmioSet (\r
+           AhciBar,\r
+           Offset,\r
+           EFI_AHCI_PORT_CMD_FR,\r
+           EFI_AHCI_PORT_CMD_FR,\r
+           Timeout\r
+           );\r
+}\r
+\r
+/**\r
+  Disable the FIS running for giving port.\r
+\r
+  @param      AhciBar        AHCI bar address.\r
+  @param      Port           The number of port.\r
+  @param      Timeout        The timeout Value of disabling FIS.\r
+\r
+  @retval EFI_DEVICE_ERROR   The FIS disable setting fails.\r
+  @retval EFI_TIMEOUT        The FIS disable setting is time out.\r
+  @retval EFI_UNSUPPORTED    The port is in running state.\r
+  @retval EFI_SUCCESS        The FIS disable successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciDisableFisReceive (\r
+  IN  UINT32                    AhciBar,\r
+  IN  UINT8                     Port,\r
+  IN  UINT64                    Timeout\r
+  )\r
+{\r
+  UINT32 Offset;\r
+  UINT32 Data;\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+  Data   = AhciReadReg (AhciBar, Offset);\r
+\r
+  //\r
+  // Before disabling Fis receive, the DMA engine of the port should NOT be in running status.\r
+  //\r
+  if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) != 0) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Check if the Fis receive DMA engine for the port is running.\r
+  //\r
+  if ((Data & EFI_AHCI_PORT_CMD_FR) != EFI_AHCI_PORT_CMD_FR) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE));\r
+\r
+  return AhciWaitMmioSet (\r
+           AhciBar,\r
+           Offset,\r
+           EFI_AHCI_PORT_CMD_FR,\r
+           0,\r
+           Timeout\r
+           );\r
+}\r
+\r
+/**\r
+  Build the command list, command table and prepare the fis receiver.\r
+\r
+  @param    AhciContext           The pointer to the AHCI_CONTEXT.\r
+  @param    Port                  The number of port.\r
+  @param    PortMultiplier        The timeout Value of stop.\r
+  @param    CommandFis            The control fis will be used for the transfer.\r
+  @param    CommandList           The command list will be used for the transfer.\r
+  @param    AtapiCommand          The atapi command will be used for the transfer.\r
+  @param    AtapiCommandLength    The Length of the atapi command.\r
+  @param    CommandSlotNumber     The command slot will be used for the transfer.\r
+  @param    DataPhysicalAddr      The pointer to the Data Buffer pci bus master address.\r
+  @param    DataLength            The Data count to be transferred.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciBuildCommand (\r
+  IN     AHCI_CONTEXT               *AhciContext,\r
+  IN     UINT8                      Port,\r
+  IN     UINT8                      PortMultiplier,\r
+  IN     EFI_AHCI_COMMAND_FIS       *CommandFis,\r
+  IN     EFI_AHCI_COMMAND_LIST      *CommandList,\r
+  IN     EFI_AHCI_ATAPI_COMMAND     *AtapiCommand OPTIONAL,\r
+  IN     UINT8                      AtapiCommandLength,\r
+  IN     UINT8                      CommandSlotNumber,\r
+  IN OUT VOID                       *DataPhysicalAddr,\r
+  IN     UINT64                     DataLength\r
+  )\r
+{\r
+  EFI_AHCI_REGISTERS    *AhciRegisters;\r
+  UINT32                AhciBar;\r
+  UINT64                BaseAddr;\r
+  UINT64                PrdtNumber;\r
+  UINTN                 RemainedData;\r
+  UINTN                 MemAddr;\r
+  DATA_64               Data64;\r
+  UINT32                Offset;\r
+\r
+  AhciRegisters = &AhciContext->AhciRegisters;\r
+  AhciBar = AhciContext->AhciBar;\r
+\r
+  //\r
+  // Filling the PRDT\r
+  //\r
+  PrdtNumber = DivU64x32 (DataLength + EFI_AHCI_MAX_DATA_PER_PRDT - 1, EFI_AHCI_MAX_DATA_PER_PRDT);\r
+\r
+  //\r
+  // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB Data block.\r
+  // It also limits that the maximum amount of the PRDT entry in the command table\r
+  // is 65535.\r
+  //\r
+  ASSERT (PrdtNumber <= 1);\r
+\r
+  Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis);\r
+\r
+  BaseAddr = Data64.Uint64;\r
+\r
+  ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));\r
+\r
+  ZeroMem (AhciRegisters->AhciCommandTable, sizeof (EFI_AHCI_COMMAND_TABLE));\r
+\r
+  CommandFis->AhciCFisPmNum = PortMultiplier;\r
+\r
+  CopyMem (&AhciRegisters->AhciCommandTable->CommandFis, CommandFis, sizeof (EFI_AHCI_COMMAND_FIS));\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+  if (AtapiCommand != NULL) {\r
+    CopyMem (\r
+      &AhciRegisters->AhciCommandTable->AtapiCmd,\r
+      AtapiCommand,\r
+      AtapiCommandLength\r
+      );\r
+\r
+    CommandList->AhciCmdA = 1;\r
+    CommandList->AhciCmdP = 1;\r
+\r
+    AhciOrReg (AhciBar, Offset, (EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));\r
+  } else {\r
+    AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));\r
+  }\r
+\r
+  RemainedData = (UINTN) DataLength;\r
+  MemAddr      = (UINTN) DataPhysicalAddr;\r
+  CommandList->AhciCmdPrdtl = (UINT32)PrdtNumber;\r
+\r
+  AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDbc = (UINT32)RemainedData - 1;\r
+\r
+  Data64.Uint64 = (UINT64)MemAddr;\r
+  AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDba  = Data64.Uint32.Lower32;\r
+  AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDbau = Data64.Uint32.Upper32;\r
+\r
+  //\r
+  // Set the last PRDT to Interrupt On Complete\r
+  //\r
+  AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtIoc = 1;\r
+\r
+  CopyMem (\r
+    (VOID *) ((UINTN) AhciRegisters->AhciCmdList + (UINTN) CommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST)),\r
+    CommandList,\r
+    sizeof (EFI_AHCI_COMMAND_LIST)\r
+    );\r
+\r
+  Data64.Uint64 = (UINT64)(UINTN) AhciRegisters->AhciCommandTable;\r
+  AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtba  = Data64.Uint32.Lower32;\r
+  AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtbau = Data64.Uint32.Upper32;\r
+  AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdPmp   = PortMultiplier;\r
+\r
+}\r
+\r
+/**\r
+  Buid a command FIS.\r
+\r
+  @param  CmdFis            A pointer to the EFI_AHCI_COMMAND_FIS Data structure.\r
+  @param  AtaCommandBlock   A pointer to the AhciBuildCommandFis Data structure.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciBuildCommandFis (\r
+  IN OUT EFI_AHCI_COMMAND_FIS    *CmdFis,\r
+  IN     EFI_ATA_COMMAND_BLOCK   *AtaCommandBlock\r
+  )\r
+{\r
+  ZeroMem (CmdFis, sizeof (EFI_AHCI_COMMAND_FIS));\r
+\r
+  CmdFis->AhciCFisType = EFI_AHCI_FIS_REGISTER_H2D;\r
+  //\r
+  // Indicator it's a command\r
+  //\r
+  CmdFis->AhciCFisCmdInd      = 0x1;\r
+  CmdFis->AhciCFisCmd         = AtaCommandBlock->AtaCommand;\r
+\r
+  CmdFis->AhciCFisFeature     = AtaCommandBlock->AtaFeatures;\r
+  CmdFis->AhciCFisFeatureExp  = AtaCommandBlock->AtaFeaturesExp;\r
+\r
+  CmdFis->AhciCFisSecNum      = AtaCommandBlock->AtaSectorNumber;\r
+  CmdFis->AhciCFisSecNumExp   = AtaCommandBlock->AtaSectorNumberExp;\r
+\r
+  CmdFis->AhciCFisClyLow      = AtaCommandBlock->AtaCylinderLow;\r
+  CmdFis->AhciCFisClyLowExp   = AtaCommandBlock->AtaCylinderLowExp;\r
+\r
+  CmdFis->AhciCFisClyHigh     = AtaCommandBlock->AtaCylinderHigh;\r
+  CmdFis->AhciCFisClyHighExp  = AtaCommandBlock->AtaCylinderHighExp;\r
+\r
+  CmdFis->AhciCFisSecCount    = AtaCommandBlock->AtaSectorCount;\r
+  CmdFis->AhciCFisSecCountExp = AtaCommandBlock->AtaSectorCountExp;\r
+\r
+  CmdFis->AhciCFisDevHead     = (UINT8) (AtaCommandBlock->AtaDeviceHead | 0xE0);\r
+}\r
+\r
+/**\r
+  Start a PIO Data transfer on specific port.\r
+\r
+  @param  AhciContext         The pointer to the AHCI_CONTEXT.\r
+  @param  Port                The number of port.\r
+  @param  PortMultiplier      The timeout Value of stop.\r
+  @param  AtapiCommand        The atapi command will be used for the transfer.\r
+  @param  AtapiCommandLength  The Length of the atapi command.\r
+  @param  Read                The transfer direction.\r
+  @param  AtaCommandBlock     The EFI_ATA_COMMAND_BLOCK Data.\r
+  @param  AtaStatusBlock      The EFI_ATA_STATUS_BLOCK Data.\r
+  @param  MemoryAddr          The pointer to the Data Buffer.\r
+  @param  DataCount           The Data count to be transferred.\r
+  @param  Timeout             The timeout Value of non Data transfer.\r
+\r
+  @retval EFI_DEVICE_ERROR    The PIO Data transfer abort with error occurs.\r
+  @retval EFI_TIMEOUT         The operation is time out.\r
+  @retval EFI_UNSUPPORTED     The device is not ready for transfer.\r
+  @retval EFI_SUCCESS         The PIO Data transfer executes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciPioTransfer (\r
+  IN     AHCI_CONTEXT               *AhciContext,\r
+  IN     UINT8                      Port,\r
+  IN     UINT8                      PortMultiplier,\r
+  IN     EFI_AHCI_ATAPI_COMMAND     *AtapiCommand OPTIONAL,\r
+  IN     UINT8                      AtapiCommandLength,\r
+  IN     BOOLEAN                    Read,\r
+  IN     EFI_ATA_COMMAND_BLOCK      *AtaCommandBlock,\r
+  IN OUT EFI_ATA_STATUS_BLOCK       *AtaStatusBlock,\r
+  IN OUT VOID                       *MemoryAddr,\r
+  IN     UINT32                     DataCount,\r
+  IN     UINT64                     Timeout\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_AHCI_REGISTERS            *AhciRegisters;\r
+  UINT32                        AhciBar;\r
+  UINT32                        FisBaseAddr;\r
+  UINT32                        Offset;\r
+  UINT32                        Delay;\r
+  EFI_AHCI_COMMAND_FIS          CFis;\r
+  EFI_AHCI_COMMAND_LIST         CmdList;\r
+  UINT32                        PortTfd;\r
+  UINT32                        PrdCount;\r
+  UINT32                        OldRfisLo;\r
+  UINT32                        OldRfisHi;\r
+  UINT32                        OldCmdListLo;\r
+  UINT32                        OldCmdListHi;\r
+\r
+  AhciRegisters = &AhciContext->AhciRegisters;\r
+  AhciBar = AhciContext->AhciBar;\r
+\r
+  Offset    = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
+  OldRfisLo = AhciReadReg (AhciBar, Offset);\r
+  Offset    = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;\r
+  OldRfisHi = AhciReadReg (AhciBar, Offset);\r
+  Offset    = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
+  AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciRFis);\r
+  Offset    = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;\r
+  AhciWriteReg (AhciBar, Offset, 0);\r
+\r
+  //\r
+  // Single task envrionment, we only use one command table for all port\r
+  //\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
+  OldCmdListLo = AhciReadReg (AhciBar, Offset);\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;\r
+  OldCmdListHi = AhciReadReg (AhciBar, Offset);\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
+  AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciCmdList);\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;\r
+  AhciWriteReg (AhciBar, Offset, 0);\r
+\r
+  //\r
+  // Package read needed\r
+  //\r
+  AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
+\r
+  ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
+\r
+  CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
+  CmdList.AhciCmdW   = Read ? 0 : 1;\r
+\r
+  AhciBuildCommand (\r
+    AhciContext,\r
+    Port,\r
+    PortMultiplier,\r
+    &CFis,\r
+    &CmdList,\r
+    AtapiCommand,\r
+    AtapiCommandLength,\r
+    0,\r
+    MemoryAddr,\r
+    DataCount\r
+    );\r
+\r
+  Status = AhciStartCommand (\r
+             AhciBar,\r
+             Port,\r
+             0,\r
+             Timeout\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Checking the status and wait the driver sending Data\r
+  //\r
+  FisBaseAddr = (UINT32)(UINTN)AhciRegisters->AhciRFis;\r
+  if (Read && (AtapiCommand == 0)) {\r
+    //\r
+    // Wait device sends the PIO setup fis before Data transfer\r
+    //\r
+    Status = EFI_TIMEOUT;\r
+    Delay  = (UINT32) (DivU64x32 (Timeout, 1000) + 1);\r
+    do {\r
+      Offset = FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET;\r
+\r
+      Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_PIO_SETUP, 0);\r
+      if (!EFI_ERROR (Status)) {\r
+        Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
+        PortTfd = AhciReadReg (AhciBar, (UINT32) Offset);\r
+        //\r
+        // PxTFD will be updated if there is a D2H or SetupFIS received.\r
+        // For PIO IN transfer, D2H means a device error. Therefore we only need to check the TFD after receiving a SetupFIS.\r
+        //\r
+        if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
+          Status = EFI_DEVICE_ERROR;\r
+          break;\r
+        }\r
+\r
+        PrdCount = *(volatile UINT32 *) (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));\r
+        if (PrdCount == DataCount) {\r
+          break;\r
+        }\r
+      }\r
+\r
+      Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
+      Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, 0);\r
+      if (!EFI_ERROR (Status)) {\r
+        Status = EFI_DEVICE_ERROR;\r
+        break;\r
+      }\r
+\r
+      //\r
+      // Stall for 100 microseconds.\r
+      //\r
+      MicroSecondDelay(100);\r
+\r
+      Delay--;\r
+    } while (Delay > 0);\r
+  } else {\r
+    //\r
+    // Wait for D2H Fis is received\r
+    //\r
+    Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
+    Status = AhciWaitMemSet (\r
+               Offset,\r
+               EFI_AHCI_FIS_TYPE_MASK,\r
+               EFI_AHCI_FIS_REGISTER_D2H,\r
+               Timeout\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
+\r
+    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
+    PortTfd = AhciReadReg (AhciBar, (UINT32) Offset);\r
+    if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
+      Status = EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
+\r
+Exit:\r
+  AhciStopCommand (\r
+    AhciBar,\r
+    Port,\r
+    Timeout\r
+    );\r
+\r
+  AhciDisableFisReceive (\r
+    AhciBar,\r
+    Port,\r
+    Timeout\r
+    );\r
+\r
+  Offset    = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
+  AhciWriteReg (AhciBar, Offset, OldRfisLo);\r
+  Offset    = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;\r
+  AhciWriteReg (AhciBar, Offset, OldRfisHi);\r
+\r
+  Offset    = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
+  AhciWriteReg (AhciBar, Offset, OldCmdListLo);\r
+  Offset    = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;\r
+  AhciWriteReg (AhciBar, Offset, OldCmdListHi);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Stop command running for giving port\r
+\r
+  @param  AhciBar            AHCI bar address.\r
+  @param  Port               The number of port.\r
+  @param  Timeout            The timeout Value of stop.\r
+\r
+  @retval EFI_DEVICE_ERROR   The command stop unsuccessfully.\r
+  @retval EFI_TIMEOUT        The operation is time out.\r
+  @retval EFI_SUCCESS        The command stop successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciStopCommand (\r
+  IN  UINT32                    AhciBar,\r
+  IN  UINT8                     Port,\r
+  IN  UINT64                    Timeout\r
+  )\r
+{\r
+  UINT32 Offset;\r
+  UINT32 Data;\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+  Data   = AhciReadReg (AhciBar, Offset);\r
+\r
+  if ((Data & (EFI_AHCI_PORT_CMD_ST |  EFI_AHCI_PORT_CMD_CR)) == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if ((Data & EFI_AHCI_PORT_CMD_ST) != 0) {\r
+    AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_ST));\r
+  }\r
+\r
+  return AhciWaitMmioSet (\r
+           AhciBar,\r
+           Offset,\r
+           EFI_AHCI_PORT_CMD_CR,\r
+           0,\r
+           Timeout\r
+           );\r
+}\r
+\r
+/**\r
+  Start command for give slot on specific port.\r
+\r
+  @param  AhciBar            AHCI bar address.\r
+  @param  Port               The number of port.\r
+  @param  CommandSlot        The number of CommandSlot.\r
+  @param  Timeout            The timeout Value of start.\r
+\r
+  @retval EFI_DEVICE_ERROR   The command start unsuccessfully.\r
+  @retval EFI_TIMEOUT        The operation is time out.\r
+  @retval EFI_SUCCESS        The command start successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciStartCommand (\r
+  IN  UINT32                    AhciBar,\r
+  IN  UINT8                     Port,\r
+  IN  UINT8                     CommandSlot,\r
+  IN  UINT64                    Timeout\r
+  )\r
+{\r
+  UINT32                        CmdSlotBit;\r
+  EFI_STATUS                    Status;\r
+  UINT32                        PortStatus;\r
+  UINT32                        StartCmd;\r
+  UINT32                        PortTfd;\r
+  UINT32                        Offset;\r
+  UINT32                        Capability;\r
+\r
+  //\r
+  // Collect AHCI controller information\r
+  //\r
+  Capability = AhciReadReg(AhciBar, EFI_AHCI_CAPABILITY_OFFSET);\r
+\r
+  CmdSlotBit = (UINT32) (1 << CommandSlot);\r
+\r
+  AhciClearPortStatus (\r
+    AhciBar,\r
+    Port\r
+    );\r
+\r
+  Status = AhciEnableFisReceive (\r
+             AhciBar,\r
+             Port,\r
+             Timeout\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+  PortStatus = AhciReadReg (AhciBar, Offset);\r
+\r
+  StartCmd = 0;\r
+  if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) != 0) {\r
+    StartCmd = AhciReadReg (AhciBar, Offset);\r
+    StartCmd &= ~EFI_AHCI_PORT_CMD_ICC_MASK;\r
+    StartCmd |= EFI_AHCI_PORT_CMD_ACTIVE;\r
+  }\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
+  PortTfd = AhciReadReg (AhciBar, Offset);\r
+\r
+  if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) != 0) {\r
+    if ((Capability & BIT24) != 0) {\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+      AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_COL);\r
+\r
+      AhciWaitMmioSet (\r
+        AhciBar,\r
+        Offset,\r
+        EFI_AHCI_PORT_CMD_COL,\r
+        0,\r
+        Timeout\r
+        );\r
+    }\r
+  }\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+  AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_ST | StartCmd);\r
+\r
+  //\r
+  // Setting the command\r
+  //\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SACT;\r
+  AhciAndReg (AhciBar, Offset, 0);\r
+  AhciOrReg (AhciBar, Offset, CmdSlotBit);\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
+  AhciAndReg (AhciBar, Offset, 0);\r
+  AhciOrReg (AhciBar, Offset, CmdSlotBit);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Do AHCI HBA reset.\r
+\r
+  @param[in]  AhciBar        AHCI bar address.\r
+  @param[in]  Timeout        The timeout Value of reset.\r
+\r
+  @retval EFI_DEVICE_ERROR   AHCI controller is failed to complete hardware reset.\r
+  @retval EFI_TIMEOUT        The reset operation is time out.\r
+  @retval EFI_SUCCESS        AHCI controller is reset successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciReset (\r
+  IN  UINT32                    AhciBar,\r
+  IN  UINT64                    Timeout\r
+  )\r
+{\r
+  UINT32                 Delay;\r
+  UINT32                 Value;\r
+  UINT32                 Capability;\r
+\r
+  //\r
+  // Collect AHCI controller information\r
+  //\r
+  Capability = AhciReadReg (AhciBar, EFI_AHCI_CAPABILITY_OFFSET);\r
+\r
+  //\r
+  // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only is not set\r
+  //\r
+  if ((Capability & EFI_AHCI_CAP_SAM) == 0) {\r
+    AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
+  }\r
+\r
+  AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);\r
+\r
+  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+\r
+  do {\r
+    Value = AhciReadReg(AhciBar, EFI_AHCI_GHC_OFFSET);\r
+    if ((Value & EFI_AHCI_GHC_RESET) == 0) {\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    //\r
+    // Stall for 100 microseconds.\r
+    //\r
+    MicroSecondDelay(100);\r
+\r
+    Delay--;\r
+  } while (Delay > 0);\r
+\r
+  return EFI_TIMEOUT;\r
+\r
+\r
+}\r
+\r
+/**\r
+  Send Buffer cmd to specific device.\r
+\r
+  @param[in]  AhciContext         The pointer to the AHCI_CONTEXT.\r
+  @param[in]  Port                The port number of attached ATA device.\r
+  @param[in]  PortMultiplier      The port number of port multiplier of attached ATA device.\r
+  @param[in, out]  Buffer         The Data Buffer to store IDENTIFY PACKET Data.\r
+\r
+  @retval EFI_DEVICE_ERROR    The cmd abort with error occurs.\r
+  @retval EFI_TIMEOUT         The operation is time out.\r
+  @retval EFI_UNSUPPORTED     The device is not ready for executing.\r
+  @retval EFI_SUCCESS         The cmd executes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciIdentify (\r
+  IN AHCI_CONTEXT             *AhciContext,\r
+  IN UINT8                    Port,\r
+  IN UINT8                    PortMultiplier,\r
+  IN OUT ATA_IDENTIFY_DATA    *Buffer\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_ATA_COMMAND_BLOCK        AtaCommandBlock;\r
+\r
+  if (AhciContext == NULL || Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+\r
+  AtaCommandBlock.AtaCommand     = ATA_CMD_IDENTIFY_DRIVE;\r
+  AtaCommandBlock.AtaSectorCount = 1;\r
+\r
+  Status = AhciPioTransfer (\r
+             AhciContext,\r
+             Port,\r
+             PortMultiplier,\r
+             NULL,\r
+             0,\r
+             TRUE,\r
+             &AtaCommandBlock,\r
+             NULL,\r
+             Buffer,\r
+             sizeof (ATA_IDENTIFY_DATA),\r
+             ATA_TIMEOUT\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Allocate transfer-related data struct which is used at AHCI mode.\r
+\r
+  @param[in, out] AhciContext   The pointer to the AHCI_CONTEXT.\r
+\r
+  @retval EFI_OUT_OF_RESOURCE   No enough resource.\r
+  @retval EFI_SUCCESS           Successful to allocate resource.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciAllocateResource (\r
+  IN OUT AHCI_CONTEXT       *AhciContext\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_AHCI_REGISTERS        *AhciRegisters;\r
+  EFI_PHYSICAL_ADDRESS      DeviceAddress;\r
+  VOID                      *Base;\r
+  VOID                      *Mapping;\r
+\r
+  AhciRegisters = &AhciContext->AhciRegisters;\r
+\r
+  //\r
+  // Allocate resources required by AHCI host controller.\r
+  //\r
+  Status = IoMmuAllocateBuffer (\r
+             EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),\r
+             &Base,\r
+             &DeviceAddress,\r
+             &Mapping\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));\r
+  AhciRegisters->AhciRFisMapping = Mapping;\r
+  AhciRegisters->AhciRFis = Base;\r
+  ZeroMem (AhciRegisters->AhciRFis, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)));\r
+\r
+  Status = IoMmuAllocateBuffer (\r
+             EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),\r
+             &Base,\r
+             &DeviceAddress,\r
+             &Mapping\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    IoMmuFreeBuffer (\r
+       EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),\r
+       AhciRegisters->AhciRFis,\r
+       AhciRegisters->AhciRFisMapping\r
+       );\r
+    AhciRegisters->AhciRFis = NULL;\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));\r
+  AhciRegisters->AhciCmdListMapping = Mapping;\r
+  AhciRegisters->AhciCmdList = Base;\r
+  ZeroMem (AhciRegisters->AhciCmdList, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)));\r
+\r
+  Status = IoMmuAllocateBuffer (\r
+             EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)),\r
+             &Base,\r
+             &DeviceAddress,\r
+             &Mapping\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    IoMmuFreeBuffer (\r
+       EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),\r
+       AhciRegisters->AhciCmdList,\r
+       AhciRegisters->AhciCmdListMapping\r
+       );\r
+    AhciRegisters->AhciCmdList = NULL;\r
+    IoMmuFreeBuffer (\r
+       EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),\r
+       AhciRegisters->AhciRFis,\r
+       AhciRegisters->AhciRFisMapping\r
+       );\r
+    AhciRegisters->AhciRFis = NULL;\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));\r
+  AhciRegisters->AhciCommandTableMapping = Mapping;\r
+  AhciRegisters->AhciCommandTable = Base;\r
+  ZeroMem (AhciRegisters->AhciCommandTable, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)));\r
+\r
+  //\r
+  // Allocate resources for data transfer.\r
+  //\r
+  Status = IoMmuAllocateBuffer (\r
+             EFI_SIZE_TO_PAGES (HDD_PAYLOAD),\r
+             &Base,\r
+             &DeviceAddress,\r
+             &Mapping\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    IoMmuFreeBuffer (\r
+       EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),\r
+       AhciRegisters->AhciCommandTable,\r
+       AhciRegisters->AhciCommandTableMapping\r
+       );\r
+    AhciRegisters->AhciCommandTable = NULL;\r
+    IoMmuFreeBuffer (\r
+       EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),\r
+       AhciRegisters->AhciCmdList,\r
+       AhciRegisters->AhciCmdListMapping\r
+       );\r
+    AhciRegisters->AhciCmdList = NULL;\r
+    IoMmuFreeBuffer (\r
+       EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),\r
+       AhciRegisters->AhciRFis,\r
+       AhciRegisters->AhciRFisMapping\r
+       );\r
+    AhciRegisters->AhciRFis = NULL;\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));\r
+  AhciContext->BufferMapping = Mapping;\r
+  AhciContext->Buffer = Base;\r
+  ZeroMem (AhciContext->Buffer, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (HDD_PAYLOAD));\r
+\r
+  DEBUG ((\r
+    DEBUG_INFO,\r
+    "%a() AhciContext 0x%x 0x%x 0x%x 0x%x\n",\r
+    __FUNCTION__,\r
+    AhciContext->Buffer,\r
+    AhciRegisters->AhciRFis,\r
+    AhciRegisters->AhciCmdList,\r
+    AhciRegisters->AhciCommandTable\r
+    ));\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Free allocated transfer-related data struct which is used at AHCI mode.\r
+\r
+  @param[in, out] AhciContext   The pointer to the AHCI_CONTEXT.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciFreeResource (\r
+  IN OUT AHCI_CONTEXT       *AhciContext\r
+  )\r
+{\r
+  EFI_AHCI_REGISTERS        *AhciRegisters;\r
+\r
+  AhciRegisters = &AhciContext->AhciRegisters;\r
+\r
+  if (AhciContext->Buffer != NULL) {\r
+    IoMmuFreeBuffer (\r
+       EFI_SIZE_TO_PAGES (HDD_PAYLOAD),\r
+       AhciContext->Buffer,\r
+       AhciContext->BufferMapping\r
+       );\r
+    AhciContext->Buffer = NULL;\r
+  }\r
+\r
+  if (AhciRegisters->AhciCommandTable != NULL) {\r
+    IoMmuFreeBuffer (\r
+       EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)),\r
+       AhciRegisters->AhciCommandTable,\r
+       AhciRegisters->AhciCommandTableMapping\r
+       );\r
+    AhciRegisters->AhciCommandTable = NULL;\r
+  }\r
+\r
+  if (AhciRegisters->AhciCmdList != NULL) {\r
+    IoMmuFreeBuffer (\r
+       EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),\r
+       AhciRegisters->AhciCmdList,\r
+       AhciRegisters->AhciCmdListMapping\r
+       );\r
+    AhciRegisters->AhciCmdList = NULL;\r
+  }\r
+\r
+  if (AhciRegisters->AhciRFis != NULL) {\r
+    IoMmuFreeBuffer (\r
+       EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),\r
+       AhciRegisters->AhciRFis,\r
+       AhciRegisters->AhciRFisMapping\r
+       );\r
+    AhciRegisters->AhciRFis = NULL;\r
+  }\r
+}\r
+\r
+/**\r
+  Initialize ATA host controller at AHCI mode.\r
+\r
+  The function is designed to initialize ATA host controller.\r
+\r
+  @param[in]  AhciContext   The pointer to the AHCI_CONTEXT.\r
+  @param[in]  Port          The port number to do initialization.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciModeInitialize (\r
+  IN AHCI_CONTEXT    *AhciContext,\r
+  IN UINT8           Port\r
+  )\r
+{\r
+  EFI_STATUS         Status;\r
+  EFI_AHCI_REGISTERS *AhciRegisters;\r
+  UINT32             AhciBar;\r
+  UINT32             Capability;\r
+  UINT32             Offset;\r
+  UINT32             Data;\r
+  UINT32             PhyDetectDelay;\r
+\r
+  AhciRegisters = &AhciContext->AhciRegisters;\r
+  AhciBar = AhciContext->AhciBar;\r
+\r
+  Status = AhciReset (AhciBar, ATA_TIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Collect AHCI controller information\r
+  //\r
+  Capability = AhciReadReg (AhciBar, EFI_AHCI_CAPABILITY_OFFSET);\r
+\r
+  //\r
+  // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only is not set\r
+  //\r
+  if ((Capability & EFI_AHCI_CAP_SAM) == 0) {\r
+    AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
+  }\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
+  AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciRFis);\r
+\r
+  //\r
+  // Single task envrionment, we only use one command table for all port\r
+  //\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
+  AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciCmdList);\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+  Data = AhciReadReg (AhciBar, Offset);\r
+  if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) {\r
+    AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_POD);\r
+  }\r
+\r
+  if ((Capability & BIT27) != 0) {\r
+    AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_SUD);\r
+  }\r
+\r
+  //\r
+  // Disable aggressive power management.\r
+  //\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
+  AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_SCTL_IPM_INIT);\r
+  //\r
+  // Disable the reporting of the corresponding interrupt to system software.\r
+  //\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;\r
+  AhciAndReg (AhciBar, Offset, 0);\r
+\r
+  Status = AhciEnableFisReceive (\r
+             AhciBar,\r
+             Port,\r
+             5000000\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ\r
+  // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.\r
+  //\r
+  PhyDetectDelay = 16 * 1000;\r
+  do {\r
+    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
+    if (AhciReadReg(AhciBar, Offset) != 0) {\r
+      AhciWriteReg (AhciBar, Offset, AhciReadReg(AhciBar, Offset));\r
+    }\r
+    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
+\r
+    Data = AhciReadReg (AhciBar, Offset) & EFI_AHCI_PORT_TFD_MASK;\r
+    if (Data == 0) {\r
+      break;\r
+    }\r
+\r
+    MicroSecondDelay (1000);\r
+    PhyDetectDelay--;\r
+  } while (PhyDetectDelay > 0);\r
+\r
+  if (PhyDetectDelay == 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;\r
+  Status = AhciWaitMmioSet (\r
+             AhciBar,\r
+             Offset,\r
+             0x0000FFFF,\r
+             0x00000101,\r
+             160000000\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.h b/SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.h
new file mode 100644 (file)
index 0000000..b1d6ed1
--- /dev/null
@@ -0,0 +1,435 @@
+/** @file\r
+  Header file for AHCI mode of ATA host controller.\r
+\r
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#ifndef __OPAL_PASSWORD_AHCI_MODE_H__\r
+#define __OPAL_PASSWORD_AHCI_MODE_H__\r
+\r
+//\r
+// OPAL LIBRARY CALLBACKS\r
+//\r
+#define ATA_COMMAND_TRUSTED_RECEIVE            0x5C\r
+#define ATA_COMMAND_TRUSTED_SEND               0x5E\r
+\r
+//\r
+// ATA TRUSTED commands express transfer Length in 512 byte multiple\r
+//\r
+#define ATA_TRUSTED_TRANSFER_LENGTH_MULTIPLE   512\r
+#define ATA_DEVICE_LBA                         0x40    ///< Set for commands with LBA (rather than CHS) addresses\r
+\r
+\r
+#define EFI_AHCI_BAR_INDEX                     0x05\r
+\r
+#define EFI_AHCI_CAPABILITY_OFFSET             0x0000\r
+#define   EFI_AHCI_CAP_SAM                     BIT18\r
+#define EFI_AHCI_GHC_OFFSET                    0x0004\r
+#define   EFI_AHCI_GHC_RESET                   BIT0\r
+#define   EFI_AHCI_GHC_IE                      BIT1\r
+#define   EFI_AHCI_GHC_ENABLE                  BIT31\r
+#define EFI_AHCI_IS_OFFSET                     0x0008\r
+#define EFI_AHCI_PI_OFFSET                     0x000C\r
+\r
+typedef struct {\r
+  UINT32  Lower32;\r
+  UINT32  Upper32;\r
+} DATA_32;\r
+\r
+typedef union {\r
+  DATA_32   Uint32;\r
+  UINT64    Uint64;\r
+} DATA_64;\r
+\r
+//\r
+// Each PRDT entry can point to a memory block up to 4M byte\r
+//\r
+#define EFI_AHCI_MAX_DATA_PER_PRDT             0x400000\r
+\r
+#define EFI_AHCI_FIS_REGISTER_H2D              0x27      //Register FIS - Host to Device\r
+#define   EFI_AHCI_FIS_REGISTER_H2D_LENGTH     20\r
+#define EFI_AHCI_FIS_REGISTER_D2H              0x34      //Register FIS - Device to Host\r
+#define   EFI_AHCI_FIS_REGISTER_D2H_LENGTH     20\r
+#define EFI_AHCI_FIS_DMA_ACTIVATE              0x39      //DMA Activate FIS - Device to Host\r
+#define   EFI_AHCI_FIS_DMA_ACTIVATE_LENGTH     4\r
+#define EFI_AHCI_FIS_DMA_SETUP                 0x41      //DMA Setup FIS - Bi-directional\r
+#define   EFI_AHCI_FIS_DMA_SETUP_LENGTH        28\r
+#define EFI_AHCI_FIS_DATA                      0x46      //Data FIS - Bi-directional\r
+#define EFI_AHCI_FIS_BIST                      0x58      //BIST Activate FIS - Bi-directional\r
+#define   EFI_AHCI_FIS_BIST_LENGTH             12\r
+#define EFI_AHCI_FIS_PIO_SETUP                 0x5F      //PIO Setup FIS - Device to Host\r
+#define   EFI_AHCI_FIS_PIO_SETUP_LENGTH        20\r
+#define EFI_AHCI_FIS_SET_DEVICE                0xA1      //Set Device Bits FIS - Device to Host\r
+#define   EFI_AHCI_FIS_SET_DEVICE_LENGTH       8\r
+\r
+#define EFI_AHCI_D2H_FIS_OFFSET                0x40\r
+#define EFI_AHCI_DMA_FIS_OFFSET                0x00\r
+#define EFI_AHCI_PIO_FIS_OFFSET                0x20\r
+#define EFI_AHCI_SDB_FIS_OFFSET                0x58\r
+#define EFI_AHCI_FIS_TYPE_MASK                 0xFF\r
+#define EFI_AHCI_U_FIS_OFFSET                  0x60\r
+\r
+//\r
+// Port register\r
+//\r
+#define EFI_AHCI_PORT_START                    0x0100\r
+#define EFI_AHCI_PORT_REG_WIDTH                0x0080\r
+#define EFI_AHCI_PORT_CLB                      0x0000\r
+#define EFI_AHCI_PORT_CLBU                     0x0004\r
+#define EFI_AHCI_PORT_FB                       0x0008\r
+#define EFI_AHCI_PORT_FBU                      0x000C\r
+#define EFI_AHCI_PORT_IS                       0x0010\r
+#define   EFI_AHCI_PORT_IS_DHRS                BIT0\r
+#define   EFI_AHCI_PORT_IS_PSS                 BIT1\r
+#define   EFI_AHCI_PORT_IS_SSS                 BIT2\r
+#define   EFI_AHCI_PORT_IS_SDBS                BIT3\r
+#define   EFI_AHCI_PORT_IS_UFS                 BIT4\r
+#define   EFI_AHCI_PORT_IS_DPS                 BIT5\r
+#define   EFI_AHCI_PORT_IS_PCS                 BIT6\r
+#define   EFI_AHCI_PORT_IS_DIS                 BIT7\r
+#define   EFI_AHCI_PORT_IS_PRCS                BIT22\r
+#define   EFI_AHCI_PORT_IS_IPMS                BIT23\r
+#define   EFI_AHCI_PORT_IS_OFS                 BIT24\r
+#define   EFI_AHCI_PORT_IS_INFS                BIT26\r
+#define   EFI_AHCI_PORT_IS_IFS                 BIT27\r
+#define   EFI_AHCI_PORT_IS_HBDS                BIT28\r
+#define   EFI_AHCI_PORT_IS_HBFS                BIT29\r
+#define   EFI_AHCI_PORT_IS_TFES                BIT30\r
+#define   EFI_AHCI_PORT_IS_CPDS                BIT31\r
+#define   EFI_AHCI_PORT_IS_CLEAR               0xFFFFFFFF\r
+#define   EFI_AHCI_PORT_IS_FIS_CLEAR           0x0000000F\r
+\r
+#define EFI_AHCI_PORT_IE                       0x0014\r
+#define EFI_AHCI_PORT_CMD                      0x0018\r
+#define   EFI_AHCI_PORT_CMD_ST_MASK            0xFFFFFFFE\r
+#define   EFI_AHCI_PORT_CMD_ST                 BIT0\r
+#define   EFI_AHCI_PORT_CMD_SUD                BIT1\r
+#define   EFI_AHCI_PORT_CMD_POD                BIT2\r
+#define   EFI_AHCI_PORT_CMD_COL                BIT3\r
+#define   EFI_AHCI_PORT_CMD_CR                 BIT15\r
+#define   EFI_AHCI_PORT_CMD_FRE                BIT4\r
+#define   EFI_AHCI_PORT_CMD_FR                 BIT14\r
+#define   EFI_AHCI_PORT_CMD_MASK               ~(EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_FRE | EFI_AHCI_PORT_CMD_COL)\r
+#define   EFI_AHCI_PORT_CMD_PMA                BIT17\r
+#define   EFI_AHCI_PORT_CMD_HPCP               BIT18\r
+#define   EFI_AHCI_PORT_CMD_MPSP               BIT19\r
+#define   EFI_AHCI_PORT_CMD_CPD                BIT20\r
+#define   EFI_AHCI_PORT_CMD_ESP                BIT21\r
+#define   EFI_AHCI_PORT_CMD_ATAPI              BIT24\r
+#define   EFI_AHCI_PORT_CMD_DLAE               BIT25\r
+#define   EFI_AHCI_PORT_CMD_ALPE               BIT26\r
+#define   EFI_AHCI_PORT_CMD_ASP                BIT27\r
+#define   EFI_AHCI_PORT_CMD_ICC_MASK           (BIT28 | BIT29 | BIT30 | BIT31)\r
+#define   EFI_AHCI_PORT_CMD_ACTIVE             (1 << 28 )\r
+#define EFI_AHCI_PORT_TFD                      0x0020\r
+#define   EFI_AHCI_PORT_TFD_MASK               (BIT7 | BIT3 | BIT0)\r
+#define   EFI_AHCI_PORT_TFD_BSY                BIT7\r
+#define   EFI_AHCI_PORT_TFD_DRQ                BIT3\r
+#define   EFI_AHCI_PORT_TFD_ERR                BIT0\r
+#define   EFI_AHCI_PORT_TFD_ERR_MASK           0x00FF00\r
+#define EFI_AHCI_PORT_SIG                      0x0024\r
+#define EFI_AHCI_PORT_SSTS                     0x0028\r
+#define   EFI_AHCI_PORT_SSTS_DET_MASK          0x000F\r
+#define   EFI_AHCI_PORT_SSTS_DET               0x0001\r
+#define   EFI_AHCI_PORT_SSTS_DET_PCE           0x0003\r
+#define   EFI_AHCI_PORT_SSTS_SPD_MASK          0x00F0\r
+#define EFI_AHCI_PORT_SCTL                     0x002C\r
+#define   EFI_AHCI_PORT_SCTL_DET_MASK          0x000F\r
+#define   EFI_AHCI_PORT_SCTL_MASK              (~EFI_AHCI_PORT_SCTL_DET_MASK)\r
+#define   EFI_AHCI_PORT_SCTL_DET_INIT          0x0001\r
+#define   EFI_AHCI_PORT_SCTL_DET_PHYCOMM       0x0003\r
+#define   EFI_AHCI_PORT_SCTL_SPD_MASK          0x00F0\r
+#define   EFI_AHCI_PORT_SCTL_IPM_MASK          0x0F00\r
+#define   EFI_AHCI_PORT_SCTL_IPM_INIT          0x0300\r
+#define   EFI_AHCI_PORT_SCTL_IPM_PSD           0x0100\r
+#define   EFI_AHCI_PORT_SCTL_IPM_SSD           0x0200\r
+#define EFI_AHCI_PORT_SERR                     0x0030\r
+#define   EFI_AHCI_PORT_SERR_RDIE              BIT0\r
+#define   EFI_AHCI_PORT_SERR_RCE               BIT1\r
+#define   EFI_AHCI_PORT_SERR_TDIE              BIT8\r
+#define   EFI_AHCI_PORT_SERR_PCDIE             BIT9\r
+#define   EFI_AHCI_PORT_SERR_PE                BIT10\r
+#define   EFI_AHCI_PORT_SERR_IE                BIT11\r
+#define   EFI_AHCI_PORT_SERR_PRC               BIT16\r
+#define   EFI_AHCI_PORT_SERR_PIE               BIT17\r
+#define   EFI_AHCI_PORT_SERR_CW                BIT18\r
+#define   EFI_AHCI_PORT_SERR_BDE               BIT19\r
+#define   EFI_AHCI_PORT_SERR_DE                BIT20\r
+#define   EFI_AHCI_PORT_SERR_CRCE              BIT21\r
+#define   EFI_AHCI_PORT_SERR_HE                BIT22\r
+#define   EFI_AHCI_PORT_SERR_LSE               BIT23\r
+#define   EFI_AHCI_PORT_SERR_TSTE              BIT24\r
+#define   EFI_AHCI_PORT_SERR_UFT               BIT25\r
+#define   EFI_AHCI_PORT_SERR_EX                BIT26\r
+#define   EFI_AHCI_PORT_ERR_CLEAR              0xFFFFFFFF\r
+#define EFI_AHCI_PORT_SACT                     0x0034\r
+#define EFI_AHCI_PORT_CI                       0x0038\r
+#define EFI_AHCI_PORT_SNTF                     0x003C\r
+\r
+\r
+#pragma pack(1)\r
+//\r
+// Command List structure includes total 32 entries.\r
+// The entry Data structure is listed at the following.\r
+//\r
+typedef struct {\r
+  UINT32   AhciCmdCfl:5;      //Command FIS Length\r
+  UINT32   AhciCmdA:1;        //ATAPI\r
+  UINT32   AhciCmdW:1;        //Write\r
+  UINT32   AhciCmdP:1;        //Prefetchable\r
+  UINT32   AhciCmdR:1;        //Reset\r
+  UINT32   AhciCmdB:1;        //BIST\r
+  UINT32   AhciCmdC:1;        //Clear Busy upon R_OK\r
+  UINT32   AhciCmdRsvd:1;\r
+  UINT32   AhciCmdPmp:4;      //Port Multiplier Port\r
+  UINT32   AhciCmdPrdtl:16;   //Physical Region Descriptor Table Length\r
+  UINT32   AhciCmdPrdbc;      //Physical Region Descriptor Byte Count\r
+  UINT32   AhciCmdCtba;       //Command Table Descriptor Base Address\r
+  UINT32   AhciCmdCtbau;      //Command Table Descriptor Base Address Upper 32-BITs\r
+  UINT32   AhciCmdRsvd1[4];\r
+} EFI_AHCI_COMMAND_LIST;\r
+\r
+//\r
+// This is a software constructed FIS.\r
+// For Data transfer operations, this is the H2D Register FIS format as\r
+// specified in the Serial ATA Revision 2.6 specification.\r
+//\r
+typedef struct {\r
+  UINT8    AhciCFisType;\r
+  UINT8    AhciCFisPmNum:4;\r
+  UINT8    AhciCFisRsvd:1;\r
+  UINT8    AhciCFisRsvd1:1;\r
+  UINT8    AhciCFisRsvd2:1;\r
+  UINT8    AhciCFisCmdInd:1;\r
+  UINT8    AhciCFisCmd;\r
+  UINT8    AhciCFisFeature;\r
+  UINT8    AhciCFisSecNum;\r
+  UINT8    AhciCFisClyLow;\r
+  UINT8    AhciCFisClyHigh;\r
+  UINT8    AhciCFisDevHead;\r
+  UINT8    AhciCFisSecNumExp;\r
+  UINT8    AhciCFisClyLowExp;\r
+  UINT8    AhciCFisClyHighExp;\r
+  UINT8    AhciCFisFeatureExp;\r
+  UINT8    AhciCFisSecCount;\r
+  UINT8    AhciCFisSecCountExp;\r
+  UINT8    AhciCFisRsvd3;\r
+  UINT8    AhciCFisControl;\r
+  UINT8    AhciCFisRsvd4[4];\r
+  UINT8    AhciCFisRsvd5[44];\r
+} EFI_AHCI_COMMAND_FIS;\r
+\r
+//\r
+// ACMD: ATAPI command (12 or 16 bytes)\r
+//\r
+typedef struct {\r
+  UINT8    AtapiCmd[0x10];\r
+} EFI_AHCI_ATAPI_COMMAND;\r
+\r
+//\r
+// Physical Region Descriptor Table includes up to 65535 entries\r
+// The entry Data structure is listed at the following.\r
+// the actual entry number comes from the PRDTL field in the command\r
+// list entry for this command slot.\r
+//\r
+typedef struct {\r
+  UINT32   AhciPrdtDba;       //Data Base Address\r
+  UINT32   AhciPrdtDbau;      //Data Base Address Upper 32-BITs\r
+  UINT32   AhciPrdtRsvd;\r
+  UINT32   AhciPrdtDbc:22;    //Data Byte Count\r
+  UINT32   AhciPrdtRsvd1:9;\r
+  UINT32   AhciPrdtIoc:1;     //Interrupt on Completion\r
+} EFI_AHCI_COMMAND_PRDT;\r
+\r
+//\r
+// Command table Data strucute which is pointed to by the entry in the command list\r
+//\r
+typedef struct {\r
+  EFI_AHCI_COMMAND_FIS      CommandFis;       // A software constructed FIS.\r
+  EFI_AHCI_ATAPI_COMMAND    AtapiCmd;         // 12 or 16 bytes ATAPI cmd.\r
+  UINT8                     Reserved[0x30];\r
+  EFI_AHCI_COMMAND_PRDT     PrdtTable;    // The scatter/gather list for Data transfer\r
+} EFI_AHCI_COMMAND_TABLE;\r
+\r
+//\r
+// Received FIS structure\r
+//\r
+typedef struct {\r
+  UINT8    AhciDmaSetupFis[0x1C];         // Dma Setup Fis: offset 0x00\r
+  UINT8    AhciDmaSetupFisRsvd[0x04];\r
+  UINT8    AhciPioSetupFis[0x14];         // Pio Setup Fis: offset 0x20\r
+  UINT8    AhciPioSetupFisRsvd[0x0C];\r
+  UINT8    AhciD2HRegisterFis[0x14];      // D2H Register Fis: offset 0x40\r
+  UINT8    AhciD2HRegisterFisRsvd[0x04];\r
+  UINT64   AhciSetDeviceBitsFis;          // Set Device Bits Fix: offset 0x58\r
+  UINT8    AhciUnknownFis[0x40];          // Unkonwn Fis: offset 0x60\r
+  UINT8    AhciUnknownFisRsvd[0x60];\r
+} EFI_AHCI_RECEIVED_FIS;\r
+\r
+#pragma pack()\r
+\r
+typedef struct {\r
+  EFI_AHCI_RECEIVED_FIS     *AhciRFis;\r
+  VOID                      *AhciRFisMapping;\r
+  EFI_AHCI_COMMAND_LIST     *AhciCmdList;\r
+  VOID                      *AhciCmdListMapping;\r
+  EFI_AHCI_COMMAND_TABLE    *AhciCommandTable;\r
+  VOID                      *AhciCommandTableMapping;\r
+} EFI_AHCI_REGISTERS;\r
+\r
+typedef struct {\r
+  VOID                      *Buffer;\r
+  VOID                      *BufferMapping;\r
+  EFI_AHCI_REGISTERS        AhciRegisters;\r
+  UINT32                    AhciBar;\r
+} AHCI_CONTEXT;\r
+\r
+/**\r
+  Send Buffer cmd to specific device.\r
+\r
+  @param  AhciContext         The pointer to the AHCI_CONTEXT.\r
+  @param  Port                The number of port.\r
+  @param  PortMultiplier      The timeout Value of stop.\r
+  @param  Buffer              The Data Buffer to store IDENTIFY PACKET Data.\r
+\r
+  @retval EFI_DEVICE_ERROR    The cmd abort with error occurs.\r
+  @retval EFI_TIMEOUT         The operation is time out.\r
+  @retval EFI_UNSUPPORTED     The device is not ready for executing.\r
+  @retval EFI_SUCCESS         The cmd executes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciIdentify (\r
+  IN AHCI_CONTEXT             *AhciContext,\r
+  IN UINT8                    Port,\r
+  IN UINT8                    PortMultiplier,\r
+  IN OUT ATA_IDENTIFY_DATA    *Buffer\r
+  );\r
+\r
+/**\r
+  Allocate transfer-related data struct which is used at AHCI mode.\r
+\r
+  @param[in, out] AhciContext   The pointer to the AHCI_CONTEXT.\r
+\r
+  @retval EFI_OUT_OF_RESOURCE   No enough resource.\r
+  @retval EFI_SUCCESS           Successful to allocate resource.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciAllocateResource (\r
+  IN OUT AHCI_CONTEXT       *AhciContext\r
+  );\r
+\r
+/**\r
+  Free allocated transfer-related data struct which is used at AHCI mode.\r
+\r
+  @param[in, out] AhciContext   The pointer to the AHCI_CONTEXT.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciFreeResource (\r
+  IN OUT AHCI_CONTEXT       *AhciContext\r
+  );\r
+\r
+/**\r
+  Initialize ATA host controller at AHCI mode.\r
+\r
+  The function is designed to initialize ATA host controller.\r
+\r
+  @param[in]  AhciContext   The pointer to the AHCI_CONTEXT.\r
+  @param[in]  Port          The port number to do initialization.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciModeInitialize (\r
+  IN AHCI_CONTEXT    *AhciContext,\r
+  IN UINT8           Port\r
+  );\r
+\r
+typedef struct _EFI_ATA_COMMAND_BLOCK {\r
+  UINT8 Reserved1[2];\r
+  UINT8 AtaCommand;\r
+  UINT8 AtaFeatures;\r
+  UINT8 AtaSectorNumber;\r
+  UINT8 AtaCylinderLow;\r
+  UINT8 AtaCylinderHigh;\r
+  UINT8 AtaDeviceHead;\r
+  UINT8 AtaSectorNumberExp;\r
+  UINT8 AtaCylinderLowExp;\r
+  UINT8 AtaCylinderHighExp; \r
+  UINT8 AtaFeaturesExp;\r
+  UINT8 AtaSectorCount;\r
+  UINT8 AtaSectorCountExp;\r
+  UINT8 Reserved2[6];\r
+} EFI_ATA_COMMAND_BLOCK;\r
+\r
+typedef struct _EFI_ATA_STATUS_BLOCK {\r
+  UINT8 Reserved1[2];\r
+  UINT8 AtaStatus;\r
+  UINT8 AtaError;\r
+  UINT8 AtaSectorNumber;\r
+  UINT8 AtaCylinderLow;\r
+  UINT8 AtaCylinderHigh;\r
+  UINT8 AtaDeviceHead;\r
+  UINT8 AtaSectorNumberExp;\r
+  UINT8 AtaCylinderLowExp;\r
+  UINT8 AtaCylinderHighExp; \r
+  UINT8 Reserved2;\r
+  UINT8 AtaSectorCount;\r
+  UINT8 AtaSectorCountExp;\r
+  UINT8 Reserved3[6];\r
+} EFI_ATA_STATUS_BLOCK;\r
+\r
+/**\r
+  Start a PIO Data transfer on specific port.\r
+\r
+  @param  AhciContext         The pointer to the AHCI_CONTEXT.\r
+  @param  Port                The number of port.\r
+  @param  PortMultiplier      The timeout Value of stop.\r
+  @param  AtapiCommand        The atapi command will be used for the transfer.\r
+  @param  AtapiCommandLength  The Length of the atapi command.\r
+  @param  Read                The transfer direction.\r
+  @param  AtaCommandBlock     The EFI_ATA_COMMAND_BLOCK Data.\r
+  @param  AtaStatusBlock      The EFI_ATA_STATUS_BLOCK Data.\r
+  @param  MemoryAddr          The pointer to the Data Buffer.\r
+  @param  DataCount           The Data count to be transferred.\r
+  @param  Timeout             The timeout Value of non Data transfer.\r
+\r
+  @retval EFI_DEVICE_ERROR    The PIO Data transfer abort with error occurs.\r
+  @retval EFI_TIMEOUT         The operation is time out.\r
+  @retval EFI_UNSUPPORTED     The device is not ready for transfer.\r
+  @retval EFI_SUCCESS         The PIO Data transfer executes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciPioTransfer (\r
+  IN     AHCI_CONTEXT               *AhciContext,\r
+  IN     UINT8                      Port,\r
+  IN     UINT8                      PortMultiplier,\r
+  IN     EFI_AHCI_ATAPI_COMMAND     *AtapiCommand OPTIONAL,\r
+  IN     UINT8                      AtapiCommandLength,\r
+  IN     BOOLEAN                    Read,\r
+  IN     EFI_ATA_COMMAND_BLOCK      *AtaCommandBlock,\r
+  IN OUT EFI_ATA_STATUS_BLOCK       *AtaStatusBlock,\r
+  IN OUT VOID                       *MemoryAddr,\r
+  IN     UINT32                     DataCount,\r
+  IN     UINT64                     Timeout\r
+  );\r
+\r
+\r
+#endif\r
+\r
diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c b/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c
new file mode 100644 (file)
index 0000000..d2597ce
--- /dev/null
@@ -0,0 +1,3006 @@
+/** @file\r
+  Entrypoint of Opal UEFI Driver and contains all the logic to\r
+  register for new Opal device instances.\r
+\r
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+// This UEFI driver consumes EFI_STORAGE_SECURITY_PROTOCOL instances and installs an\r
+// HII GUI to manage Opal features if the device is Opal capable\r
+// If the Opal device is being managed by the UEFI Driver, it shall provide a popup\r
+// window during boot requesting a user password\r
+\r
+#include "OpalDriver.h"\r
+#include "OpalHii.h"\r
+\r
+EFI_GUID mOpalDeviceAtaGuid = OPAL_DEVICE_ATA_GUID;\r
+EFI_GUID mOpalDeviceNvmeGuid = OPAL_DEVICE_NVME_GUID;\r
+\r
+BOOLEAN                 mOpalEndOfDxe = FALSE;\r
+OPAL_REQUEST_VARIABLE   *mOpalRequestVariable = NULL;\r
+UINTN                   mOpalRequestVariableSize = 0;\r
+CHAR16                  mPopUpString[256];\r
+\r
+typedef struct {\r
+  UINT32                   Address;\r
+  S3_BOOT_SCRIPT_LIB_WIDTH Width;\r
+} OPAL_HC_PCI_REGISTER_SAVE;\r
+\r
+//\r
+// To unlock the Intel SATA controller at S3 Resume, restored the following registers.\r
+//\r
+const OPAL_HC_PCI_REGISTER_SAVE mSataHcRegisterSaveTemplate[] = {\r
+  {0x9,  S3BootScriptWidthUint8},\r
+  {0x10, S3BootScriptWidthUint32},\r
+  {0x14, S3BootScriptWidthUint32},\r
+  {0x18, S3BootScriptWidthUint32},\r
+  {0x1C, S3BootScriptWidthUint32},\r
+  {0x20, S3BootScriptWidthUint32},\r
+  {0x24, S3BootScriptWidthUint32},\r
+  {0x3c, S3BootScriptWidthUint8},\r
+  {0x3d, S3BootScriptWidthUint8},\r
+  {0x40, S3BootScriptWidthUint16},\r
+  {0x42, S3BootScriptWidthUint16},\r
+  {0x92, S3BootScriptWidthUint16},\r
+  {0x94, S3BootScriptWidthUint32},\r
+  {0x9C, S3BootScriptWidthUint32},\r
+  {0x4,  S3BootScriptWidthUint16},\r
+};\r
+\r
+OPAL_DRIVER mOpalDriver;\r
+\r
+//\r
+// Globals\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL gOpalDriverBinding = {\r
+  OpalEfiDriverBindingSupported,\r
+  OpalEfiDriverBindingStart,\r
+  OpalEfiDriverBindingStop,\r
+  0x1b,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+/**\r
+\r
+  The function determines the available actions for the OPAL_DISK provided.\r
+\r
+  @param[in]   SupportedAttributes   The supported attributes for the device.\r
+  @param[in]   LockingFeature        The locking status for the device.\r
+  @param[in]   OwnerShip             The ownership for the device.\r
+  @param[out]  AvalDiskActions       Pointer to fill-out with appropriate disk actions.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportGetAvailableActions(\r
+  IN  OPAL_DISK_SUPPORT_ATTRIBUTE      *SupportedAttributes,\r
+  IN  TCG_LOCKING_FEATURE_DESCRIPTOR   *LockingFeature,\r
+  IN  UINT16                           OwnerShip,\r
+  OUT OPAL_DISK_ACTIONS                *AvalDiskActions\r
+  )\r
+{\r
+  BOOLEAN ExistingPassword;\r
+\r
+  NULL_CHECK(AvalDiskActions);\r
+\r
+  AvalDiskActions->AdminPass = 1;\r
+  AvalDiskActions->UserPass = 0;\r
+  AvalDiskActions->DisableUser = 0;\r
+  AvalDiskActions->Unlock = 0;\r
+\r
+  //\r
+  // Revert is performed on locking sp, so only allow if locking sp is enabled\r
+  //\r
+  if (LockingFeature->LockingEnabled) {\r
+    AvalDiskActions->Revert = 1;\r
+  }\r
+\r
+  //\r
+  // Psid revert is available for any device with media encryption support\r
+  // Revert is allowed for any device with media encryption support, however it requires\r
+  //\r
+  if (SupportedAttributes->MediaEncryption) {\r
+\r
+    //\r
+    // Only allow psid revert if media encryption is enabled.\r
+    // Otherwise, someone who steals a disk can psid revert the disk and the user Data is still\r
+    // intact and accessible\r
+    //\r
+    AvalDiskActions->PsidRevert = 1;\r
+    AvalDiskActions->RevertKeepDataForced = 0;\r
+\r
+    //\r
+    // Secure erase is performed by generating a new encryption key\r
+    // this is only available if encryption is supported\r
+    //\r
+    AvalDiskActions->SecureErase = 1;\r
+  } else {\r
+    AvalDiskActions->PsidRevert = 0;\r
+    AvalDiskActions->SecureErase = 0;\r
+\r
+    //\r
+    // If no media encryption is supported, then a revert (using password) will not\r
+    // erase the Data (since you can't generate a new encryption key)\r
+    //\r
+    AvalDiskActions->RevertKeepDataForced = 1;\r
+  }\r
+\r
+  if (LockingFeature->Locked) {\r
+    AvalDiskActions->Unlock = 1;\r
+  } else {\r
+    AvalDiskActions->Unlock = 0;\r
+  }\r
+\r
+  //\r
+  // Only allow user to set password if an admin password exists\r
+  //\r
+  ExistingPassword = OpalUtilAdminPasswordExists(OwnerShip, LockingFeature);\r
+  AvalDiskActions->UserPass = ExistingPassword;\r
+\r
+  //\r
+  // This will still show up even if there isn't a user, which is fine\r
+  //\r
+  AvalDiskActions->DisableUser = ExistingPassword;\r
+\r
+  return TcgResultSuccess;\r
+}\r
+\r
+/**\r
+  Enable Opal Feature for the input device.\r
+\r
+  @param[in]      Session            The opal session for the opal device.\r
+  @param[in]      Msid               Msid\r
+  @param[in]      MsidLength         Msid Length\r
+  @param[in]      Password           Admin password\r
+  @param[in]      PassLength         Length of password in bytes\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportEnableOpalFeature (\r
+  IN OPAL_SESSION              *Session,\r
+  IN VOID                      *Msid,\r
+  IN UINT32                    MsidLength,\r
+  IN VOID                      *Password,\r
+  IN UINT32                    PassLength\r
+  )\r
+{\r
+  TCG_RESULT   Ret;\r
+\r
+  NULL_CHECK(Session);\r
+  NULL_CHECK(Msid);\r
+  NULL_CHECK(Password);\r
+\r
+  Ret = OpalUtilSetAdminPasswordAsSid(\r
+                          Session,\r
+                          Msid,\r
+                          MsidLength,\r
+                          Password,\r
+                          PassLength\r
+                          );\r
+  if (Ret == TcgResultSuccess) {\r
+    //\r
+    // Enable global locking range\r
+    //\r
+    Ret = OpalUtilSetOpalLockingRange(\r
+                              Session,\r
+                              Password,\r
+                              PassLength,\r
+                              OPAL_LOCKING_SP_LOCKING_GLOBALRANGE,\r
+                              0,\r
+                              0,\r
+                              TRUE,\r
+                              TRUE,\r
+                              FALSE,\r
+                              FALSE\r
+                              );\r
+  }\r
+\r
+  return Ret;\r
+}\r
+\r
+/**\r
+  Update password for the Opal disk.\r
+\r
+  @param[in, out] OpalDisk          The disk to update password.\r
+  @param[in]      Password          The input password.\r
+  @param[in]      PasswordLength    The input password length.\r
+\r
+**/\r
+VOID\r
+OpalSupportUpdatePassword (\r
+  IN OUT OPAL_DISK      *OpalDisk,\r
+  IN VOID               *Password,\r
+  IN UINT32             PasswordLength\r
+  )\r
+{\r
+  CopyMem (OpalDisk->Password, Password, PasswordLength);\r
+  OpalDisk->PasswordLength = (UINT8) PasswordLength;\r
+}\r
+\r
+/**\r
+  Extract device info from the device path.\r
+\r
+  @param[in]  DevicePath        Device path info for the device.\r
+  @param[out] DevInfoLength     Device information length needed.\r
+  @param[out] DevInfo           Device information extracted.\r
+\r
+  @return Device type.\r
+\r
+**/\r
+UINT8\r
+ExtractDeviceInfoFromDevicePath (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *DevicePath,\r
+  OUT UINT16                    *DevInfoLength,\r
+  OUT OPAL_DEVICE_COMMON        *DevInfo OPTIONAL\r
+  )\r
+{\r
+  EFI_DEVICE_PATH_PROTOCOL      *TmpDevPath;\r
+  EFI_DEVICE_PATH_PROTOCOL      *TmpDevPath2;\r
+  PCI_DEVICE_PATH               *PciDevPath;\r
+  UINT8                         DeviceType;\r
+  UINT8                         BusNum;\r
+  OPAL_PCI_DEVICE               *PciDevice;\r
+  OPAL_DEVICE_ATA               *DevInfoAta;\r
+  OPAL_DEVICE_NVME              *DevInfoNvme;\r
+  SATA_DEVICE_PATH              *SataDevPath;\r
+  NVME_NAMESPACE_DEVICE_PATH    *NvmeDevPath;\r
+\r
+  ASSERT (DevicePath != NULL);\r
+  ASSERT (DevInfoLength != NULL);\r
+\r
+  DeviceType = OPAL_DEVICE_TYPE_UNKNOWN;\r
+  *DevInfoLength = 0;\r
+\r
+  TmpDevPath = DevicePath;\r
+\r
+  //\r
+  // Get device type.\r
+  //\r
+  while (!IsDevicePathEnd (TmpDevPath)) {\r
+    if (TmpDevPath->Type == MESSAGING_DEVICE_PATH && TmpDevPath->SubType == MSG_SATA_DP) {\r
+      //\r
+      // SATA\r
+      //\r
+      if (DevInfo != NULL) {\r
+        SataDevPath = (SATA_DEVICE_PATH *) TmpDevPath;\r
+        DevInfoAta = (OPAL_DEVICE_ATA *) DevInfo;\r
+        DevInfoAta->Port = SataDevPath->HBAPortNumber;\r
+        DevInfoAta->PortMultiplierPort = SataDevPath->PortMultiplierPortNumber;\r
+      }\r
+      DeviceType = OPAL_DEVICE_TYPE_ATA;\r
+      *DevInfoLength = sizeof (OPAL_DEVICE_ATA);\r
+      break;\r
+    } else if (TmpDevPath->Type == MESSAGING_DEVICE_PATH && TmpDevPath->SubType == MSG_NVME_NAMESPACE_DP) {\r
+      //\r
+      // NVMe\r
+      //\r
+      if (DevInfo != NULL) {\r
+        NvmeDevPath = (NVME_NAMESPACE_DEVICE_PATH *) TmpDevPath;\r
+        DevInfoNvme = (OPAL_DEVICE_NVME *) DevInfo;\r
+        DevInfoNvme->NvmeNamespaceId = NvmeDevPath->NamespaceId;\r
+      }\r
+      DeviceType = OPAL_DEVICE_TYPE_NVME;\r
+      *DevInfoLength = sizeof (OPAL_DEVICE_NVME);\r
+      break;\r
+    }\r
+    TmpDevPath = NextDevicePathNode (TmpDevPath);\r
+  }\r
+\r
+  //\r
+  // Get device info.\r
+  //\r
+  BusNum = 0;\r
+  TmpDevPath = DevicePath;\r
+  TmpDevPath2 = NextDevicePathNode (DevicePath);\r
+  while (!IsDevicePathEnd (TmpDevPath2)) {\r
+    if (TmpDevPath->Type == HARDWARE_DEVICE_PATH && TmpDevPath->SubType == HW_PCI_DP) {\r
+      PciDevPath = (PCI_DEVICE_PATH *) TmpDevPath;\r
+      if ((TmpDevPath2->Type == MESSAGING_DEVICE_PATH && TmpDevPath2->SubType == MSG_NVME_NAMESPACE_DP)||\r
+          (TmpDevPath2->Type == MESSAGING_DEVICE_PATH && TmpDevPath2->SubType == MSG_SATA_DP)) {\r
+        if (DevInfo != NULL) {\r
+          PciDevice = &DevInfo->Device;\r
+          PciDevice->Segment = 0;\r
+          PciDevice->Bus = BusNum;\r
+          PciDevice->Device = PciDevPath->Device;\r
+          PciDevice->Function = PciDevPath->Function;\r
+        }\r
+      } else {\r
+        if (DevInfo != NULL) {\r
+          PciDevice = (OPAL_PCI_DEVICE *) ((UINTN) DevInfo + *DevInfoLength);\r
+          PciDevice->Segment = 0;\r
+          PciDevice->Bus = BusNum;\r
+          PciDevice->Device = PciDevPath->Device;\r
+          PciDevice->Function = PciDevPath->Function;\r
+        }\r
+        *DevInfoLength += sizeof (OPAL_PCI_DEVICE);\r
+        if (TmpDevPath2->Type == HARDWARE_DEVICE_PATH && TmpDevPath2->SubType == HW_PCI_DP) {\r
+          BusNum = PciRead8 (PCI_LIB_ADDRESS (BusNum, PciDevPath->Device, PciDevPath->Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));\r
+        }\r
+      }\r
+    }\r
+\r
+    TmpDevPath  = NextDevicePathNode (TmpDevPath);\r
+    TmpDevPath2 = NextDevicePathNode (TmpDevPath2);\r
+  }\r
+\r
+  ASSERT (DeviceType != OPAL_DEVICE_TYPE_UNKNOWN);\r
+  return DeviceType;\r
+}\r
+\r
+/**\r
+  Save boot script for ATA OPAL device.\r
+\r
+  @param[in] DevInfo    Pointer to ATA Opal device information.\r
+\r
+ **/\r
+VOID\r
+OpalDeviceAtaSaveBootScript (\r
+  IN OPAL_DEVICE_ATA    *DevInfo\r
+  )\r
+{\r
+  UINTN                         Bus;\r
+  UINTN                         Device;\r
+  UINTN                         Function;\r
+  UINTN                         Index;\r
+  EFI_STATUS                    Status;\r
+  UINTN                         Offset;\r
+  UINT64                        Address;\r
+  S3_BOOT_SCRIPT_LIB_WIDTH      Width;\r
+  UINT32                        Data;\r
+  OPAL_HC_PCI_REGISTER_SAVE     *HcRegisterSaveListPtr;\r
+  UINTN                         Count;\r
+\r
+  Data = 0;\r
+\r
+  Bus        = DevInfo->Device.Bus;\r
+  Device     = DevInfo->Device.Device;\r
+  Function   = DevInfo->Device.Function;\r
+\r
+  HcRegisterSaveListPtr = (OPAL_HC_PCI_REGISTER_SAVE *) mSataHcRegisterSaveTemplate;\r
+  Count = sizeof (mSataHcRegisterSaveTemplate) / sizeof (OPAL_HC_PCI_REGISTER_SAVE);\r
+\r
+  for (Index = 0; Index < Count; Index++) {\r
+    Offset  = HcRegisterSaveListPtr[Index].Address;\r
+    Width   = HcRegisterSaveListPtr[Index].Width;\r
+\r
+    switch (Width) {\r
+      case S3BootScriptWidthUint8:\r
+        Data = (UINT32)PciRead8 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));\r
+        break;\r
+      case S3BootScriptWidthUint16:\r
+        Data = (UINT32)PciRead16 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));\r
+        break;\r
+      case S3BootScriptWidthUint32:\r
+        Data = PciRead32 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));\r
+        break;\r
+      default:\r
+        ASSERT (FALSE);\r
+        break;\r
+    }\r
+\r
+    Address = S3_BOOT_SCRIPT_LIB_PCI_ADDRESS (Bus, Device, Function, Offset);\r
+    Status  = S3BootScriptSavePciCfgWrite (Width, Address, 1, &Data);\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+}\r
+\r
+/**\r
+  Build ATA OPAL device info and save them to LockBox.\r
+\r
+  @param[in] BarAddr    Bar address allocated.\r
+\r
+ **/\r
+VOID\r
+BuildOpalDeviceInfoAta (\r
+  IN UINT32     BarAddr\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UINT8                 DeviceType;\r
+  OPAL_DEVICE_ATA       *DevInfoAta;\r
+  OPAL_DEVICE_ATA       *TempDevInfoAta;\r
+  UINTN                 DevInfoLengthAta;\r
+  UINT16                DevInfoLength;\r
+  OPAL_DRIVER_DEVICE    *TmpDev;\r
+\r
+  //\r
+  // Build ATA OPAL device info and save them to LockBox.\r
+  //\r
+  DevInfoLengthAta = 0;\r
+  TmpDev = mOpalDriver.DeviceList;\r
+  while (TmpDev != NULL) {\r
+    DeviceType = ExtractDeviceInfoFromDevicePath (\r
+                   TmpDev->OpalDisk.OpalDevicePath,\r
+                   &DevInfoLength,\r
+                   NULL\r
+                   );\r
+    if (DeviceType == OPAL_DEVICE_TYPE_ATA) {\r
+      DevInfoLengthAta += DevInfoLength;\r
+    }\r
+\r
+    TmpDev = TmpDev->Next;\r
+  }\r
+\r
+  if (DevInfoLengthAta == 0) {\r
+    return;\r
+  }\r
+\r
+  DevInfoAta = AllocateZeroPool (DevInfoLengthAta);\r
+  ASSERT (DevInfoAta != NULL);\r
+\r
+  TempDevInfoAta = DevInfoAta;\r
+  TmpDev = mOpalDriver.DeviceList;\r
+  while (TmpDev != NULL) {\r
+    DeviceType = ExtractDeviceInfoFromDevicePath (\r
+                   TmpDev->OpalDisk.OpalDevicePath,\r
+                   &DevInfoLength,\r
+                   NULL\r
+                   );\r
+    if (DeviceType == OPAL_DEVICE_TYPE_ATA) {\r
+      ExtractDeviceInfoFromDevicePath (\r
+        TmpDev->OpalDisk.OpalDevicePath,\r
+        &DevInfoLength,\r
+        (OPAL_DEVICE_COMMON *) TempDevInfoAta\r
+        );\r
+      TempDevInfoAta->Length = DevInfoLength;\r
+      TempDevInfoAta->OpalBaseComId = TmpDev->OpalDisk.OpalBaseComId;\r
+      TempDevInfoAta->BarAddr = BarAddr;\r
+      CopyMem (\r
+        TempDevInfoAta->Password,\r
+        TmpDev->OpalDisk.Password,\r
+        TmpDev->OpalDisk.PasswordLength\r
+        );\r
+      TempDevInfoAta->PasswordLength = TmpDev->OpalDisk.PasswordLength;\r
+      OpalDeviceAtaSaveBootScript (TempDevInfoAta);\r
+      TempDevInfoAta = (OPAL_DEVICE_ATA *) ((UINTN) TempDevInfoAta + DevInfoLength);\r
+    }\r
+\r
+    TmpDev = TmpDev->Next;\r
+  }\r
+\r
+  Status = SaveLockBox (\r
+             &mOpalDeviceAtaGuid,\r
+             DevInfoAta,\r
+             DevInfoLengthAta\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = SetLockBoxAttributes (\r
+             &mOpalDeviceAtaGuid,\r
+             LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  ZeroMem (DevInfoAta, DevInfoLengthAta);\r
+  FreePool (DevInfoAta);\r
+}\r
+\r
+/**\r
+  Build NVMe OPAL device info and save them to LockBox.\r
+\r
+  @param[in] BarAddr    Bar address allocated.\r
+\r
+ **/\r
+VOID\r
+BuildOpalDeviceInfoNvme (\r
+  IN UINT32     BarAddr\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UINT8                 DeviceType;\r
+  OPAL_DEVICE_NVME      *DevInfoNvme;\r
+  OPAL_DEVICE_NVME      *TempDevInfoNvme;\r
+  UINTN                 DevInfoLengthNvme;\r
+  UINT16                DevInfoLength;\r
+  OPAL_DRIVER_DEVICE    *TmpDev;\r
+\r
+  //\r
+  // Build NVMe OPAL device info and save them to LockBox.\r
+  //\r
+  DevInfoLengthNvme = 0;\r
+  TmpDev = mOpalDriver.DeviceList;\r
+  while (TmpDev != NULL) {\r
+    DeviceType = ExtractDeviceInfoFromDevicePath (\r
+                   TmpDev->OpalDisk.OpalDevicePath,\r
+                   &DevInfoLength,\r
+                   NULL\r
+                   );\r
+    if (DeviceType == OPAL_DEVICE_TYPE_NVME) {\r
+      DevInfoLengthNvme += DevInfoLength;\r
+    }\r
+\r
+    TmpDev = TmpDev->Next;\r
+  }\r
+\r
+  if (DevInfoLengthNvme == 0) {\r
+    return;\r
+  }\r
+\r
+  DevInfoNvme = AllocateZeroPool (DevInfoLengthNvme);\r
+  ASSERT (DevInfoNvme != NULL);\r
+\r
+  TempDevInfoNvme = DevInfoNvme;\r
+  TmpDev = mOpalDriver.DeviceList;\r
+  while (TmpDev != NULL) {\r
+    DeviceType = ExtractDeviceInfoFromDevicePath (\r
+                   TmpDev->OpalDisk.OpalDevicePath,\r
+                   &DevInfoLength,\r
+                   NULL\r
+                   );\r
+    if (DeviceType == OPAL_DEVICE_TYPE_NVME) {\r
+      ExtractDeviceInfoFromDevicePath (\r
+        TmpDev->OpalDisk.OpalDevicePath,\r
+        &DevInfoLength,\r
+        (OPAL_DEVICE_COMMON *) TempDevInfoNvme\r
+        );\r
+      TempDevInfoNvme->Length = DevInfoLength;\r
+      TempDevInfoNvme->OpalBaseComId = TmpDev->OpalDisk.OpalBaseComId;\r
+      TempDevInfoNvme->BarAddr = BarAddr;\r
+      CopyMem (\r
+        TempDevInfoNvme->Password,\r
+        TmpDev->OpalDisk.Password,\r
+        TmpDev->OpalDisk.PasswordLength\r
+        );\r
+      TempDevInfoNvme->PasswordLength = TmpDev->OpalDisk.PasswordLength;\r
+      TempDevInfoNvme = (OPAL_DEVICE_NVME *) ((UINTN) TempDevInfoNvme + DevInfoLength);\r
+    }\r
+\r
+    TmpDev = TmpDev->Next;\r
+  }\r
+\r
+  Status = SaveLockBox (\r
+             &mOpalDeviceNvmeGuid,\r
+             DevInfoNvme,\r
+             DevInfoLengthNvme\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = SetLockBoxAttributes (\r
+             &mOpalDeviceNvmeGuid,\r
+             LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  ZeroMem (DevInfoNvme, DevInfoLengthNvme);\r
+  FreePool (DevInfoNvme);\r
+}\r
+\r
+/**\r
+  Notification function of EFI_END_OF_DXE_EVENT_GROUP_GUID event group.\r
+\r
+  This is a notification function registered on EFI_END_OF_DXE_EVENT_GROUP_GUID event group.\r
+\r
+  @param  Event        Event whose notification function is being invoked.\r
+  @param  Context      Pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+OpalEndOfDxeEventNotify (\r
+  EFI_EVENT                               Event,\r
+  VOID                                    *Context\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  Address;\r
+  UINT64                Length;\r
+  OPAL_DRIVER_DEVICE    *TmpDev;\r
+\r
+  DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
+\r
+  mOpalEndOfDxe = TRUE;\r
+\r
+  if (mOpalRequestVariable != NULL) {\r
+    //\r
+    // Free the OPAL request variable buffer here\r
+    // as the OPAL requests should have been processed.\r
+    //\r
+    FreePool (mOpalRequestVariable);\r
+    mOpalRequestVariable = NULL;\r
+    mOpalRequestVariableSize = 0;\r
+  }\r
+\r
+  //\r
+  // Assume 64K size and alignment are enough.\r
+  //\r
+  Length = 0x10000;\r
+  Address = 0xFFFFFFFF;\r
+  Status = gDS->AllocateMemorySpace (\r
+                  EfiGcdAllocateMaxAddressSearchBottomUp,\r
+                  EfiGcdMemoryTypeMemoryMappedIo,\r
+                  16,                             // 2^16: 64K Alignment\r
+                  Length,\r
+                  &Address,\r
+                  gImageHandle,\r
+                  NULL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  BuildOpalDeviceInfoAta ((UINT32) Address);\r
+  BuildOpalDeviceInfoNvme ((UINT32) Address);\r
+\r
+  //\r
+  // Zero passsword.\r
+  //\r
+  TmpDev = mOpalDriver.DeviceList;\r
+  while (TmpDev != NULL) {\r
+    ZeroMem (TmpDev->OpalDisk.Password, TmpDev->OpalDisk.PasswordLength);\r
+    TmpDev = TmpDev->Next;\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
+\r
+  gBS->CloseEvent (Event);\r
+}\r
+\r
+/**\r
+  Get Psid input from the popup window.\r
+\r
+  @param[in]  Dev           The device which need Psid to process Psid Revert\r
+                            OPAL request.\r
+  @param[in]  PopUpString   Pop up string.\r
+  @param[out] PressEsc      Whether user escape function through Press ESC.\r
+\r
+  @retval Password string if success. NULL if failed.\r
+\r
+**/\r
+CHAR8 *\r
+OpalDriverPopUpPsidInput (\r
+  IN OPAL_DRIVER_DEVICE     *Dev,\r
+  IN CHAR16                 *PopUpString,\r
+  OUT BOOLEAN               *PressEsc\r
+  )\r
+{\r
+  EFI_INPUT_KEY             InputKey;\r
+  UINTN                     InputLength;\r
+  CHAR16                    Mask[PSID_CHARACTER_LENGTH + 1];\r
+  CHAR16                    Unicode[PSID_CHARACTER_LENGTH + 1];\r
+  CHAR8                     *Ascii;\r
+\r
+  ZeroMem(Unicode, sizeof(Unicode));\r
+  ZeroMem(Mask, sizeof(Mask));\r
+\r
+  *PressEsc = FALSE;\r
+\r
+  gST->ConOut->ClearScreen(gST->ConOut);\r
+\r
+  InputLength = 0;\r
+  while (TRUE) {\r
+    Mask[InputLength] = L'_';\r
+    CreatePopUp (\r
+      EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+      &InputKey,\r
+      PopUpString,\r
+      L"---------------------",\r
+      Mask,\r
+      NULL\r
+    );\r
+\r
+    //\r
+    // Check key.\r
+    //\r
+    if (InputKey.ScanCode == SCAN_NULL) {\r
+      //\r
+      // password finished\r
+      //\r
+      if (InputKey.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+        //\r
+        // Add the null terminator.\r
+        //\r
+        Unicode[InputLength] = 0;\r
+        Mask[InputLength] = 0;\r
+        break;\r
+      } else if ((InputKey.UnicodeChar == CHAR_NULL) ||\r
+                 (InputKey.UnicodeChar == CHAR_TAB) ||\r
+                 (InputKey.UnicodeChar == CHAR_LINEFEED)\r
+                ) {\r
+        continue;\r
+      } else {\r
+        //\r
+        // delete last key entered\r
+        //\r
+        if (InputKey.UnicodeChar == CHAR_BACKSPACE) {\r
+          if (InputLength > 0) {\r
+            Unicode[InputLength] = 0;\r
+            Mask[InputLength] = 0;\r
+            InputLength--;\r
+          }\r
+        } else {\r
+          //\r
+          // add Next key entry\r
+          //\r
+          Unicode[InputLength] = InputKey.UnicodeChar;\r
+          Mask[InputLength] = InputKey.UnicodeChar;\r
+          InputLength++;\r
+          if (InputLength == PSID_CHARACTER_LENGTH) {\r
+            //\r
+            // Add the null terminator.\r
+            //\r
+            Unicode[InputLength] = 0;\r
+            Mask[InputLength] = 0;\r
+            break;\r
+          }\r
+        }\r
+      }\r
+    }\r
+\r
+    //\r
+    // exit on ESC\r
+    //\r
+    if (InputKey.ScanCode == SCAN_ESC) {\r
+      *PressEsc = TRUE;\r
+      break;\r
+    }\r
+  }\r
+\r
+  gST->ConOut->ClearScreen(gST->ConOut);\r
+\r
+  if (InputLength == 0 || InputKey.ScanCode == SCAN_ESC) {\r
+    ZeroMem (Unicode, sizeof (Unicode));\r
+    ZeroMem (Mask, sizeof (Mask));\r
+    return NULL;\r
+  }\r
+\r
+  Ascii = AllocateZeroPool (PSID_CHARACTER_LENGTH + 1);\r
+  if (Ascii == NULL) {\r
+    ZeroMem (Unicode, sizeof (Unicode));\r
+    ZeroMem (Mask, sizeof (Mask));\r
+    return NULL;\r
+  }\r
+\r
+  UnicodeStrToAsciiStrS (Unicode, Ascii, PSID_CHARACTER_LENGTH + 1);\r
+  ZeroMem (Unicode, sizeof (Unicode));\r
+  ZeroMem (Mask, sizeof (Mask));\r
+\r
+  return Ascii;\r
+}\r
+\r
+\r
+/**\r
+  Get password input from the popup window.\r
+\r
+  @param[in]  Dev           The device which need password to unlock or\r
+                            process OPAL request.\r
+  @param[in]  PopUpString1  Pop up string 1.\r
+  @param[in]  PopUpString2  Pop up string 2.\r
+  @param[out] PressEsc      Whether user escape function through Press ESC.\r
+\r
+  @retval Password string if success. NULL if failed.\r
+\r
+**/\r
+CHAR8 *\r
+OpalDriverPopUpPasswordInput (\r
+  IN OPAL_DRIVER_DEVICE     *Dev,\r
+  IN CHAR16                 *PopUpString1,\r
+  IN CHAR16                 *PopUpString2,\r
+  OUT BOOLEAN               *PressEsc\r
+  )\r
+{\r
+  EFI_INPUT_KEY             InputKey;\r
+  UINTN                     InputLength;\r
+  CHAR16                    Mask[OPAL_MAX_PASSWORD_SIZE + 1];\r
+  CHAR16                    Unicode[OPAL_MAX_PASSWORD_SIZE + 1];\r
+  CHAR8                     *Ascii;\r
+\r
+  ZeroMem(Unicode, sizeof(Unicode));\r
+  ZeroMem(Mask, sizeof(Mask));\r
+\r
+  *PressEsc = FALSE;\r
+\r
+  gST->ConOut->ClearScreen(gST->ConOut);\r
+\r
+  InputLength = 0;\r
+  while (TRUE) {\r
+    Mask[InputLength] = L'_';\r
+    if (PopUpString2 == NULL) {\r
+      CreatePopUp (\r
+        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+        &InputKey,\r
+        PopUpString1,\r
+        L"---------------------",\r
+        Mask,\r
+        NULL\r
+      );\r
+    } else {\r
+      CreatePopUp (\r
+        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+        &InputKey,\r
+        PopUpString1,\r
+        PopUpString2,\r
+        L"---------------------",\r
+        Mask,\r
+        NULL\r
+      );\r
+    }\r
+\r
+    //\r
+    // Check key.\r
+    //\r
+    if (InputKey.ScanCode == SCAN_NULL) {\r
+      //\r
+      // password finished\r
+      //\r
+      if (InputKey.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+        //\r
+        // Add the null terminator.\r
+        //\r
+        Unicode[InputLength] = 0;\r
+        Mask[InputLength] = 0;\r
+        break;\r
+      } else if ((InputKey.UnicodeChar == CHAR_NULL) ||\r
+                 (InputKey.UnicodeChar == CHAR_TAB) ||\r
+                 (InputKey.UnicodeChar == CHAR_LINEFEED)\r
+                ) {\r
+        continue;\r
+      } else {\r
+        //\r
+        // delete last key entered\r
+        //\r
+        if (InputKey.UnicodeChar == CHAR_BACKSPACE) {\r
+          if (InputLength > 0) {\r
+            Unicode[InputLength] = 0;\r
+            Mask[InputLength] = 0;\r
+            InputLength--;\r
+          }\r
+        } else {\r
+          //\r
+          // add Next key entry\r
+          //\r
+          Unicode[InputLength] = InputKey.UnicodeChar;\r
+          Mask[InputLength] = L'*';\r
+          InputLength++;\r
+          if (InputLength == OPAL_MAX_PASSWORD_SIZE) {\r
+            //\r
+            // Add the null terminator.\r
+            //\r
+            Unicode[InputLength] = 0;\r
+            Mask[InputLength] = 0;\r
+            break;\r
+          }\r
+        }\r
+      }\r
+    }\r
+\r
+    //\r
+    // exit on ESC\r
+    //\r
+    if (InputKey.ScanCode == SCAN_ESC) {\r
+      *PressEsc = TRUE;\r
+      break;\r
+    }\r
+  }\r
+\r
+  gST->ConOut->ClearScreen(gST->ConOut);\r
+\r
+  if (InputLength == 0 || InputKey.ScanCode == SCAN_ESC) {\r
+    ZeroMem (Unicode, sizeof (Unicode));\r
+    return NULL;\r
+  }\r
+\r
+  Ascii = AllocateZeroPool (OPAL_MAX_PASSWORD_SIZE + 1);\r
+  if (Ascii == NULL) {\r
+    ZeroMem (Unicode, sizeof (Unicode));\r
+    return NULL;\r
+  }\r
+\r
+  UnicodeStrToAsciiStrS (Unicode, Ascii, OPAL_MAX_PASSWORD_SIZE + 1);\r
+  ZeroMem (Unicode, sizeof (Unicode));\r
+\r
+  return Ascii;\r
+}\r
+\r
+/**\r
+  Check if disk is locked, show popup window and ask for password if it is.\r
+\r
+  @param[in] Dev            The device which need to be unlocked.\r
+  @param[in] RequestString  Request string.\r
+\r
+**/\r
+CHAR16 *\r
+OpalGetPopUpString (\r
+  IN OPAL_DRIVER_DEVICE *Dev,\r
+  IN CHAR16             *RequestString\r
+  )\r
+{\r
+  UINTN                 StrLength;\r
+\r
+  StrLength = StrLen (RequestString) + 1 + MAX (StrLen (Dev->Name16), StrLen (L"Disk"));\r
+  ASSERT (StrLength < sizeof (mPopUpString) / sizeof (CHAR16));\r
+\r
+  if (Dev->Name16 == NULL) {\r
+    UnicodeSPrint (mPopUpString, StrLength + 1, L"%s Disk", RequestString);\r
+  } else {\r
+    UnicodeSPrint (mPopUpString, StrLength + 1, L"%s %s", RequestString, Dev->Name16);\r
+  }\r
+\r
+  return mPopUpString;\r
+}\r
+\r
+/**\r
+  Check if disk is locked, show popup window and ask for password if it is.\r
+\r
+  @param[in] Dev            The device which need to be unlocked.\r
+  @param[in] RequestString  Request string.\r
+\r
+**/\r
+VOID\r
+OpalDriverRequestPassword (\r
+  IN OPAL_DRIVER_DEVICE *Dev,\r
+  IN CHAR16             *RequestString\r
+  )\r
+{\r
+  UINT8                 Count;\r
+  BOOLEAN               IsEnabled;\r
+  BOOLEAN               IsLocked;\r
+  CHAR8                 *Password;\r
+  UINT32                PasswordLen;\r
+  OPAL_SESSION          Session;\r
+  BOOLEAN               PressEsc;\r
+  EFI_INPUT_KEY         Key;\r
+  TCG_RESULT            Ret;\r
+  CHAR16                *PopUpString;\r
+\r
+  if (Dev == NULL) {\r
+    return;\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
+\r
+  PopUpString = OpalGetPopUpString (Dev, RequestString);\r
+\r
+  Count = 0;\r
+\r
+  IsEnabled = OpalFeatureEnabled (&Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.LockingFeature);\r
+  if (IsEnabled) {\r
+    ZeroMem(&Session, sizeof(Session));\r
+    Session.Sscp = Dev->OpalDisk.Sscp;\r
+    Session.MediaId = Dev->OpalDisk.MediaId;\r
+    Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
+\r
+    IsLocked = OpalDeviceLocked (&Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.LockingFeature);\r
+\r
+    while (Count < MAX_PASSWORD_TRY_COUNT) {\r
+      Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, NULL, &PressEsc);\r
+      if (PressEsc) {\r
+        if (IsLocked) {\r
+          //\r
+          // Current device in the lock status and\r
+          // User not input password and press ESC,\r
+          // keep device in lock status and continue boot.\r
+          //\r
+          do {\r
+            CreatePopUp (\r
+              EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+              &Key,\r
+              L"Press ENTER to skip the request and continue boot,",\r
+              L"Press ESC to input password again",\r
+              NULL\r
+              );\r
+          } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
+\r
+          if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+            gST->ConOut->ClearScreen(gST->ConOut);\r
+            //\r
+            // Keep lock and continue boot.\r
+            //\r
+            return;\r
+          } else {\r
+            //\r
+            // Let user input password again.\r
+            //\r
+            continue;\r
+          }\r
+        } else {\r
+          //\r
+          // Current device in the unlock status and\r
+          // User not input password and press ESC,\r
+          // Shutdown the device.\r
+          //\r
+          do {\r
+            CreatePopUp (\r
+              EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+              &Key,\r
+              L"Press ENTER to shutdown, Press ESC to input password again",\r
+              NULL\r
+              );\r
+          } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
+\r
+          if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+            gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);\r
+          } else {\r
+            //\r
+            // Let user input password again.\r
+            //\r
+            continue;\r
+          }\r
+        }\r
+      }\r
+\r
+      if (Password == NULL) {\r
+        Count ++;\r
+        continue;\r
+      }\r
+      PasswordLen = (UINT32) AsciiStrLen(Password);\r
+\r
+      if (IsLocked) {\r
+        Ret = OpalUtilUpdateGlobalLockingRange(&Session, Password, PasswordLen, FALSE, FALSE);\r
+      } else {\r
+        Ret = OpalUtilUpdateGlobalLockingRange(&Session, Password, PasswordLen, TRUE, TRUE);\r
+        if (Ret == TcgResultSuccess) {\r
+          Ret = OpalUtilUpdateGlobalLockingRange(&Session, Password, PasswordLen, FALSE, FALSE);\r
+        }\r
+      }\r
+\r
+      if (Ret == TcgResultSuccess) {\r
+        OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen);\r
+        DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
+      } else {\r
+        DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
+      }\r
+\r
+      if (Password != NULL) {\r
+        ZeroMem (Password, PasswordLen);\r
+        FreePool (Password);\r
+      }\r
+\r
+      if (Ret == TcgResultSuccess) {\r
+        break;\r
+      }\r
+\r
+      Count++;\r
+\r
+      do {\r
+        CreatePopUp (\r
+          EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+          &Key,\r
+          L"Invalid password.",\r
+          L"Press ENTER to retry",\r
+          NULL\r
+          );\r
+      } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+    }\r
+\r
+    if (Count >= MAX_PASSWORD_TRY_COUNT) {\r
+      do {\r
+        CreatePopUp (\r
+          EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+          &Key,\r
+          L"Opal password retry count exceeds the limit. Must shutdown!",\r
+          L"Press ENTER to shutdown",\r
+          NULL\r
+          );\r
+      } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+\r
+      gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Process Enable Feature OPAL request.\r
+\r
+  @param[in] Dev            The device which has Enable Feature OPAL request.\r
+  @param[in] RequestString  Request string.\r
+\r
+**/\r
+VOID\r
+ProcessOpalRequestEnableFeature (\r
+  IN OPAL_DRIVER_DEVICE *Dev,\r
+  IN CHAR16             *RequestString\r
+  )\r
+{\r
+  UINT8                 Count;\r
+  CHAR8                 *Password;\r
+  UINT32                PasswordLen;\r
+  CHAR8                 *PasswordConfirm;\r
+  UINT32                PasswordLenConfirm;\r
+  OPAL_SESSION          Session;\r
+  BOOLEAN               PressEsc;\r
+  EFI_INPUT_KEY         Key;\r
+  TCG_RESULT            Ret;\r
+  CHAR16                *PopUpString;\r
+\r
+  if (Dev == NULL) {\r
+    return;\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
+\r
+  PopUpString = OpalGetPopUpString (Dev, RequestString);\r
+\r
+  Count = 0;\r
+\r
+  ZeroMem(&Session, sizeof(Session));\r
+  Session.Sscp = Dev->OpalDisk.Sscp;\r
+  Session.MediaId = Dev->OpalDisk.MediaId;\r
+  Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
+\r
+  while (Count < MAX_PASSWORD_TRY_COUNT) {\r
+    Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your new password", &PressEsc);\r
+    if (PressEsc) {\r
+        do {\r
+          CreatePopUp (\r
+            EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+            &Key,\r
+            L"Press ENTER to skip the request and continue boot,",\r
+            L"Press ESC to input password again",\r
+            NULL\r
+            );\r
+        } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
+\r
+        if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+          gST->ConOut->ClearScreen(gST->ConOut);\r
+          return;\r
+        } else {\r
+          //\r
+          // Let user input password again.\r
+          //\r
+          continue;\r
+        }\r
+    }\r
+\r
+    if (Password == NULL) {\r
+      Count ++;\r
+      continue;\r
+    }\r
+    PasswordLen = (UINT32) AsciiStrLen(Password);\r
+\r
+    PasswordConfirm = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please confirm your new password", &PressEsc);\r
+    if (PasswordConfirm == NULL) {\r
+      ZeroMem (Password, PasswordLen);\r
+      FreePool (Password);\r
+      Count ++;\r
+      continue;\r
+    }\r
+    PasswordLenConfirm = (UINT32) AsciiStrLen(PasswordConfirm);\r
+    if ((PasswordLen != PasswordLenConfirm) ||\r
+        (CompareMem (Password, PasswordConfirm, PasswordLen) != 0)) {\r
+      ZeroMem (Password, PasswordLen);\r
+      FreePool (Password);\r
+      ZeroMem (PasswordConfirm, PasswordLenConfirm);\r
+      FreePool (PasswordConfirm);\r
+      do {\r
+        CreatePopUp (\r
+          EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+          &Key,\r
+          L"Passwords are not the same.",\r
+          L"Press ENTER to retry",\r
+          NULL\r
+          );\r
+      } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+      Count ++;\r
+      continue;\r
+    }\r
+\r
+    if (PasswordConfirm != NULL) {\r
+      ZeroMem (PasswordConfirm, PasswordLenConfirm);\r
+      FreePool (PasswordConfirm);\r
+    }\r
+\r
+    Ret = OpalSupportEnableOpalFeature (&Session, Dev->OpalDisk.Msid,  Dev->OpalDisk.MsidLength, Password, PasswordLen);\r
+    if (Ret == TcgResultSuccess) {\r
+      OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen);\r
+      DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
+    } else {\r
+      DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
+    }\r
+\r
+    if (Password != NULL) {\r
+      ZeroMem (Password, PasswordLen);\r
+      FreePool (Password);\r
+    }\r
+\r
+    if (Ret == TcgResultSuccess) {\r
+      break;\r
+    }\r
+\r
+    Count++;\r
+\r
+    do {\r
+      CreatePopUp (\r
+        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+        &Key,\r
+        L"Request failed.",\r
+        L"Press ENTER to retry",\r
+        NULL\r
+        );\r
+    } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+  }\r
+\r
+  if (Count >= MAX_PASSWORD_TRY_COUNT) {\r
+    do {\r
+      CreatePopUp (\r
+        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+        &Key,\r
+        L"Opal password retry count exceeds the limit.",\r
+        L"Press ENTER to skip the request and continue boot",\r
+        NULL\r
+        );\r
+    } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+    gST->ConOut->ClearScreen(gST->ConOut);\r
+  }\r
+}\r
+\r
+/**\r
+  Process Disable User OPAL request.\r
+\r
+  @param[in] Dev            The device which has Disable User OPAL request.\r
+  @param[in] RequestString  Request string.\r
+\r
+**/\r
+VOID\r
+ProcessOpalRequestDisableUser (\r
+  IN OPAL_DRIVER_DEVICE *Dev,\r
+  IN CHAR16             *RequestString\r
+  )\r
+{\r
+  UINT8                 Count;\r
+  CHAR8                 *Password;\r
+  UINT32                PasswordLen;\r
+  OPAL_SESSION          Session;\r
+  BOOLEAN               PressEsc;\r
+  EFI_INPUT_KEY         Key;\r
+  TCG_RESULT            Ret;\r
+  BOOLEAN               PasswordFailed;\r
+  CHAR16                *PopUpString;\r
+\r
+  if (Dev == NULL) {\r
+    return;\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
+\r
+  PopUpString = OpalGetPopUpString (Dev, RequestString);\r
+\r
+  Count = 0;\r
+\r
+  ZeroMem(&Session, sizeof(Session));\r
+  Session.Sscp = Dev->OpalDisk.Sscp;\r
+  Session.MediaId = Dev->OpalDisk.MediaId;\r
+  Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
+\r
+  while (Count < MAX_PASSWORD_TRY_COUNT) {\r
+    Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, NULL, &PressEsc);\r
+    if (PressEsc) {\r
+        do {\r
+          CreatePopUp (\r
+            EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+            &Key,\r
+            L"Press ENTER to skip the request and continue boot,",\r
+            L"Press ESC to input password again",\r
+            NULL\r
+            );\r
+        } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
+\r
+        if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+          gST->ConOut->ClearScreen(gST->ConOut);\r
+          return;\r
+        } else {\r
+          //\r
+          // Let user input password again.\r
+          //\r
+          continue;\r
+        }\r
+    }\r
+\r
+    if (Password == NULL) {\r
+      Count ++;\r
+      continue;\r
+    }\r
+    PasswordLen = (UINT32) AsciiStrLen(Password);\r
+\r
+    Ret = OpalUtilDisableUser(&Session, Password, PasswordLen, &PasswordFailed);\r
+    if (Ret == TcgResultSuccess) {\r
+      OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen);\r
+      DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
+    } else {\r
+      DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
+    }\r
+\r
+    if (Password != NULL) {\r
+      ZeroMem (Password, PasswordLen);\r
+      FreePool (Password);\r
+    }\r
+\r
+    if (Ret == TcgResultSuccess) {\r
+      break;\r
+    }\r
+\r
+    Count++;\r
+\r
+    do {\r
+      CreatePopUp (\r
+        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+        &Key,\r
+        L"Invalid password, request failed.",\r
+        L"Press ENTER to retry",\r
+        NULL\r
+        );\r
+    } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+  }\r
+\r
+  if (Count >= MAX_PASSWORD_TRY_COUNT) {\r
+    do {\r
+      CreatePopUp (\r
+        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+        &Key,\r
+        L"Opal password retry count exceeds the limit.",\r
+        L"Press ENTER to skip the request and continue boot",\r
+        NULL\r
+        );\r
+    } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+    gST->ConOut->ClearScreen(gST->ConOut);\r
+  }\r
+}\r
+\r
+/**\r
+  Process Psid Revert OPAL request.\r
+\r
+  @param[in] Dev            The device which has Psid Revert OPAL request.\r
+  @param[in] RequestString  Request string.\r
+\r
+**/\r
+VOID\r
+ProcessOpalRequestPsidRevert (\r
+  IN OPAL_DRIVER_DEVICE *Dev,\r
+  IN CHAR16             *RequestString\r
+  )\r
+{\r
+  UINT8                 Count;\r
+  CHAR8                 *Psid;\r
+  UINT32                PsidLen;\r
+  OPAL_SESSION          Session;\r
+  BOOLEAN               PressEsc;\r
+  EFI_INPUT_KEY         Key;\r
+  TCG_RESULT            Ret;\r
+  CHAR16                *PopUpString;\r
+\r
+  if (Dev == NULL) {\r
+    return;\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
+\r
+  PopUpString = OpalGetPopUpString (Dev, RequestString);\r
+\r
+  Count = 0;\r
+\r
+  ZeroMem(&Session, sizeof(Session));\r
+  Session.Sscp = Dev->OpalDisk.Sscp;\r
+  Session.MediaId = Dev->OpalDisk.MediaId;\r
+  Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
+\r
+  while (Count < MAX_PSID_TRY_COUNT) {\r
+    Psid = OpalDriverPopUpPsidInput (Dev, PopUpString, &PressEsc);\r
+    if (PressEsc) {\r
+        do {\r
+          CreatePopUp (\r
+            EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+            &Key,\r
+            L"Press ENTER to skip the request and continue boot,",\r
+            L"Press ESC to input Psid again",\r
+            NULL\r
+            );\r
+        } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
+\r
+        if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+          gST->ConOut->ClearScreen(gST->ConOut);\r
+          return;\r
+        } else {\r
+          //\r
+          // Let user input Psid again.\r
+          //\r
+          continue;\r
+        }\r
+    }\r
+\r
+    if (Psid == NULL) {\r
+      Count ++;\r
+      continue;\r
+    }\r
+    PsidLen = (UINT32) AsciiStrLen(Psid);\r
+\r
+    Ret = OpalUtilPsidRevert(&Session, Psid, PsidLen);\r
+    if (Ret == TcgResultSuccess) {\r
+      DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
+    } else {\r
+      DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
+    }\r
+\r
+    if (Psid != NULL) {\r
+      ZeroMem (Psid, PsidLen);\r
+      FreePool (Psid);\r
+    }\r
+\r
+    if (Ret == TcgResultSuccess) {\r
+      break;\r
+    }\r
+\r
+    Count++;\r
+\r
+    do {\r
+      CreatePopUp (\r
+        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+        &Key,\r
+        L"Invalid Psid, request failed.",\r
+        L"Press ENTER to retry",\r
+        NULL\r
+        );\r
+    } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+  }\r
+\r
+  if (Count >= MAX_PSID_TRY_COUNT) {\r
+    do {\r
+      CreatePopUp (\r
+        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+        &Key,\r
+        L"Opal Psid retry count exceeds the limit.",\r
+        L"Press ENTER to skip the request and continue boot",\r
+        NULL\r
+        );\r
+    } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+    gST->ConOut->ClearScreen(gST->ConOut);\r
+  }\r
+}\r
+\r
+/**\r
+  Process Admin Revert OPAL request.\r
+\r
+  @param[in] Dev            The device which has Revert OPAL request.\r
+  @param[in] KeepUserData   Whether to keep user data or not.\r
+  @param[in] RequestString  Request string.\r
+\r
+**/\r
+VOID\r
+ProcessOpalRequestRevert (\r
+  IN OPAL_DRIVER_DEVICE *Dev,\r
+  IN BOOLEAN            KeepUserData,\r
+  IN CHAR16             *RequestString\r
+  )\r
+{\r
+  UINT8                 Count;\r
+  CHAR8                 *Password;\r
+  UINT32                PasswordLen;\r
+  OPAL_SESSION          Session;\r
+  BOOLEAN               PressEsc;\r
+  EFI_INPUT_KEY         Key;\r
+  TCG_RESULT            Ret;\r
+  BOOLEAN               PasswordFailed;\r
+  CHAR16                *PopUpString;\r
+\r
+  if (Dev == NULL) {\r
+    return;\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
+\r
+  PopUpString = OpalGetPopUpString (Dev, RequestString);\r
+\r
+  Count = 0;\r
+\r
+  ZeroMem(&Session, sizeof(Session));\r
+  Session.Sscp = Dev->OpalDisk.Sscp;\r
+  Session.MediaId = Dev->OpalDisk.MediaId;\r
+  Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
+\r
+  while (Count < MAX_PASSWORD_TRY_COUNT) {\r
+    Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, NULL, &PressEsc);\r
+    if (PressEsc) {\r
+        do {\r
+          CreatePopUp (\r
+            EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+            &Key,\r
+            L"Press ENTER to skip the request and continue boot,",\r
+            L"Press ESC to input password again",\r
+            NULL\r
+            );\r
+        } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
+\r
+        if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+          gST->ConOut->ClearScreen(gST->ConOut);\r
+          return;\r
+        } else {\r
+          //\r
+          // Let user input password again.\r
+          //\r
+          continue;\r
+        }\r
+    }\r
+\r
+    if (Password == NULL) {\r
+      Count ++;\r
+      continue;\r
+    }\r
+    PasswordLen = (UINT32) AsciiStrLen(Password);\r
+\r
+    if ((Dev->OpalDisk.SupportedAttributes.PyriteSsc == 1) &&\r
+        (Dev->OpalDisk.LockingFeature.MediaEncryption == 0)) {\r
+      //\r
+      // For pyrite type device which does not support media encryption,\r
+      // it does not accept "Keep User Data" parameter.\r
+      // So here hardcode a FALSE for this case.\r
+      //\r
+      Ret = OpalUtilRevert(\r
+              &Session,\r
+              FALSE,\r
+              Password,\r
+              PasswordLen,\r
+              &PasswordFailed,\r
+              Dev->OpalDisk.Msid,\r
+              Dev->OpalDisk.MsidLength\r
+              );\r
+    } else {\r
+      Ret = OpalUtilRevert(\r
+              &Session,\r
+              KeepUserData,\r
+              Password,\r
+              PasswordLen,\r
+              &PasswordFailed,\r
+              Dev->OpalDisk.Msid,\r
+              Dev->OpalDisk.MsidLength\r
+              );\r
+    }\r
+    if (Ret == TcgResultSuccess) {\r
+      OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen);\r
+      DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
+    } else {\r
+      DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
+    }\r
+\r
+    if (Password != NULL) {\r
+      ZeroMem (Password, PasswordLen);\r
+      FreePool (Password);\r
+    }\r
+\r
+    if (Ret == TcgResultSuccess) {\r
+      break;\r
+    }\r
+\r
+    Count++;\r
+\r
+    do {\r
+      CreatePopUp (\r
+        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+        &Key,\r
+        L"Invalid password, request failed.",\r
+        L"Press ENTER to retry",\r
+        NULL\r
+        );\r
+    } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+  }\r
+\r
+  if (Count >= MAX_PASSWORD_TRY_COUNT) {\r
+    do {\r
+      CreatePopUp (\r
+        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+        &Key,\r
+        L"Opal password retry count exceeds the limit.",\r
+        L"Press ENTER to skip the request and continue boot",\r
+        NULL\r
+        );\r
+    } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+    gST->ConOut->ClearScreen(gST->ConOut);\r
+  }\r
+}\r
+\r
+/**\r
+  Process Secure Erase OPAL request.\r
+\r
+  @param[in] Dev            The device which has Secure Erase OPAL request.\r
+  @param[in] RequestString  Request string.\r
+\r
+**/\r
+VOID\r
+ProcessOpalRequestSecureErase (\r
+  IN OPAL_DRIVER_DEVICE *Dev,\r
+  IN CHAR16             *RequestString\r
+  )\r
+{\r
+  UINT8                 Count;\r
+  CHAR8                 *Password;\r
+  UINT32                PasswordLen;\r
+  OPAL_SESSION          Session;\r
+  BOOLEAN               PressEsc;\r
+  EFI_INPUT_KEY         Key;\r
+  TCG_RESULT            Ret;\r
+  BOOLEAN               PasswordFailed;\r
+  CHAR16                *PopUpString;\r
+\r
+  if (Dev == NULL) {\r
+    return;\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
+\r
+  PopUpString = OpalGetPopUpString (Dev, RequestString);\r
+\r
+  Count = 0;\r
+\r
+  ZeroMem(&Session, sizeof(Session));\r
+  Session.Sscp = Dev->OpalDisk.Sscp;\r
+  Session.MediaId = Dev->OpalDisk.MediaId;\r
+  Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
+\r
+  while (Count < MAX_PASSWORD_TRY_COUNT) {\r
+    Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, NULL, &PressEsc);\r
+    if (PressEsc) {\r
+        do {\r
+          CreatePopUp (\r
+            EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+            &Key,\r
+            L"Press ENTER to skip the request and continue boot,",\r
+            L"Press ESC to input password again",\r
+            NULL\r
+            );\r
+        } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
+\r
+        if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+          gST->ConOut->ClearScreen(gST->ConOut);\r
+          return;\r
+        } else {\r
+          //\r
+          // Let user input password again.\r
+          //\r
+          continue;\r
+        }\r
+    }\r
+\r
+    if (Password == NULL) {\r
+      Count ++;\r
+      continue;\r
+    }\r
+    PasswordLen = (UINT32) AsciiStrLen(Password);\r
+\r
+    Ret = OpalUtilSecureErase(&Session, Password, PasswordLen, &PasswordFailed);\r
+    if (Ret == TcgResultSuccess) {\r
+      OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen);\r
+      DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
+    } else {\r
+      DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
+    }\r
+\r
+    if (Password != NULL) {\r
+      ZeroMem (Password, PasswordLen);\r
+      FreePool (Password);\r
+    }\r
+\r
+    if (Ret == TcgResultSuccess) {\r
+      break;\r
+    }\r
+\r
+    Count++;\r
+\r
+    do {\r
+      CreatePopUp (\r
+        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+        &Key,\r
+        L"Invalid password, request failed.",\r
+        L"Press ENTER to retry",\r
+        NULL\r
+        );\r
+    } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+  }\r
+\r
+  if (Count >= MAX_PASSWORD_TRY_COUNT) {\r
+    do {\r
+      CreatePopUp (\r
+        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+        &Key,\r
+        L"Opal password retry count exceeds the limit.",\r
+        L"Press ENTER to skip the request and continue boot",\r
+        NULL\r
+        );\r
+    } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+    gST->ConOut->ClearScreen(gST->ConOut);\r
+  }\r
+}\r
+\r
+/**\r
+  Process Set Admin Pwd OPAL request.\r
+\r
+  @param[in] Dev            The device which has Set Admin Pwd Feature OPAL request.\r
+  @param[in] RequestString  Request string.\r
+\r
+**/\r
+VOID\r
+ProcessOpalRequestSetUserPwd (\r
+  IN OPAL_DRIVER_DEVICE *Dev,\r
+  IN CHAR16             *RequestString\r
+  )\r
+{\r
+  UINT8                 Count;\r
+  CHAR8                 *OldPassword;\r
+  UINT32                OldPasswordLen;\r
+  CHAR8                 *Password;\r
+  UINT32                PasswordLen;\r
+  CHAR8                 *PasswordConfirm;\r
+  UINT32                PasswordLenConfirm;\r
+  OPAL_SESSION          Session;\r
+  BOOLEAN               PressEsc;\r
+  EFI_INPUT_KEY         Key;\r
+  TCG_RESULT            Ret;\r
+  CHAR16                *PopUpString;\r
+\r
+  if (Dev == NULL) {\r
+    return;\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
+\r
+  PopUpString = OpalGetPopUpString (Dev, RequestString);\r
+\r
+  Count = 0;\r
+\r
+  while (Count < MAX_PASSWORD_TRY_COUNT) {\r
+    OldPassword = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your password", &PressEsc);\r
+    if (PressEsc) {\r
+        do {\r
+          CreatePopUp (\r
+            EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+            &Key,\r
+            L"Press ENTER to skip the request and continue boot,",\r
+            L"Press ESC to input password again",\r
+            NULL\r
+            );\r
+        } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
+\r
+        if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+          gST->ConOut->ClearScreen(gST->ConOut);\r
+          return;\r
+        } else {\r
+          //\r
+          // Let user input password again.\r
+          //\r
+          continue;\r
+        }\r
+    }\r
+\r
+    if (OldPassword == NULL) {\r
+      Count ++;\r
+      continue;\r
+    }\r
+    OldPasswordLen = (UINT32) AsciiStrLen(OldPassword);\r
+\r
+    ZeroMem(&Session, sizeof(Session));\r
+    Session.Sscp = Dev->OpalDisk.Sscp;\r
+    Session.MediaId = Dev->OpalDisk.MediaId;\r
+    Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
+    Ret = OpalUtilVerifyPassword (&Session, OldPassword, OldPasswordLen, OPAL_LOCKING_SP_USER1_AUTHORITY);\r
+    if (Ret == TcgResultSuccess) {\r
+      DEBUG ((DEBUG_INFO, "Verify with USER1 authority : Success\n"));\r
+    } else {\r
+      Ret = OpalUtilVerifyPassword (&Session, OldPassword, OldPasswordLen, OPAL_LOCKING_SP_ADMIN1_AUTHORITY);\r
+      if (Ret == TcgResultSuccess) {\r
+        DEBUG ((DEBUG_INFO, "Verify with ADMIN1 authority: Success\n"));\r
+      } else {\r
+        ZeroMem (OldPassword, OldPasswordLen);\r
+        FreePool (OldPassword);\r
+        DEBUG ((DEBUG_INFO, "Verify: Failure\n"));\r
+        do {\r
+          CreatePopUp (\r
+            EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+            &Key,\r
+            L"Incorrect password.",\r
+            L"Press ENTER to retry",\r
+            NULL\r
+            );\r
+        } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+        Count ++;\r
+        continue;\r
+      }\r
+    }\r
+\r
+    Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your new password", &PressEsc);\r
+    if (Password == NULL) {\r
+      ZeroMem (OldPassword, OldPasswordLen);\r
+      FreePool (OldPassword);\r
+      Count ++;\r
+      continue;\r
+    }\r
+    PasswordLen = (UINT32) AsciiStrLen(Password);\r
+\r
+    PasswordConfirm = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please confirm your new password", &PressEsc);\r
+    if (PasswordConfirm == NULL) {\r
+      ZeroMem (OldPassword, OldPasswordLen);\r
+      FreePool (OldPassword);\r
+      ZeroMem (Password, PasswordLen);\r
+      FreePool (Password);\r
+      Count ++;\r
+      continue;\r
+    }\r
+    PasswordLenConfirm = (UINT32) AsciiStrLen(PasswordConfirm);\r
+    if ((PasswordLen != PasswordLenConfirm) ||\r
+        (CompareMem (Password, PasswordConfirm, PasswordLen) != 0)) {\r
+      ZeroMem (OldPassword, OldPasswordLen);\r
+      FreePool (OldPassword);\r
+      ZeroMem (Password, PasswordLen);\r
+      FreePool (Password);\r
+      ZeroMem (PasswordConfirm, PasswordLenConfirm);\r
+      FreePool (PasswordConfirm);\r
+      do {\r
+        CreatePopUp (\r
+          EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+          &Key,\r
+          L"Passwords are not the same.",\r
+          L"Press ENTER to retry",\r
+          NULL\r
+          );\r
+      } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+      Count ++;\r
+      continue;\r
+    }\r
+\r
+    if (PasswordConfirm != NULL) {\r
+      ZeroMem (PasswordConfirm, PasswordLenConfirm);\r
+      FreePool (PasswordConfirm);\r
+    }\r
+\r
+    ZeroMem(&Session, sizeof(Session));\r
+    Session.Sscp = Dev->OpalDisk.Sscp;\r
+    Session.MediaId = Dev->OpalDisk.MediaId;\r
+    Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
+    Ret = OpalUtilSetUserPassword(\r
+            &Session,\r
+            OldPassword,\r
+            OldPasswordLen,\r
+            Password,\r
+            PasswordLen\r
+            );\r
+    if (Ret == TcgResultSuccess) {\r
+      OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen);\r
+      DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
+    } else {\r
+      DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
+    }\r
+\r
+    if (OldPassword != NULL) {\r
+      ZeroMem (OldPassword, OldPasswordLen);\r
+      FreePool (OldPassword);\r
+    }\r
+\r
+    if (Password != NULL) {\r
+      ZeroMem (Password, PasswordLen);\r
+      FreePool (Password);\r
+    }\r
+\r
+    if (Ret == TcgResultSuccess) {\r
+      break;\r
+    }\r
+\r
+    Count++;\r
+\r
+    do {\r
+      CreatePopUp (\r
+        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+        &Key,\r
+        L"Request failed.",\r
+        L"Press ENTER to retry",\r
+        NULL\r
+        );\r
+    } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+  }\r
+\r
+  if (Count >= MAX_PASSWORD_TRY_COUNT) {\r
+    do {\r
+      CreatePopUp (\r
+        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+        &Key,\r
+        L"Opal password retry count exceeds the limit.",\r
+        L"Press ENTER to skip the request and continue boot",\r
+        NULL\r
+        );\r
+    } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+    gST->ConOut->ClearScreen(gST->ConOut);\r
+  }\r
+}\r
+\r
+/**\r
+  Process Set Admin Pwd OPAL request.\r
+\r
+  @param[in] Dev            The device which has Set Admin Pwd Feature OPAL request.\r
+  @param[in] RequestString  Request string.\r
+\r
+**/\r
+VOID\r
+ProcessOpalRequestSetAdminPwd (\r
+  IN OPAL_DRIVER_DEVICE *Dev,\r
+  IN CHAR16             *RequestString\r
+  )\r
+{\r
+  UINT8                 Count;\r
+  CHAR8                 *OldPassword;\r
+  UINT32                OldPasswordLen;\r
+  CHAR8                 *Password;\r
+  UINT32                PasswordLen;\r
+  CHAR8                 *PasswordConfirm;\r
+  UINT32                PasswordLenConfirm;\r
+  OPAL_SESSION          Session;\r
+  BOOLEAN               PressEsc;\r
+  EFI_INPUT_KEY         Key;\r
+  TCG_RESULT            Ret;\r
+  CHAR16                *PopUpString;\r
+\r
+  if (Dev == NULL) {\r
+    return;\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
+\r
+  PopUpString = OpalGetPopUpString (Dev, RequestString);\r
+\r
+  Count = 0;\r
+\r
+  while (Count < MAX_PASSWORD_TRY_COUNT) {\r
+    OldPassword = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your password", &PressEsc);\r
+    if (PressEsc) {\r
+        do {\r
+          CreatePopUp (\r
+            EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+            &Key,\r
+            L"Press ENTER to skip the request and continue boot,",\r
+            L"Press ESC to input password again",\r
+            NULL\r
+            );\r
+        } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
+\r
+        if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+          gST->ConOut->ClearScreen(gST->ConOut);\r
+          return;\r
+        } else {\r
+          //\r
+          // Let user input password again.\r
+          //\r
+          continue;\r
+        }\r
+    }\r
+\r
+    if (OldPassword == NULL) {\r
+      Count ++;\r
+      continue;\r
+    }\r
+    OldPasswordLen = (UINT32) AsciiStrLen(OldPassword);\r
+\r
+    ZeroMem(&Session, sizeof(Session));\r
+    Session.Sscp = Dev->OpalDisk.Sscp;\r
+    Session.MediaId = Dev->OpalDisk.MediaId;\r
+    Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
+    Ret = OpalUtilVerifyPassword (&Session, OldPassword, OldPasswordLen, OPAL_LOCKING_SP_ADMIN1_AUTHORITY);\r
+    if (Ret == TcgResultSuccess) {\r
+      DEBUG ((DEBUG_INFO, "Verify: Success\n"));\r
+    } else {\r
+      ZeroMem (OldPassword, OldPasswordLen);\r
+      FreePool (OldPassword);\r
+      DEBUG ((DEBUG_INFO, "Verify: Failure\n"));\r
+      do {\r
+        CreatePopUp (\r
+          EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+          &Key,\r
+          L"Incorrect password.",\r
+          L"Press ENTER to retry",\r
+          NULL\r
+          );\r
+      } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+      Count ++;\r
+      continue;\r
+    }\r
+\r
+    Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your new password", &PressEsc);\r
+    if (Password == NULL) {\r
+      ZeroMem (OldPassword, OldPasswordLen);\r
+      FreePool (OldPassword);\r
+      Count ++;\r
+      continue;\r
+    }\r
+    PasswordLen = (UINT32) AsciiStrLen(Password);\r
+\r
+    PasswordConfirm = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please confirm your new password", &PressEsc);\r
+    if (PasswordConfirm == NULL) {\r
+      ZeroMem (OldPassword, OldPasswordLen);\r
+      FreePool (OldPassword);\r
+      ZeroMem (Password, PasswordLen);\r
+      FreePool (Password);\r
+      Count ++;\r
+      continue;\r
+    }\r
+    PasswordLenConfirm = (UINT32) AsciiStrLen(PasswordConfirm);\r
+    if ((PasswordLen != PasswordLenConfirm) ||\r
+        (CompareMem (Password, PasswordConfirm, PasswordLen) != 0)) {\r
+      ZeroMem (OldPassword, OldPasswordLen);\r
+      FreePool (OldPassword);\r
+      ZeroMem (Password, PasswordLen);\r
+      FreePool (Password);\r
+      ZeroMem (PasswordConfirm, PasswordLenConfirm);\r
+      FreePool (PasswordConfirm);\r
+      do {\r
+        CreatePopUp (\r
+          EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+          &Key,\r
+          L"Passwords are not the same.",\r
+          L"Press ENTER to retry",\r
+          NULL\r
+          );\r
+      } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+      Count ++;\r
+      continue;\r
+    }\r
+\r
+    if (PasswordConfirm != NULL) {\r
+      ZeroMem (PasswordConfirm, PasswordLenConfirm);\r
+      FreePool (PasswordConfirm);\r
+    }\r
+\r
+\r
+    ZeroMem(&Session, sizeof(Session));\r
+    Session.Sscp = Dev->OpalDisk.Sscp;\r
+    Session.MediaId = Dev->OpalDisk.MediaId;\r
+    Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
+    Ret = OpalUtilSetAdminPassword(\r
+            &Session,\r
+            OldPassword,\r
+            OldPasswordLen,\r
+            Password,\r
+            PasswordLen\r
+            );\r
+    if (Ret == TcgResultSuccess) {\r
+      OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen);\r
+      DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
+    } else {\r
+      DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
+    }\r
+\r
+    if (OldPassword != NULL) {\r
+      ZeroMem (OldPassword, OldPasswordLen);\r
+      FreePool (OldPassword);\r
+    }\r
+\r
+    if (Password != NULL) {\r
+      ZeroMem (Password, PasswordLen);\r
+      FreePool (Password);\r
+    }\r
+\r
+    if (Ret == TcgResultSuccess) {\r
+      break;\r
+    }\r
+\r
+    Count++;\r
+\r
+    do {\r
+      CreatePopUp (\r
+        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+        &Key,\r
+        L"Request failed.",\r
+        L"Press ENTER to retry",\r
+        NULL\r
+        );\r
+    } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+  }\r
+\r
+  if (Count >= MAX_PASSWORD_TRY_COUNT) {\r
+    do {\r
+      CreatePopUp (\r
+        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+        &Key,\r
+        L"Opal password retry count exceeds the limit.",\r
+        L"Press ENTER to skip the request and continue boot",\r
+        NULL\r
+        );\r
+    } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+    gST->ConOut->ClearScreen(gST->ConOut);\r
+  }\r
+}\r
+\r
+/**\r
+  Process OPAL request.\r
+\r
+  @param[in] Dev            The device which has OPAL request.\r
+\r
+**/\r
+VOID\r
+ProcessOpalRequest (\r
+  IN OPAL_DRIVER_DEVICE     *Dev\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  OPAL_REQUEST_VARIABLE     *TempVariable;\r
+  OPAL_REQUEST_VARIABLE     *Variable;\r
+  UINTN                     VariableSize;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePathInVariable;\r
+  UINTN                     DevicePathSizeInVariable;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  UINTN                     DevicePathSize;\r
+  BOOLEAN                   KeepUserData;\r
+\r
+  DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
+\r
+  if (mOpalRequestVariable == NULL) {\r
+    Status = GetVariable2 (\r
+               OPAL_REQUEST_VARIABLE_NAME,\r
+               &gHiiSetupVariableGuid,\r
+               (VOID **) &Variable,\r
+               &VariableSize\r
+               );\r
+    if (EFI_ERROR (Status) || (Variable == NULL)) {\r
+      return;\r
+    }\r
+    mOpalRequestVariable = Variable;\r
+    mOpalRequestVariableSize = VariableSize;\r
+\r
+    //\r
+    // Delete the OPAL request variable.\r
+    //\r
+    Status = gRT->SetVariable (\r
+                    OPAL_REQUEST_VARIABLE_NAME,\r
+                    (EFI_GUID *) &gHiiSetupVariableGuid,\r
+                    0,\r
+                    0,\r
+                    NULL\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+  } else {\r
+    Variable = mOpalRequestVariable;\r
+    VariableSize = mOpalRequestVariableSize;\r
+  }\r
+\r
+  //\r
+  // Process the OPAL requests.\r
+  //\r
+  TempVariable = Variable;\r
+  while ((VariableSize > sizeof (OPAL_REQUEST_VARIABLE)) &&\r
+         (VariableSize >= TempVariable->Length) &&\r
+         (TempVariable->Length > sizeof (OPAL_REQUEST_VARIABLE))) {\r
+    DevicePathInVariable = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) TempVariable + sizeof (OPAL_REQUEST_VARIABLE));\r
+    DevicePathSizeInVariable = GetDevicePathSize (DevicePathInVariable);\r
+    DevicePath = Dev->OpalDisk.OpalDevicePath;\r
+    DevicePathSize = GetDevicePathSize (DevicePath);\r
+    if ((DevicePathSize == DevicePathSizeInVariable) &&\r
+        (CompareMem (DevicePath, DevicePathInVariable, DevicePathSize) == 0)) {\r
+      //\r
+      // Found the node for the OPAL device.\r
+      //\r
+      if (TempVariable->OpalRequest.SetAdminPwd != 0) {\r
+        ProcessOpalRequestSetAdminPwd (Dev, L"Update Admin Pwd:");\r
+      }\r
+      if (TempVariable->OpalRequest.SetUserPwd != 0) {\r
+        ProcessOpalRequestSetUserPwd (Dev, L"Set User Pwd:");\r
+      }\r
+      if (TempVariable->OpalRequest.SecureErase!= 0) {\r
+        ProcessOpalRequestSecureErase (Dev, L"Secure Erase:");\r
+      }\r
+      if (TempVariable->OpalRequest.Revert != 0) {\r
+        KeepUserData = (BOOLEAN) TempVariable->OpalRequest.KeepUserData;\r
+        ProcessOpalRequestRevert (\r
+          Dev,\r
+          KeepUserData,\r
+          KeepUserData ? L"Admin Revert(keep):" : L"Admin Revert:"\r
+          );\r
+      }\r
+      if (TempVariable->OpalRequest.PsidRevert != 0) {\r
+        ProcessOpalRequestPsidRevert (Dev, L"Psid Revert:");\r
+      }\r
+      if (TempVariable->OpalRequest.DisableUser != 0) {\r
+        ProcessOpalRequestDisableUser (Dev, L"Disable User:");\r
+      }\r
+      if (TempVariable->OpalRequest.EnableFeature != 0) {\r
+        ProcessOpalRequestEnableFeature (Dev, L"Enable Feature:");\r
+      }\r
+\r
+      break;\r
+    }\r
+\r
+    VariableSize -= TempVariable->Length;\r
+    TempVariable = (OPAL_REQUEST_VARIABLE *) ((UINTN) TempVariable + TempVariable->Length);\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
+}\r
+\r
+/**\r
+  Add new device to the global device list.\r
+\r
+  @param Dev             New create device.\r
+\r
+**/\r
+VOID\r
+AddDeviceToTail(\r
+  IN OPAL_DRIVER_DEVICE    *Dev\r
+  )\r
+{\r
+  OPAL_DRIVER_DEVICE                *TmpDev;\r
+\r
+  if (mOpalDriver.DeviceList == NULL) {\r
+    mOpalDriver.DeviceList = Dev;\r
+  } else {\r
+    TmpDev = mOpalDriver.DeviceList;\r
+    while (TmpDev->Next != NULL) {\r
+      TmpDev = TmpDev->Next;\r
+    }\r
+\r
+    TmpDev->Next = Dev;\r
+  }\r
+}\r
+\r
+/**\r
+  Remove one device in the global device list.\r
+\r
+  @param Dev             The device need to be removed.\r
+\r
+**/\r
+VOID\r
+RemoveDevice (\r
+  IN OPAL_DRIVER_DEVICE    *Dev\r
+  )\r
+{\r
+  OPAL_DRIVER_DEVICE                *TmpDev;\r
+\r
+  if (mOpalDriver.DeviceList == NULL) {\r
+    return;\r
+  }\r
+\r
+  if (mOpalDriver.DeviceList == Dev) {\r
+    mOpalDriver.DeviceList = NULL;\r
+    return;\r
+  }\r
+\r
+  TmpDev = mOpalDriver.DeviceList;\r
+  while (TmpDev->Next != NULL) {\r
+    if (TmpDev->Next == Dev) {\r
+      TmpDev->Next = Dev->Next;\r
+      break;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Get current device count.\r
+\r
+  @retval  return the current created device count.\r
+\r
+**/\r
+UINT8\r
+GetDeviceCount (\r
+  VOID\r
+  )\r
+{\r
+  UINT8                Count;\r
+  OPAL_DRIVER_DEVICE   *TmpDev;\r
+\r
+  Count = 0;\r
+  TmpDev = mOpalDriver.DeviceList;\r
+\r
+  while (TmpDev != NULL) {\r
+    Count++;\r
+    TmpDev = TmpDev->Next;\r
+  }\r
+\r
+  return Count;\r
+}\r
+\r
+/**\r
+  Get devcie list info.\r
+\r
+  @retval     return the device list pointer.\r
+**/\r
+OPAL_DRIVER_DEVICE*\r
+OpalDriverGetDeviceList(\r
+  VOID\r
+  )\r
+{\r
+  return mOpalDriver.DeviceList;\r
+}\r
+\r
+/**\r
+  ReadyToBoot callback to send BlockSid command.\r
+\r
+  @param  Event   Pointer to this event\r
+  @param  Context Event handler private Data\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+ReadyToBootCallback (\r
+  IN EFI_EVENT        Event,\r
+  IN VOID             *Context\r
+  )\r
+{\r
+  OPAL_DRIVER_DEVICE                         *Itr;\r
+  TCG_RESULT                                 Result;\r
+  OPAL_SESSION                               Session;\r
+  UINT32                                     PpStorageFlag;\r
+\r
+  gBS->CloseEvent (Event);\r
+\r
+  PpStorageFlag = Tcg2PhysicalPresenceLibGetManagementFlags ();\r
+  if ((PpStorageFlag & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID) != 0) {\r
+    //\r
+    // Send BlockSID command to each Opal disk\r
+    //\r
+    Itr = mOpalDriver.DeviceList;\r
+    while (Itr != NULL) {\r
+      if (Itr->OpalDisk.SupportedAttributes.BlockSid) {\r
+        ZeroMem(&Session, sizeof(Session));\r
+        Session.Sscp = Itr->OpalDisk.Sscp;\r
+        Session.MediaId = Itr->OpalDisk.MediaId;\r
+        Session.OpalBaseComId = Itr->OpalDisk.OpalBaseComId;\r
+\r
+        Result = OpalBlockSid (&Session, TRUE);  // HardwareReset must always be TRUE\r
+        if (Result != TcgResultSuccess) {\r
+          DEBUG ((DEBUG_ERROR, "OpalBlockSid fail\n"));\r
+          break;\r
+        }\r
+      }\r
+\r
+      Itr = Itr->Next;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Stop this Controller.\r
+\r
+  @param  Dev               The device need to be stopped.\r
+\r
+**/\r
+VOID\r
+OpalDriverStopDevice (\r
+  OPAL_DRIVER_DEVICE     *Dev\r
+  )\r
+{\r
+  //\r
+  // free each name\r
+  //\r
+  FreePool(Dev->Name16);\r
+\r
+  //\r
+  // remove OPAL_DRIVER_DEVICE from the list\r
+  // it updates the controllerList pointer\r
+  //\r
+  RemoveDevice(Dev);\r
+\r
+  //\r
+  // close protocols that were opened\r
+  //\r
+  gBS->CloseProtocol(\r
+    Dev->Handle,\r
+    &gEfiStorageSecurityCommandProtocolGuid,\r
+    gOpalDriverBinding.DriverBindingHandle,\r
+    Dev->Handle\r
+    );\r
+\r
+  gBS->CloseProtocol(\r
+    Dev->Handle,\r
+    &gEfiBlockIoProtocolGuid,\r
+    gOpalDriverBinding.DriverBindingHandle,\r
+    Dev->Handle\r
+    );\r
+\r
+  FreePool(Dev);\r
+}\r
+\r
+/**\r
+  Get devcie name through the component name protocol.\r
+\r
+  @param[in]       AllHandlesBuffer   The handle buffer for current system.\r
+  @param[in]       NumAllHandles      The number of handles for the handle buffer.\r
+  @param[in]       Dev                The device which need to get name.\r
+  @param[in]       UseComp1           Whether use component name or name2 protocol.\r
+\r
+  @retval     TRUE        Find the name for this device.\r
+  @retval     FALSE       Not found the name for this device.\r
+**/\r
+BOOLEAN\r
+OpalDriverGetDeviceNameByProtocol(\r
+  EFI_HANDLE             *AllHandlesBuffer,\r
+  UINTN                  NumAllHandles,\r
+  OPAL_DRIVER_DEVICE     *Dev,\r
+  BOOLEAN                UseComp1\r
+  )\r
+{\r
+  EFI_HANDLE*                   ProtocolHandlesBuffer;\r
+  UINTN                         NumProtocolHandles;\r
+  EFI_STATUS                    Status;\r
+  EFI_COMPONENT_NAME2_PROTOCOL* Cnp1_2; // efi component name and componentName2 have same layout\r
+  EFI_GUID                      Protocol;\r
+  UINTN                         StrLength;\r
+  EFI_DEVICE_PATH_PROTOCOL*     TmpDevPath;\r
+  UINTN                         Index1;\r
+  UINTN                         Index2;\r
+  EFI_HANDLE                    TmpHandle;\r
+  CHAR16                        *DevName;\r
+\r
+  if (Dev == NULL || AllHandlesBuffer == NULL || NumAllHandles == 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  Protocol = UseComp1 ? gEfiComponentNameProtocolGuid : gEfiComponentName2ProtocolGuid;\r
+\r
+  //\r
+  // Find all EFI_HANDLES with protocol\r
+  //\r
+  Status = gBS->LocateHandleBuffer(\r
+               ByProtocol,\r
+               &Protocol,\r
+               NULL,\r
+               &NumProtocolHandles,\r
+               &ProtocolHandlesBuffer\r
+               );\r
+  if (EFI_ERROR(Status)) {\r
+    return FALSE;\r
+  }\r
+\r
+\r
+  //\r
+  // Exit early if no supported devices\r
+  //\r
+  if (NumProtocolHandles == 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Get printable name by iterating through all protocols\r
+  // using the handle as the child, and iterate through all handles for the controller\r
+  // exit loop early once found, if not found, then delete device\r
+  // storage security protocol instances already exist, add them to internal list\r
+  //\r
+  Status = EFI_DEVICE_ERROR;\r
+  for (Index1 = 0; Index1 < NumProtocolHandles; Index1++) {\r
+    DevName = NULL;\r
+\r
+    if (Dev->Name16 != NULL) {\r
+      return TRUE;\r
+    }\r
+\r
+    TmpHandle = ProtocolHandlesBuffer[Index1];\r
+\r
+    Status = gBS->OpenProtocol(\r
+                 TmpHandle,\r
+                 &Protocol,\r
+                 (VOID**)&Cnp1_2,\r
+                 gImageHandle,\r
+                 NULL,\r
+                 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                 );\r
+    if (EFI_ERROR(Status) || Cnp1_2 == NULL) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Use all handles array as controller handle\r
+    //\r
+    for (Index2 = 0; Index2 < NumAllHandles; Index2++) {\r
+      Status = Cnp1_2->GetControllerName(\r
+                   Cnp1_2,\r
+                   AllHandlesBuffer[Index2],\r
+                   Dev->Handle,\r
+                   LANGUAGE_ISO_639_2_ENGLISH,\r
+                   &DevName\r
+                   );\r
+      if (EFI_ERROR(Status)) {\r
+        Status = Cnp1_2->GetControllerName(\r
+                     Cnp1_2,\r
+                     AllHandlesBuffer[Index2],\r
+                     Dev->Handle,\r
+                     LANGUAGE_RFC_3066_ENGLISH,\r
+                     &DevName\r
+                     );\r
+      }\r
+      if (!EFI_ERROR(Status) && DevName != NULL) {\r
+        StrLength = StrLen(DevName) + 1;        // Add one for NULL terminator\r
+        Dev->Name16 = AllocateZeroPool(StrLength * sizeof (CHAR16));\r
+        ASSERT (Dev->Name16 != NULL);\r
+        StrCpyS (Dev->Name16, StrLength, DevName);\r
+        Dev->NameZ = (CHAR8*)AllocateZeroPool(StrLength);\r
+        UnicodeStrToAsciiStrS (DevName, Dev->NameZ, StrLength);\r
+\r
+        //\r
+        // Retrieve bridge BDF info and port number or namespace depending on type\r
+        //\r
+        TmpDevPath = NULL;\r
+        Status = gBS->OpenProtocol(\r
+            Dev->Handle,\r
+            &gEfiDevicePathProtocolGuid,\r
+            (VOID**)&TmpDevPath,\r
+            gImageHandle,\r
+            NULL,\r
+            EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+            );\r
+        if (!EFI_ERROR(Status)) {\r
+          Dev->OpalDevicePath = DuplicateDevicePath (TmpDevPath);\r
+          return TRUE;\r
+        }\r
+\r
+        if (Dev->Name16 != NULL) {\r
+          FreePool(Dev->Name16);\r
+          Dev->Name16 = NULL;\r
+        }\r
+        if (Dev->NameZ != NULL) {\r
+          FreePool(Dev->NameZ);\r
+          Dev->NameZ = NULL;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Get devcie name through the component name protocol.\r
+\r
+  @param[in]       Dev                The device which need to get name.\r
+\r
+  @retval     TRUE        Find the name for this device.\r
+  @retval     FALSE       Not found the name for this device.\r
+**/\r
+BOOLEAN\r
+OpalDriverGetDriverDeviceName(\r
+  OPAL_DRIVER_DEVICE          *Dev\r
+  )\r
+{\r
+  EFI_HANDLE*                  AllHandlesBuffer;\r
+  UINTN                        NumAllHandles;\r
+  EFI_STATUS                   Status;\r
+\r
+  if (Dev == NULL) {\r
+    DEBUG((DEBUG_ERROR | DEBUG_INIT, "OpalDriverGetDriverDeviceName Exiting, Dev=NULL\n"));\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Iterate through ComponentName2 handles to get name, if fails, try ComponentName\r
+  //\r
+  if (Dev->Name16 == NULL) {\r
+    DEBUG((DEBUG_ERROR | DEBUG_INIT, "Name is null, update it\n"));\r
+    //\r
+    // Find all EFI_HANDLES\r
+    //\r
+    Status = gBS->LocateHandleBuffer(\r
+                 AllHandles,\r
+                 NULL,\r
+                 NULL,\r
+                 &NumAllHandles,\r
+                 &AllHandlesBuffer\r
+                 );\r
+    if (EFI_ERROR(Status)) {\r
+      DEBUG ((DEBUG_INFO, "LocateHandleBuffer for AllHandles failed %r\n", Status ));\r
+      return FALSE;\r
+    }\r
+\r
+    //\r
+    // Try component Name2\r
+    //\r
+    if (!OpalDriverGetDeviceNameByProtocol(AllHandlesBuffer, NumAllHandles, Dev, FALSE)) {\r
+      DEBUG((DEBUG_ERROR | DEBUG_INIT, "ComponentName2 failed to get device name, try ComponentName\n"));\r
+      if (!OpalDriverGetDeviceNameByProtocol(AllHandlesBuffer, NumAllHandles, Dev, TRUE)) {\r
+        DEBUG((DEBUG_ERROR | DEBUG_INIT, "ComponentName failed to get device name, skip device\n"));\r
+        return FALSE;\r
+      }\r
+    }\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Main entry for this driver.\r
+\r
+  @param ImageHandle     Image Handle this driver.\r
+  @param SystemTable     Pointer to SystemTable.\r
+\r
+  @retval EFI_SUCESS     This function always complete successfully.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiDriverEntryPoint(\r
+  IN EFI_HANDLE         ImageHandle,\r
+  IN EFI_SYSTEM_TABLE*  SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  EFI_EVENT                      ReadyToBootEvent;\r
+  EFI_EVENT                      EndOfDxeEvent;\r
+\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gOpalDriverBinding,\r
+             ImageHandle,\r
+             &gOpalComponentName,\r
+             &gOpalComponentName2\r
+             );\r
+\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG((DEBUG_ERROR, "Install protocols to Opal driver Handle failed\n"));\r
+    return Status ;\r
+  }\r
+\r
+  //\r
+  // Initialize Driver object\r
+  //\r
+  ZeroMem(&mOpalDriver, sizeof(mOpalDriver));\r
+  mOpalDriver.Handle = ImageHandle;\r
+\r
+  Status = gBS->CreateEventEx (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  OpalEndOfDxeEventNotify,\r
+                  NULL,\r
+                  &gEfiEndOfDxeEventGroupGuid,\r
+                  &EndOfDxeEvent\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // register a ReadyToBoot event callback for sending BlockSid command\r
+  //\r
+  Status = EfiCreateEventReadyToBootEx (\r
+                  TPL_CALLBACK,\r
+                  ReadyToBootCallback,\r
+                  (VOID *) &ImageHandle,\r
+                  &ReadyToBootEvent\r
+                  );\r
+\r
+  //\r
+  // Install Hii packages.\r
+  //\r
+  HiiInstall();\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Tests to see if this driver supports a given controller.\r
+\r
+  This function checks to see if the controller contains an instance of the\r
+  EFI_STORAGE_SECURITY_COMMAND_PROTOCOL and the EFI_BLOCK_IO_PROTOCL\r
+  and returns EFI_SUCCESS if it does.\r
+\r
+  @param[in]  This                  A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle      The Handle of the controller to test. This Handle\r
+                                    must support a protocol interface that supplies\r
+                                    an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  This parameter is ignored.\r
+\r
+  @retval EFI_SUCCESS               The device contains required protocols\r
+  @retval EFI_ALREADY_STARTED       The device specified by ControllerHandle and\r
+                                    RemainingDevicePath is already being managed by the driver\r
+                                    specified by This.\r
+  @retval EFI_ACCESS_DENIED         The device specified by ControllerHandle and\r
+                                    RemainingDevicePath is already being managed by a different\r
+                                    driver or an application that requires exclusive access.\r
+                                    Currently not implemented.\r
+  @retval EFI_UNSUPPORTED           The device does not contain requires protocols\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverBindingSupported(\r
+  IN EFI_DRIVER_BINDING_PROTOCOL* This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL*    RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+  EFI_STORAGE_SECURITY_COMMAND_PROTOCOL*  SecurityCommand;\r
+  EFI_BLOCK_IO_PROTOCOL*                  BlkIo;\r
+\r
+  if (mOpalEndOfDxe) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Test EFI_STORAGE_SECURITY_COMMAND_PROTOCOL on controller Handle.\r
+  //\r
+  Status = gBS->OpenProtocol(\r
+    Controller,\r
+    &gEfiStorageSecurityCommandProtocolGuid,\r
+    ( VOID ** )&SecurityCommand,\r
+    This->DriverBindingHandle,\r
+    Controller,\r
+    EFI_OPEN_PROTOCOL_BY_DRIVER\r
+    );\r
+\r
+  if (Status == EFI_ALREADY_STARTED) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Close protocol and reopen in Start call\r
+  //\r
+  gBS->CloseProtocol(\r
+      Controller,\r
+      &gEfiStorageSecurityCommandProtocolGuid,\r
+      This->DriverBindingHandle,\r
+      Controller\r
+      );\r
+\r
+  //\r
+  // Test EFI_BLOCK_IO_PROTOCOL on controller Handle, required by EFI_STORAGE_SECURITY_COMMAND_PROTOCOL\r
+  // function APIs\r
+  //\r
+  Status = gBS->OpenProtocol(\r
+    Controller,\r
+    &gEfiBlockIoProtocolGuid,\r
+    (VOID **)&BlkIo,\r
+    This->DriverBindingHandle,\r
+    Controller,\r
+    EFI_OPEN_PROTOCOL_BY_DRIVER\r
+    );\r
+\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG((DEBUG_INFO, "No EFI_BLOCK_IO_PROTOCOL on controller\n"));\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Close protocol and reopen in Start call\r
+  //\r
+  gBS->CloseProtocol(\r
+    Controller,\r
+    &gEfiBlockIoProtocolGuid,\r
+    This->DriverBindingHandle,\r
+    Controller\r
+    );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Enables Opal Management on a supported device if available.\r
+\r
+  The start function is designed to be called after the Opal UEFI Driver has confirmed the\r
+  "controller", which is a child Handle, contains the EF_STORAGE_SECURITY_COMMAND protocols.\r
+  This function will complete the other necessary checks, such as verifying the device supports\r
+  the correct version of Opal.  Upon verification, it will add the device to the\r
+  Opal HII list in order to expose Opal managmeent options.\r
+\r
+  @param[in]  This                  A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle      The Handle of the controller to start. This Handle\r
+                                    must support a protocol interface that supplies\r
+                                    an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath   A pointer to the remaining portion of a device path.  This\r
+                                    parameter is ignored by device drivers, and is optional for bus\r
+                                    drivers. For a bus driver, if this parameter is NULL, then handles\r
+                                    for all the children of Controller are created by this driver.\r
+                                    If this parameter is not NULL and the first Device Path Node is\r
+                                    not the End of Device Path Node, then only the Handle for the\r
+                                    child device specified by the first Device Path Node of\r
+                                    RemainingDevicePath is created by this driver.\r
+                                    If the first Device Path Node of RemainingDevicePath is\r
+                                    the End of Device Path Node, no child Handle is created by this\r
+                                    driver.\r
+\r
+  @retval EFI_SUCCESS               Opal management was enabled.\r
+  @retval EFI_DEVICE_ERROR          The device could not be started due to a device error.Currently not implemented.\r
+  @retval EFI_OUT_OF_RESOURCES      The request could not be completed due to a lack of resources.\r
+  @retval Others                    The driver failed to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverBindingStart(\r
+  IN EFI_DRIVER_BINDING_PROTOCOL* This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL*    RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_BLOCK_IO_PROTOCOL       *BlkIo;\r
+  OPAL_DRIVER_DEVICE          *Dev;\r
+  OPAL_DRIVER_DEVICE          *Itr;\r
+  BOOLEAN                     Result;\r
+\r
+  Itr = mOpalDriver.DeviceList;\r
+  while (Itr != NULL) {\r
+    if (Controller == Itr->Handle) {\r
+      return EFI_SUCCESS;\r
+    }\r
+    Itr = Itr->Next;\r
+  }\r
+\r
+  //\r
+  // Create internal device for tracking.  This allows all disks to be tracked\r
+  // by same HII form\r
+  //\r
+  Dev = (OPAL_DRIVER_DEVICE*)AllocateZeroPool(sizeof(OPAL_DRIVER_DEVICE));\r
+  if (Dev == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  Dev->Handle = Controller;\r
+\r
+  //\r
+  // Open EFI_STORAGE_SECURITY_COMMAND_PROTOCOL to perform Opal supported checks\r
+  //\r
+  Status = gBS->OpenProtocol(\r
+    Controller,\r
+    &gEfiStorageSecurityCommandProtocolGuid,\r
+    (VOID **)&Dev->Sscp,\r
+    This->DriverBindingHandle,\r
+    Controller,\r
+    EFI_OPEN_PROTOCOL_BY_DRIVER\r
+    );\r
+  if (EFI_ERROR(Status)) {\r
+    FreePool(Dev);\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Open EFI_BLOCK_IO_PROTOCOL on controller Handle, required by EFI_STORAGE_SECURITY_COMMAND_PROTOCOL\r
+  // function APIs\r
+  //\r
+  Status = gBS->OpenProtocol(\r
+    Controller,\r
+    &gEfiBlockIoProtocolGuid,\r
+    (VOID **)&BlkIo,\r
+    This->DriverBindingHandle,\r
+    Controller,\r
+    EFI_OPEN_PROTOCOL_BY_DRIVER\r
+    );\r
+  if (EFI_ERROR(Status)) {\r
+    //\r
+    // Close storage security that was opened\r
+    //\r
+    gBS->CloseProtocol(\r
+        Controller,\r
+        &gEfiStorageSecurityCommandProtocolGuid,\r
+        This->DriverBindingHandle,\r
+        Controller\r
+        );\r
+\r
+    FreePool(Dev);\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Save mediaId\r
+  //\r
+  Dev->MediaId = BlkIo->Media->MediaId;\r
+\r
+  gBS->CloseProtocol(\r
+    Controller,\r
+    &gEfiBlockIoProtocolGuid,\r
+    This->DriverBindingHandle,\r
+    Controller\r
+    );\r
+\r
+  //\r
+  // Acquire Ascii printable name of child, if not found, then ignore device\r
+  //\r
+  Result = OpalDriverGetDriverDeviceName (Dev);\r
+  if (!Result) {\r
+    goto Done;\r
+  }\r
+\r
+  Status = OpalDiskInitialize (Dev);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  AddDeviceToTail(Dev);\r
+\r
+  //\r
+  // Check if device is locked and prompt for password.\r
+  //\r
+  OpalDriverRequestPassword (Dev, L"Unlock:");\r
+\r
+  //\r
+  // Process OPAL request from last boot.\r
+  //\r
+  ProcessOpalRequest (Dev);\r
+\r
+  return EFI_SUCCESS;\r
+\r
+Done:\r
+  //\r
+  // free device, close protocols and exit\r
+  //\r
+  gBS->CloseProtocol(\r
+      Controller,\r
+      &gEfiStorageSecurityCommandProtocolGuid,\r
+      This->DriverBindingHandle,\r
+      Controller\r
+      );\r
+\r
+  FreePool(Dev);\r
+\r
+  return EFI_DEVICE_ERROR;\r
+}\r
+\r
+/**\r
+  Stop this driver on Controller.\r
+\r
+  @param  This              Protocol instance pointer.\r
+  @param  Controller        Handle of device to stop driver on\r
+  @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of\r
+                            children is zero stop the entire bus driver.\r
+  @param  ChildHandleBuffer List of Child Handles to Stop.\r
+\r
+  @retval EFI_SUCCESS       This driver is removed Controller.\r
+  @retval other             This driver could not be removed from this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverBindingStop(\r
+  EFI_DRIVER_BINDING_PROTOCOL*    This,\r
+  EFI_HANDLE                      Controller,\r
+  UINTN                           NumberOfChildren,\r
+  EFI_HANDLE*                     ChildHandleBuffer\r
+  )\r
+{\r
+  OPAL_DRIVER_DEVICE*   Itr;\r
+\r
+  Itr = mOpalDriver.DeviceList;\r
+\r
+  //\r
+  // does Controller match any of the devices we are managing for Opal\r
+  //\r
+  while (Itr != NULL) {\r
+    if (Itr->Handle == Controller) {\r
+      OpalDriverStopDevice (Itr);\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    Itr = Itr->Next;\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  Unloads UEFI Driver.  Very useful for debugging and testing.\r
+\r
+  @param ImageHandle            Image Handle this driver.\r
+\r
+  @retval EFI_SUCCESS           This function always complete successfully.\r
+  @retval EFI_INVALID_PARAMETER The input ImageHandle is not valid.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverUnload (\r
+  IN EFI_HANDLE ImageHandle\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  OPAL_DRIVER_DEVICE                   *Itr;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  if (ImageHandle != gImageHandle) {\r
+    return (EFI_INVALID_PARAMETER);\r
+  }\r
+\r
+  //\r
+  // Uninstall any interface added to each device by us\r
+  //\r
+  while (mOpalDriver.DeviceList) {\r
+    Itr = mOpalDriver.DeviceList;\r
+    //\r
+    // Remove OPAL_DRIVER_DEVICE from the list\r
+    // it updates the controllerList pointer\r
+    //\r
+    OpalDriverStopDevice(Itr);\r
+  }\r
+\r
+  //\r
+  // Uninstall the HII capability\r
+  //\r
+  Status = HiiUninstall();\r
+\r
+  return Status;\r
+}\r
+\r
diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.h b/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.h
new file mode 100644 (file)
index 0000000..2154523
--- /dev/null
@@ -0,0 +1,612 @@
+/** @file\r
+  Values defined and used by the Opal UEFI Driver.\r
+\r
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _OPAL_DRIVER_H_\r
+#define _OPAL_DRIVER_H_\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <IndustryStandard/Pci.h>\r
+\r
+#include <Protocol/PciIo.h>\r
+#include <Protocol/SmmCommunication.h>\r
+#include <Protocol/BlockIo.h>\r
+#include <Protocol/LoadedImage.h>\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/DevicePathToText.h>\r
+#include <Protocol/StorageSecurityCommand.h>\r
+\r
+#include <Guid/EventGroup.h>\r
+\r
+#include <Library/UefiLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/HiiLib.h>\r
+#include <Library/UefiHiiServicesLib.h>\r
+#include <Library/PciLib.h>\r
+#include <Library/S3BootScriptLib.h>\r
+#include <Library/LockBoxLib.h>\r
+#include <Library/TcgStorageOpalLib.h>\r
+#include <Library/Tcg2PhysicalPresenceLib.h>\r
+\r
+#include "OpalPasswordCommon.h"\r
+#include "OpalHiiFormValues.h"\r
+\r
+#define EFI_DRIVER_NAME_UNICODE L"1.0 UEFI Opal Driver"\r
+\r
+// UEFI 2.1\r
+#define LANGUAGE_RFC_3066_ENGLISH ((CHAR8*)"en")\r
+\r
+// UEFI/EFI < 2.1\r
+#define LANGUAGE_ISO_639_2_ENGLISH ((CHAR8*)"eng")\r
+\r
+#define CONCAT_(x, y) x ## y\r
+#define CONCAT(x, y) CONCAT_(x, y)\r
+\r
+#define UNICODE_STR(x) CONCAT( L, x )\r
+\r
+extern EFI_DRIVER_BINDING_PROTOCOL   gOpalDriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL   gOpalComponentName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL  gOpalComponentName2;\r
+\r
+#define OPAL_MSID_LENGHT        128\r
+\r
+#define MAX_PASSWORD_TRY_COUNT  5\r
+\r
+// PSID Length\r
+#define PSID_CHARACTER_LENGTH   0x20\r
+#define MAX_PSID_TRY_COUNT      5\r
+\r
+#pragma pack(1)\r
+\r
+//\r
+// Structure that is used to represent the available actions for an OpalDisk.\r
+// The data can then be utilized to expose/hide certain actions available to an end user\r
+// by the consumer of this library.\r
+//\r
+typedef struct {\r
+    //\r
+    // Indicates if the disk can support PSID Revert action.  should verify disk supports PSID authority\r
+    //\r
+    UINT16 PsidRevert : 1;\r
+\r
+    //\r
+    // Indicates if the disk can support Revert action\r
+    //\r
+    UINT16 Revert : 1;\r
+\r
+    //\r
+    // Indicates if the user must keep data for revert action.  It is true if no media encryption is supported.\r
+    //\r
+    UINT16 RevertKeepDataForced : 1;\r
+\r
+    //\r
+    // Indicates if the disk can support set Admin password\r
+    //\r
+    UINT16 AdminPass : 1;\r
+\r
+    //\r
+    // Indicates if the disk can support set User password.  This action requires that a user\r
+    // password is first enabled.\r
+    //\r
+    UINT16 UserPass : 1;\r
+\r
+    //\r
+    // Indicates if unlock action is available.  Requires disk to be currently locked.\r
+    //\r
+    UINT16 Unlock : 1;\r
+\r
+    //\r
+    // Indicates if Secure Erase action is available.  Action requires admin credentials and media encryption support.\r
+    //\r
+    UINT16 SecureErase : 1;\r
+\r
+    //\r
+    // Indicates if Disable User action is available.  Action requires admin credentials.\r
+    //\r
+    UINT16 DisableUser : 1;\r
+} OPAL_DISK_ACTIONS;\r
+\r
+//\r
+// Structure that is used to represent an OPAL_DISK.\r
+//\r
+typedef struct {\r
+  UINT32                                          MsidLength;             // Byte length of MSID Pin for device\r
+  UINT8                                           Msid[OPAL_MSID_LENGHT]; // MSID Pin for device\r
+  EFI_STORAGE_SECURITY_COMMAND_PROTOCOL           *Sscp;\r
+  UINT32                                          MediaId;                // MediaId is used by Ssc Protocol.\r
+  EFI_DEVICE_PATH_PROTOCOL                        *OpalDevicePath;\r
+  UINT16                                          OpalBaseComId;          // Opal SSC 1 base com id.\r
+  OPAL_OWNER_SHIP                                 Owner;\r
+  OPAL_DISK_SUPPORT_ATTRIBUTE                     SupportedAttributes;\r
+  TCG_LOCKING_FEATURE_DESCRIPTOR                  LockingFeature;         // Locking Feature Descriptor retrieved from performing a Level 0 Discovery\r
+  UINT8                                           PasswordLength;\r
+  UINT8                                           Password[OPAL_MAX_PASSWORD_SIZE];\r
+} OPAL_DISK;\r
+\r
+//\r
+// Device with block IO protocol\r
+//\r
+typedef struct _OPAL_DRIVER_DEVICE OPAL_DRIVER_DEVICE;\r
+\r
+struct _OPAL_DRIVER_DEVICE {\r
+  OPAL_DRIVER_DEVICE                              *Next;              ///< Linked list pointer\r
+  EFI_HANDLE                                      Handle;             ///< Device handle\r
+  OPAL_DISK                                       OpalDisk;           ///< User context\r
+  CHAR16                                          *Name16;            ///< Allocated/freed by UEFI Filter Driver at device creation/removal\r
+  CHAR8                                           *NameZ;             ///< Allocated/freed by UEFI Filter Driver at device creation/removal\r
+  UINT32                                          MediaId;            ///< Required parameter for EFI_STORAGE_SECURITY_COMMAND_PROTOCOL, from BLOCK_IO_MEDIA\r
+\r
+  EFI_STORAGE_SECURITY_COMMAND_PROTOCOL           *Sscp;              /// Device protocols consumed\r
+  EFI_DEVICE_PATH_PROTOCOL                        *OpalDevicePath;\r
+};\r
+\r
+//\r
+// Opal Driver UEFI Driver Model\r
+//\r
+typedef struct {\r
+  EFI_HANDLE           Handle;              ///< Driver image handle\r
+  OPAL_DRIVER_DEVICE   *DeviceList;         ///< Linked list of controllers owned by this Driver\r
+} OPAL_DRIVER;\r
+\r
+#pragma pack()\r
+\r
+//\r
+// Retrieves a OPAL_DRIVER_DEVICE based on the pointer to its StorageSecurity protocol.\r
+//\r
+#define DRIVER_DEVICE_FROM_OPALDISK(OpalDiskPointer) (OPAL_DRIVER_DEVICE*)(BASE_CR(OpalDiskPointer, OPAL_DRIVER_DEVICE, OpalDisk))\r
+\r
+/**\r
+  Get devcie list info.\r
+\r
+  @retval     return the device list pointer.\r
+**/\r
+OPAL_DRIVER_DEVICE*\r
+OpalDriverGetDeviceList(\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Get devcie name through the component name protocol.\r
+\r
+  @param[in]       Dev                The device which need to get name.\r
+\r
+  @retval     TRUE        Find the name for this device.\r
+  @retval     FALSE       Not found the name for this device.\r
+**/\r
+BOOLEAN\r
+OpalDriverGetDriverDeviceName(\r
+  OPAL_DRIVER_DEVICE          *Dev\r
+  );\r
+\r
+/**\r
+  Get current device count.\r
+\r
+  @retval  return the current created device count.\r
+\r
+**/\r
+UINT8\r
+GetDeviceCount (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Update password for the Opal disk.\r
+\r
+  @param[in, out] OpalDisk          The disk to update password.\r
+  @param[in]      Password          The input password.\r
+  @param[in]      PasswordLength    The input password length.\r
+\r
+**/\r
+VOID\r
+OpalSupportUpdatePassword (\r
+  IN OUT OPAL_DISK      *OpalDisk,\r
+  IN VOID               *Password,\r
+  IN UINT32             PasswordLength\r
+  );\r
+\r
+/**\r
+\r
+  The function performs determines the available actions for the OPAL_DISK provided.\r
+\r
+  @param[in]   SupportedAttributes   The support attribute for the device.\r
+  @param[in]   LockingFeature        The locking status for the device.\r
+  @param[in]   OwnerShip             The ownership for the device.\r
+  @param[out]  AvalDiskActions       Pointer to fill-out with appropriate disk actions.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportGetAvailableActions(\r
+  IN  OPAL_DISK_SUPPORT_ATTRIBUTE      *SupportedAttributes,\r
+  IN  TCG_LOCKING_FEATURE_DESCRIPTOR   *LockingFeature,\r
+  IN  UINT16                           OwnerShip,\r
+  OUT OPAL_DISK_ACTIONS                *AvalDiskActions\r
+  );\r
+\r
+/**\r
+  Enable Opal Feature for the input device.\r
+\r
+  @param[in]      Session            The opal session for the opal device.\r
+  @param[in]      Msid               Msid\r
+  @param[in]      MsidLength         Msid Length\r
+  @param[in]      Password           Admin password\r
+  @param[in]      PassLength         Length of password in bytes \r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportEnableOpalFeature (\r
+  IN OPAL_SESSION              *Session,\r
+  IN VOID                      *Msid,\r
+  IN UINT32                    MsidLength,\r
+  IN VOID                      *Password,\r
+  IN UINT32                    PassLength\r
+  );\r
+\r
+/**\r
+  Unloads UEFI Driver.  Very useful for debugging and testing.\r
+\r
+  @param ImageHandle            Image handle this driver.\r
+\r
+  @retval EFI_SUCCESS           This function always complete successfully.\r
+  @retval EFI_INVALID_PARAMETER The input ImageHandle is not valid.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiDriverUnload(\r
+  EFI_HANDLE ImageHandle\r
+  );\r
+\r
+\r
+/**\r
+  Test to see if this driver supports Controller.\r
+\r
+  @param  This                Protocol instance pointer.\r
+  @param  ControllerHandle    Handle of device to test\r
+  @param  RemainingDevicePath Optional parameter use to pick a specific child\r
+                              device to start.\r
+\r
+  @retval EFI_SUCCESS         This driver supports this device.\r
+  @retval EFI_ALREADY_STARTED This driver is already running on this device.\r
+  @retval other               This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverBindingSupported(\r
+  EFI_DRIVER_BINDING_PROTOCOL*    This,\r
+  EFI_HANDLE                      Controller,\r
+  EFI_DEVICE_PATH_PROTOCOL*       RemainingDevicePath\r
+  );\r
+\r
+/**\r
+  Enables Opal Management on a supported device if available.\r
+\r
+  The start function is designed to be called after the Opal UEFI Driver has confirmed the\r
+  "controller", which is a child handle, contains the EF_STORAGE_SECURITY_COMMAND protocols.\r
+  This function will complete the other necessary checks, such as verifying the device supports\r
+  the correct version of Opal.  Upon verification, it will add the device to the\r
+  Opal HII list in order to expose Opal managmeent options.\r
+\r
+  @param[in]  This                  A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle      The handle of the controller to start. This handle\r
+                                    must support a protocol interface that supplies\r
+                                    an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath   A pointer to the remaining portion of a device path.  This\r
+                                    parameter is ignored by device drivers, and is optional for bus\r
+                                    drivers. For a bus driver, if this parameter is NULL, then handles\r
+                                    for all the children of Controller are created by this driver.\r
+                                    If this parameter is not NULL and the first Device Path Node is\r
+                                    not the End of Device Path Node, then only the handle for the\r
+                                    child device specified by the first Device Path Node of\r
+                                    RemainingDevicePath is created by this driver.\r
+                                    If the first Device Path Node of RemainingDevicePath is\r
+                                    the End of Device Path Node, no child handle is created by this\r
+                                    driver.\r
+\r
+  @retval EFI_SUCCESS               Opal management was enabled.\r
+  @retval EFI_DEVICE_ERROR          The device could not be started due to a device error.Currently not implemented.\r
+  @retval EFI_OUT_OF_RESOURCES      The request could not be completed due to a lack of resources.\r
+  @retval Others                    The driver failed to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverBindingStart(\r
+  EFI_DRIVER_BINDING_PROTOCOL*    This,\r
+  EFI_HANDLE                      Controller,\r
+  EFI_DEVICE_PATH_PROTOCOL*       RemainingDevicePath\r
+  );\r
+\r
+/**\r
+  Stop this driver on Controller.\r
+\r
+  @param  This              Protocol instance pointer.\r
+  @param  Controller        Handle of device to stop driver on\r
+  @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of\r
+                            children is zero stop the entire bus driver.\r
+  @param  ChildHandleBuffer List of Child Handles to Stop.\r
+\r
+  @retval EFI_SUCCESS       This driver is removed Controller.\r
+  @retval other             This driver could not be removed from this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverBindingStop(\r
+  EFI_DRIVER_BINDING_PROTOCOL*    This,\r
+  EFI_HANDLE                      Controller,\r
+  UINTN                           NumberOfChildren,\r
+  EFI_HANDLE*                     ChildHandleBuffer\r
+  );\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverComponentNameGetDriverName(\r
+  EFI_COMPONENT_NAME_PROTOCOL*    This,\r
+  CHAR8*                          Language,\r
+  CHAR16**                        DriverName\r
+  );\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverComponentNameGetControllerName(\r
+  EFI_COMPONENT_NAME_PROTOCOL*    This,\r
+  EFI_HANDLE                      ControllerHandle,\r
+  EFI_HANDLE                      ChildHandle,\r
+  CHAR8*                          Language,\r
+  CHAR16**                        ControllerName\r
+  );\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverComponentName2GetDriverName(\r
+  EFI_COMPONENT_NAME2_PROTOCOL*   This,\r
+  CHAR8*                          Language,\r
+  CHAR16**                        DriverName\r
+  );\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverComponentName2GetControllerName(\r
+  EFI_COMPONENT_NAME2_PROTOCOL*   This,\r
+  EFI_HANDLE                      ControllerHandle,\r
+  EFI_HANDLE                      ChildHandle,\r
+  CHAR8*                          Language,\r
+  CHAR16**                        ControllerName\r
+  );\r
+\r
+#endif //_OPAL_DRIVER_H_\r
diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.c b/SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.c
new file mode 100644 (file)
index 0000000..e497222
--- /dev/null
@@ -0,0 +1,1178 @@
+/** @file\r
+  Implementation of the HII for the Opal UEFI Driver.\r
+\r
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "OpalHii.h"\r
+\r
+//\r
+// This is the generated IFR binary Data for each formset defined in VFR.\r
+// This Data array is ready to be used as input of HiiAddPackages() to\r
+// create a packagelist (which contains Form packages, String packages, etc).\r
+//\r
+extern UINT8  OpalPasswordFormBin[];\r
+\r
+//\r
+// This is the generated String package Data for all .UNI files.\r
+// This Data array is ready to be used as input of HiiAddPackages() to\r
+// create a packagelist (which contains Form packages, String packages, etc).\r
+//\r
+extern UINT8  OpalPasswordDxeStrings[];\r
+\r
+CHAR16  OpalPasswordStorageName[] = L"OpalHiiConfig";\r
+\r
+EFI_HII_CONFIG_ACCESS_PROTOCOL gHiiConfigAccessProtocol;\r
+\r
+//\r
+// Handle to the list of HII packages (forms and strings) for this driver\r
+//\r
+EFI_HII_HANDLE gHiiPackageListHandle = NULL;\r
+\r
+//\r
+// Package List GUID containing all form and string packages\r
+//\r
+const EFI_GUID gHiiPackageListGuid = PACKAGE_LIST_GUID;\r
+const EFI_GUID gHiiSetupVariableGuid = SETUP_VARIABLE_GUID;\r
+\r
+//\r
+// Structure that contains state of the HII\r
+// This structure is updated by Hii.cpp and its contents\r
+// is rendered in the HII.\r
+//\r
+OPAL_HII_CONFIGURATION gHiiConfiguration;\r
+\r
+//\r
+// The device path containing the VENDOR_DEVICE_PATH and EFI_DEVICE_PATH_PROTOCOL\r
+//\r
+HII_VENDOR_DEVICE_PATH gHiiVendorDevicePath = {\r
+    {\r
+        {\r
+            HARDWARE_DEVICE_PATH,\r
+            HW_VENDOR_DP,\r
+            {\r
+                (UINT8)(sizeof(VENDOR_DEVICE_PATH)),\r
+                (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8)\r
+            }\r
+        },\r
+        OPAL_PASSWORD_CONFIG_GUID\r
+    },\r
+    {\r
+        END_DEVICE_PATH_TYPE,\r
+        END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+        {\r
+            (UINT8)(END_DEVICE_PATH_LENGTH),\r
+            (UINT8)((END_DEVICE_PATH_LENGTH) >> 8)\r
+        }\r
+    }\r
+};\r
+\r
+/**\r
+  Get saved OPAL request.\r
+\r
+  @param[in]  OpalDisk      The disk needs to get the saved OPAL request.\r
+  @param[out] OpalRequest   OPAL request got.\r
+\r
+**/\r
+VOID\r
+GetSavedOpalRequest (\r
+  IN OPAL_DISK              *OpalDisk,\r
+  OUT OPAL_REQUEST          *OpalRequest\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  OPAL_REQUEST_VARIABLE     *TempVariable;\r
+  OPAL_REQUEST_VARIABLE     *Variable;\r
+  UINTN                     VariableSize;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePathInVariable;\r
+  UINTN                     DevicePathSizeInVariable;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  UINTN                     DevicePathSize;\r
+\r
+  DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
+\r
+  Variable = NULL;\r
+  VariableSize = 0;\r
+\r
+  Status = GetVariable2 (\r
+             OPAL_REQUEST_VARIABLE_NAME,\r
+             &gHiiSetupVariableGuid,\r
+             (VOID **) &Variable,\r
+             &VariableSize\r
+             );\r
+  if (EFI_ERROR (Status) || (Variable == NULL)) {\r
+    return;\r
+  }\r
+\r
+  TempVariable = Variable;\r
+  while ((VariableSize > sizeof (OPAL_REQUEST_VARIABLE)) &&\r
+         (VariableSize >= TempVariable->Length) &&\r
+         (TempVariable->Length > sizeof (OPAL_REQUEST_VARIABLE))) {\r
+    DevicePathInVariable = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) TempVariable + sizeof (OPAL_REQUEST_VARIABLE));\r
+    DevicePathSizeInVariable = GetDevicePathSize (DevicePathInVariable);\r
+    DevicePath = OpalDisk->OpalDevicePath;\r
+    DevicePathSize = GetDevicePathSize (DevicePath);\r
+    if ((DevicePathSize == DevicePathSizeInVariable) &&\r
+        (CompareMem (DevicePath, DevicePathInVariable, DevicePathSize) == 0)) {\r
+      //\r
+      // Found the node for the OPAL device.\r
+      // Get the OPAL request.\r
+      //\r
+      CopyMem (OpalRequest, &TempVariable->OpalRequest, sizeof (OPAL_REQUEST));\r
+      DEBUG ((\r
+        DEBUG_INFO,\r
+        "OpalRequest got: 0x%x\n",\r
+        *OpalRequest\r
+        ));\r
+      break;\r
+    }\r
+    VariableSize -= TempVariable->Length;\r
+    TempVariable = (OPAL_REQUEST_VARIABLE *) ((UINTN) TempVariable + TempVariable->Length);\r
+  }\r
+\r
+  FreePool (Variable);\r
+\r
+  DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
+}\r
+\r
+/**\r
+  Save OPAL request.\r
+\r
+  @param[in] OpalDisk       The disk has OPAL request to save.\r
+  @param[in] OpalRequest    OPAL request to save.\r
+\r
+**/\r
+VOID\r
+SaveOpalRequest (\r
+  IN OPAL_DISK              *OpalDisk,\r
+  IN OPAL_REQUEST           OpalRequest\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  OPAL_REQUEST_VARIABLE     *TempVariable;\r
+  UINTN                     TempVariableSize;\r
+  OPAL_REQUEST_VARIABLE     *Variable;\r
+  UINTN                     VariableSize;\r
+  OPAL_REQUEST_VARIABLE     *NewVariable;\r
+  UINTN                     NewVariableSize;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePathInVariable;\r
+  UINTN                     DevicePathSizeInVariable;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  UINTN                     DevicePathSize;\r
+\r
+  DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
+\r
+  DEBUG ((\r
+    DEBUG_INFO,\r
+    "OpalRequest to save: 0x%x\n",\r
+    OpalRequest\r
+    ));\r
+\r
+  Variable = NULL;\r
+  VariableSize = 0;\r
+  NewVariable = NULL;\r
+  NewVariableSize = 0;\r
+\r
+  Status = GetVariable2 (\r
+             OPAL_REQUEST_VARIABLE_NAME,\r
+             &gHiiSetupVariableGuid,\r
+             (VOID **) &Variable,\r
+             &VariableSize\r
+             );\r
+  if (!EFI_ERROR (Status) && (Variable != NULL)) {\r
+    TempVariable = Variable;\r
+    TempVariableSize = VariableSize;\r
+    while ((TempVariableSize > sizeof (OPAL_REQUEST_VARIABLE)) &&\r
+           (TempVariableSize >= TempVariable->Length) &&\r
+           (TempVariable->Length > sizeof (OPAL_REQUEST_VARIABLE))) {\r
+      DevicePathInVariable = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) TempVariable + sizeof (OPAL_REQUEST_VARIABLE));\r
+      DevicePathSizeInVariable = GetDevicePathSize (DevicePathInVariable);\r
+      DevicePath = OpalDisk->OpalDevicePath;\r
+      DevicePathSize = GetDevicePathSize (DevicePath);\r
+      if ((DevicePathSize == DevicePathSizeInVariable) &&\r
+          (CompareMem (DevicePath, DevicePathInVariable, DevicePathSize) == 0)) {\r
+        //\r
+        // Found the node for the OPAL device.\r
+        // Update the OPAL request.\r
+        //\r
+        CopyMem (&TempVariable->OpalRequest, &OpalRequest, sizeof (OPAL_REQUEST));\r
+        NewVariable = Variable;\r
+        NewVariableSize = VariableSize;\r
+        break;\r
+      }\r
+      TempVariableSize -= TempVariable->Length;\r
+      TempVariable = (OPAL_REQUEST_VARIABLE *) ((UINTN) TempVariable + TempVariable->Length);\r
+    }\r
+    if (NewVariable == NULL) {\r
+      //\r
+      // The node for the OPAL device is not found.\r
+      // Create node for the OPAL device.\r
+      //\r
+      DevicePath = OpalDisk->OpalDevicePath;\r
+      DevicePathSize = GetDevicePathSize (DevicePath);\r
+      NewVariableSize = VariableSize + sizeof (OPAL_REQUEST_VARIABLE) + DevicePathSize;\r
+      NewVariable = AllocatePool (NewVariableSize);\r
+      ASSERT (NewVariable != NULL);\r
+      CopyMem (NewVariable, Variable, VariableSize);\r
+      TempVariable = (OPAL_REQUEST_VARIABLE *) ((UINTN) NewVariable + VariableSize);\r
+      TempVariable->Length = (UINT32) (sizeof (OPAL_REQUEST_VARIABLE) + DevicePathSize);\r
+      CopyMem (&TempVariable->OpalRequest, &OpalRequest, sizeof (OPAL_REQUEST));\r
+      DevicePathInVariable = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) TempVariable + sizeof (OPAL_REQUEST_VARIABLE));\r
+      CopyMem (DevicePathInVariable, DevicePath, DevicePathSize);\r
+    }\r
+  } else {\r
+    DevicePath = OpalDisk->OpalDevicePath;\r
+    DevicePathSize = GetDevicePathSize (DevicePath);\r
+    NewVariableSize = sizeof (OPAL_REQUEST_VARIABLE) + DevicePathSize;\r
+    NewVariable = AllocatePool (NewVariableSize);\r
+    ASSERT (NewVariable != NULL);\r
+    NewVariable->Length = (UINT32) (sizeof (OPAL_REQUEST_VARIABLE) + DevicePathSize);\r
+    CopyMem (&NewVariable->OpalRequest, &OpalRequest, sizeof (OPAL_REQUEST));\r
+    DevicePathInVariable = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) NewVariable + sizeof (OPAL_REQUEST_VARIABLE));\r
+    CopyMem (DevicePathInVariable, DevicePath, DevicePathSize);\r
+  }\r
+  Status = gRT->SetVariable (\r
+                  OPAL_REQUEST_VARIABLE_NAME,\r
+                  (EFI_GUID *) &gHiiSetupVariableGuid,\r
+                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+                  NewVariableSize,\r
+                  NewVariable\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_INFO, "OpalRequest variable set failed (%r)\n", Status));\r
+  }\r
+  if (NewVariable != Variable) {\r
+    FreePool (NewVariable);\r
+  }\r
+  if (Variable != NULL) {\r
+    FreePool (Variable);\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
+}\r
+\r
+/**\r
+  Sets the current system state of global config variables.\r
+\r
+**/\r
+VOID\r
+HiiSetCurrentConfiguration(\r
+  VOID\r
+  )\r
+{\r
+  UINT32                                       PpStorageFlag;\r
+  EFI_STRING                                   NewString;\r
+\r
+  gHiiConfiguration.NumDisks = GetDeviceCount();\r
+\r
+  //\r
+  // Update the BlockSID status string.\r
+  //\r
+  PpStorageFlag = Tcg2PhysicalPresenceLibGetManagementFlags ();\r
+\r
+  if ((PpStorageFlag & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID) != 0) {\r
+    NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_ENABLED), NULL);\r
+    if (NewString == NULL) {\r
+      DEBUG ((DEBUG_INFO,  "HiiSetCurrentConfiguration: HiiGetString( ) failed\n"));\r
+      return;\r
+    }\r
+  } else {\r
+    NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_DISABLED), NULL);\r
+    if (NewString == NULL) {\r
+      DEBUG ((DEBUG_INFO,  "HiiSetCurrentConfiguration: HiiGetString( ) failed\n"));\r
+      return;\r
+    }\r
+  }\r
+  HiiSetString(gHiiPackageListHandle, STRING_TOKEN(STR_BLOCKSID_STATUS1), NewString, NULL);\r
+  FreePool (NewString);\r
+\r
+  if ((PpStorageFlag & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_ENABLE_BLOCK_SID) != 0) {\r
+    NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_TRUE), NULL);\r
+    if (NewString == NULL) {\r
+      DEBUG ((DEBUG_INFO,  "HiiSetCurrentConfiguration: HiiGetString( ) failed\n"));\r
+      return;\r
+    }\r
+  } else {\r
+    NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_FALSE), NULL);\r
+    if (NewString == NULL) {\r
+      DEBUG ((DEBUG_INFO,  "HiiSetCurrentConfiguration: HiiGetString( ) failed\n"));\r
+      return;\r
+    }\r
+  }\r
+  HiiSetString(gHiiPackageListHandle, STRING_TOKEN(STR_BLOCKSID_STATUS2), NewString, NULL);\r
+  FreePool (NewString);\r
+\r
+  if ((PpStorageFlag & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_DISABLE_BLOCK_SID) != 0) {\r
+    NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_DISK_INFO_DISABLE_BLOCKSID_TRUE), NULL);\r
+    if (NewString == NULL) {\r
+      DEBUG ((DEBUG_INFO,  "HiiSetCurrentConfiguration: HiiGetString( ) failed\n"));\r
+      return;\r
+    }\r
+  } else {\r
+    NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_DISK_INFO_DISABLE_BLOCKSID_FALSE), NULL);\r
+    if (NewString == NULL) {\r
+      DEBUG ((DEBUG_INFO,  "HiiSetCurrentConfiguration: HiiGetString( ) failed\n"));\r
+      return;\r
+    }\r
+  }\r
+  HiiSetString(gHiiPackageListHandle, STRING_TOKEN(STR_BLOCKSID_STATUS3), NewString, NULL);\r
+  FreePool (NewString);\r
+}\r
+\r
+/**\r
+  Install the HII related resources.\r
+\r
+  @retval  EFI_SUCCESS        Install all the resources success.\r
+  @retval  other              Error occur when install the resources.\r
+**/\r
+EFI_STATUS\r
+HiiInstall(\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_HANDLE                   DriverHandle;\r
+\r
+  //\r
+  // Clear the global configuration.\r
+  //\r
+  ZeroMem(&gHiiConfiguration, sizeof(gHiiConfiguration));\r
+\r
+  //\r
+  // Obtain the driver handle that the BIOS assigned us\r
+  //\r
+  DriverHandle = HiiGetDriverImageHandleCB();\r
+\r
+  //\r
+  // Populate the config access protocol with the three functions we are publishing\r
+  //\r
+  gHiiConfigAccessProtocol.ExtractConfig = ExtractConfig;\r
+  gHiiConfigAccessProtocol.RouteConfig = RouteConfig;\r
+  gHiiConfigAccessProtocol.Callback = DriverCallback;\r
+\r
+  //\r
+  // Associate the required protocols with our driver handle\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces(\r
+               &DriverHandle,\r
+               &gEfiHiiConfigAccessProtocolGuid,\r
+               &gHiiConfigAccessProtocol,      // HII callback\r
+               &gEfiDevicePathProtocolGuid,\r
+               &gHiiVendorDevicePath,        // required for HII callback allow all disks to be shown in same hii\r
+               NULL\r
+           );\r
+\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return OpalHiiAddPackages();\r
+}\r
+\r
+/**\r
+  Install the HII form and string packages.\r
+\r
+  @retval  EFI_SUCCESS           Install all the resources success.\r
+  @retval  EFI_OUT_OF_RESOURCES  Out of resource error.\r
+**/\r
+EFI_STATUS\r
+OpalHiiAddPackages(\r
+  VOID\r
+  )\r
+{\r
+  EFI_HANDLE                   DriverHandle;\r
+  CHAR16                       *NewString;\r
+\r
+  DriverHandle = HiiGetDriverImageHandleCB();\r
+\r
+  //\r
+  // Publish the HII form and HII string packages\r
+  //\r
+  gHiiPackageListHandle = HiiAddPackages(\r
+                                &gHiiPackageListGuid,\r
+                                DriverHandle,\r
+                                OpalPasswordDxeStrings,\r
+                                OpalPasswordFormBin,\r
+                                (VOID*)NULL\r
+                                );\r
+\r
+  //\r
+  // Make sure the packages installed successfully\r
+  //\r
+  if (gHiiPackageListHandle == NULL) {\r
+    DEBUG ((DEBUG_INFO, "OpalHiiAddPackages failed\n"));\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Update Version String in main window\r
+  //\r
+  NewString = HiiGetDriverNameCB ();\r
+  if (HiiSetString(gHiiPackageListHandle, STRING_TOKEN(STR_MAIN_OPAL_VERSION), NewString, NULL) == 0) {\r
+    DEBUG ((DEBUG_INFO,  "OpalHiiAddPackages: HiiSetString( ) failed\n"));\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Uninstall the HII capability.\r
+\r
+  @retval  EFI_SUCCESS           Uninstall all the resources success.\r
+  @retval  others                Other errors occur when unistall the hii resource.\r
+**/\r
+EFI_STATUS\r
+HiiUninstall(\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+\r
+  //\r
+  // Remove the packages we've provided to the BIOS\r
+  //\r
+  HiiRemovePackages(gHiiPackageListHandle);\r
+\r
+  //\r
+  // Remove the protocols from our driver handle\r
+  //\r
+  Status = gBS->UninstallMultipleProtocolInterfaces(\r
+                          HiiGetDriverImageHandleCB(),\r
+                          &gEfiHiiConfigAccessProtocolGuid,\r
+                          &gHiiConfigAccessProtocol,        // HII callback\r
+                          &gEfiDevicePathProtocolGuid,\r
+                          &gHiiVendorDevicePath,            // required for HII callback\r
+                          NULL\r
+                      );\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG ((DEBUG_INFO, "Cannot uninstall Hii Protocols: %r\n", Status));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Updates the main menu form.\r
+\r
+  @retval  EFI_SUCCESS           update the main form success.\r
+**/\r
+EFI_STATUS\r
+HiiPopulateMainMenuForm (\r
+  VOID\r
+  )\r
+{\r
+  UINT8         Index;\r
+  CHAR8         *DiskName;\r
+  EFI_STRING_ID DiskNameId;\r
+  OPAL_DISK     *OpalDisk;\r
+\r
+  HiiSetCurrentConfiguration();\r
+\r
+  gHiiConfiguration.SupportedDisks = 0;\r
+\r
+  for (Index = 0; Index < gHiiConfiguration.NumDisks; Index++) {\r
+    OpalDisk = HiiGetOpalDiskCB (Index);\r
+    if ((OpalDisk != NULL) && OpalFeatureSupported (&OpalDisk->SupportedAttributes)) {\r
+      gHiiConfiguration.SupportedDisks |= (1 << Index);\r
+      DiskNameId = GetDiskNameStringId (Index);\r
+      DiskName = HiiDiskGetNameCB (Index);\r
+      if ((DiskName == NULL) || (DiskNameId == 0)) {\r
+        return EFI_UNSUPPORTED;\r
+      }\r
+      HiiSetFormString(DiskNameId, DiskName);\r
+    }\r
+  }\r
+\r
+  OpalHiiSetBrowserData ();\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get disk name string id.\r
+\r
+  @param   DiskIndex             The input disk index info.\r
+\r
+  @retval  The disk name string id.\r
+\r
+**/\r
+EFI_STRING_ID\r
+GetDiskNameStringId(\r
+  UINT8 DiskIndex\r
+  )\r
+{\r
+  switch (DiskIndex) {\r
+    case 0: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_0);\r
+    case 1: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_1);\r
+    case 2: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_2);\r
+    case 3: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_3);\r
+    case 4: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_4);\r
+    case 5: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_5);\r
+  }\r
+  return 0;\r
+}\r
+\r
+/**\r
+  This function processes the results of changes in configuration.\r
+\r
+  @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param  Action                 Specifies the type of action taken by the browser.\r
+  @param  QuestionId             A unique value which is sent to the original\r
+                                 exporting driver so that it can identify the type\r
+                                 of data to expect.\r
+  @param  Type                   The type of value for the question.\r
+  @param  Value                  A pointer to the data being sent to the original\r
+                                 exporting driver.\r
+  @param  ActionRequest          On return, points to the action requested by the\r
+                                 callback function.\r
+\r
+  @retval EFI_SUCCESS            The callback successfully handled the action.\r
+  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the\r
+                                 variable and its data.\r
+  @retval EFI_DEVICE_ERROR       The variable could not be saved.\r
+  @retval EFI_UNSUPPORTED        The specified Action is not supported by the\r
+                                 callback.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DriverCallback(\r
+  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL    *This,\r
+  EFI_BROWSER_ACTION                      Action,\r
+  EFI_QUESTION_ID                         QuestionId,\r
+  UINT8                                   Type,\r
+  EFI_IFR_TYPE_VALUE                      *Value,\r
+  EFI_BROWSER_ACTION_REQUEST              *ActionRequest\r
+  )\r
+{\r
+  HII_KEY    HiiKey;\r
+  UINT8      HiiKeyId;\r
+  UINT32     PpRequest;\r
+  OPAL_DISK  *OpalDisk;\r
+\r
+  if (ActionRequest != NULL) {\r
+    *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
+  } else {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // If QuestionId is an auto-generated key (label, empty line, etc.), ignore it.\r
+  //\r
+  if ((QuestionId & HII_KEY_FLAG) == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  HiiKey.Raw = QuestionId;\r
+  HiiKeyId   = (UINT8) HiiKey.KeyBits.Id;\r
+\r
+  if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {\r
+    switch (HiiKeyId) {\r
+      case HII_KEY_ID_VAR_SUPPORTED_DISKS:\r
+        DEBUG ((DEBUG_INFO,  "HII_KEY_ID_VAR_SUPPORTED_DISKS\n"));\r
+        return HiiPopulateMainMenuForm ();\r
+\r
+      case HII_KEY_ID_VAR_SELECTED_DISK_AVAILABLE_ACTIONS:\r
+        DEBUG ((DEBUG_INFO,  "HII_KEY_ID_VAR_SELECTED_DISK_AVAILABLE_ACTIONS\n"));\r
+        return HiiPopulateDiskInfoForm();\r
+    }\r
+  } else if (Action == EFI_BROWSER_ACTION_CHANGING) {\r
+    switch (HiiKeyId) {\r
+      case HII_KEY_ID_GOTO_DISK_INFO:\r
+        return HiiSelectDisk((UINT8)HiiKey.KeyBits.Index);\r
+    }\r
+  } else if (Action == EFI_BROWSER_ACTION_CHANGED) {\r
+    switch (HiiKeyId) {\r
+      case HII_KEY_ID_BLOCKSID:\r
+        switch (Value->u8) {\r
+          case 0:\r
+            PpRequest = TCG2_PHYSICAL_PRESENCE_NO_ACTION;\r
+            break;\r
+\r
+          case 1:\r
+            PpRequest = TCG2_PHYSICAL_PRESENCE_ENABLE_BLOCK_SID;\r
+            break;\r
+\r
+          case 2:\r
+            PpRequest = TCG2_PHYSICAL_PRESENCE_DISABLE_BLOCK_SID;\r
+            break;\r
+\r
+          case 3:\r
+            PpRequest = TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_TRUE;\r
+            break;\r
+\r
+          case 4:\r
+            PpRequest = TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_FALSE;\r
+            break;\r
+\r
+          case 5:\r
+            PpRequest = TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_TRUE;\r
+            break;\r
+\r
+          case 6:\r
+            PpRequest = TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_FALSE;\r
+            break;\r
+\r
+          default:\r
+            PpRequest = TCG2_PHYSICAL_PRESENCE_NO_ACTION;\r
+            DEBUG ((DEBUG_ERROR, "Invalid value input!\n"));\r
+            break;\r
+        }\r
+        HiiSetBlockSidAction(PpRequest);\r
+\r
+        *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
+        return EFI_SUCCESS;\r
+\r
+      case HII_KEY_ID_SET_ADMIN_PWD:\r
+        DEBUG ((DEBUG_INFO,  "HII_KEY_ID_SET_ADMIN_PWD\n"));\r
+        gHiiConfiguration.OpalRequest.SetAdminPwd = Value->b;\r
+        OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);\r
+        if (OpalDisk != NULL) {\r
+          SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);\r
+        }\r
+        *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
+        return EFI_SUCCESS;\r
+\r
+      case HII_KEY_ID_SET_USER_PWD:\r
+        DEBUG ((DEBUG_INFO,  "HII_KEY_ID_SET_USER_PWD\n"));\r
+        gHiiConfiguration.OpalRequest.SetUserPwd = Value->b;\r
+        OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);\r
+        if (OpalDisk != NULL) {\r
+          SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);\r
+        }\r
+        *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
+        return EFI_SUCCESS;\r
+\r
+      case HII_KEY_ID_SECURE_ERASE:\r
+        DEBUG ((DEBUG_INFO,  "HII_KEY_ID_SECURE_ERASE\n"));\r
+        gHiiConfiguration.OpalRequest.SecureErase = Value->b;\r
+        OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);\r
+        if (OpalDisk != NULL) {\r
+          SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);\r
+        }\r
+        *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
+        return EFI_SUCCESS;\r
\r
+      case HII_KEY_ID_REVERT:\r
+        DEBUG ((DEBUG_INFO,  "HII_KEY_ID_REVERT\n"));\r
+        gHiiConfiguration.OpalRequest.Revert = Value->b;\r
+        OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);\r
+        if (OpalDisk != NULL) {\r
+          SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);\r
+        }\r
+        *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
+        return EFI_SUCCESS;\r
+      case HII_KEY_ID_KEEP_USER_DATA:\r
+        DEBUG ((DEBUG_INFO,  "HII_KEY_ID_KEEP_USER_DATA\n"));\r
+        gHiiConfiguration.OpalRequest.KeepUserData = Value->b;\r
+        OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);\r
+        if (OpalDisk != NULL) {\r
+          SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);\r
+        }\r
+        *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
+        return EFI_SUCCESS;\r
+\r
+      case HII_KEY_ID_PSID_REVERT:\r
+        DEBUG ((DEBUG_INFO,  "HII_KEY_ID_PSID_REVERT\n"));\r
+        gHiiConfiguration.OpalRequest.PsidRevert = Value->b;\r
+        OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);\r
+        if (OpalDisk != NULL) {\r
+          SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);\r
+        }\r
+        *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
+        return EFI_SUCCESS;\r
+\r
+      case HII_KEY_ID_DISABLE_USER:\r
+        DEBUG ((DEBUG_INFO,  "HII_KEY_ID_DISABLE_USER\n"));\r
+        gHiiConfiguration.OpalRequest.DisableUser = Value->b;\r
+        OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);\r
+        if (OpalDisk != NULL) {\r
+          SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);\r
+        }\r
+        *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
+        return EFI_SUCCESS;\r
+\r
+      case HII_KEY_ID_ENABLE_FEATURE:\r
+        DEBUG ((DEBUG_INFO,  "HII_KEY_ID_ENABLE_FEATURE\n"));\r
+        gHiiConfiguration.OpalRequest.EnableFeature = Value->b;\r
+        OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);\r
+        if (OpalDisk != NULL) {\r
+          SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);\r
+        }\r
+        *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
+        return EFI_SUCCESS;\r
+\r
+      default:\r
+        break;\r
+    }\r
+  }\r
+\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  Update the global Disk index info.\r
+\r
+  @param   Index             The input disk index info.\r
+\r
+  @retval  EFI_SUCCESS       Update the disk index info success.\r
+\r
+**/\r
+EFI_STATUS\r
+HiiSelectDisk(\r
+  UINT8 Index\r
+  )\r
+{\r
+  OpalHiiGetBrowserData();\r
+  gHiiConfiguration.SelectedDiskIndex = Index;\r
+  OpalHiiSetBrowserData ();\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Draws the disk info form.\r
+\r
+  @retval  EFI_SUCCESS       Draw the disk info success.\r
+\r
+**/\r
+EFI_STATUS\r
+HiiPopulateDiskInfoForm(\r
+  VOID\r
+  )\r
+{\r
+  OPAL_DISK*                    OpalDisk;\r
+  OPAL_DISK_ACTIONS             AvailActions;\r
+  TCG_RESULT                    Ret;\r
+  CHAR8                         *DiskName;\r
+\r
+  OpalHiiGetBrowserData();\r
+\r
+  DiskName = HiiDiskGetNameCB (gHiiConfiguration.SelectedDiskIndex);\r
+  if (DiskName == NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  HiiSetFormString(STRING_TOKEN(STR_DISK_INFO_SELECTED_DISK_NAME), DiskName);\r
+\r
+  gHiiConfiguration.SelectedDiskAvailableActions = HII_ACTION_NONE;\r
+  ZeroMem (&gHiiConfiguration.OpalRequest, sizeof (OPAL_REQUEST));\r
+  gHiiConfiguration.KeepUserDataForced = FALSE;\r
+\r
+  OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);\r
+\r
+  if (OpalDisk != NULL) {\r
+    OpalDiskUpdateStatus (OpalDisk);\r
+    Ret = OpalSupportGetAvailableActions(&OpalDisk->SupportedAttributes, &OpalDisk->LockingFeature, OpalDisk->Owner, &AvailActions);\r
+    if (Ret == TcgResultSuccess) {\r
+      //\r
+      // Update actions, always allow PSID Revert\r
+      //\r
+      gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.PsidRevert == 1) ? HII_ACTION_PSID_REVERT : HII_ACTION_NONE;\r
+\r
+      //\r
+      // Always allow unlock to handle device migration\r
+      //\r
+      gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.Unlock == 1) ? HII_ACTION_UNLOCK : HII_ACTION_NONE;\r
+\r
+      if (!OpalFeatureEnabled (&OpalDisk->SupportedAttributes, &OpalDisk->LockingFeature)) {\r
+        if (OpalDisk->Owner == OpalOwnershipNobody) {\r
+          gHiiConfiguration.SelectedDiskAvailableActions |= HII_ACTION_ENABLE_FEATURE;\r
+\r
+          //\r
+          // Update strings\r
+          //\r
+          HiiSetFormString( STRING_TOKEN(STR_DISK_INFO_PSID_REVERT), "PSID Revert to factory default");\r
+        } else {\r
+          DEBUG ((DEBUG_INFO, "Feature disabled but ownership != nobody\n"));\r
+        }\r
+      } else {\r
+        gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.Revert == 1) ? HII_ACTION_REVERT : HII_ACTION_NONE;\r
+        gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.AdminPass == 1) ? HII_ACTION_SET_ADMIN_PWD : HII_ACTION_NONE;\r
+        gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.UserPass == 1) ? HII_ACTION_SET_USER_PWD : HII_ACTION_NONE;\r
+        gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.SecureErase == 1) ? HII_ACTION_SECURE_ERASE : HII_ACTION_NONE;\r
+        gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.DisableUser == 1) ? HII_ACTION_DISABLE_USER : HII_ACTION_NONE;\r
+\r
+        HiiSetFormString (STRING_TOKEN(STR_DISK_INFO_PSID_REVERT), "PSID Revert to factory default and Disable");\r
+\r
+        //\r
+        // Determine revert options for disk\r
+        // Default initialize keep user Data to be true\r
+        //\r
+        gHiiConfiguration.OpalRequest.KeepUserData = 1;\r
+        if (AvailActions.RevertKeepDataForced) {\r
+          gHiiConfiguration.KeepUserDataForced = TRUE;\r
+        }\r
+      }\r
+    }\r
+\r
+    GetSavedOpalRequest (OpalDisk, &gHiiConfiguration.OpalRequest);\r
+  }\r
+\r
+  //\r
+  // Pass the current configuration to the BIOS\r
+  //\r
+  OpalHiiSetBrowserData ();\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Send BlockSid request through TPM physical presence module.\r
+\r
+  @param   PpRequest         TPM physical presence operation request.\r
+\r
+  @retval  EFI_SUCCESS       Do the required action success.\r
+  @retval  Others            Other error occur.\r
+\r
+**/\r
+EFI_STATUS\r
+HiiSetBlockSidAction (\r
+  IN UINT32          PpRequest\r
+  )\r
+{\r
+  UINT32                           ReturnCode;\r
+  EFI_STATUS                       Status;\r
+\r
+  ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (PpRequest, 0);\r
+  if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS) {\r
+    Status = EFI_SUCCESS;\r
+  } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+  } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED) {\r
+    Status = EFI_UNSUPPORTED;\r
+  } else {\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function processes the results of changes in configuration.\r
+\r
+  @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param  Configuration          A null-terminated Unicode string in <ConfigResp>\r
+                                 format.\r
+  @param  Progress               A pointer to a string filled in with the offset of\r
+                                 the most recent '&' before the first failing\r
+                                 name/value pair (or the beginning of the string if\r
+                                 the failure is in the first name/value pair) or\r
+                                 the terminating NULL if all was successful.\r
+\r
+  @retval EFI_SUCCESS            The Results is processed successfully.\r
+  @retval EFI_INVALID_PARAMETER  Configuration is NULL.\r
+  @retval EFI_NOT_FOUND          Routing data doesn't match any storage in this\r
+                                 driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RouteConfig(\r
+  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL    *This,\r
+  CONST EFI_STRING                        Configuration,\r
+  EFI_STRING                              *Progress\r
+  )\r
+{\r
+  if (Configuration == NULL || Progress == NULL) {\r
+    return (EFI_INVALID_PARAMETER);\r
+  }\r
+\r
+  *Progress = Configuration;\r
+  if (!HiiIsConfigHdrMatch (Configuration, &gHiiSetupVariableGuid, OpalPasswordStorageName)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  *Progress = Configuration + StrLen (Configuration);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function allows a caller to extract the current configuration for one\r
+  or more named elements from the target driver.\r
+\r
+  @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param  Request                A null-terminated Unicode string in\r
+                                 <ConfigRequest> format.\r
+  @param  Progress               On return, points to a character in the Request\r
+                                 string. Points to the string's null terminator if\r
+                                 request was successful. Points to the most recent\r
+                                 '&' before the first failing name/value pair (or\r
+                                 the beginning of the string if the failure is in\r
+                                 the first name/value pair) if the request was not\r
+                                 successful.\r
+  @param  Results                A null-terminated Unicode string in\r
+                                 <ConfigAltResp> format which has all values filled\r
+                                 in for the names in the Request string. String to\r
+                                 be allocated by the called function.\r
+\r
+  @retval EFI_SUCCESS            The Results is filled with the requested values.\r
+  @retval EFI_OUT_OF_RESOURCES   Not enough memory to store the results.\r
+  @retval EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.\r
+  @retval EFI_NOT_FOUND          Routing data doesn't match any storage in this\r
+                                 driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ExtractConfig(\r
+  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL    *This,\r
+  CONST EFI_STRING                        Request,\r
+  EFI_STRING                              *Progress,\r
+  EFI_STRING                              *Results\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+  EFI_STRING                              ConfigRequest;\r
+  EFI_STRING                              ConfigRequestHdr;\r
+  UINTN                                   BufferSize;\r
+  UINTN                                   Size;\r
+  BOOLEAN                                 AllocatedRequest;\r
+  EFI_HANDLE                              DriverHandle;\r
+\r
+  //\r
+  // Check for valid parameters\r
+  //\r
+  if (Progress == NULL || Results == NULL) {\r
+    return (EFI_INVALID_PARAMETER);\r
+  }\r
+\r
+  *Progress = Request;\r
+  if ((Request != NULL) &&\r
+    !HiiIsConfigHdrMatch (Request, &gHiiSetupVariableGuid, OpalPasswordStorageName)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  AllocatedRequest = FALSE;\r
+  BufferSize = sizeof (OPAL_HII_CONFIGURATION);\r
+  ConfigRequest = Request;\r
+  if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {\r
+    //\r
+    // Request has no request element, construct full request string.\r
+    // Allocate and fill a buffer large enough to hold the <ConfigHdr> template\r
+    // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator\r
+    //\r
+    DriverHandle = HiiGetDriverImageHandleCB();\r
+    ConfigRequestHdr = HiiConstructConfigHdr (&gHiiSetupVariableGuid, OpalPasswordStorageName, DriverHandle);\r
+    Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);\r
+    ConfigRequest = AllocateZeroPool (Size);\r
+    if (ConfigRequest == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    AllocatedRequest = TRUE;\r
+    UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);\r
+    FreePool (ConfigRequestHdr);\r
+  }\r
+\r
+  //\r
+  // Convert Buffer Data to <ConfigResp> by helper function BlockToConfig( )\r
+  //\r
+  Status = gHiiConfigRouting->BlockToConfig(\r
+               gHiiConfigRouting,\r
+               ConfigRequest,\r
+               (UINT8*)&gHiiConfiguration,\r
+               sizeof(OPAL_HII_CONFIGURATION),\r
+               Results,\r
+               Progress\r
+           );\r
+\r
+  //\r
+  // Free the allocated config request string.\r
+  //\r
+  if (AllocatedRequest) {\r
+    FreePool (ConfigRequest);\r
+    ConfigRequest = NULL;\r
+  }\r
+\r
+  //\r
+  // Set Progress string to the original request string.\r
+  //\r
+  if (Request == NULL) {\r
+    *Progress = NULL;\r
+  } else if (StrStr (Request, L"OFFSET") == NULL) {\r
+    *Progress = Request + StrLen (Request);\r
+  }\r
+\r
+  return (Status);\r
+}\r
+\r
+\r
+/**\r
+\r
+  Pass the current system state to the bios via the hii_G_Configuration.\r
+\r
+**/\r
+VOID\r
+OpalHiiSetBrowserData (\r
+  VOID\r
+  )\r
+{\r
+  HiiSetBrowserData(\r
+      &gHiiSetupVariableGuid,\r
+      (CHAR16*)L"OpalHiiConfig",\r
+      sizeof(gHiiConfiguration),\r
+      (UINT8*)&gHiiConfiguration,\r
+      NULL\r
+  );\r
+}\r
+\r
+\r
+/**\r
+\r
+  Populate the hii_g_Configuraton with the browser Data.\r
+\r
+**/\r
+VOID\r
+OpalHiiGetBrowserData (\r
+  VOID\r
+  )\r
+{\r
+  HiiGetBrowserData(\r
+      &gHiiSetupVariableGuid,\r
+      (CHAR16*)L"OpalHiiConfig",\r
+      sizeof(gHiiConfiguration),\r
+      (UINT8*)&gHiiConfiguration\r
+  );\r
+}\r
+\r
+/**\r
+  Set a string Value in a form.\r
+\r
+  @param      DestStringId   The stringid which need to update.\r
+  @param      SrcAsciiStr    The string nned to update.\r
+\r
+  @retval  EFI_SUCCESS       Do the required action success.\r
+  @retval  Others            Other error occur.\r
+\r
+**/\r
+EFI_STATUS\r
+HiiSetFormString(\r
+  EFI_STRING_ID       DestStringId,\r
+  CHAR8               *SrcAsciiStr\r
+  )\r
+{\r
+  UINT32                    Len;\r
+  UINT32                    UniSize;\r
+  CHAR16*                   UniStr;\r
+\r
+  //\r
+  // Determine the Length of the sting\r
+  //\r
+  Len = ( UINT32 )AsciiStrLen( SrcAsciiStr );\r
+\r
+  //\r
+  // Allocate space for the unicode string, including terminator\r
+  //\r
+  UniSize = (Len + 1) * sizeof(CHAR16);\r
+  UniStr = (CHAR16*)AllocateZeroPool(UniSize);\r
+\r
+  //\r
+  // Copy into unicode string, then copy into string id\r
+  //\r
+  AsciiStrToUnicodeStrS ( SrcAsciiStr, UniStr, Len + 1);\r
+\r
+  //\r
+  // Update the string in the form\r
+  //\r
+  if (HiiSetString(gHiiPackageListHandle, DestStringId, UniStr, NULL) == 0) {\r
+    DEBUG ((DEBUG_INFO,  "HiiSetFormString( ) failed\n"));\r
+    FreePool(UniStr);\r
+    return (EFI_OUT_OF_RESOURCES);\r
+  }\r
+\r
+  //\r
+  // Free the memory\r
+  //\r
+  FreePool(UniStr);\r
+\r
+  return (EFI_SUCCESS);\r
+}\r
+\r
+/**\r
+  Initialize the Opal disk base on the hardware info get from device.\r
+\r
+  @param Dev                  The Opal device.\r
+\r
+  @retval EFI_SUCESS          Initialize the device success.\r
+  @retval EFI_DEVICE_ERROR    Get info from device failed.\r
+\r
+**/\r
+EFI_STATUS\r
+OpalDiskInitialize (\r
+  IN OPAL_DRIVER_DEVICE          *Dev\r
+  )\r
+{\r
+  TCG_RESULT                  TcgResult;\r
+  OPAL_SESSION                Session;\r
+\r
+  ZeroMem(&Dev->OpalDisk, sizeof(OPAL_DISK));\r
+  Dev->OpalDisk.Sscp = Dev->Sscp;\r
+  Dev->OpalDisk.MediaId = Dev->MediaId;\r
+  Dev->OpalDisk.OpalDevicePath = Dev->OpalDevicePath;\r
+\r
+  ZeroMem(&Session, sizeof(Session));\r
+  Session.Sscp = Dev->Sscp;\r
+  Session.MediaId = Dev->MediaId;\r
+\r
+  TcgResult = OpalGetSupportedAttributesInfo (&Session, &Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.OpalBaseComId);\r
+  if (TcgResult != TcgResultSuccess) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
+\r
+  TcgResult = OpalUtilGetMsid (&Session, Dev->OpalDisk.Msid, OPAL_MSID_LENGHT, &Dev->OpalDisk.MsidLength);\r
+  if (TcgResult != TcgResultSuccess) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return OpalDiskUpdateStatus (&Dev->OpalDisk);\r
+}\r
+\r
+/**\r
+  Update the device info.\r
+\r
+  @param OpalDisk                The Opal device.\r
+\r
+  @retval EFI_SUCESS             Initialize the device success.\r
+  @retval EFI_DEVICE_ERROR       Get info from device failed.\r
+  @retval EFI_INVALID_PARAMETER  Not get Msid info before get ownership info.\r
+\r
+**/\r
+EFI_STATUS\r
+OpalDiskUpdateStatus (\r
+  OPAL_DISK        *OpalDisk\r
+  )\r
+{\r
+  TCG_RESULT                  TcgResult;\r
+  OPAL_SESSION                Session;\r
+\r
+  ZeroMem(&Session, sizeof(Session));\r
+  Session.Sscp = OpalDisk->Sscp;\r
+  Session.MediaId = OpalDisk->MediaId;\r
+  Session.OpalBaseComId = OpalDisk->OpalBaseComId;\r
+\r
+  TcgResult = OpalGetLockingInfo(&Session, &OpalDisk->LockingFeature);\r
+  if (TcgResult != TcgResultSuccess) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if (OpalDisk->MsidLength == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  } else {\r
+    //\r
+    // Base on the Msid info to get the ownership, so Msid info must get first.\r
+    //\r
+    OpalDisk->Owner = OpalUtilDetermineOwnership(&Session, OpalDisk->Msid, OpalDisk->MsidLength);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.h b/SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.h
new file mode 100644 (file)
index 0000000..a1b1131
--- /dev/null
@@ -0,0 +1,380 @@
+/** @file\r
+  Public Header file of HII library used by Opal UEFI Driver.\r
+  Defines required callbacks of Opal HII library.\r
+\r
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _OPAL_HII_H_\r
+#define _OPAL_HII_H_\r
+\r
+#include <Protocol/HiiConfigAccess.h>\r
+\r
+#include "OpalDriver.h"\r
+#include "OpalHiiFormValues.h"\r
+\r
+#define  OPAL_PASSWORD_CONFIG_GUID \\r
+  { \\r
+    0x0d510a4f, 0xa81b, 0x473f, { 0x87, 0x07, 0xb7, 0xfd, 0xfb, 0xc0, 0x45, 0xba } \\r
+  }\r
+\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+  UINT16 Id: HII_KEY_ID_BITS;\r
+  UINT16 Index: HII_KEY_INDEX_BITS;\r
+  UINT16 Flag: HII_KEY_FLAG_BITS;\r
+} KEY_BITS;\r
+\r
+typedef union {\r
+    UINT16    Raw;\r
+    KEY_BITS  KeyBits;\r
+} HII_KEY;\r
+\r
+typedef struct {\r
+    VENDOR_DEVICE_PATH             VendorDevicePath;\r
+    EFI_DEVICE_PATH_PROTOCOL       End;\r
+} HII_VENDOR_DEVICE_PATH;\r
+\r
+#pragma pack()\r
+\r
+extern const EFI_GUID gHiiSetupVariableGuid;\r
+\r
+/**\r
+  This function processes the results of changes in configuration.\r
+\r
+  @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param  Configuration          A null-terminated Unicode string in <ConfigResp>\r
+                                 format.\r
+  @param  Progress               A pointer to a string filled in with the offset of\r
+                                 the most recent '&' before the first failing\r
+                                 name/value pair (or the beginning of the string if\r
+                                 the failure is in the first name/value pair) or\r
+                                 the terminating NULL if all was successful.\r
+\r
+  @retval EFI_SUCCESS            The Results is processed successfully.\r
+  @retval EFI_INVALID_PARAMETER  Configuration is NULL.\r
+  @retval EFI_NOT_FOUND          Routing data doesn't match any storage in this\r
+                                 driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RouteConfig(\r
+  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL    *This,\r
+  CONST EFI_STRING                        Configuration,\r
+  EFI_STRING                              *Progress\r
+  );\r
+\r
+/**\r
+  This function allows a caller to extract the current configuration for one\r
+  or more named elements from the target driver.\r
+\r
+  @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param  Request                A null-terminated Unicode string in\r
+                                 <ConfigRequest> format.\r
+  @param  Progress               On return, points to a character in the Request\r
+                                 string. Points to the string's null terminator if\r
+                                 request was successful. Points to the most recent\r
+                                 '&' before the first failing name/value pair (or\r
+                                 the beginning of the string if the failure is in\r
+                                 the first name/value pair) if the request was not\r
+                                 successful.\r
+  @param  Results                A null-terminated Unicode string in\r
+                                 <ConfigAltResp> format which has all values filled\r
+                                 in for the names in the Request string. String to\r
+                                 be allocated by the called function.\r
+\r
+  @retval EFI_SUCCESS            The Results is filled with the requested values.\r
+  @retval EFI_OUT_OF_RESOURCES   Not enough memory to store the results.\r
+  @retval EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.\r
+  @retval EFI_NOT_FOUND          Routing data doesn't match any storage in this\r
+                                 driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ExtractConfig(\r
+  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL    *This,\r
+  CONST EFI_STRING                        Request,\r
+  EFI_STRING                              *Progress,\r
+  EFI_STRING                              *Results\r
+  );\r
+\r
+/**\r
+  This function processes the results of changes in configuration.\r
+\r
+  @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param  Action                 Specifies the type of action taken by the browser.\r
+  @param  QuestionId             A unique value which is sent to the original\r
+                                 exporting driver so that it can identify the type\r
+                                 of data to expect.\r
+  @param  Type                   The type of value for the question.\r
+  @param  Value                  A pointer to the data being sent to the original\r
+                                 exporting driver.\r
+  @param  ActionRequest          On return, points to the action requested by the\r
+                                 callback function.\r
+\r
+  @retval EFI_SUCCESS            The callback successfully handled the action.\r
+  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the\r
+                                 variable and its data.\r
+  @retval EFI_DEVICE_ERROR       The variable could not be saved.\r
+  @retval EFI_UNSUPPORTED        The specified Action is not supported by the\r
+                                 callback.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DriverCallback(\r
+  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL*   This,\r
+  EFI_BROWSER_ACTION                      Action,\r
+  EFI_QUESTION_ID                         QuestionId,\r
+  UINT8                                   Type,\r
+  EFI_IFR_TYPE_VALUE*                     Value,\r
+  EFI_BROWSER_ACTION_REQUEST*             ActionRequest\r
+  );\r
+\r
+/**\r
+\r
+  Pass the current system state to the bios via the hii_G_Configuration.\r
+\r
+**/\r
+VOID\r
+OpalHiiSetBrowserData (\r
+  VOID\r
+  );\r
+\r
+/**\r
+\r
+  Populate the hii_g_Configuraton with the browser Data.\r
+\r
+**/\r
+VOID\r
+OpalHiiGetBrowserData (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Draws the disk info form.\r
+\r
+  @retval  EFI_SUCCESS       Draw the disk info success.\r
+\r
+**/\r
+EFI_STATUS\r
+HiiPopulateDiskInfoForm(\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Update the global Disk index info.\r
+\r
+  @param   Index             The input disk index info.\r
+\r
+  @retval  EFI_SUCCESS       Update the disk index info success.\r
+\r
+**/\r
+EFI_STATUS\r
+HiiSelectDisk(\r
+  UINT8 Index\r
+  );\r
+\r
+/**\r
+  Use the input password to do the specified action.\r
+\r
+  @param      Str            The input password saved in.\r
+\r
+  @retval  EFI_SUCCESS       Do the required action success.\r
+  @retval  Others            Other error occur.\r
+\r
+**/\r
+EFI_STATUS\r
+HiiPasswordEntered(\r
+  EFI_STRING_ID            Str\r
+  );\r
+\r
+/**\r
+  Update block sid info.\r
+\r
+  @param      PpRequest      Input the Pp Request.\r
+\r
+  @retval  EFI_SUCCESS       Do the required action success.\r
+  @retval  Others            Other error occur.\r
+\r
+**/\r
+EFI_STATUS\r
+HiiSetBlockSidAction (\r
+  UINT32          PpRequest\r
+  );\r
+\r
+/**\r
+  Reverts the Opal disk to factory default.\r
+\r
+  @param   PsidStringId      The string id for the PSID info.\r
+\r
+  @retval  EFI_SUCCESS       Do the required action success.\r
+\r
+**/\r
+EFI_STATUS\r
+HiiPsidRevert(\r
+  EFI_STRING_ID         PsidStringId\r
+  );\r
+\r
+/**\r
+  Get disk name string id.\r
+\r
+  @param   DiskIndex             The input disk index info.\r
+\r
+  @retval  The disk name string id.\r
+\r
+**/\r
+EFI_STRING_ID\r
+GetDiskNameStringId(\r
+  UINT8 DiskIndex\r
+  );\r
+\r
+/**\r
+  Update the device info.\r
+\r
+  @param OpalDisk                The Opal device.\r
+\r
+  @retval EFI_SUCESS             Initialize the device success.\r
+  @retval EFI_DEVICE_ERROR       Get info from device failed.\r
+  @retval EFI_INVALID_PARAMETER  Not get Msid info before get ownership info.\r
+\r
+**/\r
+EFI_STATUS\r
+OpalDiskUpdateStatus (\r
+  OPAL_DISK        *OpalDisk\r
+  );\r
+\r
+/**\r
+  Get the driver image handle.\r
+\r
+  @retval  the driver image handle.\r
+\r
+**/\r
+EFI_HANDLE\r
+HiiGetDriverImageHandleCB(\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Install the HII form and string packages.\r
+\r
+  @retval  EFI_SUCCESS           Install all the resources success.\r
+  @retval  EFI_OUT_OF_RESOURCES  Out of resource error.\r
+**/\r
+EFI_STATUS\r
+OpalHiiAddPackages(\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Check whether enable feature or not.\r
+\r
+  @retval  Return the disk number.\r
+\r
+**/\r
+UINT8\r
+HiiGetNumConfigRequiredOpalDisksCB(\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Returns the driver name.\r
+\r
+  @retval Returns the driver name.\r
+\r
+**/\r
+CHAR16*\r
+HiiGetDriverNameCB(\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Returns the opaque pointer to a physical disk context.\r
+\r
+  @param  DiskIndex       Input the disk index.\r
+\r
+  @retval The device pointer.\r
+\r
+**/\r
+OPAL_DISK*\r
+HiiGetOpalDiskCB(\r
+  UINT8 DiskIndex\r
+  );\r
+\r
+/**\r
+  Returns the disk name.\r
+\r
+  @param  DiskIndex       Input the disk index.\r
+\r
+  @retval Returns the disk name.\r
+\r
+**/\r
+CHAR8*\r
+HiiDiskGetNameCB(\r
+  UINT8 DiskIndex\r
+  );\r
+\r
+/**\r
+  Set a string Value in a form.\r
+\r
+  @param      DestStringId   The stringid which need to update.\r
+  @param      SrcAsciiStr    The string nned to update.\r
+\r
+  @retval  EFI_SUCCESS       Do the required action success.\r
+  @retval  Others            Other error occur.\r
+\r
+**/\r
+EFI_STATUS\r
+HiiSetFormString(\r
+  EFI_STRING_ID       DestStringId,\r
+  CHAR8               *SrcAsciiStr\r
+  );\r
+\r
+/**\r
+  Install the HII related resources.\r
+\r
+  @retval  EFI_SUCCESS        Install all the resources success.\r
+  @retval  other              Error occur when install the resources.\r
+**/\r
+EFI_STATUS\r
+HiiInstall(\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Uninstall the HII capability.\r
+\r
+  @retval  EFI_SUCCESS           Uninstall all the resources success.\r
+  @retval  others                Other errors occur when unistall the hii resource.\r
+**/\r
+EFI_STATUS\r
+HiiUninstall(\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Initialize the Opal disk base on the hardware info get from device.\r
+\r
+  @param Dev                  The Opal device.\r
+\r
+  @retval EFI_SUCESS          Initialize the device success.\r
+  @retval EFI_DEVICE_ERROR    Get info from device failed.\r
+\r
+**/\r
+EFI_STATUS\r
+OpalDiskInitialize (\r
+  IN OPAL_DRIVER_DEVICE          *Dev\r
+  );\r
+\r
+#endif // _HII_H_\r
diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiCallbacks.c b/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiCallbacks.c
new file mode 100644 (file)
index 0000000..b07e38c
--- /dev/null
@@ -0,0 +1,219 @@
+/** @file\r
+  Callbacks required by the HII of the Opal UEFI Driver to help display\r
+  Opal device information.\r
+\r
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "OpalHii.h"\r
+\r
+/**\r
+  Get Opal var name.\r
+  The return Value must be freed by caller if not NULL\r
+\r
+  @param      OpalDisk       The disk.\r
+  @param      Prefix         The prefix string.\r
+\r
+  @retval  The var name string.\r
+\r
+**/\r
+CHAR16*\r
+OpalDriverGetOpalVarName(\r
+  OPAL_DISK        *OpalDisk,\r
+  const CHAR16     *Prefix\r
+  )\r
+{\r
+  OPAL_DRIVER_DEVICE*          Dev;\r
+  UINTN                        PrefixLen;\r
+  UINTN                        NameLen;\r
+  UINTN                        VarNameLen;\r
+  CHAR16*                      VarName;\r
+\r
+  Dev = DRIVER_DEVICE_FROM_OPALDISK(OpalDisk);\r
+  if (Dev == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  PrefixLen = StrLen(Prefix);\r
+\r
+  NameLen = 0;\r
+  if (Dev->Name16 != NULL) {\r
+    NameLen = StrLen(Dev->Name16);\r
+  }\r
+\r
+  VarNameLen = PrefixLen + NameLen;\r
+\r
+  VarName = (CHAR16*)AllocateZeroPool((VarNameLen + 1) * sizeof(CHAR16));\r
+  if (VarName == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  CopyMem(VarName, Prefix, PrefixLen * sizeof(CHAR16));\r
+  if (Dev->Name16 != NULL) {\r
+    CopyMem(VarName + PrefixLen, Dev->Name16, NameLen * sizeof(CHAR16));\r
+  }\r
+  VarName[VarNameLen] = 0;\r
+\r
+  return VarName;\r
+}\r
+\r
+/**\r
+  Get the driver image handle.\r
+\r
+  @retval  the driver image handle.\r
+\r
+**/\r
+EFI_HANDLE\r
+HiiGetDriverImageHandleCB(\r
+  VOID\r
+  )\r
+{\r
+  return gImageHandle;\r
+}\r
+\r
+/**\r
+  Check whether enable feature or not.\r
+\r
+  @retval  Return the disk number.\r
+\r
+**/\r
+UINT8\r
+HiiGetNumConfigRequiredOpalDisksCB(\r
+  VOID\r
+  )\r
+{\r
+  UINT8                        NumDisks;\r
+  UINT8                        NumLockedOpalDisks;\r
+  OPAL_DISK                    *OpalDisk;\r
+  UINT8                        Index;\r
+\r
+  NumLockedOpalDisks = 0;\r
+\r
+  NumDisks = GetDeviceCount();\r
+\r
+  for (Index = 0; Index < NumDisks; Index++) {\r
+    OpalDisk = HiiGetOpalDiskCB(Index);\r
+\r
+    if (OpalDisk != NULL) {\r
+      if (!OpalFeatureEnabled (&OpalDisk->SupportedAttributes, &OpalDisk->LockingFeature)) {\r
+        DEBUG ((DEBUG_INFO, "Ignoring disk %u because feature is disabled or health has already been inspected\n", Index));\r
+      } else if (OpalDeviceLocked (&OpalDisk->SupportedAttributes, &OpalDisk->LockingFeature)) {\r
+        NumLockedOpalDisks++;\r
+      }\r
+    }\r
+  }\r
+\r
+  return NumLockedOpalDisks;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Returns the opaque pointer to a physical disk context.\r
+\r
+  @param  DiskIndex       Input the disk index.\r
+\r
+  @retval The device pointer.\r
+\r
+**/\r
+VOID *\r
+HiiGetDiskContextCB(\r
+  UINT8 DiskIndex\r
+  )\r
+{\r
+  OPAL_DRIVER_DEVICE*                Dev;\r
+  UINT8                              CurrentDisk;\r
+\r
+  Dev = OpalDriverGetDeviceList();\r
+  CurrentDisk = 0;\r
+\r
+  if (DiskIndex >= GetDeviceCount()) {\r
+    return NULL;\r
+  }\r
+\r
+  while (Dev != NULL) {\r
+    if (CurrentDisk == DiskIndex) {\r
+      return Dev;\r
+    } else {\r
+      Dev = Dev->Next;\r
+      CurrentDisk++;\r
+    }\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Returns the opaque pointer to a physical disk context.\r
+\r
+  @param  DiskIndex       Input the disk index.\r
+\r
+  @retval The device pointer.\r
+\r
+**/\r
+OPAL_DISK*\r
+HiiGetOpalDiskCB(\r
+  UINT8 DiskIndex\r
+  )\r
+{\r
+  VOID                           *Ctx;\r
+  OPAL_DRIVER_DEVICE             *Tmp;\r
+\r
+  Ctx = HiiGetDiskContextCB (DiskIndex);\r
+\r
+  if (Ctx == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Tmp = (OPAL_DRIVER_DEVICE*) Ctx;\r
+\r
+  return &Tmp->OpalDisk;\r
+}\r
+\r
+/**\r
+  Returns the disk name.\r
+\r
+  @param  DiskIndex       Input the disk index.\r
+\r
+  @retval Returns the disk name.\r
+\r
+**/\r
+CHAR8*\r
+HiiDiskGetNameCB(\r
+  UINT8 DiskIndex\r
+  )\r
+{\r
+  OPAL_DRIVER_DEVICE*                Ctx;\r
+\r
+  Ctx = (OPAL_DRIVER_DEVICE*) HiiGetDiskContextCB (DiskIndex);\r
+\r
+  if (Ctx != NULL) {\r
+    if (Ctx->NameZ == NULL) {\r
+      OpalDriverGetDriverDeviceName (Ctx);\r
+    }\r
+    return Ctx->NameZ;\r
+  }\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Returns the driver name.\r
+\r
+  @retval Returns the driver name.\r
+\r
+**/\r
+CHAR16*\r
+HiiGetDriverNameCB(\r
+  VOID\r
+  )\r
+{\r
+  return (CHAR16*)EFI_DRIVER_NAME_UNICODE;\r
+}\r
diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormStrings.uni b/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormStrings.uni
new file mode 100644 (file)
index 0000000..5f753df
--- /dev/null
@@ -0,0 +1,85 @@
+// /** @file\r
+//\r
+//   String definitions for Setup formset.\r
+//\r
+// Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions of the BSD License\r
+// which accompanies this distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+/=#\r
+/////////////////////////////////   GENERIC DEFINITIONS   /////////////////////////////////\r
+#langdef en-US                                  "English"\r
+#string STR_NULL                                #language en-US " "\r
+\r
+/////////////////////////////////   FORM SET   /////////////////////////////////\r
+#string STR_FORM_SET_HELP                        #language en-US "Manage Opal disks"\r
+\r
+/////////////////////////////////   MULTIPLE FORMS   /////////////////////////////////\r
+#string STR_OPAL                                 #language en-US "Opal"\r
+#string STR_MAIN_OPAL_VERSION                    #language en-US "Version 00.0.0.0000"\r
+\r
+/////////////////////////////////   MAIN MENU FORM   /////////////////////////////////\r
+#string STR_MAIN_PHY_DISKS_LBL                   #language en-US "Physical Disks:"\r
+\r
+#string STR_MAIN_GOTO_DISK_INFO_0                #language en-US " "\r
+#string STR_MAIN_GOTO_DISK_INFO_1                #language en-US " "\r
+#string STR_MAIN_GOTO_DISK_INFO_2                #language en-US " "\r
+#string STR_MAIN_GOTO_DISK_INFO_3                #language en-US " "\r
+#string STR_MAIN_GOTO_DISK_INFO_4                #language en-US " "\r
+#string STR_MAIN_GOTO_DISK_INFO_5                #language en-US " "\r
+\r
+#string STR_MAIN_GOTO_DISK_INFO_HELP             #language en-US "Select to see Opal disk actions"\r
+\r
+#string STR_MAIN_NO_DISKS_PRESENT_LBL            #language en-US "No disks connected to system"\r
+#string STR_MAIN_NO_DISKS_PRESENT_LBL_HELP       #language en-US "The storage needs to be connected before EndOfDxe"\r
+\r
+/////////////////////////////////   DISK INFO MENU FORM   /////////////////////////////////\r
+#string STR_DISK_INFO_SELECTED_DISK_NAME         #language en-US " "\r
+\r
+#string STR_DISK_INFO_LOCK                       #language en-US "Lock"\r
+#string STR_DISK_INFO_UNLOCK                     #language en-US "Unlock"\r
+#string STR_DISK_INFO_SET_ADMIN_PSWD             #language en-US "Update Drive Admin Password"\r
+#string STR_DISK_INFO_SET_USER_PSWD              #language en-US "Set Drive User Password"\r
+#string STR_DISK_INFO_SECURE_ERASE               #language en-US "Secure Erase User Data"\r
+#string STR_DISK_INFO_PSID_REVERT                #language en-US "PSID Revert to factory default"\r
+#string STR_DISK_INFO_REVERT                     #language en-US "Admin Revert to factory default and Disable"\r
+#string STR_DISK_INFO_DISABLE_USER               #language en-US "Disable User"\r
+#string STR_DISK_INFO_ENABLE_FEATURE             #language en-US "Enable Feature"\r
+#string STR_DISK_INFO_ENABLE_BLOCKSID            #language en-US "TCG Storage Action"\r
+#string STR_ENABLED                              #language en-US "Enable BlockSID"\r
+#string STR_DISABLED                             #language en-US "Disable BlockSID"\r
+\r
+#string STR_NONE                                 #language en-US "None"\r
+#string STR_DISK_INFO_ENABLE_BLOCKSID_TRUE       #language en-US "Require physical presence when remote enable BlockSID"\r
+#string STR_DISK_INFO_ENABLE_BLOCKSID_FALSE      #language en-US "Not require physical presence when remote enable BlockSID"\r
+#string STR_DISK_INFO_DISABLE_BLOCKSID_TRUE      #language en-US "Require physical presence when remote disable BlockSID"\r
+#string STR_DISK_INFO_DISABLE_BLOCKSID_FALSE     #language en-US "Not require physical presence when remote disable BlockSID"\r
+\r
+#string STR_BLOCKSID_STATUS_HELP                 #language en-US "BlockSID action change status"\r
+#string STR_BLOCKSID_STATUS                      #language en-US "Current BlockSID Status:"\r
+#string STR_BLOCKSID_STATUS1                     #language en-US ""\r
+#string STR_BLOCKSID_STATUS2                     #language en-US ""\r
+#string STR_BLOCKSID_STATUS3                     #language en-US ""\r
+\r
+#string STR_OPAL_REQUESTS_LBL                    #language en-US "Opal Password Requests:"\r
+#string STR_DISK_INFO_LOCK_HELP                  #language en-US "Lock the disk"\r
+#string STR_DISK_INFO_UNLOCK_HELP                #language en-US "Unlock the disk"\r
+#string STR_DISK_INFO_SET_ADMIN_PSWD_HELP        #language en-US "Set password for the administrator, reset is required for the request to be processed in next boot"\r
+#string STR_DISK_INFO_SET_USER_PSWD_HELP         #language en-US "Set password for User 1, reset is required for the request to be processed in next boot"\r
+#string STR_DISK_INFO_SECURE_ERASE_HELP          #language en-US "Securely erase the disk, reset is required for the request to be processed in next boot"\r
+#string STR_DISK_INFO_REVERT_HELP                #language en-US "Revert the disk to factory defaults, reset is required for the request to be processed in next boot"\r
+#string STR_DISK_INFO_PSID_REVERT_HELP           #language en-US "Revert the disk to factory defaults, PSID is a 32 character case sensitive value, reset is required for the request to be processed in next boot"\r
+#string STR_DISK_INFO_DISABLE_USER_HELP          #language en-US "Disable User, reset is required for the request to be processed in next boot"\r
+#string STR_DISK_INFO_ENABLE_FEATURE_HELP        #language en-US "Enable Feature, reset is required for the request to be processed in next boot"\r
+#string STR_KEEP_USER_DATA_PROMPT                #language en-US "  Keep User Data"\r
+#string STR_KEEP_USER_DATA_HELP                  #language en-US "Check to keep user data, otherwise data will be lost"\r
+\r
+#string STR_DISK_INFO_ENABLE_BLOCKSID_HELP       #language en-US "Change BlockSID actions, includes enable or disable BlockSID, Require or not require physical presence when remote enable or disable BlockSID"\r
diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormValues.h b/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormValues.h
new file mode 100644 (file)
index 0000000..3ff7d47
--- /dev/null
@@ -0,0 +1,123 @@
+/** @file\r
+  Defines Opal HII form ids, structures and values.