From: "Yao, Jiewen" <jiewen.yao@intel.com>
To: "Zeng, Star" <star.zeng@intel.com>,
"edk2-devel@lists.01.org" <edk2-devel@lists.01.org>
Cc: "Dong, Eric" <eric.dong@intel.com>,
"Zhang, Chao B" <chao.b.zhang@intel.com>
Subject: Re: [PATCH V2 4/7] SecurityPkg OpalPassword: Add solution without SMM device code
Date: Thu, 8 Mar 2018 11:44:23 +0000 [thread overview]
Message-ID: <74D8A39837DF1E4DA445A8C0B3885C503AAE2D98@shsmsx102.ccr.corp.intel.com> (raw)
In-Reply-To: <1520428757-69040-5-git-send-email-star.zeng@intel.com>
One minor:
> + if (InputLength == 0 || InputKey.ScanCode == SCAN_ESC) {
I prefer we also zero Unicode here. ESC just means exit, the Unicode buffer might already be filled.
> + return NULL;
> + }
> +
> + Ascii = AllocateZeroPool (PSID_CHARACTER_LENGTH + 1);
> + if (Ascii == NULL) {
> + ZeroMem (Unicode, sizeof (Unicode));
> + ZeroMem (Mask, sizeof (Mask));
> + return NULL;
> + }
With above change, Reviewed-by: Jiewen.yao@intel.com
> -----Original Message-----
> From: Zeng, Star
> Sent: Wednesday, March 7, 2018 9:19 PM
> To: edk2-devel@lists.01.org
> Cc: Zeng, Star <star.zeng@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>;
> Dong, Eric <eric.dong@intel.com>; Zhang, Chao B <chao.b.zhang@intel.com>
> Subject: [PATCH V2 4/7] SecurityPkg OpalPassword: Add solution without SMM
> device code
>
> 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>
> ---
> SecurityPkg/SecurityPkg.dsc | 2 +
> SecurityPkg/Tcg/Opal/OpalPassword/ComponentName.c | 398 +++
> SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.c | 1335 +++++++++
> SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.h | 435 +++
> SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c | 3003
> ++++++++++++++++++++
> SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.h | 613 ++++
> SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.c | 1178 ++++++++
> SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.h | 380 +++
> .../Tcg/Opal/OpalPassword/OpalHiiCallbacks.c | 219 ++
> .../Tcg/Opal/OpalPassword/OpalHiiFormStrings.uni | 84 +
> .../Tcg/Opal/OpalPassword/OpalHiiFormValues.h | 123 +
> SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.c | 2144
> ++++++++++++++
> SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.h | 455 +++
> SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeReg.h | 815 ++++++
> .../Tcg/Opal/OpalPassword/OpalPasswordCommon.h | 65 +
> .../Tcg/Opal/OpalPassword/OpalPasswordDxe.inf | 81 +
> .../Tcg/Opal/OpalPassword/OpalPasswordForm.vfr | 309 ++
> .../Tcg/Opal/OpalPassword/OpalPasswordPei.c | 940 ++++++
> .../Tcg/Opal/OpalPassword/OpalPasswordPei.h | 133 +
> .../Tcg/Opal/OpalPassword/OpalPasswordPei.inf | 63 +
> 20 files changed, 12775 insertions(+)
> create mode 100644 SecurityPkg/Tcg/Opal/OpalPassword/ComponentName.c
> create mode 100644 SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.c
> create mode 100644 SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.h
> create mode 100644 SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c
> create mode 100644 SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.h
> create mode 100644 SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.c
> create mode 100644 SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.h
> create mode 100644 SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiCallbacks.c
> create mode 100644
> SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormStrings.uni
> create mode 100644
> SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormValues.h
> create mode 100644 SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.c
> create mode 100644 SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.h
> create mode 100644 SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeReg.h
> create mode 100644
> SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordCommon.h
> create mode 100644
> SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordDxe.inf
> create mode 100644
> SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordForm.vfr
> create mode 100644 SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.c
> create mode 100644 SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.h
> create mode 100644
> SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.inf
>
> diff --git a/SecurityPkg/SecurityPkg.dsc b/SecurityPkg/SecurityPkg.dsc
> index 65a2fe3d7967..f82703a17b82 100644
> --- a/SecurityPkg/SecurityPkg.dsc
> +++ b/SecurityPkg/SecurityPkg.dsc
> @@ -324,6 +324,8 @@ [Components.IA32, Components.X64]
> #
> SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordDxe.inf
> SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.inf
> + SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordDxe.inf
> + SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.inf
>
> [Components.IPF]
> SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.inf
> diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/ComponentName.c
> b/SecurityPkg/Tcg/Opal/OpalPassword/ComponentName.c
> new file mode 100644
> index 000000000000..ef963d0e0b62
> --- /dev/null
> +++ b/SecurityPkg/Tcg/Opal/OpalPassword/ComponentName.c
> @@ -0,0 +1,398 @@
> +/** @file
> + UEFI Component Name(2) protocol implementation for Opal driver.
> +
> +Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution. The full text of the license may be found
> at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +
> +#include "OpalDriver.h"
> +
> +//
> +// EFI Component Name Protocol
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL
> gOpalComponentName = {
> + OpalEfiDriverComponentNameGetDriverName,
> + OpalEfiDriverComponentNameGetControllerName,
> + "eng"
> +};
> +
> +//
> +// EFI Component Name 2 Protocol
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL
> gOpalComponentName2 = {
> + OpalEfiDriverComponentName2GetDriverName,
> + OpalEfiDriverComponentName2GetControllerName,
> + "en"
> +};
> +
> +
> +/// The name of the driver in all the languages we support.
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE
> mOpalDriverNameTable[] = {
> + { LANGUAGE_RFC_3066_ENGLISH,
> (CHAR16*)EFI_DRIVER_NAME_UNICODE },
> + { LANGUAGE_ISO_639_2_ENGLISH,
> (CHAR16*)EFI_DRIVER_NAME_UNICODE },
> + { 0, 0 }
> +};
> +
> +/**
> + Retrieves a Unicode string that is the user readable name of the driver.
> +
> + This function retrieves the user readable name of a driver in the form of a
> + Unicode string. If the driver specified by This has a user readable name in
> + the language specified by Language, then a pointer to the driver name is
> + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
> + by This does not support the language specified by Language,
> + then EFI_UNSUPPORTED is returned.
> +
> + @param This[in] A pointer to the
> EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL
> instance.
> +
> + @param Language[in] A pointer to a Null-terminated ASCII
> string
> + array indicating the language. This is the
> + language of the driver name that the
> caller is
> + requesting, and it must match one of the
> + languages specified in
> SupportedLanguages. The
> + number of languages supported by a
> driver is up
> + to the driver writer. Language is specified
> + in RFC 4646 or ISO 639-2 language code
> format.
> +
> + @param DriverName[out] A pointer to the Unicode string to
> return.
> + This Unicode string is the name of the
> + driver specified by This in the language
> + specified by Language.
> +
> + @retval EFI_SUCCESS The Unicode string for the Driver specified
> by
> + This and the language specified by
> Language was
> + returned in DriverName.
> +
> + @retval EFI_INVALID_PARAMETER Language is NULL.
> +
> + @retval EFI_INVALID_PARAMETER DriverName is NULL.
> +
> + @retval EFI_UNSUPPORTED The driver specified by This does not
> support
> + the language specified by Language.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +OpalEfiDriverComponentNameGetDriverName(
> + EFI_COMPONENT_NAME_PROTOCOL* This,
> + CHAR8* Language,
> + CHAR16** DriverName
> + )
> +{
> + return LookupUnicodeString2(
> + Language,
> + This->SupportedLanguages,
> + mOpalDriverNameTable,
> + DriverName,
> + TRUE
> + );
> +}
> +
> +/**
> + Retrieves a Unicode string that is the user readable name of the driver.
> +
> + This function retrieves the user readable name of a driver in the form of a
> + Unicode string. If the driver specified by This has a user readable name in
> + the language specified by Language, then a pointer to the driver name is
> + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
> + by This does not support the language specified by Language,
> + then EFI_UNSUPPORTED is returned.
> +
> + @param This[in] A pointer to the
> EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL
> instance.
> +
> + @param Language[in] A pointer to a Null-terminated ASCII
> string
> + array indicating the language. This is the
> + language of the driver name that the
> caller is
> + requesting, and it must match one of the
> + languages specified in
> SupportedLanguages. The
> + number of languages supported by a
> driver is up
> + to the driver writer. Language is specified
> + in RFC 4646 or ISO 639-2 language code
> format.
> +
> + @param DriverName[out] A pointer to the Unicode string to
> return.
> + This Unicode string is the name of the
> + driver specified by This in the language
> + specified by Language.
> +
> + @retval EFI_SUCCESS The Unicode string for the Driver specified
> by
> + This and the language specified by
> Language was
> + returned in DriverName.
> +
> + @retval EFI_INVALID_PARAMETER Language is NULL.
> +
> + @retval EFI_INVALID_PARAMETER DriverName is NULL.
> +
> + @retval EFI_UNSUPPORTED The driver specified by This does not
> support
> + the language specified by Language.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +OpalEfiDriverComponentName2GetDriverName(
> + EFI_COMPONENT_NAME2_PROTOCOL* This,
> + CHAR8* Language,
> + CHAR16** DriverName
> + )
> +{
> + return LookupUnicodeString2(
> + Language,
> + This->SupportedLanguages,
> + mOpalDriverNameTable,
> + DriverName,
> + FALSE
> + );
> +}
> +
> +/**
> + Retrieves a Unicode string that is the user readable name of the controller
> + that is being managed by a driver.
> +
> + This function retrieves the user readable name of the controller specified by
> + ControllerHandle and ChildHandle in the form of a Unicode string. If the
> + driver specified by This has a user readable name in the language specified by
> + Language, then a pointer to the controller name is returned in
> ControllerName,
> + and EFI_SUCCESS is returned. If the driver specified by This is not currently
> + managing the controller specified by ControllerHandle and ChildHandle,
> + then EFI_UNSUPPORTED is returned. If the driver specified by This does not
> + support the language specified by Language, then EFI_UNSUPPORTED is
> returned.
> +
> + @param ControllerHandle[in] The handle of a controller that the driver
> + specified by This is managing. This
> handle
> + specifies the controller whose name is to
> be
> + returned.
> +
> + @param ChildHandle[in] The handle of the child controller to
> retrieve
> + the name of. This is an optional
> parameter that
> + may be NULL. It will be NULL for device
> + drivers. It will also be NULL for a bus
> drivers
> + that wish to retrieve the name of the bus
> + controller. It will not be NULL for a bus
> + driver that wishes to retrieve the name of
> a
> + child controller.
> +
> +
> + @param Language[in] A pointer to a Null-terminated ASCII
> string
> + array indicating the language. This is the
> + language of the driver name that the
> caller is
> + requesting, and it must match one of the
> + languages specified in
> SupportedLanguages. The
> + number of languages supported by a
> driver is up
> + to the driver writer. Language is specified
> in
> + RFC 4646 or ISO 639-2 language code
> format.
> +
> + @param ControllerName[out] A pointer to the Unicode string to return.
> + This Unicode string is the name of the
> + controller specified by ControllerHandle
> and
> + ChildHandle in the language specified by
> + Language from the point of view of the
> driver
> + specified by This.
> +
> + @retval EFI_SUCCESS The Unicode string for the user readable
> name in
> + the language specified by Language for
> the
> + driver specified by This was returned in
> + DriverName.
> +
> + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
> +
> + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a
> valid
> + EFI_HANDLE.
> +
> + @retval EFI_INVALID_PARAMETER Language is NULL.
> +
> + @retval EFI_INVALID_PARAMETER ControllerName is NULL.
> +
> + @retval EFI_UNSUPPORTED The driver specified by This is not
> currently
> + managing the controller specified by
> + ControllerHandle and ChildHandle.
> +
> + @retval EFI_UNSUPPORTED The driver specified by This does not
> support
> + the language specified by Language.
> +
> +**/
> +EFI_STATUS
> +GetControllerName(
> + EFI_HANDLE ControllerHandle,
> + EFI_HANDLE ChildHandle,
> + CHAR8* Language,
> + CHAR16** ControllerName
> + )
> +{
> + if (Language == NULL || ControllerName == NULL || ControllerHandle ==
> NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + // don't support any controller or children names
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> + Retrieves a Unicode string that is the user readable name of the controller
> + that is being managed by a driver.
> +
> + This function retrieves the user readable name of the controller specified by
> + ControllerHandle and ChildHandle in the form of a Unicode string. If the
> + driver specified by This has a user readable name in the language specified by
> + Language, then a pointer to the controller name is returned in
> ControllerName,
> + and EFI_SUCCESS is returned. If the driver specified by This is not currently
> + managing the controller specified by ControllerHandle and ChildHandle,
> + then EFI_UNSUPPORTED is returned. If the driver specified by This does not
> + support the language specified by Language, then EFI_UNSUPPORTED is
> returned.
> +
> + @param This[in] A pointer to the
> EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL
> instance.
> +
> + @param ControllerHandle[in] The handle of a controller that the driver
> + specified by This is managing. This
> handle
> + specifies the controller whose name is to
> be
> + returned.
> +
> + @param ChildHandle[in] The handle of the child controller to
> retrieve
> + the name of. This is an optional
> parameter that
> + may be NULL. It will be NULL for device
> + drivers. It will also be NULL for a bus
> drivers
> + that wish to retrieve the name of the bus
> + controller. It will not be NULL for a bus
> + driver that wishes to retrieve the name of
> a
> + child controller.
> +
> + @param Language[in] A pointer to a Null-terminated ASCII
> string
> + array indicating the language. This is the
> + language of the driver name that the
> caller is
> + requesting, and it must match one of the
> + languages specified in
> SupportedLanguages. The
> + number of languages supported by a
> driver is up
> + to the driver writer. Language is specified
> in
> + RFC 4646 or ISO 639-2 language code
> format.
> +
> + @param ControllerName[out] A pointer to the Unicode string to return.
> + This Unicode string is the name of the
> + controller specified by ControllerHandle
> and
> + ChildHandle in the language specified by
> + Language from the point of view of the
> driver
> + specified by This.
> +
> + @retval EFI_SUCCESS The Unicode string for the user readable
> name in
> + the language specified by Language for
> the
> + driver specified by This was returned in
> + DriverName.
> +
> + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
> +
> + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a
> valid
> + EFI_HANDLE.
> +
> + @retval EFI_INVALID_PARAMETER Language is NULL.
> +
> + @retval EFI_INVALID_PARAMETER ControllerName is NULL.
> +
> + @retval EFI_UNSUPPORTED The driver specified by This is not
> currently
> + managing the controller specified by
> + ControllerHandle and ChildHandle.
> +
> + @retval EFI_UNSUPPORTED The driver specified by This does not
> support
> + the language specified by Language.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +OpalEfiDriverComponentNameGetControllerName(
> + EFI_COMPONENT_NAME_PROTOCOL* This,
> + EFI_HANDLE ControllerHandle,
> + EFI_HANDLE ChildHandle,
> + CHAR8* Language,
> + CHAR16** ControllerName
> + )
> +{
> + return (GetControllerName( ControllerHandle, ChildHandle, Language,
> ControllerName));
> +}
> +
> +/**
> + Retrieves a Unicode string that is the user readable name of the controller
> + that is being managed by a driver.
> +
> + This function retrieves the user readable name of the controller specified by
> + ControllerHandle and ChildHandle in the form of a Unicode string. If the
> + driver specified by This has a user readable name in the language specified by
> + Language, then a pointer to the controller name is returned in
> ControllerName,
> + and EFI_SUCCESS is returned. If the driver specified by This is not currently
> + managing the controller specified by ControllerHandle and ChildHandle,
> + then EFI_UNSUPPORTED is returned. If the driver specified by This does not
> + support the language specified by Language, then EFI_UNSUPPORTED is
> returned.
> +
> + @param This[in] A pointer to the
> EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL
> instance.
> +
> + @param ControllerHandle[in] The handle of a controller that the driver
> + specified by This is managing. This
> handle
> + specifies the controller whose name is to
> be
> + returned.
> +
> + @param ChildHandle[in] The handle of the child controller to
> retrieve
> + the name of. This is an optional
> parameter that
> + may be NULL. It will be NULL for device
> + drivers. It will also be NULL for a bus
> drivers
> + that wish to retrieve the name of the bus
> + controller. It will not be NULL for a bus
> + driver that wishes to retrieve the name of
> a
> + child controller.
> +
> + @param Language[in] A pointer to a Null-terminated ASCII
> string
> + array indicating the language. This is the
> + language of the driver name that the
> caller is
> + requesting, and it must match one of the
> + languages specified in
> SupportedLanguages. The
> + number of languages supported by a
> driver is up
> + to the driver writer. Language is specified
> in
> + RFC 4646 or ISO 639-2 language code
> format.
> +
> + @param ControllerName[out] A pointer to the Unicode string to return.
> + This Unicode string is the name of the
> + controller specified by ControllerHandle
> and
> + ChildHandle in the language specified by
> + Language from the point of view of the
> driver
> + specified by This.
> +
> + @retval EFI_SUCCESS The Unicode string for the user readable
> name in
> + the language specified by Language for
> the
> + driver specified by This was returned in
> + DriverName.
> +
> + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
> +
> + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a
> valid
> + EFI_HANDLE.
> +
> + @retval EFI_INVALID_PARAMETER Language is NULL.
> +
> + @retval EFI_INVALID_PARAMETER ControllerName is NULL.
> +
> + @retval EFI_UNSUPPORTED The driver specified by This is not
> currently
> + managing the controller specified by
> + ControllerHandle and ChildHandle.
> +
> + @retval EFI_UNSUPPORTED The driver specified by This does not
> support
> + the language specified by Language.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +OpalEfiDriverComponentName2GetControllerName(
> + EFI_COMPONENT_NAME2_PROTOCOL* This,
> + EFI_HANDLE ControllerHandle,
> + EFI_HANDLE ChildHandle,
> + CHAR8* Language,
> + CHAR16** ControllerName
> + )
> +{
> + return (GetControllerName(ControllerHandle, ChildHandle, Language,
> ControllerName));
> +}
> +
> diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.c
> b/SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.c
> new file mode 100644
> index 000000000000..550abacc9c75
> --- /dev/null
> +++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.c
> @@ -0,0 +1,1335 @@
> +/** @file
> + This driver is used for Opal Password Feature support at AHCI mode.
> +
> +Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution. The full text of the license may be found
> at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +
> +
> +#include "OpalPasswordPei.h"
> +
> +/**
> + Start command for give slot on specific port.
> +
> + @param AhciBar AHCI bar address.
> + @param Port The number of port.
> + @param CommandSlot The number of CommandSlot.
> + @param Timeout The timeout Value of start.
> +
> + @retval EFI_DEVICE_ERROR The command start unsuccessfully.
> + @retval EFI_TIMEOUT The operation is time out.
> + @retval EFI_SUCCESS The command start successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciStartCommand (
> + IN UINT32 AhciBar,
> + IN UINT8 Port,
> + IN UINT8 CommandSlot,
> + IN UINT64 Timeout
> + );
> +
> +/**
> + Stop command running for giving port
> +
> + @param AhciBar AHCI bar address.
> + @param Port The number of port.
> + @param Timeout The timeout Value of stop.
> +
> + @retval EFI_DEVICE_ERROR The command stop unsuccessfully.
> + @retval EFI_TIMEOUT The operation is time out.
> + @retval EFI_SUCCESS The command stop successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciStopCommand (
> + IN UINT32 AhciBar,
> + IN UINT8 Port,
> + IN UINT64 Timeout
> + );
> +
> +/**
> + Read AHCI Operation register.
> +
> + @param AhciBar AHCI bar address.
> + @param Offset The operation register offset.
> +
> + @return The register content read.
> +
> +**/
> +UINT32
> +EFIAPI
> +AhciReadReg (
> + IN UINT32 AhciBar,
> + IN UINT32 Offset
> + )
> +{
> + UINT32 Data;
> +
> + Data = 0;
> +
> + Data = MmioRead32 (AhciBar + Offset);
> +
> + return Data;
> +}
> +
> +/**
> + Write AHCI Operation register.
> +
> + @param AhciBar AHCI bar address.
> + @param Offset The operation register offset.
> + @param Data The Data used to write down.
> +
> +**/
> +VOID
> +EFIAPI
> +AhciWriteReg (
> + IN UINT32 AhciBar,
> + IN UINT32 Offset,
> + IN UINT32 Data
> + )
> +{
> + MmioWrite32 (AhciBar + Offset, Data);
> +
> + return ;
> +}
> +
> +/**
> + Do AND operation with the Value of AHCI Operation register.
> +
> + @param AhciBar AHCI bar address.
> + @param Offset The operation register offset.
> + @param AndData The Data used to do AND operation.
> +
> +**/
> +VOID
> +EFIAPI
> +AhciAndReg (
> + IN UINT32 AhciBar,
> + IN UINT32 Offset,
> + IN UINT32 AndData
> + )
> +{
> + UINT32 Data;
> +
> + Data = AhciReadReg (AhciBar, Offset);
> +
> + Data &= AndData;
> +
> + AhciWriteReg (AhciBar, Offset, Data);
> +}
> +
> +/**
> + Do OR operation with the Value of AHCI Operation register.
> +
> + @param AhciBar AHCI bar address.
> + @param Offset The operation register offset.
> + @param OrData The Data used to do OR operation.
> +
> +**/
> +VOID
> +EFIAPI
> +AhciOrReg (
> + IN UINT32 AhciBar,
> + IN UINT32 Offset,
> + IN UINT32 OrData
> + )
> +{
> + UINT32 Data;
> +
> + Data = AhciReadReg (AhciBar, Offset);
> +
> + Data |= OrData;
> +
> + AhciWriteReg (AhciBar, Offset, Data);
> +}
> +
> +/**
> + Wait for memory set to the test Value.
> +
> + @param AhciBar AHCI bar address.
> + @param Offset The memory offset to test.
> + @param MaskValue The mask Value of memory.
> + @param TestValue The test Value of memory.
> + @param Timeout The time out Value for wait memory set.
> +
> + @retval EFI_DEVICE_ERROR The memory is not set.
> + @retval EFI_TIMEOUT The memory setting is time out.
> + @retval EFI_SUCCESS The memory is correct set.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciWaitMmioSet (
> + IN UINT32 AhciBar,
> + IN UINT32 Offset,
> + IN UINT32 MaskValue,
> + IN UINT32 TestValue,
> + IN UINT64 Timeout
> + )
> +{
> + UINT32 Value;
> + UINT32 Delay;
> +
> + Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
> +
> + do {
> + Value = AhciReadReg (AhciBar, Offset) & MaskValue;
> +
> + if (Value == TestValue) {
> + return EFI_SUCCESS;
> + }
> +
> + //
> + // Stall for 100 microseconds.
> + //
> + MicroSecondDelay (100);
> +
> + Delay--;
> +
> + } while (Delay > 0);
> +
> + return EFI_TIMEOUT;
> +}
> +/**
> + Wait for the Value of the specified system memory set to the test Value.
> +
> + @param Address The system memory address to test.
> + @param MaskValue The mask Value of memory.
> + @param TestValue The test Value of memory.
> + @param Timeout The time out Value for wait memory set,
> uses 100ns as a unit.
> +
> + @retval EFI_TIMEOUT The system memory setting is time out.
> + @retval EFI_SUCCESS The system memory is correct set.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciWaitMemSet (
> + IN EFI_PHYSICAL_ADDRESS Address,
> + IN UINT32 MaskValue,
> + IN UINT32 TestValue,
> + IN UINT64 Timeout
> + )
> +{
> + UINT32 Value;
> + UINT32 Delay;
> +
> + Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);
> +
> + do {
> + //
> + // Access sytem memory to see if the Value is the tested one.
> + //
> + // The system memory pointed by Address will be updated by the
> + // SATA Host Controller, "volatile" is introduced to prevent
> + // compiler from optimizing the access to the memory address
> + // to only read once.
> + //
> + Value = *(volatile UINT32 *) (UINTN) Address;
> + Value &= MaskValue;
> +
> + if (Value == TestValue) {
> + return EFI_SUCCESS;
> + }
> +
> + //
> + // Stall for 100 microseconds.
> + //
> + MicroSecondDelay (100);
> +
> + Delay--;
> +
> + } while (Delay > 0);
> +
> + return EFI_TIMEOUT;
> +}
> +
> +/**
> + Check the memory status to the test Value.
> +
> + @param[in] Address The memory address to test.
> + @param[in] MaskValue The mask Value of memory.
> + @param[in] TestValue The test Value of memory.
> + @param[in, out] RetryTimes The retry times Value for waitting
> memory set. If 0, then just try once.
> +
> + @retval EFI_NOTREADY The memory is not set.
> + @retval EFI_TIMEOUT The memory setting retry times out.
> + @retval EFI_SUCCESS The memory is correct set.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciCheckMemSet (
> + IN UINTN Address,
> + IN UINT32 MaskValue,
> + IN UINT32 TestValue,
> + IN OUT UINTN *RetryTimes OPTIONAL
> + )
> +{
> + UINT32 Value;
> +
> + if (RetryTimes != NULL) {
> + (*RetryTimes)--;
> + }
> +
> + Value = *(volatile UINT32 *) Address;
> + Value &= MaskValue;
> +
> + if (Value == TestValue) {
> + return EFI_SUCCESS;
> + }
> +
> + if ((RetryTimes != NULL) && (*RetryTimes == 0)) {
> + return EFI_TIMEOUT;
> + } else {
> + return EFI_NOT_READY;
> + }
> +}
> +
> +/**
> + Clear the port interrupt and error status. It will also clear
> + HBA interrupt status.
> +
> + @param AhciBar AHCI bar address.
> + @param Port The number of port.
> +
> +**/
> +VOID
> +EFIAPI
> +AhciClearPortStatus (
> + IN UINT32 AhciBar,
> + IN UINT8 Port
> + )
> +{
> + UINT32 Offset;
> +
> + //
> + // Clear any error status
> + //
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_SERR;
> + AhciWriteReg (AhciBar, Offset, AhciReadReg (AhciBar, Offset));
> +
> + //
> + // Clear any port interrupt status
> + //
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_IS;
> + AhciWriteReg (AhciBar, Offset, AhciReadReg (AhciBar, Offset));
> +
> + //
> + // Clear any HBA interrupt status
> + //
> + AhciWriteReg (AhciBar, EFI_AHCI_IS_OFFSET, AhciReadReg (AhciBar,
> EFI_AHCI_IS_OFFSET));
> +}
> +
> +/**
> + Enable the FIS running for giving port.
> +
> + @param AhciBar AHCI bar address.
> + @param Port The number of port.
> + @param Timeout The timeout Value of enabling FIS.
> +
> + @retval EFI_DEVICE_ERROR The FIS enable setting fails.
> + @retval EFI_TIMEOUT The FIS enable setting is time out.
> + @retval EFI_SUCCESS The FIS enable successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciEnableFisReceive (
> + IN UINT32 AhciBar,
> + IN UINT8 Port,
> + IN UINT64 Timeout
> + )
> +{
> + UINT32 Offset;
> +
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_CMD;
> + AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_FRE);
> +
> + return AhciWaitMmioSet (
> + AhciBar,
> + Offset,
> + EFI_AHCI_PORT_CMD_FR,
> + EFI_AHCI_PORT_CMD_FR,
> + Timeout
> + );
> +}
> +
> +/**
> + Disable the FIS running for giving port.
> +
> + @param AhciBar AHCI bar address.
> + @param Port The number of port.
> + @param Timeout The timeout Value of disabling FIS.
> +
> + @retval EFI_DEVICE_ERROR The FIS disable setting fails.
> + @retval EFI_TIMEOUT The FIS disable setting is time out.
> + @retval EFI_UNSUPPORTED The port is in running state.
> + @retval EFI_SUCCESS The FIS disable successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciDisableFisReceive (
> + IN UINT32 AhciBar,
> + IN UINT8 Port,
> + IN UINT64 Timeout
> + )
> +{
> + UINT32 Offset;
> + UINT32 Data;
> +
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_CMD;
> + Data = AhciReadReg (AhciBar, Offset);
> +
> + //
> + // Before disabling Fis receive, the DMA engine of the port should NOT be in
> running status.
> + //
> + if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) != 0) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + //
> + // Check if the Fis receive DMA engine for the port is running.
> + //
> + if ((Data & EFI_AHCI_PORT_CMD_FR) != EFI_AHCI_PORT_CMD_FR) {
> + return EFI_SUCCESS;
> + }
> +
> + AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE));
> +
> + return AhciWaitMmioSet (
> + AhciBar,
> + Offset,
> + EFI_AHCI_PORT_CMD_FR,
> + 0,
> + Timeout
> + );
> +}
> +
> +/**
> + Build the command list, command table and prepare the fis receiver.
> +
> + @param AhciContext The pointer to the AHCI_CONTEXT.
> + @param Port The number of port.
> + @param PortMultiplier The timeout Value of stop.
> + @param CommandFis The control fis will be used for the
> transfer.
> + @param CommandList The command list will be used for the
> transfer.
> + @param AtapiCommand The atapi command will be used for
> the transfer.
> + @param AtapiCommandLength The Length of the atapi command.
> + @param CommandSlotNumber The command slot will be used for
> the transfer.
> + @param DataPhysicalAddr The pointer to the Data Buffer pci bus
> master address.
> + @param DataLength The Data count to be transferred.
> +
> +**/
> +VOID
> +EFIAPI
> +AhciBuildCommand (
> + IN AHCI_CONTEXT *AhciContext,
> + IN UINT8 Port,
> + IN UINT8 PortMultiplier,
> + IN EFI_AHCI_COMMAND_FIS *CommandFis,
> + IN EFI_AHCI_COMMAND_LIST *CommandList,
> + IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,
> + IN UINT8 AtapiCommandLength,
> + IN UINT8 CommandSlotNumber,
> + IN OUT VOID *DataPhysicalAddr,
> + IN UINT64 DataLength
> + )
> +{
> + EFI_AHCI_REGISTERS *AhciRegisters;
> + UINT32 AhciBar;
> + UINT64 BaseAddr;
> + UINT64 PrdtNumber;
> + UINTN RemainedData;
> + UINTN MemAddr;
> + DATA_64 Data64;
> + UINT32 Offset;
> +
> + AhciRegisters = &AhciContext->AhciRegisters;
> + AhciBar = AhciContext->AhciBar;
> +
> + //
> + // Filling the PRDT
> + //
> + PrdtNumber = DivU64x32 (DataLength + EFI_AHCI_MAX_DATA_PER_PRDT -
> 1, EFI_AHCI_MAX_DATA_PER_PRDT);
> +
> + //
> + // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB
> Data block.
> + // It also limits that the maximum amount of the PRDT entry in the command
> table
> + // is 65535.
> + //
> + ASSERT (PrdtNumber <= 1);
> +
> + Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis);
> +
> + BaseAddr = Data64.Uint64;
> +
> + ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));
> +
> + ZeroMem (AhciRegisters->AhciCommandTable, sizeof
> (EFI_AHCI_COMMAND_TABLE));
> +
> + CommandFis->AhciCFisPmNum = PortMultiplier;
> +
> + CopyMem (&AhciRegisters->AhciCommandTable->CommandFis,
> CommandFis, sizeof (EFI_AHCI_COMMAND_FIS));
> +
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_CMD;
> + if (AtapiCommand != NULL) {
> + CopyMem (
> + &AhciRegisters->AhciCommandTable->AtapiCmd,
> + AtapiCommand,
> + AtapiCommandLength
> + );
> +
> + CommandList->AhciCmdA = 1;
> + CommandList->AhciCmdP = 1;
> +
> + AhciOrReg (AhciBar, Offset, (EFI_AHCI_PORT_CMD_DLAE |
> EFI_AHCI_PORT_CMD_ATAPI));
> + } else {
> + AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_DLAE |
> EFI_AHCI_PORT_CMD_ATAPI));
> + }
> +
> + RemainedData = (UINTN) DataLength;
> + MemAddr = (UINTN) DataPhysicalAddr;
> + CommandList->AhciCmdPrdtl = (UINT32)PrdtNumber;
> +
> + AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDbc =
> (UINT32)RemainedData - 1;
> +
> + Data64.Uint64 = (UINT64)MemAddr;
> + AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDba =
> Data64.Uint32.Lower32;
> + AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDbau =
> Data64.Uint32.Upper32;
> +
> + //
> + // Set the last PRDT to Interrupt On Complete
> + //
> + AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtIoc = 1;
> +
> + CopyMem (
> + (VOID *) ((UINTN) AhciRegisters->AhciCmdList + (UINTN)
> CommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST)),
> + CommandList,
> + sizeof (EFI_AHCI_COMMAND_LIST)
> + );
> +
> + Data64.Uint64 = (UINT64)(UINTN) AhciRegisters->AhciCommandTable;
> + AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtba =
> Data64.Uint32.Lower32;
> + AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtbau =
> Data64.Uint32.Upper32;
> + AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdPmp =
> PortMultiplier;
> +
> +}
> +
> +/**
> + Buid a command FIS.
> +
> + @param CmdFis A pointer to the EFI_AHCI_COMMAND_FIS
> Data structure.
> + @param AtaCommandBlock A pointer to the AhciBuildCommandFis
> Data structure.
> +
> +**/
> +VOID
> +EFIAPI
> +AhciBuildCommandFis (
> + IN OUT EFI_AHCI_COMMAND_FIS *CmdFis,
> + IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock
> + )
> +{
> + ZeroMem (CmdFis, sizeof (EFI_AHCI_COMMAND_FIS));
> +
> + CmdFis->AhciCFisType = EFI_AHCI_FIS_REGISTER_H2D;
> + //
> + // Indicator it's a command
> + //
> + CmdFis->AhciCFisCmdInd = 0x1;
> + CmdFis->AhciCFisCmd = AtaCommandBlock->AtaCommand;
> +
> + CmdFis->AhciCFisFeature = AtaCommandBlock->AtaFeatures;
> + CmdFis->AhciCFisFeatureExp = AtaCommandBlock->AtaFeaturesExp;
> +
> + CmdFis->AhciCFisSecNum = AtaCommandBlock->AtaSectorNumber;
> + CmdFis->AhciCFisSecNumExp =
> AtaCommandBlock->AtaSectorNumberExp;
> +
> + CmdFis->AhciCFisClyLow = AtaCommandBlock->AtaCylinderLow;
> + CmdFis->AhciCFisClyLowExp = AtaCommandBlock->AtaCylinderLowExp;
> +
> + CmdFis->AhciCFisClyHigh = AtaCommandBlock->AtaCylinderHigh;
> + CmdFis->AhciCFisClyHighExp = AtaCommandBlock->AtaCylinderHighExp;
> +
> + CmdFis->AhciCFisSecCount = AtaCommandBlock->AtaSectorCount;
> + CmdFis->AhciCFisSecCountExp = AtaCommandBlock->AtaSectorCountExp;
> +
> + CmdFis->AhciCFisDevHead = (UINT8)
> (AtaCommandBlock->AtaDeviceHead | 0xE0);
> +}
> +
> +/**
> + Start a PIO Data transfer on specific port.
> +
> + @param AhciContext The pointer to the AHCI_CONTEXT.
> + @param Port The number of port.
> + @param PortMultiplier The timeout Value of stop.
> + @param AtapiCommand The atapi command will be used for the
> transfer.
> + @param AtapiCommandLength The Length of the atapi command.
> + @param Read The transfer direction.
> + @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK Data.
> + @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK Data.
> + @param MemoryAddr The pointer to the Data Buffer.
> + @param DataCount The Data count to be transferred.
> + @param Timeout The timeout Value of non Data transfer.
> +
> + @retval EFI_DEVICE_ERROR The PIO Data transfer abort with error
> occurs.
> + @retval EFI_TIMEOUT The operation is time out.
> + @retval EFI_UNSUPPORTED The device is not ready for transfer.
> + @retval EFI_SUCCESS The PIO Data transfer executes successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciPioTransfer (
> + IN AHCI_CONTEXT *AhciContext,
> + IN UINT8 Port,
> + IN UINT8 PortMultiplier,
> + IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,
> + IN UINT8 AtapiCommandLength,
> + IN BOOLEAN Read,
> + IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
> + IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
> + IN OUT VOID *MemoryAddr,
> + IN UINT32 DataCount,
> + IN UINT64 Timeout
> + )
> +{
> + EFI_STATUS Status;
> + EFI_AHCI_REGISTERS *AhciRegisters;
> + UINT32 AhciBar;
> + UINT32 FisBaseAddr;
> + UINT32 Offset;
> + UINT32 Delay;
> + EFI_AHCI_COMMAND_FIS CFis;
> + EFI_AHCI_COMMAND_LIST CmdList;
> + UINT32 PortTfd;
> + UINT32 PrdCount;
> + UINT32 OldRfisLo;
> + UINT32 OldRfisHi;
> + UINT32 OldCmdListLo;
> + UINT32 OldCmdListHi;
> +
> + AhciRegisters = &AhciContext->AhciRegisters;
> + AhciBar = AhciContext->AhciBar;
> +
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_FB;
> + OldRfisLo = AhciReadReg (AhciBar, Offset);
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_FBU;
> + OldRfisHi = AhciReadReg (AhciBar, Offset);
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_FB;
> + AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciRFis);
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_FBU;
> + AhciWriteReg (AhciBar, Offset, 0);
> +
> + //
> + // Single task envrionment, we only use one command table for all port
> + //
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_CLB;
> + OldCmdListLo = AhciReadReg (AhciBar, Offset);
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_CLBU;
> + OldCmdListHi = AhciReadReg (AhciBar, Offset);
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_CLB;
> + AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciCmdList);
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_CLBU;
> + AhciWriteReg (AhciBar, Offset, 0);
> +
> + //
> + // Package read needed
> + //
> + AhciBuildCommandFis (&CFis, AtaCommandBlock);
> +
> + ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));
> +
> + CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;
> + CmdList.AhciCmdW = Read ? 0 : 1;
> +
> + AhciBuildCommand (
> + AhciContext,
> + Port,
> + PortMultiplier,
> + &CFis,
> + &CmdList,
> + AtapiCommand,
> + AtapiCommandLength,
> + 0,
> + MemoryAddr,
> + DataCount
> + );
> +
> + Status = AhciStartCommand (
> + AhciBar,
> + Port,
> + 0,
> + Timeout
> + );
> + if (EFI_ERROR (Status)) {
> + goto Exit;
> + }
> +
> + //
> + // Checking the status and wait the driver sending Data
> + //
> + FisBaseAddr = (UINT32)(UINTN)AhciRegisters->AhciRFis;
> + if (Read && (AtapiCommand == 0)) {
> + //
> + // Wait device sends the PIO setup fis before Data transfer
> + //
> + Status = EFI_TIMEOUT;
> + Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);
> + do {
> + Offset = FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET;
> +
> + Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK,
> EFI_AHCI_FIS_PIO_SETUP, 0);
> + if (!EFI_ERROR (Status)) {
> + Offset = EFI_AHCI_PORT_START + Port *
> EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
> + PortTfd = AhciReadReg (AhciBar, (UINT32) Offset);
> + //
> + // PxTFD will be updated if there is a D2H or SetupFIS received.
> + // For PIO IN transfer, D2H means a device error. Therefore we only
> need to check the TFD after receiving a SetupFIS.
> + //
> + if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {
> + Status = EFI_DEVICE_ERROR;
> + break;
> + }
> +
> + PrdCount = *(volatile UINT32 *)
> (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));
> + if (PrdCount == DataCount) {
> + break;
> + }
> + }
> +
> + Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
> + Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK,
> EFI_AHCI_FIS_REGISTER_D2H, 0);
> + if (!EFI_ERROR (Status)) {
> + Status = EFI_DEVICE_ERROR;
> + break;
> + }
> +
> + //
> + // Stall for 100 microseconds.
> + //
> + MicroSecondDelay(100);
> +
> + Delay--;
> + } while (Delay > 0);
> + } else {
> + //
> + // Wait for D2H Fis is received
> + //
> + Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
> + Status = AhciWaitMemSet (
> + Offset,
> + EFI_AHCI_FIS_TYPE_MASK,
> + EFI_AHCI_FIS_REGISTER_D2H,
> + Timeout
> + );
> +
> + if (EFI_ERROR (Status)) {
> + goto Exit;
> + }
> +
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_TFD;
> + PortTfd = AhciReadReg (AhciBar, (UINT32) Offset);
> + if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {
> + Status = EFI_DEVICE_ERROR;
> + }
> + }
> +
> +Exit:
> + AhciStopCommand (
> + AhciBar,
> + Port,
> + Timeout
> + );
> +
> + AhciDisableFisReceive (
> + AhciBar,
> + Port,
> + Timeout
> + );
> +
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_FB;
> + AhciWriteReg (AhciBar, Offset, OldRfisLo);
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_FBU;
> + AhciWriteReg (AhciBar, Offset, OldRfisHi);
> +
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_CLB;
> + AhciWriteReg (AhciBar, Offset, OldCmdListLo);
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_CLBU;
> + AhciWriteReg (AhciBar, Offset, OldCmdListHi);
> +
> + return Status;
> +}
> +
> +/**
> + Stop command running for giving port
> +
> + @param AhciBar AHCI bar address.
> + @param Port The number of port.
> + @param Timeout The timeout Value of stop.
> +
> + @retval EFI_DEVICE_ERROR The command stop unsuccessfully.
> + @retval EFI_TIMEOUT The operation is time out.
> + @retval EFI_SUCCESS The command stop successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciStopCommand (
> + IN UINT32 AhciBar,
> + IN UINT8 Port,
> + IN UINT64 Timeout
> + )
> +{
> + UINT32 Offset;
> + UINT32 Data;
> +
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_CMD;
> + Data = AhciReadReg (AhciBar, Offset);
> +
> + if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) == 0) {
> + return EFI_SUCCESS;
> + }
> +
> + if ((Data & EFI_AHCI_PORT_CMD_ST) != 0) {
> + AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_ST));
> + }
> +
> + return AhciWaitMmioSet (
> + AhciBar,
> + Offset,
> + EFI_AHCI_PORT_CMD_CR,
> + 0,
> + Timeout
> + );
> +}
> +
> +/**
> + Start command for give slot on specific port.
> +
> + @param AhciBar AHCI bar address.
> + @param Port The number of port.
> + @param CommandSlot The number of CommandSlot.
> + @param Timeout The timeout Value of start.
> +
> + @retval EFI_DEVICE_ERROR The command start unsuccessfully.
> + @retval EFI_TIMEOUT The operation is time out.
> + @retval EFI_SUCCESS The command start successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciStartCommand (
> + IN UINT32 AhciBar,
> + IN UINT8 Port,
> + IN UINT8 CommandSlot,
> + IN UINT64 Timeout
> + )
> +{
> + UINT32 CmdSlotBit;
> + EFI_STATUS Status;
> + UINT32 PortStatus;
> + UINT32 StartCmd;
> + UINT32 PortTfd;
> + UINT32 Offset;
> + UINT32 Capability;
> +
> + //
> + // Collect AHCI controller information
> + //
> + Capability = AhciReadReg(AhciBar, EFI_AHCI_CAPABILITY_OFFSET);
> +
> + CmdSlotBit = (UINT32) (1 << CommandSlot);
> +
> + AhciClearPortStatus (
> + AhciBar,
> + Port
> + );
> +
> + Status = AhciEnableFisReceive (
> + AhciBar,
> + Port,
> + Timeout
> + );
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_CMD;
> + PortStatus = AhciReadReg (AhciBar, Offset);
> +
> + StartCmd = 0;
> + if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) != 0) {
> + StartCmd = AhciReadReg (AhciBar, Offset);
> + StartCmd &= ~EFI_AHCI_PORT_CMD_ICC_MASK;
> + StartCmd |= EFI_AHCI_PORT_CMD_ACTIVE;
> + }
> +
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_TFD;
> + PortTfd = AhciReadReg (AhciBar, Offset);
> +
> + if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) != 0)
> {
> + if ((Capability & BIT24) != 0) {
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH
> + EFI_AHCI_PORT_CMD;
> + AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_COL);
> +
> + AhciWaitMmioSet (
> + AhciBar,
> + Offset,
> + EFI_AHCI_PORT_CMD_COL,
> + 0,
> + Timeout
> + );
> + }
> + }
> +
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_CMD;
> + AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_ST | StartCmd);
> +
> + //
> + // Setting the command
> + //
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_SACT;
> + AhciAndReg (AhciBar, Offset, 0);
> + AhciOrReg (AhciBar, Offset, CmdSlotBit);
> +
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_CI;
> + AhciAndReg (AhciBar, Offset, 0);
> + AhciOrReg (AhciBar, Offset, CmdSlotBit);
> + return EFI_SUCCESS;
> +}
> +
> +
> +/**
> + Do AHCI HBA reset.
> +
> + @param[in] AhciBar AHCI bar address.
> + @param[in] Timeout The timeout Value of reset.
> +
> + @retval EFI_DEVICE_ERROR AHCI controller is failed to complete
> hardware reset.
> + @retval EFI_TIMEOUT The reset operation is time out.
> + @retval EFI_SUCCESS AHCI controller is reset successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciReset (
> + IN UINT32 AhciBar,
> + IN UINT64 Timeout
> + )
> +{
> + UINT32 Delay;
> + UINT32 Value;
> + UINT32 Capability;
> +
> + //
> + // Collect AHCI controller information
> + //
> + Capability = AhciReadReg (AhciBar, EFI_AHCI_CAPABILITY_OFFSET);
> +
> + //
> + // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only
> is not set
> + //
> + if ((Capability & EFI_AHCI_CAP_SAM) == 0) {
> + AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);
> + }
> +
> + AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);
> +
> + Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
> +
> + do {
> + Value = AhciReadReg(AhciBar, EFI_AHCI_GHC_OFFSET);
> + if ((Value & EFI_AHCI_GHC_RESET) == 0) {
> + return EFI_SUCCESS;
> + }
> +
> + //
> + // Stall for 100 microseconds.
> + //
> + MicroSecondDelay(100);
> +
> + Delay--;
> + } while (Delay > 0);
> +
> + return EFI_TIMEOUT;
> +
> +
> +}
> +
> +/**
> + Send Buffer cmd to specific device.
> +
> + @param[in] AhciContext The pointer to the AHCI_CONTEXT.
> + @param[in] Port The port number of attached ATA
> device.
> + @param[in] PortMultiplier The port number of port multiplier of
> attached ATA device.
> + @param[in, out] Buffer The Data Buffer to store IDENTIFY
> PACKET Data.
> +
> + @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
> + @retval EFI_TIMEOUT The operation is time out.
> + @retval EFI_UNSUPPORTED The device is not ready for executing.
> + @retval EFI_SUCCESS The cmd executes successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciIdentify (
> + IN AHCI_CONTEXT *AhciContext,
> + IN UINT8 Port,
> + IN UINT8 PortMultiplier,
> + IN OUT ATA_IDENTIFY_DATA *Buffer
> + )
> +{
> + EFI_STATUS Status;
> + EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
> +
> + if (AhciContext == NULL || Buffer == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
> +
> + AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DRIVE;
> + AtaCommandBlock.AtaSectorCount = 1;
> +
> + Status = AhciPioTransfer (
> + AhciContext,
> + Port,
> + PortMultiplier,
> + NULL,
> + 0,
> + TRUE,
> + &AtaCommandBlock,
> + NULL,
> + Buffer,
> + sizeof (ATA_IDENTIFY_DATA),
> + ATA_TIMEOUT
> + );
> +
> + return Status;
> +}
> +
> +/**
> + Allocate transfer-related data struct which is used at AHCI mode.
> +
> + @param[in, out] AhciContext The pointer to the AHCI_CONTEXT.
> +
> + @retval EFI_OUT_OF_RESOURCE No enough resource.
> + @retval EFI_SUCCESS Successful to allocate resource.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciAllocateResource (
> + IN OUT AHCI_CONTEXT *AhciContext
> + )
> +{
> + EFI_STATUS Status;
> + EFI_AHCI_REGISTERS *AhciRegisters;
> + EFI_PHYSICAL_ADDRESS DeviceAddress;
> + VOID *Base;
> + VOID *Mapping;
> +
> + AhciRegisters = &AhciContext->AhciRegisters;
> +
> + //
> + // Allocate resources required by AHCI host controller.
> + //
> + Status = IoMmuAllocateBuffer (
> + EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
> + &Base,
> + &DeviceAddress,
> + &Mapping
> + );
> + if (EFI_ERROR (Status)) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> + ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
> + AhciRegisters->AhciRFisMapping = Mapping;
> + AhciRegisters->AhciRFis = Base;
> + ZeroMem (AhciRegisters->AhciRFis, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES
> (sizeof (EFI_AHCI_RECEIVED_FIS)));
> +
> + Status = IoMmuAllocateBuffer (
> + EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),
> + &Base,
> + &DeviceAddress,
> + &Mapping
> + );
> + if (EFI_ERROR (Status)) {
> + IoMmuFreeBuffer (
> + EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
> + AhciRegisters->AhciRFis,
> + AhciRegisters->AhciRFisMapping
> + );
> + AhciRegisters->AhciRFis = NULL;
> + return EFI_OUT_OF_RESOURCES;
> + }
> + ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
> + AhciRegisters->AhciCmdListMapping = Mapping;
> + AhciRegisters->AhciCmdList = Base;
> + ZeroMem (AhciRegisters->AhciCmdList, EFI_PAGE_SIZE *
> EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)));
> +
> + Status = IoMmuAllocateBuffer (
> + EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)),
> + &Base,
> + &DeviceAddress,
> + &Mapping
> + );
> + if (EFI_ERROR (Status)) {
> + IoMmuFreeBuffer (
> + EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
> + AhciRegisters->AhciRFis,
> + AhciRegisters->AhciRFisMapping
> + );
> + AhciRegisters->AhciRFis = NULL;
> + IoMmuFreeBuffer (
> + EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),
> + AhciRegisters->AhciCmdList,
> + AhciRegisters->AhciCmdListMapping
> + );
> + AhciRegisters->AhciCmdList = NULL;
> + return EFI_OUT_OF_RESOURCES;
> + }
> + ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
> + AhciRegisters->AhciCommandTableMapping = Mapping;
> + AhciRegisters->AhciCommandTable = Base;
> + ZeroMem (AhciRegisters->AhciCommandTable, EFI_PAGE_SIZE *
> EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)));
> +
> + //
> + // Allocate resources for data transfer.
> + //
> + Status = IoMmuAllocateBuffer (
> + EFI_SIZE_TO_PAGES (HDD_PAYLOAD),
> + &Base,
> + &DeviceAddress,
> + &Mapping
> + );
> + if (EFI_ERROR (Status)) {
> + IoMmuFreeBuffer (
> + EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
> + AhciRegisters->AhciRFis,
> + AhciRegisters->AhciRFisMapping
> + );
> + AhciRegisters->AhciRFis = NULL;
> + IoMmuFreeBuffer (
> + EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),
> + AhciRegisters->AhciCmdList,
> + AhciRegisters->AhciCmdListMapping
> + );
> + AhciRegisters->AhciCmdList = NULL;
> + IoMmuFreeBuffer (
> + EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
> + AhciRegisters->AhciCommandTable,
> + AhciRegisters->AhciCommandTableMapping
> + );
> + AhciRegisters->AhciCommandTable = NULL;
> +
> + return EFI_OUT_OF_RESOURCES;
> + }
> + ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
> + AhciContext->BufferMapping = Mapping;
> + AhciContext->Buffer = Base;
> + ZeroMem (AhciContext->Buffer, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES
> (HDD_PAYLOAD));
> +
> + DEBUG ((
> + DEBUG_INFO,
> + "%a() AhciContext 0x%x 0x%x 0x%x 0x%x\n",
> + __FUNCTION__,
> + AhciContext->Buffer,
> + AhciRegisters->AhciRFis,
> + AhciRegisters->AhciCmdList,
> + AhciRegisters->AhciCommandTable
> + ));
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Free allocated transfer-related data struct which is used at AHCI mode.
> +
> + @param[in, out] AhciContext The pointer to the AHCI_CONTEXT.
> +
> +**/
> +VOID
> +EFIAPI
> +AhciFreeResource (
> + IN OUT AHCI_CONTEXT *AhciContext
> + )
> +{
> + EFI_AHCI_REGISTERS *AhciRegisters;
> +
> + AhciRegisters = &AhciContext->AhciRegisters;
> +
> + if (AhciRegisters->AhciRFis != NULL) {
> + IoMmuFreeBuffer (
> + EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
> + AhciRegisters->AhciRFis,
> + AhciRegisters->AhciRFisMapping
> + );
> + AhciRegisters->AhciRFis = NULL;
> + }
> +
> + if (AhciRegisters->AhciCmdList != NULL) {
> + IoMmuFreeBuffer (
> + EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),
> + AhciRegisters->AhciCmdList,
> + AhciRegisters->AhciCmdListMapping
> + );
> + AhciRegisters->AhciCmdList = NULL;
> + }
> +
> + if (AhciRegisters->AhciCommandTable != NULL) {
> + IoMmuFreeBuffer (
> + EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)),
> + AhciRegisters->AhciCommandTable,
> + AhciRegisters->AhciCommandTableMapping
> + );
> + AhciRegisters->AhciCommandTable = NULL;
> + }
> +
> + if (AhciContext->Buffer != NULL) {
> + IoMmuFreeBuffer (
> + EFI_SIZE_TO_PAGES (HDD_PAYLOAD),
> + AhciContext->Buffer,
> + AhciContext->BufferMapping
> + );
> + AhciContext->Buffer = NULL;
> + }
> +}
> +
> +/**
> + Initialize ATA host controller at AHCI mode.
> +
> + The function is designed to initialize ATA host controller.
> +
> + @param[in] AhciContext The pointer to the AHCI_CONTEXT.
> + @param[in] Port The port number to do initialization.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciModeInitialize (
> + IN AHCI_CONTEXT *AhciContext,
> + IN UINT8 Port
> + )
> +{
> + EFI_STATUS Status;
> + EFI_AHCI_REGISTERS *AhciRegisters;
> + UINT32 AhciBar;
> + UINT32 Capability;
> + UINT32 Offset;
> + UINT32 Data;
> + UINT32 PhyDetectDelay;
> +
> + AhciRegisters = &AhciContext->AhciRegisters;
> + AhciBar = AhciContext->AhciBar;
> +
> + Status = AhciReset (AhciBar, ATA_TIMEOUT);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + //
> + // Collect AHCI controller information
> + //
> + Capability = AhciReadReg (AhciBar, EFI_AHCI_CAPABILITY_OFFSET);
> +
> + //
> + // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only
> is not set
> + //
> + if ((Capability & EFI_AHCI_CAP_SAM) == 0) {
> + AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);
> + }
> +
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_FB;
> + AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciRFis);
> +
> + //
> + // Single task envrionment, we only use one command table for all port
> + //
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_CLB;
> + AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciCmdList);
> +
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_CMD;
> + Data = AhciReadReg (AhciBar, Offset);
> + if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) {
> + AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_POD);
> + }
> +
> + if ((Capability & BIT27) != 0) {
> + AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_SUD);
> + }
> +
> + //
> + // Disable aggressive power management.
> + //
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_SCTL;
> + AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_SCTL_IPM_INIT);
> + //
> + // Disable the reporting of the corresponding interrupt to system software.
> + //
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_IE;
> + AhciAndReg (AhciBar, Offset, 0);
> +
> + Status = AhciEnableFisReceive (
> + AhciBar,
> + Port,
> + 5000000
> + );
> + ASSERT_EFI_ERROR (Status);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + //
> + // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY
> and PxTFD.DRQ
> + // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined
> at ATA spec.
> + //
> + PhyDetectDelay = 16 * 1000;
> + do {
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_SERR;
> + if (AhciReadReg(AhciBar, Offset) != 0) {
> + AhciWriteReg (AhciBar, Offset, AhciReadReg(AhciBar, Offset));
> + }
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_TFD;
> +
> + Data = AhciReadReg (AhciBar, Offset) & EFI_AHCI_PORT_TFD_MASK;
> + if (Data == 0) {
> + break;
> + }
> +
> + MicroSecondDelay (1000);
> + PhyDetectDelay--;
> + } while (PhyDetectDelay > 0);
> +
> + if (PhyDetectDelay == 0) {
> + return EFI_NOT_FOUND;
> + }
> +
> + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH +
> EFI_AHCI_PORT_SIG;
> + Status = AhciWaitMmioSet (
> + AhciBar,
> + Offset,
> + 0x0000FFFF,
> + 0x00000101,
> + 160000000
> + );
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + return Status;
> +}
> +
> diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.h
> b/SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.h
> new file mode 100644
> index 000000000000..b1d6ed13d5b9
> --- /dev/null
> +++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.h
> @@ -0,0 +1,435 @@
> +/** @file
> + Header file for AHCI mode of ATA host controller.
> +
> +Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution. The full text of the license may be found
> at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +
> +
> +#ifndef __OPAL_PASSWORD_AHCI_MODE_H__
> +#define __OPAL_PASSWORD_AHCI_MODE_H__
> +
> +//
> +// OPAL LIBRARY CALLBACKS
> +//
> +#define ATA_COMMAND_TRUSTED_RECEIVE 0x5C
> +#define ATA_COMMAND_TRUSTED_SEND 0x5E
> +
> +//
> +// ATA TRUSTED commands express transfer Length in 512 byte multiple
> +//
> +#define ATA_TRUSTED_TRANSFER_LENGTH_MULTIPLE 512
> +#define ATA_DEVICE_LBA 0x40 ///< Set for
> commands with LBA (rather than CHS) addresses
> +
> +
> +#define EFI_AHCI_BAR_INDEX 0x05
> +
> +#define EFI_AHCI_CAPABILITY_OFFSET 0x0000
> +#define EFI_AHCI_CAP_SAM BIT18
> +#define EFI_AHCI_GHC_OFFSET 0x0004
> +#define EFI_AHCI_GHC_RESET BIT0
> +#define EFI_AHCI_GHC_IE BIT1
> +#define EFI_AHCI_GHC_ENABLE BIT31
> +#define EFI_AHCI_IS_OFFSET 0x0008
> +#define EFI_AHCI_PI_OFFSET 0x000C
> +
> +typedef struct {
> + UINT32 Lower32;
> + UINT32 Upper32;
> +} DATA_32;
> +
> +typedef union {
> + DATA_32 Uint32;
> + UINT64 Uint64;
> +} DATA_64;
> +
> +//
> +// Each PRDT entry can point to a memory block up to 4M byte
> +//
> +#define EFI_AHCI_MAX_DATA_PER_PRDT 0x400000
> +
> +#define EFI_AHCI_FIS_REGISTER_H2D 0x27 //Register
> FIS - Host to Device
> +#define EFI_AHCI_FIS_REGISTER_H2D_LENGTH 20
> +#define EFI_AHCI_FIS_REGISTER_D2H 0x34 //Register
> FIS - Device to Host
> +#define EFI_AHCI_FIS_REGISTER_D2H_LENGTH 20
> +#define EFI_AHCI_FIS_DMA_ACTIVATE 0x39 //DMA
> Activate FIS - Device to Host
> +#define EFI_AHCI_FIS_DMA_ACTIVATE_LENGTH 4
> +#define EFI_AHCI_FIS_DMA_SETUP 0x41 //DMA
> Setup FIS - Bi-directional
> +#define EFI_AHCI_FIS_DMA_SETUP_LENGTH 28
> +#define EFI_AHCI_FIS_DATA 0x46 //Data FIS -
> Bi-directional
> +#define EFI_AHCI_FIS_BIST 0x58 //BIST
> Activate FIS - Bi-directional
> +#define EFI_AHCI_FIS_BIST_LENGTH 12
> +#define EFI_AHCI_FIS_PIO_SETUP 0x5F //PIO Setup
> FIS - Device to Host
> +#define EFI_AHCI_FIS_PIO_SETUP_LENGTH 20
> +#define EFI_AHCI_FIS_SET_DEVICE 0xA1 //Set Device
> Bits FIS - Device to Host
> +#define EFI_AHCI_FIS_SET_DEVICE_LENGTH 8
> +
> +#define EFI_AHCI_D2H_FIS_OFFSET 0x40
> +#define EFI_AHCI_DMA_FIS_OFFSET 0x00
> +#define EFI_AHCI_PIO_FIS_OFFSET 0x20
> +#define EFI_AHCI_SDB_FIS_OFFSET 0x58
> +#define EFI_AHCI_FIS_TYPE_MASK 0xFF
> +#define EFI_AHCI_U_FIS_OFFSET 0x60
> +
> +//
> +// Port register
> +//
> +#define EFI_AHCI_PORT_START 0x0100
> +#define EFI_AHCI_PORT_REG_WIDTH 0x0080
> +#define EFI_AHCI_PORT_CLB 0x0000
> +#define EFI_AHCI_PORT_CLBU 0x0004
> +#define EFI_AHCI_PORT_FB 0x0008
> +#define EFI_AHCI_PORT_FBU 0x000C
> +#define EFI_AHCI_PORT_IS 0x0010
> +#define EFI_AHCI_PORT_IS_DHRS BIT0
> +#define EFI_AHCI_PORT_IS_PSS BIT1
> +#define EFI_AHCI_PORT_IS_SSS BIT2
> +#define EFI_AHCI_PORT_IS_SDBS BIT3
> +#define EFI_AHCI_PORT_IS_UFS BIT4
> +#define EFI_AHCI_PORT_IS_DPS BIT5
> +#define EFI_AHCI_PORT_IS_PCS BIT6
> +#define EFI_AHCI_PORT_IS_DIS BIT7
> +#define EFI_AHCI_PORT_IS_PRCS BIT22
> +#define EFI_AHCI_PORT_IS_IPMS BIT23
> +#define EFI_AHCI_PORT_IS_OFS BIT24
> +#define EFI_AHCI_PORT_IS_INFS BIT26
> +#define EFI_AHCI_PORT_IS_IFS BIT27
> +#define EFI_AHCI_PORT_IS_HBDS BIT28
> +#define EFI_AHCI_PORT_IS_HBFS BIT29
> +#define EFI_AHCI_PORT_IS_TFES BIT30
> +#define EFI_AHCI_PORT_IS_CPDS BIT31
> +#define EFI_AHCI_PORT_IS_CLEAR 0xFFFFFFFF
> +#define EFI_AHCI_PORT_IS_FIS_CLEAR 0x0000000F
> +
> +#define EFI_AHCI_PORT_IE 0x0014
> +#define EFI_AHCI_PORT_CMD 0x0018
> +#define EFI_AHCI_PORT_CMD_ST_MASK 0xFFFFFFFE
> +#define EFI_AHCI_PORT_CMD_ST BIT0
> +#define EFI_AHCI_PORT_CMD_SUD BIT1
> +#define EFI_AHCI_PORT_CMD_POD BIT2
> +#define EFI_AHCI_PORT_CMD_COL BIT3
> +#define EFI_AHCI_PORT_CMD_CR BIT15
> +#define EFI_AHCI_PORT_CMD_FRE BIT4
> +#define EFI_AHCI_PORT_CMD_FR BIT14
> +#define EFI_AHCI_PORT_CMD_MASK
> ~(EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_FRE |
> EFI_AHCI_PORT_CMD_COL)
> +#define EFI_AHCI_PORT_CMD_PMA BIT17
> +#define EFI_AHCI_PORT_CMD_HPCP BIT18
> +#define EFI_AHCI_PORT_CMD_MPSP BIT19
> +#define EFI_AHCI_PORT_CMD_CPD BIT20
> +#define EFI_AHCI_PORT_CMD_ESP BIT21
> +#define EFI_AHCI_PORT_CMD_ATAPI BIT24
> +#define EFI_AHCI_PORT_CMD_DLAE BIT25
> +#define EFI_AHCI_PORT_CMD_ALPE BIT26
> +#define EFI_AHCI_PORT_CMD_ASP BIT27
> +#define EFI_AHCI_PORT_CMD_ICC_MASK (BIT28 | BIT29 |
> BIT30 | BIT31)
> +#define EFI_AHCI_PORT_CMD_ACTIVE (1 << 28 )
> +#define EFI_AHCI_PORT_TFD 0x0020
> +#define EFI_AHCI_PORT_TFD_MASK (BIT7 | BIT3 | BIT0)
> +#define EFI_AHCI_PORT_TFD_BSY BIT7
> +#define EFI_AHCI_PORT_TFD_DRQ BIT3
> +#define EFI_AHCI_PORT_TFD_ERR BIT0
> +#define EFI_AHCI_PORT_TFD_ERR_MASK 0x00FF00
> +#define EFI_AHCI_PORT_SIG 0x0024
> +#define EFI_AHCI_PORT_SSTS 0x0028
> +#define EFI_AHCI_PORT_SSTS_DET_MASK 0x000F
> +#define EFI_AHCI_PORT_SSTS_DET 0x0001
> +#define EFI_AHCI_PORT_SSTS_DET_PCE 0x0003
> +#define EFI_AHCI_PORT_SSTS_SPD_MASK 0x00F0
> +#define EFI_AHCI_PORT_SCTL 0x002C
> +#define EFI_AHCI_PORT_SCTL_DET_MASK 0x000F
> +#define EFI_AHCI_PORT_SCTL_MASK
> (~EFI_AHCI_PORT_SCTL_DET_MASK)
> +#define EFI_AHCI_PORT_SCTL_DET_INIT 0x0001
> +#define EFI_AHCI_PORT_SCTL_DET_PHYCOMM 0x0003
> +#define EFI_AHCI_PORT_SCTL_SPD_MASK 0x00F0
> +#define EFI_AHCI_PORT_SCTL_IPM_MASK 0x0F00
> +#define EFI_AHCI_PORT_SCTL_IPM_INIT 0x0300
> +#define EFI_AHCI_PORT_SCTL_IPM_PSD 0x0100
> +#define EFI_AHCI_PORT_SCTL_IPM_SSD 0x0200
> +#define EFI_AHCI_PORT_SERR 0x0030
> +#define EFI_AHCI_PORT_SERR_RDIE BIT0
> +#define EFI_AHCI_PORT_SERR_RCE BIT1
> +#define EFI_AHCI_PORT_SERR_TDIE BIT8
> +#define EFI_AHCI_PORT_SERR_PCDIE BIT9
> +#define EFI_AHCI_PORT_SERR_PE BIT10
> +#define EFI_AHCI_PORT_SERR_IE BIT11
> +#define EFI_AHCI_PORT_SERR_PRC BIT16
> +#define EFI_AHCI_PORT_SERR_PIE BIT17
> +#define EFI_AHCI_PORT_SERR_CW BIT18
> +#define EFI_AHCI_PORT_SERR_BDE BIT19
> +#define EFI_AHCI_PORT_SERR_DE BIT20
> +#define EFI_AHCI_PORT_SERR_CRCE BIT21
> +#define EFI_AHCI_PORT_SERR_HE BIT22
> +#define EFI_AHCI_PORT_SERR_LSE BIT23
> +#define EFI_AHCI_PORT_SERR_TSTE BIT24
> +#define EFI_AHCI_PORT_SERR_UFT BIT25
> +#define EFI_AHCI_PORT_SERR_EX BIT26
> +#define EFI_AHCI_PORT_ERR_CLEAR 0xFFFFFFFF
> +#define EFI_AHCI_PORT_SACT 0x0034
> +#define EFI_AHCI_PORT_CI 0x0038
> +#define EFI_AHCI_PORT_SNTF 0x003C
> +
> +
> +#pragma pack(1)
> +//
> +// Command List structure includes total 32 entries.
> +// The entry Data structure is listed at the following.
> +//
> +typedef struct {
> + UINT32 AhciCmdCfl:5; //Command FIS Length
> + UINT32 AhciCmdA:1; //ATAPI
> + UINT32 AhciCmdW:1; //Write
> + UINT32 AhciCmdP:1; //Prefetchable
> + UINT32 AhciCmdR:1; //Reset
> + UINT32 AhciCmdB:1; //BIST
> + UINT32 AhciCmdC:1; //Clear Busy upon R_OK
> + UINT32 AhciCmdRsvd:1;
> + UINT32 AhciCmdPmp:4; //Port Multiplier Port
> + UINT32 AhciCmdPrdtl:16; //Physical Region Descriptor Table Length
> + UINT32 AhciCmdPrdbc; //Physical Region Descriptor Byte Count
> + UINT32 AhciCmdCtba; //Command Table Descriptor Base Address
> + UINT32 AhciCmdCtbau; //Command Table Descriptor Base Address
> Upper 32-BITs
> + UINT32 AhciCmdRsvd1[4];
> +} EFI_AHCI_COMMAND_LIST;
> +
> +//
> +// This is a software constructed FIS.
> +// For Data transfer operations, this is the H2D Register FIS format as
> +// specified in the Serial ATA Revision 2.6 specification.
> +//
> +typedef struct {
> + UINT8 AhciCFisType;
> + UINT8 AhciCFisPmNum:4;
> + UINT8 AhciCFisRsvd:1;
> + UINT8 AhciCFisRsvd1:1;
> + UINT8 AhciCFisRsvd2:1;
> + UINT8 AhciCFisCmdInd:1;
> + UINT8 AhciCFisCmd;
> + UINT8 AhciCFisFeature;
> + UINT8 AhciCFisSecNum;
> + UINT8 AhciCFisClyLow;
> + UINT8 AhciCFisClyHigh;
> + UINT8 AhciCFisDevHead;
> + UINT8 AhciCFisSecNumExp;
> + UINT8 AhciCFisClyLowExp;
> + UINT8 AhciCFisClyHighExp;
> + UINT8 AhciCFisFeatureExp;
> + UINT8 AhciCFisSecCount;
> + UINT8 AhciCFisSecCountExp;
> + UINT8 AhciCFisRsvd3;
> + UINT8 AhciCFisControl;
> + UINT8 AhciCFisRsvd4[4];
> + UINT8 AhciCFisRsvd5[44];
> +} EFI_AHCI_COMMAND_FIS;
> +
> +//
> +// ACMD: ATAPI command (12 or 16 bytes)
> +//
> +typedef struct {
> + UINT8 AtapiCmd[0x10];
> +} EFI_AHCI_ATAPI_COMMAND;
> +
> +//
> +// Physical Region Descriptor Table includes up to 65535 entries
> +// The entry Data structure is listed at the following.
> +// the actual entry number comes from the PRDTL field in the command
> +// list entry for this command slot.
> +//
> +typedef struct {
> + UINT32 AhciPrdtDba; //Data Base Address
> + UINT32 AhciPrdtDbau; //Data Base Address Upper 32-BITs
> + UINT32 AhciPrdtRsvd;
> + UINT32 AhciPrdtDbc:22; //Data Byte Count
> + UINT32 AhciPrdtRsvd1:9;
> + UINT32 AhciPrdtIoc:1; //Interrupt on Completion
> +} EFI_AHCI_COMMAND_PRDT;
> +
> +//
> +// Command table Data strucute which is pointed to by the entry in the
> command list
> +//
> +typedef struct {
> + EFI_AHCI_COMMAND_FIS CommandFis; // A software
> constructed FIS.
> + EFI_AHCI_ATAPI_COMMAND AtapiCmd; // 12 or 16 bytes
> ATAPI cmd.
> + UINT8 Reserved[0x30];
> + EFI_AHCI_COMMAND_PRDT PrdtTable; // The scatter/gather list
> for Data transfer
> +} EFI_AHCI_COMMAND_TABLE;
> +
> +//
> +// Received FIS structure
> +//
> +typedef struct {
> + UINT8 AhciDmaSetupFis[0x1C]; // Dma Setup Fis: offset 0x00
> + UINT8 AhciDmaSetupFisRsvd[0x04];
> + UINT8 AhciPioSetupFis[0x14]; // Pio Setup Fis: offset 0x20
> + UINT8 AhciPioSetupFisRsvd[0x0C];
> + UINT8 AhciD2HRegisterFis[0x14]; // D2H Register Fis: offset 0x40
> + UINT8 AhciD2HRegisterFisRsvd[0x04];
> + UINT64 AhciSetDeviceBitsFis; // Set Device Bits Fix: offset 0x58
> + UINT8 AhciUnknownFis[0x40]; // Unkonwn Fis: offset 0x60
> + UINT8 AhciUnknownFisRsvd[0x60];
> +} EFI_AHCI_RECEIVED_FIS;
> +
> +#pragma pack()
> +
> +typedef struct {
> + EFI_AHCI_RECEIVED_FIS *AhciRFis;
> + VOID *AhciRFisMapping;
> + EFI_AHCI_COMMAND_LIST *AhciCmdList;
> + VOID *AhciCmdListMapping;
> + EFI_AHCI_COMMAND_TABLE *AhciCommandTable;
> + VOID *AhciCommandTableMapping;
> +} EFI_AHCI_REGISTERS;
> +
> +typedef struct {
> + VOID *Buffer;
> + VOID *BufferMapping;
> + EFI_AHCI_REGISTERS AhciRegisters;
> + UINT32 AhciBar;
> +} AHCI_CONTEXT;
> +
> +/**
> + Send Buffer cmd to specific device.
> +
> + @param AhciContext The pointer to the AHCI_CONTEXT.
> + @param Port The number of port.
> + @param PortMultiplier The timeout Value of stop.
> + @param Buffer The Data Buffer to store IDENTIFY PACKET
> Data.
> +
> + @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
> + @retval EFI_TIMEOUT The operation is time out.
> + @retval EFI_UNSUPPORTED The device is not ready for executing.
> + @retval EFI_SUCCESS The cmd executes successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciIdentify (
> + IN AHCI_CONTEXT *AhciContext,
> + IN UINT8 Port,
> + IN UINT8 PortMultiplier,
> + IN OUT ATA_IDENTIFY_DATA *Buffer
> + );
> +
> +/**
> + Allocate transfer-related data struct which is used at AHCI mode.
> +
> + @param[in, out] AhciContext The pointer to the AHCI_CONTEXT.
> +
> + @retval EFI_OUT_OF_RESOURCE No enough resource.
> + @retval EFI_SUCCESS Successful to allocate resource.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciAllocateResource (
> + IN OUT AHCI_CONTEXT *AhciContext
> + );
> +
> +/**
> + Free allocated transfer-related data struct which is used at AHCI mode.
> +
> + @param[in, out] AhciContext The pointer to the AHCI_CONTEXT.
> +
> +**/
> +VOID
> +EFIAPI
> +AhciFreeResource (
> + IN OUT AHCI_CONTEXT *AhciContext
> + );
> +
> +/**
> + Initialize ATA host controller at AHCI mode.
> +
> + The function is designed to initialize ATA host controller.
> +
> + @param[in] AhciContext The pointer to the AHCI_CONTEXT.
> + @param[in] Port The port number to do initialization.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciModeInitialize (
> + IN AHCI_CONTEXT *AhciContext,
> + IN UINT8 Port
> + );
> +
> +typedef struct _EFI_ATA_COMMAND_BLOCK {
> + UINT8 Reserved1[2];
> + UINT8 AtaCommand;
> + UINT8 AtaFeatures;
> + UINT8 AtaSectorNumber;
> + UINT8 AtaCylinderLow;
> + UINT8 AtaCylinderHigh;
> + UINT8 AtaDeviceHead;
> + UINT8 AtaSectorNumberExp;
> + UINT8 AtaCylinderLowExp;
> + UINT8 AtaCylinderHighExp;
> + UINT8 AtaFeaturesExp;
> + UINT8 AtaSectorCount;
> + UINT8 AtaSectorCountExp;
> + UINT8 Reserved2[6];
> +} EFI_ATA_COMMAND_BLOCK;
> +
> +typedef struct _EFI_ATA_STATUS_BLOCK {
> + UINT8 Reserved1[2];
> + UINT8 AtaStatus;
> + UINT8 AtaError;
> + UINT8 AtaSectorNumber;
> + UINT8 AtaCylinderLow;
> + UINT8 AtaCylinderHigh;
> + UINT8 AtaDeviceHead;
> + UINT8 AtaSectorNumberExp;
> + UINT8 AtaCylinderLowExp;
> + UINT8 AtaCylinderHighExp;
> + UINT8 Reserved2;
> + UINT8 AtaSectorCount;
> + UINT8 AtaSectorCountExp;
> + UINT8 Reserved3[6];
> +} EFI_ATA_STATUS_BLOCK;
> +
> +/**
> + Start a PIO Data transfer on specific port.
> +
> + @param AhciContext The pointer to the AHCI_CONTEXT.
> + @param Port The number of port.
> + @param PortMultiplier The timeout Value of stop.
> + @param AtapiCommand The atapi command will be used for the
> transfer.
> + @param AtapiCommandLength The Length of the atapi command.
> + @param Read The transfer direction.
> + @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK Data.
> + @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK Data.
> + @param MemoryAddr The pointer to the Data Buffer.
> + @param DataCount The Data count to be transferred.
> + @param Timeout The timeout Value of non Data transfer.
> +
> + @retval EFI_DEVICE_ERROR The PIO Data transfer abort with error
> occurs.
> + @retval EFI_TIMEOUT The operation is time out.
> + @retval EFI_UNSUPPORTED The device is not ready for transfer.
> + @retval EFI_SUCCESS The PIO Data transfer executes successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciPioTransfer (
> + IN AHCI_CONTEXT *AhciContext,
> + IN UINT8 Port,
> + IN UINT8 PortMultiplier,
> + IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,
> + IN UINT8 AtapiCommandLength,
> + IN BOOLEAN Read,
> + IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
> + IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
> + IN OUT VOID *MemoryAddr,
> + IN UINT32 DataCount,
> + IN UINT64 Timeout
> + );
> +
> +
> +#endif
> +
> diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c
> b/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c
> new file mode 100644
> index 000000000000..62a71d9f440f
> --- /dev/null
> +++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c
> @@ -0,0 +1,3003 @@
> +/** @file
> + Entrypoint of Opal UEFI Driver and contains all the logic to
> + register for new Opal device instances.
> +
> +Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution. The full text of the license may be found
> at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +
> +// This UEFI driver consumes EFI_STORAGE_SECURITY_PROTOCOL instances
> and installs an
> +// HII GUI to manage Opal features if the device is Opal capable
> +// If the Opal device is being managed by the UEFI Driver, it shall provide a
> popup
> +// window during boot requesting a user password
> +
> +#include "OpalDriver.h"
> +#include "OpalHii.h"
> +
> +EFI_GUID mOpalDeviceAtaGuid = OPAL_DEVICE_ATA_GUID;
> +EFI_GUID mOpalDeviceNvmeGuid = OPAL_DEVICE_NVME_GUID;
> +
> +BOOLEAN mOpalEndOfDxe = FALSE;
> +OPAL_REQUEST_VARIABLE *mOpalRequestVariable = NULL;
> +UINTN mOpalRequestVariableSize = 0;
> +CHAR16 mPopUpString[256];
> +
> +typedef struct {
> + UINT32 Address;
> + S3_BOOT_SCRIPT_LIB_WIDTH Width;
> +} OPAL_HC_PCI_REGISTER_SAVE;
> +
> +//
> +// To unlock the Intel SATA controller at S3 Resume, restored the following
> registers.
> +//
> +const OPAL_HC_PCI_REGISTER_SAVE mSataHcRegisterSaveTemplate[] = {
> + {0x9, S3BootScriptWidthUint8},
> + {0x10, S3BootScriptWidthUint32},
> + {0x14, S3BootScriptWidthUint32},
> + {0x18, S3BootScriptWidthUint32},
> + {0x1C, S3BootScriptWidthUint32},
> + {0x20, S3BootScriptWidthUint32},
> + {0x24, S3BootScriptWidthUint32},
> + {0x3c, S3BootScriptWidthUint8},
> + {0x3d, S3BootScriptWidthUint8},
> + {0x40, S3BootScriptWidthUint16},
> + {0x42, S3BootScriptWidthUint16},
> + {0x92, S3BootScriptWidthUint16},
> + {0x94, S3BootScriptWidthUint32},
> + {0x9C, S3BootScriptWidthUint32},
> + {0x4, S3BootScriptWidthUint16},
> +};
> +
> +OPAL_DRIVER mOpalDriver;
> +
> +//
> +// Globals
> +//
> +EFI_DRIVER_BINDING_PROTOCOL gOpalDriverBinding = {
> + OpalEfiDriverBindingSupported,
> + OpalEfiDriverBindingStart,
> + OpalEfiDriverBindingStop,
> + 0x1b,
> + NULL,
> + NULL
> +};
> +
> +/**
> +
> + The function determines the available actions for the OPAL_DISK provided.
> +
> + @param[in] SupportedAttributes The supported attributes for the
> device.
> + @param[in] LockingFeature The locking status for the device.
> + @param[in] OwnerShip The ownership for the device.
> + @param[out] AvalDiskActions Pointer to fill-out with appropriate
> disk actions.
> +
> +**/
> +TCG_RESULT
> +EFIAPI
> +OpalSupportGetAvailableActions(
> + IN OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes,
> + IN TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature,
> + IN UINT16 OwnerShip,
> + OUT OPAL_DISK_ACTIONS *AvalDiskActions
> + )
> +{
> + BOOLEAN ExistingPassword;
> +
> + NULL_CHECK(AvalDiskActions);
> +
> + AvalDiskActions->AdminPass = 1;
> + AvalDiskActions->UserPass = 0;
> + AvalDiskActions->DisableUser = 0;
> + AvalDiskActions->Unlock = 0;
> +
> + //
> + // Revert is performed on locking sp, so only allow if locking sp is enabled
> + //
> + if (LockingFeature->LockingEnabled) {
> + AvalDiskActions->Revert = 1;
> + }
> +
> + //
> + // Psid revert is available for any device with media encryption support
> + // Revert is allowed for any device with media encryption support, however
> it requires
> + //
> + if (SupportedAttributes->MediaEncryption) {
> +
> + //
> + // Only allow psid revert if media encryption is enabled.
> + // Otherwise, someone who steals a disk can psid revert the disk and the
> user Data is still
> + // intact and accessible
> + //
> + AvalDiskActions->PsidRevert = 1;
> + AvalDiskActions->RevertKeepDataForced = 0;
> +
> + //
> + // Secure erase is performed by generating a new encryption key
> + // this is only available if encryption is supported
> + //
> + AvalDiskActions->SecureErase = 1;
> + } else {
> + AvalDiskActions->PsidRevert = 0;
> + AvalDiskActions->SecureErase = 0;
> +
> + //
> + // If no media encryption is supported, then a revert (using password) will
> not
> + // erase the Data (since you can't generate a new encryption key)
> + //
> + AvalDiskActions->RevertKeepDataForced = 1;
> + }
> +
> + if (LockingFeature->Locked) {
> + AvalDiskActions->Unlock = 1;
> + } else {
> + AvalDiskActions->Unlock = 0;
> + }
> +
> + //
> + // Only allow user to set password if an admin password exists
> + //
> + ExistingPassword = OpalUtilAdminPasswordExists(OwnerShip,
> LockingFeature);
> + AvalDiskActions->UserPass = ExistingPassword;
> +
> + //
> + // This will still show up even if there isn't a user, which is fine
> + //
> + AvalDiskActions->DisableUser = ExistingPassword;
> +
> + return TcgResultSuccess;
> +}
> +
> +/**
> + Enable Opal Feature for the input device.
> +
> + @param[in] Session The opal session for the opal device.
> + @param[in] Msid Msid
> + @param[in] MsidLength Msid Length
> + @param[in] Password Admin password
> + @param[in] PassLength Length of password in bytes
> +
> +**/
> +TCG_RESULT
> +EFIAPI
> +OpalSupportEnableOpalFeature (
> + IN OPAL_SESSION *Session,
> + IN VOID *Msid,
> + IN UINT32 MsidLength,
> + IN VOID *Password,
> + IN UINT32 PassLength
> + )
> +{
> + TCG_RESULT Ret;
> +
> + NULL_CHECK(Session);
> + NULL_CHECK(Msid);
> + NULL_CHECK(Password);
> +
> + Ret = OpalUtilSetAdminPasswordAsSid(
> + Session,
> + Msid,
> + MsidLength,
> + Password,
> + PassLength
> + );
> + if (Ret == TcgResultSuccess) {
> + //
> + // Enable global locking range
> + //
> + Ret = OpalUtilSetOpalLockingRange(
> + Session,
> + Password,
> + PassLength,
> +
> OPAL_LOCKING_SP_LOCKING_GLOBALRANGE,
> + 0,
> + 0,
> + TRUE,
> + TRUE,
> + FALSE,
> + FALSE
> + );
> + }
> +
> + return Ret;
> +}
> +
> +/**
> + Update password for the Opal disk.
> +
> + @param[in, out] OpalDisk The disk to update password.
> + @param[in] Password The input password.
> + @param[in] PasswordLength The input password length.
> +
> +**/
> +VOID
> +OpalSupportUpdatePassword (
> + IN OUT OPAL_DISK *OpalDisk,
> + IN VOID *Password,
> + IN UINT32 PasswordLength
> + )
> +{
> + CopyMem (OpalDisk->Password, Password, PasswordLength);
> + OpalDisk->PasswordLength = (UINT8) PasswordLength;
> +}
> +
> +/**
> + Extract device info from the device path.
> +
> + @param[in] DevicePath Device path info for the device.
> + @param[out] DevInfoLength Device information length needed.
> + @param[out] DevInfo Device information extracted.
> +
> + @return Device type.
> +
> +**/
> +UINT8
> +ExtractDeviceInfoFromDevicePath (
> + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
> + OUT UINT16 *DevInfoLength,
> + OUT OPAL_DEVICE_COMMON *DevInfo OPTIONAL
> + )
> +{
> + EFI_DEVICE_PATH_PROTOCOL *TmpDevPath;
> + EFI_DEVICE_PATH_PROTOCOL *TmpDevPath2;
> + PCI_DEVICE_PATH *PciDevPath;
> + UINT8 DeviceType;
> + UINT8 BusNum;
> + OPAL_PCI_DEVICE *PciDevice;
> + OPAL_DEVICE_ATA *DevInfoAta;
> + OPAL_DEVICE_NVME *DevInfoNvme;
> + SATA_DEVICE_PATH *SataDevPath;
> + NVME_NAMESPACE_DEVICE_PATH *NvmeDevPath;
> +
> + ASSERT (DevicePath != NULL);
> + ASSERT (DevInfoLength != NULL);
> +
> + DeviceType = OPAL_DEVICE_TYPE_UNKNOWN;
> + *DevInfoLength = 0;
> +
> + TmpDevPath = DevicePath;
> +
> + //
> + // Get device type.
> + //
> + while (!IsDevicePathEnd (TmpDevPath)) {
> + if (TmpDevPath->Type == MESSAGING_DEVICE_PATH &&
> TmpDevPath->SubType == MSG_SATA_DP) {
> + //
> + // SATA
> + //
> + if (DevInfo != NULL) {
> + SataDevPath = (SATA_DEVICE_PATH *) TmpDevPath;
> + DevInfoAta = (OPAL_DEVICE_ATA *) DevInfo;
> + DevInfoAta->Port = SataDevPath->HBAPortNumber;
> + DevInfoAta->PortMultiplierPort =
> SataDevPath->PortMultiplierPortNumber;
> + }
> + DeviceType = OPAL_DEVICE_TYPE_ATA;
> + *DevInfoLength = sizeof (OPAL_DEVICE_ATA);
> + break;
> + } else if (TmpDevPath->Type == MESSAGING_DEVICE_PATH &&
> TmpDevPath->SubType == MSG_NVME_NAMESPACE_DP) {
> + //
> + // NVMe
> + //
> + if (DevInfo != NULL) {
> + NvmeDevPath = (NVME_NAMESPACE_DEVICE_PATH *) TmpDevPath;
> + DevInfoNvme = (OPAL_DEVICE_NVME *) DevInfo;
> + DevInfoNvme->NvmeNamespaceId = NvmeDevPath->NamespaceId;
> + }
> + DeviceType = OPAL_DEVICE_TYPE_NVME;
> + *DevInfoLength = sizeof (OPAL_DEVICE_NVME);
> + break;
> + }
> + TmpDevPath = NextDevicePathNode (TmpDevPath);
> + }
> +
> + //
> + // Get device info.
> + //
> + BusNum = 0;
> + TmpDevPath = DevicePath;
> + TmpDevPath2 = NextDevicePathNode (DevicePath);
> + while (!IsDevicePathEnd (TmpDevPath2)) {
> + if (TmpDevPath->Type == HARDWARE_DEVICE_PATH &&
> TmpDevPath->SubType == HW_PCI_DP) {
> + PciDevPath = (PCI_DEVICE_PATH *) TmpDevPath;
> + if ((TmpDevPath2->Type == MESSAGING_DEVICE_PATH &&
> TmpDevPath2->SubType == MSG_NVME_NAMESPACE_DP)||
> + (TmpDevPath2->Type == MESSAGING_DEVICE_PATH &&
> TmpDevPath2->SubType == MSG_SATA_DP)) {
> + if (DevInfo != NULL) {
> + PciDevice = &DevInfo->Device;
> + PciDevice->Segment = 0;
> + PciDevice->Bus = BusNum;
> + PciDevice->Device = PciDevPath->Device;
> + PciDevice->Function = PciDevPath->Function;
> + }
> + } else {
> + if (DevInfo != NULL) {
> + PciDevice = (OPAL_PCI_DEVICE *) ((UINTN) DevInfo +
> *DevInfoLength);
> + PciDevice->Segment = 0;
> + PciDevice->Bus = BusNum;
> + PciDevice->Device = PciDevPath->Device;
> + PciDevice->Function = PciDevPath->Function;
> + }
> + *DevInfoLength += sizeof (OPAL_PCI_DEVICE);
> + if (TmpDevPath2->Type == HARDWARE_DEVICE_PATH &&
> TmpDevPath2->SubType == HW_PCI_DP) {
> + BusNum = PciRead8 (PCI_LIB_ADDRESS (BusNum,
> PciDevPath->Device, PciDevPath->Function,
> PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));
> + }
> + }
> + }
> +
> + TmpDevPath = NextDevicePathNode (TmpDevPath);
> + TmpDevPath2 = NextDevicePathNode (TmpDevPath2);
> + }
> +
> + ASSERT (DeviceType != OPAL_DEVICE_TYPE_UNKNOWN);
> + return DeviceType;
> +}
> +
> +/**
> + Save boot script for ATA OPAL device.
> +
> + @param[in] DevInfo Pointer to ATA Opal device information.
> +
> + **/
> +VOID
> +OpalDeviceAtaSaveBootScript (
> + IN OPAL_DEVICE_ATA *DevInfo
> + )
> +{
> + UINTN Bus;
> + UINTN Device;
> + UINTN Function;
> + UINTN Index;
> + EFI_STATUS Status;
> + UINTN Offset;
> + UINT64 Address;
> + S3_BOOT_SCRIPT_LIB_WIDTH Width;
> + UINT32 Data;
> + OPAL_HC_PCI_REGISTER_SAVE *HcRegisterSaveListPtr;
> + UINTN Count;
> +
> + Data = 0;
> +
> + Bus = DevInfo->Device.Bus;
> + Device = DevInfo->Device.Device;
> + Function = DevInfo->Device.Function;
> +
> + HcRegisterSaveListPtr = (OPAL_HC_PCI_REGISTER_SAVE *)
> mSataHcRegisterSaveTemplate;
> + Count = sizeof (mSataHcRegisterSaveTemplate) / sizeof
> (OPAL_HC_PCI_REGISTER_SAVE);
> +
> + for (Index = 0; Index < Count; Index++) {
> + Offset = HcRegisterSaveListPtr[Index].Address;
> + Width = HcRegisterSaveListPtr[Index].Width;
> +
> + switch (Width) {
> + case S3BootScriptWidthUint8:
> + Data = (UINT32)PciRead8
> (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));
> + break;
> + case S3BootScriptWidthUint16:
> + Data = (UINT32)PciRead16
> (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));
> + break;
> + case S3BootScriptWidthUint32:
> + Data = PciRead32 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));
> + break;
> + default:
> + ASSERT (FALSE);
> + break;
> + }
> +
> + Address = S3_BOOT_SCRIPT_LIB_PCI_ADDRESS (Bus, Device, Function,
> Offset);
> + Status = S3BootScriptSavePciCfgWrite (Width, Address, 1, &Data);
> + ASSERT_EFI_ERROR (Status);
> + }
> +}
> +
> +/**
> + Build ATA OPAL device info and save them to LockBox.
> +
> + @param[in] BarAddr Bar address allocated.
> +
> + **/
> +VOID
> +BuildOpalDeviceInfoAta (
> + IN UINT32 BarAddr
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 DeviceType;
> + OPAL_DEVICE_ATA *DevInfoAta;
> + OPAL_DEVICE_ATA *TempDevInfoAta;
> + UINTN DevInfoLengthAta;
> + UINT16 DevInfoLength;
> + OPAL_DRIVER_DEVICE *TmpDev;
> +
> + //
> + // Build ATA OPAL device info and save them to LockBox.
> + //
> + DevInfoLengthAta = 0;
> + TmpDev = mOpalDriver.DeviceList;
> + while (TmpDev != NULL) {
> + DeviceType = ExtractDeviceInfoFromDevicePath (
> + TmpDev->OpalDisk.OpalDevicePath,
> + &DevInfoLength,
> + NULL
> + );
> + if (DeviceType == OPAL_DEVICE_TYPE_ATA) {
> + DevInfoLengthAta += DevInfoLength;
> + }
> +
> + TmpDev = TmpDev->Next;
> + }
> +
> + if (DevInfoLengthAta == 0) {
> + return;
> + }
> +
> + DevInfoAta = AllocateZeroPool (DevInfoLengthAta);
> + ASSERT (DevInfoAta != NULL);
> +
> + TempDevInfoAta = DevInfoAta;
> + TmpDev = mOpalDriver.DeviceList;
> + while (TmpDev != NULL) {
> + DeviceType = ExtractDeviceInfoFromDevicePath (
> + TmpDev->OpalDisk.OpalDevicePath,
> + &DevInfoLength,
> + NULL
> + );
> + if (DeviceType == OPAL_DEVICE_TYPE_ATA) {
> + ExtractDeviceInfoFromDevicePath (
> + TmpDev->OpalDisk.OpalDevicePath,
> + &DevInfoLength,
> + (OPAL_DEVICE_COMMON *) TempDevInfoAta
> + );
> + TempDevInfoAta->Length = DevInfoLength;
> + TempDevInfoAta->OpalBaseComId =
> TmpDev->OpalDisk.OpalBaseComId;
> + TempDevInfoAta->BarAddr = BarAddr;
> + CopyMem (
> + TempDevInfoAta->Password,
> + TmpDev->OpalDisk.Password,
> + TmpDev->OpalDisk.PasswordLength
> + );
> + TempDevInfoAta->PasswordLength =
> TmpDev->OpalDisk.PasswordLength;
> + OpalDeviceAtaSaveBootScript (TempDevInfoAta);
> + TempDevInfoAta = (OPAL_DEVICE_ATA *) ((UINTN) TempDevInfoAta +
> DevInfoLength);
> + }
> +
> + TmpDev = TmpDev->Next;
> + }
> +
> + Status = SaveLockBox (
> + &mOpalDeviceAtaGuid,
> + DevInfoAta,
> + DevInfoLengthAta
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + Status = SetLockBoxAttributes (
> + &mOpalDeviceAtaGuid,
> + LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + ZeroMem (DevInfoAta, DevInfoLengthAta);
> + FreePool (DevInfoAta);
> +}
> +
> +/**
> + Build NVMe OPAL device info and save them to LockBox.
> +
> + @param[in] BarAddr Bar address allocated.
> +
> + **/
> +VOID
> +BuildOpalDeviceInfoNvme (
> + IN UINT32 BarAddr
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 DeviceType;
> + OPAL_DEVICE_NVME *DevInfoNvme;
> + OPAL_DEVICE_NVME *TempDevInfoNvme;
> + UINTN DevInfoLengthNvme;
> + UINT16 DevInfoLength;
> + OPAL_DRIVER_DEVICE *TmpDev;
> +
> + //
> + // Build NVMe OPAL device info and save them to LockBox.
> + //
> + DevInfoLengthNvme = 0;
> + TmpDev = mOpalDriver.DeviceList;
> + while (TmpDev != NULL) {
> + DeviceType = ExtractDeviceInfoFromDevicePath (
> + TmpDev->OpalDisk.OpalDevicePath,
> + &DevInfoLength,
> + NULL
> + );
> + if (DeviceType == OPAL_DEVICE_TYPE_NVME) {
> + DevInfoLengthNvme += DevInfoLength;
> + }
> +
> + TmpDev = TmpDev->Next;
> + }
> +
> + if (DevInfoLengthNvme == 0) {
> + return;
> + }
> +
> + DevInfoNvme = AllocateZeroPool (DevInfoLengthNvme);
> + ASSERT (DevInfoNvme != NULL);
> +
> + TempDevInfoNvme = DevInfoNvme;
> + TmpDev = mOpalDriver.DeviceList;
> + while (TmpDev != NULL) {
> + DeviceType = ExtractDeviceInfoFromDevicePath (
> + TmpDev->OpalDisk.OpalDevicePath,
> + &DevInfoLength,
> + NULL
> + );
> + if (DeviceType == OPAL_DEVICE_TYPE_NVME) {
> + ExtractDeviceInfoFromDevicePath (
> + TmpDev->OpalDisk.OpalDevicePath,
> + &DevInfoLength,
> + (OPAL_DEVICE_COMMON *) TempDevInfoNvme
> + );
> + TempDevInfoNvme->Length = DevInfoLength;
> + TempDevInfoNvme->OpalBaseComId =
> TmpDev->OpalDisk.OpalBaseComId;
> + TempDevInfoNvme->BarAddr = BarAddr;
> + CopyMem (
> + TempDevInfoNvme->Password,
> + TmpDev->OpalDisk.Password,
> + TmpDev->OpalDisk.PasswordLength
> + );
> + TempDevInfoNvme->PasswordLength =
> TmpDev->OpalDisk.PasswordLength;
> + TempDevInfoNvme = (OPAL_DEVICE_NVME *) ((UINTN)
> TempDevInfoNvme + DevInfoLength);
> + }
> +
> + TmpDev = TmpDev->Next;
> + }
> +
> + Status = SaveLockBox (
> + &mOpalDeviceNvmeGuid,
> + DevInfoNvme,
> + DevInfoLengthNvme
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + Status = SetLockBoxAttributes (
> + &mOpalDeviceNvmeGuid,
> + LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + ZeroMem (DevInfoNvme, DevInfoLengthNvme);
> + FreePool (DevInfoNvme);
> +}
> +
> +/**
> + Notification function of EFI_END_OF_DXE_EVENT_GROUP_GUID event
> group.
> +
> + This is a notification function registered on
> EFI_END_OF_DXE_EVENT_GROUP_GUID event group.
> +
> + @param Event Event whose notification function is being invoked.
> + @param Context Pointer to the notification function's context.
> +
> +**/
> +VOID
> +EFIAPI
> +OpalEndOfDxeEventNotify (
> + EFI_EVENT Event,
> + VOID *Context
> + )
> +{
> + EFI_STATUS Status;
> + EFI_PHYSICAL_ADDRESS Address;
> + UINT64 Length;
> + OPAL_DRIVER_DEVICE *TmpDev;
> +
> + DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));
> +
> + mOpalEndOfDxe = TRUE;
> +
> + if (mOpalRequestVariable != NULL) {
> + //
> + // Free the OPAL request variable buffer here
> + // as the OPAL requests should have been processed.
> + //
> + FreePool (mOpalRequestVariable);
> + mOpalRequestVariable = NULL;
> + mOpalRequestVariableSize = 0;
> + }
> +
> + //
> + // Assume 64K size and alignment are enough.
> + //
> + Length = 0x10000;
> + Address = 0xFFFFFFFF;
> + Status = gDS->AllocateMemorySpace (
> + EfiGcdAllocateMaxAddressSearchBottomUp,
> + EfiGcdMemoryTypeMemoryMappedIo,
> + 16, // 2^16: 64K
> Alignment
> + Length,
> + &Address,
> + gImageHandle,
> + NULL
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + BuildOpalDeviceInfoAta ((UINT32) Address);
> + BuildOpalDeviceInfoNvme ((UINT32) Address);
> +
> + //
> + // Zero passsword.
> + //
> + TmpDev = mOpalDriver.DeviceList;
> + while (TmpDev != NULL) {
> + ZeroMem (TmpDev->OpalDisk.Password,
> TmpDev->OpalDisk.PasswordLength);
> + TmpDev = TmpDev->Next;
> + }
> +
> + DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));
> +
> + gBS->CloseEvent (Event);
> +}
> +
> +/**
> + Get Psid input from the popup window.
> +
> + @param[in] Dev The device which need Psid to process Psid
> Revert
> + OPAL request.
> + @param[in] PopUpString Pop up string.
> + @param[out] PressEsc Whether user escape function through Press
> ESC.
> +
> + @retval Password string if success. NULL if failed.
> +
> +**/
> +CHAR8 *
> +OpalDriverPopUpPsidInput (
> + IN OPAL_DRIVER_DEVICE *Dev,
> + IN CHAR16 *PopUpString,
> + OUT BOOLEAN *PressEsc
> + )
> +{
> + EFI_INPUT_KEY InputKey;
> + UINTN InputLength;
> + CHAR16 Mask[PSID_CHARACTER_LENGTH + 1];
> + CHAR16 Unicode[PSID_CHARACTER_LENGTH + 1];
> + CHAR8 *Ascii;
> +
> + ZeroMem(Unicode, sizeof(Unicode));
> + ZeroMem(Mask, sizeof(Mask));
> +
> + *PressEsc = FALSE;
> +
> + gST->ConOut->ClearScreen(gST->ConOut);
> +
> + InputLength = 0;
> + while (TRUE) {
> + Mask[InputLength] = L'_';
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &InputKey,
> + PopUpString,
> + L"---------------------",
> + Mask,
> + NULL
> + );
> +
> + //
> + // Check key.
> + //
> + if (InputKey.ScanCode == SCAN_NULL) {
> + //
> + // password finished
> + //
> + if (InputKey.UnicodeChar == CHAR_CARRIAGE_RETURN) {
> + //
> + // Add the null terminator.
> + //
> + Unicode[InputLength] = 0;
> + Mask[InputLength] = 0;
> + break;
> + } else if ((InputKey.UnicodeChar == CHAR_NULL) ||
> + (InputKey.UnicodeChar == CHAR_TAB) ||
> + (InputKey.UnicodeChar == CHAR_LINEFEED)
> + ) {
> + continue;
> + } else {
> + //
> + // delete last key entered
> + //
> + if (InputKey.UnicodeChar == CHAR_BACKSPACE) {
> + if (InputLength > 0) {
> + Unicode[InputLength] = 0;
> + Mask[InputLength] = 0;
> + InputLength--;
> + }
> + } else {
> + //
> + // add Next key entry
> + //
> + Unicode[InputLength] = InputKey.UnicodeChar;
> + Mask[InputLength] = InputKey.UnicodeChar;
> + InputLength++;
> + if (InputLength == PSID_CHARACTER_LENGTH) {
> + //
> + // Add the null terminator.
> + //
> + Unicode[InputLength] = 0;
> + Mask[InputLength] = 0;
> + break;
> + }
> + }
> + }
> + }
> +
> + //
> + // exit on ESC
> + //
> + if (InputKey.ScanCode == SCAN_ESC) {
> + *PressEsc = TRUE;
> + break;
> + }
> + }
> +
> + gST->ConOut->ClearScreen(gST->ConOut);
> +
> + if (InputLength == 0 || InputKey.ScanCode == SCAN_ESC) {
> + return NULL;
> + }
> +
> + Ascii = AllocateZeroPool (PSID_CHARACTER_LENGTH + 1);
> + if (Ascii == NULL) {
> + ZeroMem (Unicode, sizeof (Unicode));
> + ZeroMem (Mask, sizeof (Mask));
> + return NULL;
> + }
> +
> + UnicodeStrToAsciiStrS (Unicode, Ascii, PSID_CHARACTER_LENGTH + 1);
> + ZeroMem (Unicode, sizeof (Unicode));
> + ZeroMem (Mask, sizeof (Mask));
> +
> + return Ascii;
> +}
> +
> +
> +/**
> + Get password input from the popup window.
> +
> + @param[in] Dev The device which need password to unlock or
> + process OPAL request.
> + @param[in] PopUpString1 Pop up string 1.
> + @param[in] PopUpString2 Pop up string 2.
> + @param[out] PressEsc Whether user escape function through Press
> ESC.
> +
> + @retval Password string if success. NULL if failed.
> +
> +**/
> +CHAR8 *
> +OpalDriverPopUpPasswordInput (
> + IN OPAL_DRIVER_DEVICE *Dev,
> + IN CHAR16 *PopUpString1,
> + IN CHAR16 *PopUpString2,
> + OUT BOOLEAN *PressEsc
> + )
> +{
> + EFI_INPUT_KEY InputKey;
> + UINTN InputLength;
> + CHAR16 Mask[MAX_PASSWORD_SIZE + 1];
> + CHAR16 Unicode[MAX_PASSWORD_SIZE + 1];
> + CHAR8 *Ascii;
> +
> + ZeroMem(Unicode, sizeof(Unicode));
> + ZeroMem(Mask, sizeof(Mask));
> +
> + *PressEsc = FALSE;
> +
> + gST->ConOut->ClearScreen(gST->ConOut);
> +
> + InputLength = 0;
> + while (TRUE) {
> + Mask[InputLength] = L'_';
> + if (PopUpString2 == NULL) {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &InputKey,
> + PopUpString1,
> + L"---------------------",
> + Mask,
> + NULL
> + );
> + } else {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &InputKey,
> + PopUpString1,
> + PopUpString2,
> + L"---------------------",
> + Mask,
> + NULL
> + );
> + }
> +
> + //
> + // Check key.
> + //
> + if (InputKey.ScanCode == SCAN_NULL) {
> + //
> + // password finished
> + //
> + if (InputKey.UnicodeChar == CHAR_CARRIAGE_RETURN) {
> + //
> + // Add the null terminator.
> + //
> + Unicode[InputLength] = 0;
> + Mask[InputLength] = 0;
> + break;
> + } else if ((InputKey.UnicodeChar == CHAR_NULL) ||
> + (InputKey.UnicodeChar == CHAR_TAB) ||
> + (InputKey.UnicodeChar == CHAR_LINEFEED)
> + ) {
> + continue;
> + } else {
> + //
> + // delete last key entered
> + //
> + if (InputKey.UnicodeChar == CHAR_BACKSPACE) {
> + if (InputLength > 0) {
> + Unicode[InputLength] = 0;
> + Mask[InputLength] = 0;
> + InputLength--;
> + }
> + } else {
> + //
> + // add Next key entry
> + //
> + Unicode[InputLength] = InputKey.UnicodeChar;
> + Mask[InputLength] = L'*';
> + InputLength++;
> + if (InputLength == MAX_PASSWORD_SIZE) {
> + //
> + // Add the null terminator.
> + //
> + Unicode[InputLength] = 0;
> + Mask[InputLength] = 0;
> + break;
> + }
> + }
> + }
> + }
> +
> + //
> + // exit on ESC
> + //
> + if (InputKey.ScanCode == SCAN_ESC) {
> + *PressEsc = TRUE;
> + break;
> + }
> + }
> +
> + gST->ConOut->ClearScreen(gST->ConOut);
> +
> + if (InputLength == 0 || InputKey.ScanCode == SCAN_ESC) {
> + return NULL;
> + }
> +
> + Ascii = AllocateZeroPool (MAX_PASSWORD_SIZE + 1);
> + if (Ascii == NULL) {
> + ZeroMem (Unicode, sizeof (Unicode));
> + return NULL;
> + }
> +
> + UnicodeStrToAsciiStrS (Unicode, Ascii, MAX_PASSWORD_SIZE + 1);
> + ZeroMem (Unicode, sizeof (Unicode));
> +
> + return Ascii;
> +}
> +
> +/**
> + Check if disk is locked, show popup window and ask for password if it is.
> +
> + @param[in] Dev The device which need to be unlocked.
> + @param[in] RequestString Request string.
> +
> +**/
> +CHAR16 *
> +OpalGetPopUpString (
> + IN OPAL_DRIVER_DEVICE *Dev,
> + IN CHAR16 *RequestString
> + )
> +{
> + UINTN StrLength;
> +
> + StrLength = StrLen (RequestString) + 1 + MAX (StrLen (Dev->Name16),
> StrLen (L"Disk"));
> + ASSERT (StrLength < sizeof (mPopUpString) / sizeof (CHAR16));
> +
> + if (Dev->Name16 == NULL) {
> + UnicodeSPrint (mPopUpString, StrLength + 1, L"%s Disk", RequestString);
> + } else {
> + UnicodeSPrint (mPopUpString, StrLength + 1, L"%s %s", RequestString,
> Dev->Name16);
> + }
> +
> + return mPopUpString;
> +}
> +
> +/**
> + Check if disk is locked, show popup window and ask for password if it is.
> +
> + @param[in] Dev The device which need to be unlocked.
> + @param[in] RequestString Request string.
> +
> +**/
> +VOID
> +OpalDriverRequestPassword (
> + IN OPAL_DRIVER_DEVICE *Dev,
> + IN CHAR16 *RequestString
> + )
> +{
> + UINT8 Count;
> + BOOLEAN IsEnabled;
> + BOOLEAN IsLocked;
> + CHAR8 *Password;
> + UINT32 PasswordLen;
> + OPAL_SESSION Session;
> + BOOLEAN PressEsc;
> + EFI_INPUT_KEY Key;
> + TCG_RESULT Ret;
> + CHAR16 *PopUpString;
> +
> + if (Dev == NULL) {
> + return;
> + }
> +
> + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));
> +
> + PopUpString = OpalGetPopUpString (Dev, RequestString);
> +
> + Count = 0;
> +
> + IsEnabled = OpalFeatureEnabled (&Dev->OpalDisk.SupportedAttributes,
> &Dev->OpalDisk.LockingFeature);
> + if (IsEnabled) {
> + ZeroMem(&Session, sizeof(Session));
> + Session.Sscp = Dev->OpalDisk.Sscp;
> + Session.MediaId = Dev->OpalDisk.MediaId;
> + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;
> +
> + IsLocked = OpalDeviceLocked (&Dev->OpalDisk.SupportedAttributes,
> &Dev->OpalDisk.LockingFeature);
> +
> + while (Count < MAX_PASSWORD_TRY_COUNT) {
> + Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, NULL,
> &PressEsc);
> + if (PressEsc) {
> + if (IsLocked) {
> + //
> + // Current device in the lock status and
> + // User not input password and press ESC,
> + // keep device in lock status and continue boot.
> + //
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Press ENTER to skip the request and continue boot,",
> + L"Press ESC to input password again",
> + NULL
> + );
> + } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar !=
> CHAR_CARRIAGE_RETURN));
> +
> + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
> + gST->ConOut->ClearScreen(gST->ConOut);
> + //
> + // Keep lock and continue boot.
> + //
> + return;
> + } else {
> + //
> + // Let user input password again.
> + //
> + continue;
> + }
> + } else {
> + //
> + // Current device in the unlock status and
> + // User not input password and press ESC,
> + // Shutdown the device.
> + //
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Press ENTER to shutdown, Press ESC to input password
> again",
> + NULL
> + );
> + } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar !=
> CHAR_CARRIAGE_RETURN));
> +
> + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
> + gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);
> + } else {
> + //
> + // Let user input password again.
> + //
> + continue;
> + }
> + }
> + }
> +
> + if (Password == NULL) {
> + Count ++;
> + continue;
> + }
> + PasswordLen = (UINT32) AsciiStrLen(Password);
> +
> + if (IsLocked) {
> + Ret = OpalUtilUpdateGlobalLockingRange(&Session, Password,
> PasswordLen, FALSE, FALSE);
> + } else {
> + Ret = OpalUtilUpdateGlobalLockingRange(&Session, Password,
> PasswordLen, TRUE, TRUE);
> + if (Ret == TcgResultSuccess) {
> + Ret = OpalUtilUpdateGlobalLockingRange(&Session, Password,
> PasswordLen, FALSE, FALSE);
> + }
> + }
> +
> + if (Ret == TcgResultSuccess) {
> + OpalSupportUpdatePassword (&Dev->OpalDisk, Password,
> PasswordLen);
> + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));
> + } else {
> + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));
> + }
> +
> + if (Password != NULL) {
> + ZeroMem (Password, PasswordLen);
> + FreePool (Password);
> + }
> +
> + if (Ret == TcgResultSuccess) {
> + break;
> + }
> +
> + Count++;
> +
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Invalid password.",
> + L"Press ENTER to retry",
> + NULL
> + );
> + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> + }
> +
> + if (Count >= MAX_PASSWORD_TRY_COUNT) {
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Opal password retry count exceeds the limit. Must shutdown!",
> + L"Press ENTER to shutdown",
> + NULL
> + );
> + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> +
> + gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);
> + }
> + }
> +}
> +
> +/**
> + Process Enable Feature OPAL request.
> +
> + @param[in] Dev The device which has Enable Feature OPAL
> request.
> + @param[in] RequestString Request string.
> +
> +**/
> +VOID
> +ProcessOpalRequestEnableFeature (
> + IN OPAL_DRIVER_DEVICE *Dev,
> + IN CHAR16 *RequestString
> + )
> +{
> + UINT8 Count;
> + CHAR8 *Password;
> + UINT32 PasswordLen;
> + CHAR8 *PasswordConfirm;
> + UINT32 PasswordLenConfirm;
> + OPAL_SESSION Session;
> + BOOLEAN PressEsc;
> + EFI_INPUT_KEY Key;
> + TCG_RESULT Ret;
> + CHAR16 *PopUpString;
> +
> + if (Dev == NULL) {
> + return;
> + }
> +
> + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));
> +
> + PopUpString = OpalGetPopUpString (Dev, RequestString);
> +
> + Count = 0;
> +
> + ZeroMem(&Session, sizeof(Session));
> + Session.Sscp = Dev->OpalDisk.Sscp;
> + Session.MediaId = Dev->OpalDisk.MediaId;
> + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;
> +
> + while (Count < MAX_PASSWORD_TRY_COUNT) {
> + Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please
> type in your new password", &PressEsc);
> + if (PressEsc) {
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Press ENTER to skip the request and continue boot,",
> + L"Press ESC to input password again",
> + NULL
> + );
> + } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar !=
> CHAR_CARRIAGE_RETURN));
> +
> + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
> + gST->ConOut->ClearScreen(gST->ConOut);
> + return;
> + } else {
> + //
> + // Let user input password again.
> + //
> + continue;
> + }
> + }
> +
> + if (Password == NULL) {
> + Count ++;
> + continue;
> + }
> + PasswordLen = (UINT32) AsciiStrLen(Password);
> +
> + PasswordConfirm = OpalDriverPopUpPasswordInput (Dev, PopUpString,
> L"Please confirm your new password", &PressEsc);
> + if (PasswordConfirm == NULL) {
> + ZeroMem (Password, PasswordLen);
> + FreePool (Password);
> + Count ++;
> + continue;
> + }
> + PasswordLenConfirm = (UINT32) AsciiStrLen(PasswordConfirm);
> + if ((PasswordLen != PasswordLenConfirm) ||
> + (CompareMem (Password, PasswordConfirm, PasswordLen) != 0)) {
> + ZeroMem (Password, PasswordLen);
> + FreePool (Password);
> + ZeroMem (PasswordConfirm, PasswordLenConfirm);
> + FreePool (PasswordConfirm);
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Passwords are not the same.",
> + L"Press ENTER to retry",
> + NULL
> + );
> + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> + Count ++;
> + continue;
> + }
> +
> + if (PasswordConfirm != NULL) {
> + ZeroMem (PasswordConfirm, PasswordLenConfirm);
> + FreePool (PasswordConfirm);
> + }
> +
> + Ret = OpalSupportEnableOpalFeature (&Session, Dev->OpalDisk.Msid,
> Dev->OpalDisk.MsidLength, Password, PasswordLen);
> + if (Ret == TcgResultSuccess) {
> + OpalSupportUpdatePassword (&Dev->OpalDisk, Password,
> PasswordLen);
> + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));
> + } else {
> + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));
> + }
> +
> + if (Password != NULL) {
> + ZeroMem (Password, PasswordLen);
> + FreePool (Password);
> + }
> +
> + if (Ret == TcgResultSuccess) {
> + break;
> + }
> +
> + Count++;
> +
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Request failed.",
> + L"Press ENTER to retry",
> + NULL
> + );
> + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> + }
> +
> + if (Count >= MAX_PASSWORD_TRY_COUNT) {
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Opal password retry count exceeds the limit.",
> + L"Press ENTER to skip the request and continue boot",
> + NULL
> + );
> + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> + gST->ConOut->ClearScreen(gST->ConOut);
> + }
> +}
> +
> +/**
> + Process Disable User OPAL request.
> +
> + @param[in] Dev The device which has Disable User OPAL
> request.
> + @param[in] RequestString Request string.
> +
> +**/
> +VOID
> +ProcessOpalRequestDisableUser (
> + IN OPAL_DRIVER_DEVICE *Dev,
> + IN CHAR16 *RequestString
> + )
> +{
> + UINT8 Count;
> + CHAR8 *Password;
> + UINT32 PasswordLen;
> + OPAL_SESSION Session;
> + BOOLEAN PressEsc;
> + EFI_INPUT_KEY Key;
> + TCG_RESULT Ret;
> + BOOLEAN PasswordFailed;
> + CHAR16 *PopUpString;
> +
> + if (Dev == NULL) {
> + return;
> + }
> +
> + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));
> +
> + PopUpString = OpalGetPopUpString (Dev, RequestString);
> +
> + Count = 0;
> +
> + ZeroMem(&Session, sizeof(Session));
> + Session.Sscp = Dev->OpalDisk.Sscp;
> + Session.MediaId = Dev->OpalDisk.MediaId;
> + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;
> +
> + while (Count < MAX_PASSWORD_TRY_COUNT) {
> + Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, NULL,
> &PressEsc);
> + if (PressEsc) {
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Press ENTER to skip the request and continue boot,",
> + L"Press ESC to input password again",
> + NULL
> + );
> + } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar !=
> CHAR_CARRIAGE_RETURN));
> +
> + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
> + gST->ConOut->ClearScreen(gST->ConOut);
> + return;
> + } else {
> + //
> + // Let user input password again.
> + //
> + continue;
> + }
> + }
> +
> + if (Password == NULL) {
> + Count ++;
> + continue;
> + }
> + PasswordLen = (UINT32) AsciiStrLen(Password);
> +
> + Ret = OpalUtilDisableUser(&Session, Password, PasswordLen,
> &PasswordFailed);
> + if (Ret == TcgResultSuccess) {
> + OpalSupportUpdatePassword (&Dev->OpalDisk, Password,
> PasswordLen);
> + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));
> + } else {
> + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));
> + }
> +
> + if (Password != NULL) {
> + ZeroMem (Password, PasswordLen);
> + FreePool (Password);
> + }
> +
> + if (Ret == TcgResultSuccess) {
> + break;
> + }
> +
> + Count++;
> +
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Invalid password, request failed.",
> + L"Press ENTER to retry",
> + NULL
> + );
> + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> + }
> +
> + if (Count >= MAX_PASSWORD_TRY_COUNT) {
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Opal password retry count exceeds the limit.",
> + L"Press ENTER to skip the request and continue boot",
> + NULL
> + );
> + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> + gST->ConOut->ClearScreen(gST->ConOut);
> + }
> +}
> +
> +/**
> + Process Psid Revert OPAL request.
> +
> + @param[in] Dev The device which has Psid Revert OPAL
> request.
> + @param[in] RequestString Request string.
> +
> +**/
> +VOID
> +ProcessOpalRequestPsidRevert (
> + IN OPAL_DRIVER_DEVICE *Dev,
> + IN CHAR16 *RequestString
> + )
> +{
> + UINT8 Count;
> + CHAR8 *Psid;
> + UINT32 PsidLen;
> + OPAL_SESSION Session;
> + BOOLEAN PressEsc;
> + EFI_INPUT_KEY Key;
> + TCG_RESULT Ret;
> + CHAR16 *PopUpString;
> +
> + if (Dev == NULL) {
> + return;
> + }
> +
> + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));
> +
> + PopUpString = OpalGetPopUpString (Dev, RequestString);
> +
> + Count = 0;
> +
> + ZeroMem(&Session, sizeof(Session));
> + Session.Sscp = Dev->OpalDisk.Sscp;
> + Session.MediaId = Dev->OpalDisk.MediaId;
> + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;
> +
> + while (Count < MAX_PSID_TRY_COUNT) {
> + Psid = OpalDriverPopUpPsidInput (Dev, PopUpString, &PressEsc);
> + if (PressEsc) {
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Press ENTER to skip the request and continue boot,",
> + L"Press ESC to input Psid again",
> + NULL
> + );
> + } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar !=
> CHAR_CARRIAGE_RETURN));
> +
> + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
> + gST->ConOut->ClearScreen(gST->ConOut);
> + return;
> + } else {
> + //
> + // Let user input Psid again.
> + //
> + continue;
> + }
> + }
> +
> + if (Psid == NULL) {
> + Count ++;
> + continue;
> + }
> + PsidLen = (UINT32) AsciiStrLen(Psid);
> +
> + Ret = OpalUtilPsidRevert(&Session, Psid, PsidLen);
> + if (Ret == TcgResultSuccess) {
> + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));
> + } else {
> + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));
> + }
> +
> + if (Psid != NULL) {
> + ZeroMem (Psid, PsidLen);
> + FreePool (Psid);
> + }
> +
> + if (Ret == TcgResultSuccess) {
> + break;
> + }
> +
> + Count++;
> +
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Invalid Psid, request failed.",
> + L"Press ENTER to retry",
> + NULL
> + );
> + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> + }
> +
> + if (Count >= MAX_PSID_TRY_COUNT) {
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Opal Psid retry count exceeds the limit.",
> + L"Press ENTER to skip the request and continue boot",
> + NULL
> + );
> + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> + gST->ConOut->ClearScreen(gST->ConOut);
> + }
> +}
> +
> +/**
> + Process Admin Revert OPAL request.
> +
> + @param[in] Dev The device which has Revert OPAL request.
> + @param[in] KeepUserData Whether to keep user data or not.
> + @param[in] RequestString Request string.
> +
> +**/
> +VOID
> +ProcessOpalRequestRevert (
> + IN OPAL_DRIVER_DEVICE *Dev,
> + IN BOOLEAN KeepUserData,
> + IN CHAR16 *RequestString
> + )
> +{
> + UINT8 Count;
> + CHAR8 *Password;
> + UINT32 PasswordLen;
> + OPAL_SESSION Session;
> + BOOLEAN PressEsc;
> + EFI_INPUT_KEY Key;
> + TCG_RESULT Ret;
> + BOOLEAN PasswordFailed;
> + CHAR16 *PopUpString;
> +
> + if (Dev == NULL) {
> + return;
> + }
> +
> + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));
> +
> + PopUpString = OpalGetPopUpString (Dev, RequestString);
> +
> + Count = 0;
> +
> + ZeroMem(&Session, sizeof(Session));
> + Session.Sscp = Dev->OpalDisk.Sscp;
> + Session.MediaId = Dev->OpalDisk.MediaId;
> + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;
> +
> + while (Count < MAX_PASSWORD_TRY_COUNT) {
> + Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, NULL,
> &PressEsc);
> + if (PressEsc) {
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Press ENTER to skip the request and continue boot,",
> + L"Press ESC to input password again",
> + NULL
> + );
> + } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar !=
> CHAR_CARRIAGE_RETURN));
> +
> + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
> + gST->ConOut->ClearScreen(gST->ConOut);
> + return;
> + } else {
> + //
> + // Let user input password again.
> + //
> + continue;
> + }
> + }
> +
> + if (Password == NULL) {
> + Count ++;
> + continue;
> + }
> + PasswordLen = (UINT32) AsciiStrLen(Password);
> +
> + if ((Dev->OpalDisk.SupportedAttributes.PyriteSsc == 1) &&
> + (Dev->OpalDisk.LockingFeature.MediaEncryption == 0)) {
> + //
> + // For pyrite type device which does not support media encryption,
> + // it does not accept "Keep User Data" parameter.
> + // So here hardcode a FALSE for this case.
> + //
> + Ret = OpalUtilRevert(
> + &Session,
> + FALSE,
> + Password,
> + PasswordLen,
> + &PasswordFailed,
> + Dev->OpalDisk.Msid,
> + Dev->OpalDisk.MsidLength
> + );
> + } else {
> + Ret = OpalUtilRevert(
> + &Session,
> + KeepUserData,
> + Password,
> + PasswordLen,
> + &PasswordFailed,
> + Dev->OpalDisk.Msid,
> + Dev->OpalDisk.MsidLength
> + );
> + }
> + if (Ret == TcgResultSuccess) {
> + OpalSupportUpdatePassword (&Dev->OpalDisk, Password,
> PasswordLen);
> + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));
> + } else {
> + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));
> + }
> +
> + if (Password != NULL) {
> + ZeroMem (Password, PasswordLen);
> + FreePool (Password);
> + }
> +
> + if (Ret == TcgResultSuccess) {
> + break;
> + }
> +
> + Count++;
> +
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Invalid password, request failed.",
> + L"Press ENTER to retry",
> + NULL
> + );
> + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> + }
> +
> + if (Count >= MAX_PASSWORD_TRY_COUNT) {
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Opal password retry count exceeds the limit.",
> + L"Press ENTER to skip the request and continue boot",
> + NULL
> + );
> + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> + gST->ConOut->ClearScreen(gST->ConOut);
> + }
> +}
> +
> +/**
> + Process Secure Erase OPAL request.
> +
> + @param[in] Dev The device which has Secure Erase OPAL
> request.
> + @param[in] RequestString Request string.
> +
> +**/
> +VOID
> +ProcessOpalRequestSecureErase (
> + IN OPAL_DRIVER_DEVICE *Dev,
> + IN CHAR16 *RequestString
> + )
> +{
> + UINT8 Count;
> + CHAR8 *Password;
> + UINT32 PasswordLen;
> + OPAL_SESSION Session;
> + BOOLEAN PressEsc;
> + EFI_INPUT_KEY Key;
> + TCG_RESULT Ret;
> + BOOLEAN PasswordFailed;
> + CHAR16 *PopUpString;
> +
> + if (Dev == NULL) {
> + return;
> + }
> +
> + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));
> +
> + PopUpString = OpalGetPopUpString (Dev, RequestString);
> +
> + Count = 0;
> +
> + ZeroMem(&Session, sizeof(Session));
> + Session.Sscp = Dev->OpalDisk.Sscp;
> + Session.MediaId = Dev->OpalDisk.MediaId;
> + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;
> +
> + while (Count < MAX_PASSWORD_TRY_COUNT) {
> + Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, NULL,
> &PressEsc);
> + if (PressEsc) {
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Press ENTER to skip the request and continue boot,",
> + L"Press ESC to input password again",
> + NULL
> + );
> + } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar !=
> CHAR_CARRIAGE_RETURN));
> +
> + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
> + gST->ConOut->ClearScreen(gST->ConOut);
> + return;
> + } else {
> + //
> + // Let user input password again.
> + //
> + continue;
> + }
> + }
> +
> + if (Password == NULL) {
> + Count ++;
> + continue;
> + }
> + PasswordLen = (UINT32) AsciiStrLen(Password);
> +
> + Ret = OpalUtilSecureErase(&Session, Password, PasswordLen,
> &PasswordFailed);
> + if (Ret == TcgResultSuccess) {
> + OpalSupportUpdatePassword (&Dev->OpalDisk, Password,
> PasswordLen);
> + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));
> + } else {
> + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));
> + }
> +
> + if (Password != NULL) {
> + ZeroMem (Password, PasswordLen);
> + FreePool (Password);
> + }
> +
> + if (Ret == TcgResultSuccess) {
> + break;
> + }
> +
> + Count++;
> +
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Invalid password, request failed.",
> + L"Press ENTER to retry",
> + NULL
> + );
> + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> + }
> +
> + if (Count >= MAX_PASSWORD_TRY_COUNT) {
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Opal password retry count exceeds the limit.",
> + L"Press ENTER to skip the request and continue boot",
> + NULL
> + );
> + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> + gST->ConOut->ClearScreen(gST->ConOut);
> + }
> +}
> +
> +/**
> + Process Set Admin Pwd OPAL request.
> +
> + @param[in] Dev The device which has Set Admin Pwd Feature
> OPAL request.
> + @param[in] RequestString Request string.
> +
> +**/
> +VOID
> +ProcessOpalRequestSetUserPwd (
> + IN OPAL_DRIVER_DEVICE *Dev,
> + IN CHAR16 *RequestString
> + )
> +{
> + UINT8 Count;
> + CHAR8 *OldPassword;
> + UINT32 OldPasswordLen;
> + CHAR8 *Password;
> + UINT32 PasswordLen;
> + CHAR8 *PasswordConfirm;
> + UINT32 PasswordLenConfirm;
> + OPAL_SESSION Session;
> + BOOLEAN PressEsc;
> + EFI_INPUT_KEY Key;
> + TCG_RESULT Ret;
> + CHAR16 *PopUpString;
> +
> + if (Dev == NULL) {
> + return;
> + }
> +
> + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));
> +
> + PopUpString = OpalGetPopUpString (Dev, RequestString);
> +
> + Count = 0;
> +
> + while (Count < MAX_PASSWORD_TRY_COUNT) {
> + OldPassword = OpalDriverPopUpPasswordInput (Dev, PopUpString,
> L"Please type in your password", &PressEsc);
> + if (PressEsc) {
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Press ENTER to skip the request and continue boot,",
> + L"Press ESC to input password again",
> + NULL
> + );
> + } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar !=
> CHAR_CARRIAGE_RETURN));
> +
> + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
> + gST->ConOut->ClearScreen(gST->ConOut);
> + return;
> + } else {
> + //
> + // Let user input password again.
> + //
> + continue;
> + }
> + }
> +
> + if (OldPassword == NULL) {
> + Count ++;
> + continue;
> + }
> + OldPasswordLen = (UINT32) AsciiStrLen(OldPassword);
> +
> + ZeroMem(&Session, sizeof(Session));
> + Session.Sscp = Dev->OpalDisk.Sscp;
> + Session.MediaId = Dev->OpalDisk.MediaId;
> + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;
> + Ret = OpalUtilVerifyPassword (&Session, OldPassword, OldPasswordLen,
> OPAL_LOCKING_SP_USER1_AUTHORITY);
> + if (Ret == TcgResultSuccess) {
> + DEBUG ((DEBUG_INFO, "Verify with USER1 authority : Success\n"));
> + } else {
> + Ret = OpalUtilVerifyPassword (&Session, OldPassword, OldPasswordLen,
> OPAL_LOCKING_SP_ADMIN1_AUTHORITY);
> + if (Ret == TcgResultSuccess) {
> + DEBUG ((DEBUG_INFO, "Verify with ADMIN1 authority: Success\n"));
> + } else {
> + ZeroMem (OldPassword, OldPasswordLen);
> + FreePool (OldPassword);
> + DEBUG ((DEBUG_INFO, "Verify: Failure\n"));
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Incorrect password.",
> + L"Press ENTER to retry",
> + NULL
> + );
> + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> + Count ++;
> + continue;
> + }
> + }
> +
> + Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please
> type in your new password", &PressEsc);
> + if (Password == NULL) {
> + ZeroMem (OldPassword, OldPasswordLen);
> + FreePool (OldPassword);
> + Count ++;
> + continue;
> + }
> + PasswordLen = (UINT32) AsciiStrLen(Password);
> +
> + PasswordConfirm = OpalDriverPopUpPasswordInput (Dev, PopUpString,
> L"Please confirm your new password", &PressEsc);
> + if (PasswordConfirm == NULL) {
> + ZeroMem (OldPassword, OldPasswordLen);
> + FreePool (OldPassword);
> + ZeroMem (Password, PasswordLen);
> + FreePool (Password);
> + Count ++;
> + continue;
> + }
> + PasswordLenConfirm = (UINT32) AsciiStrLen(PasswordConfirm);
> + if ((PasswordLen != PasswordLenConfirm) ||
> + (CompareMem (Password, PasswordConfirm, PasswordLen) != 0)) {
> + ZeroMem (OldPassword, OldPasswordLen);
> + FreePool (OldPassword);
> + ZeroMem (Password, PasswordLen);
> + FreePool (Password);
> + ZeroMem (PasswordConfirm, PasswordLenConfirm);
> + FreePool (PasswordConfirm);
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Passwords are not the same.",
> + L"Press ENTER to retry",
> + NULL
> + );
> + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> + Count ++;
> + continue;
> + }
> +
> + if (PasswordConfirm != NULL) {
> + ZeroMem (PasswordConfirm, PasswordLenConfirm);
> + FreePool (PasswordConfirm);
> + }
> +
> + ZeroMem(&Session, sizeof(Session));
> + Session.Sscp = Dev->OpalDisk.Sscp;
> + Session.MediaId = Dev->OpalDisk.MediaId;
> + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;
> + Ret = OpalUtilSetUserPassword(
> + &Session,
> + OldPassword,
> + OldPasswordLen,
> + Password,
> + PasswordLen
> + );
> + if (Ret == TcgResultSuccess) {
> + OpalSupportUpdatePassword (&Dev->OpalDisk, Password,
> PasswordLen);
> + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));
> + } else {
> + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));
> + }
> +
> + if (OldPassword != NULL) {
> + ZeroMem (OldPassword, OldPasswordLen);
> + FreePool (OldPassword);
> + }
> +
> + if (Password != NULL) {
> + ZeroMem (Password, PasswordLen);
> + FreePool (Password);
> + }
> +
> + if (Ret == TcgResultSuccess) {
> + break;
> + }
> +
> + Count++;
> +
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Request failed.",
> + L"Press ENTER to retry",
> + NULL
> + );
> + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> + }
> +
> + if (Count >= MAX_PASSWORD_TRY_COUNT) {
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Opal password retry count exceeds the limit.",
> + L"Press ENTER to skip the request and continue boot",
> + NULL
> + );
> + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> + gST->ConOut->ClearScreen(gST->ConOut);
> + }
> +}
> +
> +/**
> + Process Set Admin Pwd OPAL request.
> +
> + @param[in] Dev The device which has Set Admin Pwd Feature
> OPAL request.
> + @param[in] RequestString Request string.
> +
> +**/
> +VOID
> +ProcessOpalRequestSetAdminPwd (
> + IN OPAL_DRIVER_DEVICE *Dev,
> + IN CHAR16 *RequestString
> + )
> +{
> + UINT8 Count;
> + CHAR8 *OldPassword;
> + UINT32 OldPasswordLen;
> + CHAR8 *Password;
> + UINT32 PasswordLen;
> + CHAR8 *PasswordConfirm;
> + UINT32 PasswordLenConfirm;
> + OPAL_SESSION Session;
> + BOOLEAN PressEsc;
> + EFI_INPUT_KEY Key;
> + TCG_RESULT Ret;
> + CHAR16 *PopUpString;
> +
> + if (Dev == NULL) {
> + return;
> + }
> +
> + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));
> +
> + PopUpString = OpalGetPopUpString (Dev, RequestString);
> +
> + Count = 0;
> +
> + while (Count < MAX_PASSWORD_TRY_COUNT) {
> + OldPassword = OpalDriverPopUpPasswordInput (Dev, PopUpString,
> L"Please type in your password", &PressEsc);
> + if (PressEsc) {
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Press ENTER to skip the request and continue boot,",
> + L"Press ESC to input password again",
> + NULL
> + );
> + } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar !=
> CHAR_CARRIAGE_RETURN));
> +
> + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
> + gST->ConOut->ClearScreen(gST->ConOut);
> + return;
> + } else {
> + //
> + // Let user input password again.
> + //
> + continue;
> + }
> + }
> +
> + if (OldPassword == NULL) {
> + Count ++;
> + continue;
> + }
> + OldPasswordLen = (UINT32) AsciiStrLen(OldPassword);
> +
> + ZeroMem(&Session, sizeof(Session));
> + Session.Sscp = Dev->OpalDisk.Sscp;
> + Session.MediaId = Dev->OpalDisk.MediaId;
> + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;
> + Ret = OpalUtilVerifyPassword (&Session, OldPassword, OldPasswordLen,
> OPAL_LOCKING_SP_ADMIN1_AUTHORITY);
> + if (Ret == TcgResultSuccess) {
> + DEBUG ((DEBUG_INFO, "Verify: Success\n"));
> + } else {
> + ZeroMem (OldPassword, OldPasswordLen);
> + FreePool (OldPassword);
> + DEBUG ((DEBUG_INFO, "Verify: Failure\n"));
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Incorrect password.",
> + L"Press ENTER to retry",
> + NULL
> + );
> + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> + Count ++;
> + continue;
> + }
> +
> + Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please
> type in your new password", &PressEsc);
> + if (Password == NULL) {
> + ZeroMem (OldPassword, OldPasswordLen);
> + FreePool (OldPassword);
> + Count ++;
> + continue;
> + }
> + PasswordLen = (UINT32) AsciiStrLen(Password);
> +
> + PasswordConfirm = OpalDriverPopUpPasswordInput (Dev, PopUpString,
> L"Please confirm your new password", &PressEsc);
> + if (PasswordConfirm == NULL) {
> + ZeroMem (OldPassword, OldPasswordLen);
> + FreePool (OldPassword);
> + ZeroMem (Password, PasswordLen);
> + FreePool (Password);
> + Count ++;
> + continue;
> + }
> + PasswordLenConfirm = (UINT32) AsciiStrLen(PasswordConfirm);
> + if ((PasswordLen != PasswordLenConfirm) ||
> + (CompareMem (Password, PasswordConfirm, PasswordLen) != 0)) {
> + ZeroMem (OldPassword, OldPasswordLen);
> + FreePool (OldPassword);
> + ZeroMem (Password, PasswordLen);
> + FreePool (Password);
> + ZeroMem (PasswordConfirm, PasswordLenConfirm);
> + FreePool (PasswordConfirm);
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Passwords are not the same.",
> + L"Press ENTER to retry",
> + NULL
> + );
> + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> + Count ++;
> + continue;
> + }
> +
> + if (PasswordConfirm != NULL) {
> + ZeroMem (PasswordConfirm, PasswordLenConfirm);
> + FreePool (PasswordConfirm);
> + }
> +
> +
> + ZeroMem(&Session, sizeof(Session));
> + Session.Sscp = Dev->OpalDisk.Sscp;
> + Session.MediaId = Dev->OpalDisk.MediaId;
> + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;
> + Ret = OpalUtilSetAdminPassword(
> + &Session,
> + OldPassword,
> + OldPasswordLen,
> + Password,
> + PasswordLen
> + );
> + if (Ret == TcgResultSuccess) {
> + OpalSupportUpdatePassword (&Dev->OpalDisk, Password,
> PasswordLen);
> + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));
> + } else {
> + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));
> + }
> +
> + if (OldPassword != NULL) {
> + ZeroMem (OldPassword, OldPasswordLen);
> + FreePool (OldPassword);
> + }
> +
> + if (Password != NULL) {
> + ZeroMem (Password, PasswordLen);
> + FreePool (Password);
> + }
> +
> + if (Ret == TcgResultSuccess) {
> + break;
> + }
> +
> + Count++;
> +
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Request failed.",
> + L"Press ENTER to retry",
> + NULL
> + );
> + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> + }
> +
> + if (Count >= MAX_PASSWORD_TRY_COUNT) {
> + do {
> + CreatePopUp (
> + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> + &Key,
> + L"Opal password retry count exceeds the limit.",
> + L"Press ENTER to skip the request and continue boot",
> + NULL
> + );
> + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> + gST->ConOut->ClearScreen(gST->ConOut);
> + }
> +}
> +
> +/**
> + Process OPAL request.
> +
> + @param[in] Dev The device which has OPAL request.
> +
> +**/
> +VOID
> +ProcessOpalRequest (
> + IN OPAL_DRIVER_DEVICE *Dev
> + )
> +{
> + EFI_STATUS Status;
> + OPAL_REQUEST_VARIABLE *TempVariable;
> + OPAL_REQUEST_VARIABLE *Variable;
> + UINTN VariableSize;
> + EFI_DEVICE_PATH_PROTOCOL *DevicePathInVariable;
> + UINTN DevicePathSizeInVariable;
> + EFI_DEVICE_PATH_PROTOCOL *DevicePath;
> + UINTN DevicePathSize;
> + BOOLEAN KeepUserData;
> +
> + DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));
> +
> + if (mOpalRequestVariable == NULL) {
> + Status = GetVariable2 (
> + OPAL_REQUEST_VARIABLE_NAME,
> + &gHiiSetupVariableGuid,
> + (VOID **) &Variable,
> + &VariableSize
> + );
> + if (EFI_ERROR (Status) || (Variable == NULL)) {
> + return;
> + }
> + mOpalRequestVariable = Variable;
> + mOpalRequestVariableSize = VariableSize;
> +
> + //
> + // Delete the OPAL request variable.
> + //
> + Status = gRT->SetVariable (
> + OPAL_REQUEST_VARIABLE_NAME,
> + (EFI_GUID *) &gHiiSetupVariableGuid,
> + 0,
> + 0,
> + NULL
> + );
> + ASSERT_EFI_ERROR (Status);
> + } else {
> + Variable = mOpalRequestVariable;
> + VariableSize = mOpalRequestVariableSize;
> + }
> +
> + //
> + // Process the OPAL requests.
> + //
> + TempVariable = Variable;
> + while ((VariableSize > sizeof (OPAL_REQUEST_VARIABLE)) &&
> + (VariableSize >= TempVariable->Length) &&
> + (TempVariable->Length > sizeof (OPAL_REQUEST_VARIABLE))) {
> + DevicePathInVariable = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN)
> TempVariable + sizeof (OPAL_REQUEST_VARIABLE));
> + DevicePathSizeInVariable = GetDevicePathSize (DevicePathInVariable);
> + DevicePath = Dev->OpalDisk.OpalDevicePath;
> + DevicePathSize = GetDevicePathSize (DevicePath);
> + if ((DevicePathSize == DevicePathSizeInVariable) &&
> + (CompareMem (DevicePath, DevicePathInVariable, DevicePathSize)
> == 0)) {
> + //
> + // Found the node for the OPAL device.
> + //
> + if (TempVariable->OpalRequest.SetAdminPwd != 0) {
> + ProcessOpalRequestSetAdminPwd (Dev, L"Update Admin Pwd:");
> + }
> + if (TempVariable->OpalRequest.SetUserPwd != 0) {
> + ProcessOpalRequestSetUserPwd (Dev, L"Set User Pwd:");
> + }
> + if (TempVariable->OpalRequest.SecureErase!= 0) {
> + ProcessOpalRequestSecureErase (Dev, L"Secure Erase:");
> + }
> + if (TempVariable->OpalRequest.Revert != 0) {
> + KeepUserData = (BOOLEAN)
> TempVariable->OpalRequest.KeepUserData;
> + ProcessOpalRequestRevert (
> + Dev,
> + KeepUserData,
> + KeepUserData ? L"Admin Revert(keep):" : L"Admin Revert:"
> + );
> + }
> + if (TempVariable->OpalRequest.PsidRevert != 0) {
> + ProcessOpalRequestPsidRevert (Dev, L"Psid Revert:");
> + }
> + if (TempVariable->OpalRequest.DisableUser != 0) {
> + ProcessOpalRequestDisableUser (Dev, L"Disable User:");
> + }
> + if (TempVariable->OpalRequest.EnableFeature != 0) {
> + ProcessOpalRequestEnableFeature (Dev, L"Enable Feature:");
> + }
> +
> + break;
> + }
> +
> + VariableSize -= TempVariable->Length;
> + TempVariable = (OPAL_REQUEST_VARIABLE *) ((UINTN) TempVariable +
> TempVariable->Length);
> + }
> +
> + DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));
> +}
> +
> +/**
> + Add new device to the global device list.
> +
> + @param Dev New create device.
> +
> +**/
> +VOID
> +AddDeviceToTail(
> + IN OPAL_DRIVER_DEVICE *Dev
> + )
> +{
> + OPAL_DRIVER_DEVICE *TmpDev;
> +
> + if (mOpalDriver.DeviceList == NULL) {
> + mOpalDriver.DeviceList = Dev;
> + } else {
> + TmpDev = mOpalDriver.DeviceList;
> + while (TmpDev->Next != NULL) {
> + TmpDev = TmpDev->Next;
> + }
> +
> + TmpDev->Next = Dev;
> + }
> +}
> +
> +/**
> + Remove one device in the global device list.
> +
> + @param Dev The device need to be removed.
> +
> +**/
> +VOID
> +RemoveDevice (
> + IN OPAL_DRIVER_DEVICE *Dev
> + )
> +{
> + OPAL_DRIVER_DEVICE *TmpDev;
> +
> + if (mOpalDriver.DeviceList == NULL) {
> + return;
> + }
> +
> + if (mOpalDriver.DeviceList == Dev) {
> + mOpalDriver.DeviceList = NULL;
> + return;
> + }
> +
> + TmpDev = mOpalDriver.DeviceList;
> + while (TmpDev->Next != NULL) {
> + if (TmpDev->Next == Dev) {
> + TmpDev->Next = Dev->Next;
> + break;
> + }
> + }
> +}
> +
> +/**
> + Get current device count.
> +
> + @retval return the current created device count.
> +
> +**/
> +UINT8
> +GetDeviceCount (
> + VOID
> + )
> +{
> + UINT8 Count;
> + OPAL_DRIVER_DEVICE *TmpDev;
> +
> + Count = 0;
> + TmpDev = mOpalDriver.DeviceList;
> +
> + while (TmpDev != NULL) {
> + Count++;
> + TmpDev = TmpDev->Next;
> + }
> +
> + return Count;
> +}
> +
> +/**
> + Get devcie list info.
> +
> + @retval return the device list pointer.
> +**/
> +OPAL_DRIVER_DEVICE*
> +OpalDriverGetDeviceList(
> + VOID
> + )
> +{
> + return mOpalDriver.DeviceList;
> +}
> +
> +/**
> + ReadyToBoot callback to send BlockSid command.
> +
> + @param Event Pointer to this event
> + @param Context Event handler private Data
> +
> +**/
> +VOID
> +EFIAPI
> +ReadyToBootCallback (
> + IN EFI_EVENT Event,
> + IN VOID *Context
> + )
> +{
> + OPAL_DRIVER_DEVICE *Itr;
> + TCG_RESULT Result;
> + OPAL_SESSION Session;
> + UINT32 PpStorageFlag;
> +
> + gBS->CloseEvent (Event);
> +
> + PpStorageFlag = Tcg2PhysicalPresenceLibGetManagementFlags ();
> + if ((PpStorageFlag &
> TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID) != 0) {
> + //
> + // Send BlockSID command to each Opal disk
> + //
> + Itr = mOpalDriver.DeviceList;
> + while (Itr != NULL) {
> + if (Itr->OpalDisk.SupportedAttributes.BlockSid) {
> + ZeroMem(&Session, sizeof(Session));
> + Session.Sscp = Itr->OpalDisk.Sscp;
> + Session.MediaId = Itr->OpalDisk.MediaId;
> + Session.OpalBaseComId = Itr->OpalDisk.OpalBaseComId;
> +
> + Result = OpalBlockSid (&Session, TRUE); // HardwareReset must
> always be TRUE
> + if (Result != TcgResultSuccess) {
> + DEBUG ((DEBUG_ERROR, "OpalBlockSid fail\n"));
> + break;
> + }
> + }
> +
> + Itr = Itr->Next;
> + }
> + }
> +}
> +
> +/**
> + Stop this Controller.
> +
> + @param Dev The device need to be stopped.
> +
> +**/
> +VOID
> +OpalDriverStopDevice (
> + OPAL_DRIVER_DEVICE *Dev
> + )
> +{
> + //
> + // free each name
> + //
> + FreePool(Dev->Name16);
> +
> + //
> + // remove OPAL_DRIVER_DEVICE from the list
> + // it updates the controllerList pointer
> + //
> + RemoveDevice(Dev);
> +
> + //
> + // close protocols that were opened
> + //
> + gBS->CloseProtocol(
> + Dev->Handle,
> + &gEfiStorageSecurityCommandProtocolGuid,
> + gOpalDriverBinding.DriverBindingHandle,
> + Dev->Handle
> + );
> +
> + gBS->CloseProtocol(
> + Dev->Handle,
> + &gEfiBlockIoProtocolGuid,
> + gOpalDriverBinding.DriverBindingHandle,
> + Dev->Handle
> + );
> +
> + FreePool(Dev);
> +}
> +
> +/**
> + Get devcie name through the component name protocol.
> +
> + @param[in] AllHandlesBuffer The handle buffer for current
> system.
> + @param[in] NumAllHandles The number of handles for the
> handle buffer.
> + @param[in] Dev The device which need to get
> name.
> + @param[in] UseComp1 Whether use component name
> or name2 protocol.
> +
> + @retval TRUE Find the name for this device.
> + @retval FALSE Not found the name for this device.
> +**/
> +BOOLEAN
> +OpalDriverGetDeviceNameByProtocol(
> + EFI_HANDLE *AllHandlesBuffer,
> + UINTN NumAllHandles,
> + OPAL_DRIVER_DEVICE *Dev,
> + BOOLEAN UseComp1
> + )
> +{
> + EFI_HANDLE* ProtocolHandlesBuffer;
> + UINTN NumProtocolHandles;
> + EFI_STATUS Status;
> + EFI_COMPONENT_NAME2_PROTOCOL* Cnp1_2; // efi component name
> and componentName2 have same layout
> + EFI_GUID Protocol;
> + UINTN StrLength;
> + EFI_DEVICE_PATH_PROTOCOL* TmpDevPath;
> + UINTN Index1;
> + UINTN Index2;
> + EFI_HANDLE TmpHandle;
> + CHAR16 *DevName;
> +
> + if (Dev == NULL || AllHandlesBuffer == NULL || NumAllHandles == 0) {
> + return FALSE;
> + }
> +
> + Protocol = UseComp1 ? gEfiComponentNameProtocolGuid :
> gEfiComponentName2ProtocolGuid;
> +
> + //
> + // Find all EFI_HANDLES with protocol
> + //
> + Status = gBS->LocateHandleBuffer(
> + ByProtocol,
> + &Protocol,
> + NULL,
> + &NumProtocolHandles,
> + &ProtocolHandlesBuffer
> + );
> + if (EFI_ERROR(Status)) {
> + return FALSE;
> + }
> +
> +
> + //
> + // Exit early if no supported devices
> + //
> + if (NumProtocolHandles == 0) {
> + return FALSE;
> + }
> +
> + //
> + // Get printable name by iterating through all protocols
> + // using the handle as the child, and iterate through all handles for the
> controller
> + // exit loop early once found, if not found, then delete device
> + // storage security protocol instances already exist, add them to internal list
> + //
> + Status = EFI_DEVICE_ERROR;
> + for (Index1 = 0; Index1 < NumProtocolHandles; Index1++) {
> + DevName = NULL;
> +
> + if (Dev->Name16 != NULL) {
> + return TRUE;
> + }
> +
> + TmpHandle = ProtocolHandlesBuffer[Index1];
> +
> + Status = gBS->OpenProtocol(
> + TmpHandle,
> + &Protocol,
> + (VOID**)&Cnp1_2,
> + gImageHandle,
> + NULL,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> + if (EFI_ERROR(Status) || Cnp1_2 == NULL) {
> + continue;
> + }
> +
> + //
> + // Use all handles array as controller handle
> + //
> + for (Index2 = 0; Index2 < NumAllHandles; Index2++) {
> + Status = Cnp1_2->GetControllerName(
> + Cnp1_2,
> + AllHandlesBuffer[Index2],
> + Dev->Handle,
> + LANGUAGE_ISO_639_2_ENGLISH,
> + &DevName
> + );
> + if (EFI_ERROR(Status)) {
> + Status = Cnp1_2->GetControllerName(
> + Cnp1_2,
> + AllHandlesBuffer[Index2],
> + Dev->Handle,
> + LANGUAGE_RFC_3066_ENGLISH,
> + &DevName
> + );
> + }
> + if (!EFI_ERROR(Status) && DevName != NULL) {
> + StrLength = StrLen(DevName) + 1; // Add one for NULL
> terminator
> + Dev->Name16 = AllocateZeroPool(StrLength * sizeof (CHAR16));
> + ASSERT (Dev->Name16 != NULL);
> + StrCpyS (Dev->Name16, StrLength, DevName);
> + Dev->NameZ = (CHAR8*)AllocateZeroPool(StrLength);
> + UnicodeStrToAsciiStrS (DevName, Dev->NameZ, StrLength);
> +
> + //
> + // Retrieve bridge BDF info and port number or namespace depending
> on type
> + //
> + TmpDevPath = NULL;
> + Status = gBS->OpenProtocol(
> + Dev->Handle,
> + &gEfiDevicePathProtocolGuid,
> + (VOID**)&TmpDevPath,
> + gImageHandle,
> + NULL,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> + if (!EFI_ERROR(Status)) {
> + Dev->OpalDevicePath = DuplicateDevicePath (TmpDevPath);
> + return TRUE;
> + }
> +
> + if (Dev->Name16 != NULL) {
> + FreePool(Dev->Name16);
> + Dev->Name16 = NULL;
> + }
> + if (Dev->NameZ != NULL) {
> + FreePool(Dev->NameZ);
> + Dev->NameZ = NULL;
> + }
> + }
> + }
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + Get devcie name through the component name protocol.
> +
> + @param[in] Dev The device which need to get
> name.
> +
> + @retval TRUE Find the name for this device.
> + @retval FALSE Not found the name for this device.
> +**/
> +BOOLEAN
> +OpalDriverGetDriverDeviceName(
> + OPAL_DRIVER_DEVICE *Dev
> + )
> +{
> + EFI_HANDLE* AllHandlesBuffer;
> + UINTN NumAllHandles;
> + EFI_STATUS Status;
> +
> + if (Dev == NULL) {
> + DEBUG((DEBUG_ERROR | DEBUG_INIT, "OpalDriverGetDriverDeviceName
> Exiting, Dev=NULL\n"));
> + return FALSE;
> + }
> +
> + //
> + // Iterate through ComponentName2 handles to get name, if fails, try
> ComponentName
> + //
> + if (Dev->Name16 == NULL) {
> + DEBUG((DEBUG_ERROR | DEBUG_INIT, "Name is null, update it\n"));
> + //
> + // Find all EFI_HANDLES
> + //
> + Status = gBS->LocateHandleBuffer(
> + AllHandles,
> + NULL,
> + NULL,
> + &NumAllHandles,
> + &AllHandlesBuffer
> + );
> + if (EFI_ERROR(Status)) {
> + DEBUG ((DEBUG_INFO, "LocateHandleBuffer for AllHandles failed %r\n",
> Status ));
> + return FALSE;
> + }
> +
> + //
> + // Try component Name2
> + //
> + if (!OpalDriverGetDeviceNameByProtocol(AllHandlesBuffer,
> NumAllHandles, Dev, FALSE)) {
> + DEBUG((DEBUG_ERROR | DEBUG_INIT, "ComponentName2 failed to get
> device name, try ComponentName\n"));
> + if (!OpalDriverGetDeviceNameByProtocol(AllHandlesBuffer,
> NumAllHandles, Dev, TRUE)) {
> + DEBUG((DEBUG_ERROR | DEBUG_INIT, "ComponentName failed to
> get device name, skip device\n"));
> + return FALSE;
> + }
> + }
> + }
> +
> + return TRUE;
> +}
> +
> +/**
> + Main entry for this driver.
> +
> + @param ImageHandle Image Handle this driver.
> + @param SystemTable Pointer to SystemTable.
> +
> + @retval EFI_SUCESS This function always complete successfully.
> +**/
> +EFI_STATUS
> +EFIAPI
> +EfiDriverEntryPoint(
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE* SystemTable
> + )
> +{
> + EFI_STATUS Status;
> + EFI_EVENT ReadyToBootEvent;
> + EFI_EVENT EndOfDxeEvent;
> +
> + Status = EfiLibInstallDriverBindingComponentName2 (
> + ImageHandle,
> + SystemTable,
> + &gOpalDriverBinding,
> + ImageHandle,
> + &gOpalComponentName,
> + &gOpalComponentName2
> + );
> +
> + if (EFI_ERROR(Status)) {
> + DEBUG((DEBUG_ERROR, "Install protocols to Opal driver Handle
> failed\n"));
> + return Status ;
> + }
> +
> + //
> + // Initialize Driver object
> + //
> + ZeroMem(&mOpalDriver, sizeof(mOpalDriver));
> + mOpalDriver.Handle = ImageHandle;
> +
> + Status = gBS->CreateEventEx (
> + EVT_NOTIFY_SIGNAL,
> + TPL_CALLBACK,
> + OpalEndOfDxeEventNotify,
> + NULL,
> + &gEfiEndOfDxeEventGroupGuid,
> + &EndOfDxeEvent
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + //
> + // register a ReadyToBoot event callback for sending BlockSid command
> + //
> + Status = EfiCreateEventReadyToBootEx (
> + TPL_CALLBACK,
> + ReadyToBootCallback,
> + (VOID *) &ImageHandle,
> + &ReadyToBootEvent
> + );
> +
> + //
> + // Install Hii packages.
> + //
> + HiiInstall();
> +
> + return Status;
> +}
> +
> +/**
> + Tests to see if this driver supports a given controller.
> +
> + This function checks to see if the controller contains an instance of the
> + EFI_STORAGE_SECURITY_COMMAND_PROTOCOL and the
> EFI_BLOCK_IO_PROTOCL
> + and returns EFI_SUCCESS if it does.
> +
> + @param[in] This A pointer to the
> EFI_DRIVER_BINDING_PROTOCOL instance.
> + @param[in] ControllerHandle The Handle of the controller to test.
> This Handle
> + must support a protocol interface
> that supplies
> + an I/O abstraction to the driver.
> + @param[in] RemainingDevicePath This parameter is ignored.
> +
> + @retval EFI_SUCCESS The device contains required
> protocols
> + @retval EFI_ALREADY_STARTED The device specified by
> ControllerHandle and
> + RemainingDevicePath is already
> being managed by the driver
> + specified by This.
> + @retval EFI_ACCESS_DENIED The device specified by
> ControllerHandle and
> + RemainingDevicePath is already
> being managed by a different
> + driver or an application that requires
> exclusive access.
> + Currently not implemented.
> + @retval EFI_UNSUPPORTED The device does not contain
> requires protocols
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +OpalEfiDriverBindingSupported(
> + IN EFI_DRIVER_BINDING_PROTOCOL* This,
> + IN EFI_HANDLE Controller,
> + IN EFI_DEVICE_PATH_PROTOCOL* RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + EFI_STORAGE_SECURITY_COMMAND_PROTOCOL* SecurityCommand;
> + EFI_BLOCK_IO_PROTOCOL* BlkIo;
> +
> + if (mOpalEndOfDxe) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + //
> + // Test EFI_STORAGE_SECURITY_COMMAND_PROTOCOL on controller
> Handle.
> + //
> + Status = gBS->OpenProtocol(
> + Controller,
> + &gEfiStorageSecurityCommandProtocolGuid,
> + ( VOID ** )&SecurityCommand,
> + This->DriverBindingHandle,
> + Controller,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> +
> + if (Status == EFI_ALREADY_STARTED) {
> + return EFI_SUCCESS;
> + }
> +
> + if (EFI_ERROR(Status)) {
> + return Status;
> + }
> +
> + //
> + // Close protocol and reopen in Start call
> + //
> + gBS->CloseProtocol(
> + Controller,
> + &gEfiStorageSecurityCommandProtocolGuid,
> + This->DriverBindingHandle,
> + Controller
> + );
> +
> + //
> + // Test EFI_BLOCK_IO_PROTOCOL on controller Handle, required by
> EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
> + // function APIs
> + //
> + Status = gBS->OpenProtocol(
> + Controller,
> + &gEfiBlockIoProtocolGuid,
> + (VOID **)&BlkIo,
> + This->DriverBindingHandle,
> + Controller,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> +
> + if (EFI_ERROR(Status)) {
> + DEBUG((DEBUG_INFO, "No EFI_BLOCK_IO_PROTOCOL on controller\n"));
> + return Status;
> + }
> +
> + //
> + // Close protocol and reopen in Start call
> + //
> + gBS->CloseProtocol(
> + Controller,
> + &gEfiBlockIoProtocolGuid,
> + This->DriverBindingHandle,
> + Controller
> + );
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Enables Opal Management on a supported device if available.
> +
> + The start function is designed to be called after the Opal UEFI Driver has
> confirmed the
> + "controller", which is a child Handle, contains the
> EF_STORAGE_SECURITY_COMMAND protocols.
> + This function will complete the other necessary checks, such as verifying the
> device supports
> + the correct version of Opal. Upon verification, it will add the device to the
> + Opal HII list in order to expose Opal managmeent options.
> +
> + @param[in] This A pointer to the
> EFI_DRIVER_BINDING_PROTOCOL instance.
> + @param[in] ControllerHandle The Handle of the controller to start.
> This Handle
> + must support a protocol interface
> that supplies
> + an I/O abstraction to the driver.
> + @param[in] RemainingDevicePath A pointer to the remaining portion of
> a device path. This
> + parameter is ignored by device
> drivers, and is optional for bus
> + drivers. For a bus driver, if this
> parameter is NULL, then handles
> + for all the children of Controller are
> created by this driver.
> + If this parameter is not NULL and the
> first Device Path Node is
> + not the End of Device Path Node,
> then only the Handle for the
> + child device specified by the first
> Device Path Node of
> + RemainingDevicePath is created by
> this driver.
> + If the first Device Path Node of
> RemainingDevicePath is
> + the End of Device Path Node, no
> child Handle is created by this
> + driver.
> +
> + @retval EFI_SUCCESS Opal management was enabled.
> + @retval EFI_DEVICE_ERROR The device could not be started due
> to a device error.Currently not implemented.
> + @retval EFI_OUT_OF_RESOURCES The request could not be
> completed due to a lack of resources.
> + @retval Others The driver failed to start the device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +OpalEfiDriverBindingStart(
> + IN EFI_DRIVER_BINDING_PROTOCOL* This,
> + IN EFI_HANDLE Controller,
> + IN EFI_DEVICE_PATH_PROTOCOL* RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + EFI_BLOCK_IO_PROTOCOL *BlkIo;
> + OPAL_DRIVER_DEVICE *Dev;
> + OPAL_DRIVER_DEVICE *Itr;
> + BOOLEAN Result;
> +
> + Itr = mOpalDriver.DeviceList;
> + while (Itr != NULL) {
> + if (Controller == Itr->Handle) {
> + return EFI_SUCCESS;
> + }
> + Itr = Itr->Next;
> + }
> +
> + //
> + // Create internal device for tracking. This allows all disks to be tracked
> + // by same HII form
> + //
> + Dev =
> (OPAL_DRIVER_DEVICE*)AllocateZeroPool(sizeof(OPAL_DRIVER_DEVICE));
> + if (Dev == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> + Dev->Handle = Controller;
> +
> + //
> + // Open EFI_STORAGE_SECURITY_COMMAND_PROTOCOL to perform Opal
> supported checks
> + //
> + Status = gBS->OpenProtocol(
> + Controller,
> + &gEfiStorageSecurityCommandProtocolGuid,
> + (VOID **)&Dev->Sscp,
> + This->DriverBindingHandle,
> + Controller,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR(Status)) {
> + FreePool(Dev);
> + return Status;
> + }
> +
> + //
> + // Open EFI_BLOCK_IO_PROTOCOL on controller Handle, required by
> EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
> + // function APIs
> + //
> + Status = gBS->OpenProtocol(
> + Controller,
> + &gEfiBlockIoProtocolGuid,
> + (VOID **)&BlkIo,
> + This->DriverBindingHandle,
> + Controller,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR(Status)) {
> + //
> + // Close storage security that was opened
> + //
> + gBS->CloseProtocol(
> + Controller,
> + &gEfiStorageSecurityCommandProtocolGuid,
> + This->DriverBindingHandle,
> + Controller
> + );
> +
> + FreePool(Dev);
> + return Status;
> + }
> +
> + //
> + // Save mediaId
> + //
> + Dev->MediaId = BlkIo->Media->MediaId;
> +
> + gBS->CloseProtocol(
> + Controller,
> + &gEfiBlockIoProtocolGuid,
> + This->DriverBindingHandle,
> + Controller
> + );
> +
> + //
> + // Acquire Ascii printable name of child, if not found, then ignore device
> + //
> + Result = OpalDriverGetDriverDeviceName (Dev);
> + if (!Result) {
> + goto Done;
> + }
> +
> + Status = OpalDiskInitialize (Dev);
> + if (EFI_ERROR (Status)) {
> + goto Done;
> + }
> +
> + AddDeviceToTail(Dev);
> +
> + //
> + // Check if device is locked and prompt for password.
> + //
> + OpalDriverRequestPassword (Dev, L"Unlock:");
> +
> + //
> + // Process OPAL request from last boot.
> + //
> + ProcessOpalRequest (Dev);
> +
> + return EFI_SUCCESS;
> +
> +Done:
> + //
> + // free device, close protocols and exit
> + //
> + gBS->CloseProtocol(
> + Controller,
> + &gEfiStorageSecurityCommandProtocolGuid,
> + This->DriverBindingHandle,
> + Controller
> + );
> +
> + FreePool(Dev);
> +
> + return EFI_DEVICE_ERROR;
> +}
> +
> +/**
> + Stop this driver on Controller.
> +
> + @param This Protocol instance pointer.
> + @param Controller Handle of device to stop driver on
> + @param NumberOfChildren Number of Handles in ChildHandleBuffer. If
> number of
> + children is zero stop the entire bus driver.
> + @param ChildHandleBuffer List of Child Handles to Stop.
> +
> + @retval EFI_SUCCESS This driver is removed Controller.
> + @retval other This driver could not be removed from this
> device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +OpalEfiDriverBindingStop(
> + EFI_DRIVER_BINDING_PROTOCOL* This,
> + EFI_HANDLE Controller,
> + UINTN NumberOfChildren,
> + EFI_HANDLE* ChildHandleBuffer
> + )
> +{
> + OPAL_DRIVER_DEVICE* Itr;
> +
> + Itr = mOpalDriver.DeviceList;
> +
> + //
> + // does Controller match any of the devices we are managing for Opal
> + //
> + while (Itr != NULL) {
> + if (Itr->Handle == Controller) {
> + OpalDriverStopDevice (Itr);
> + return EFI_SUCCESS;
> + }
> +
> + Itr = Itr->Next;
> + }
> +
> + return EFI_NOT_FOUND;
> +}
> +
> +
> +/**
> + Unloads UEFI Driver. Very useful for debugging and testing.
> +
> + @param ImageHandle Image Handle this driver.
> +
> + @retval EFI_SUCCESS This function always complete
> successfully.
> + @retval EFI_INVALID_PARAMETER The input ImageHandle is not valid.
> +**/
> +EFI_STATUS
> +EFIAPI
> +OpalEfiDriverUnload (
> + IN EFI_HANDLE ImageHandle
> + )
> +{
> + EFI_STATUS Status;
> + OPAL_DRIVER_DEVICE *Itr;
> +
> + Status = EFI_SUCCESS;
> +
> + if (ImageHandle != gImageHandle) {
> + return (EFI_INVALID_PARAMETER);
> + }
> +
> + //
> + // Uninstall any interface added to each device by us
> + //
> + while (mOpalDriver.DeviceList) {
> + Itr = mOpalDriver.DeviceList;
> + //
> + // Remove OPAL_DRIVER_DEVICE from the list
> + // it updates the controllerList pointer
> + //
> + OpalDriverStopDevice(Itr);
> + }
> +
> + //
> + // Uninstall the HII capability
> + //
> + Status = HiiUninstall();
> +
> + return Status;
> +}
> +
> diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.h
> b/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.h
> new file mode 100644
> index 000000000000..a66b5a5345ff
> --- /dev/null
> +++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.h
> @@ -0,0 +1,613 @@
> +/** @file
> + Values defined and used by the Opal UEFI Driver.
> +
> +Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution. The full text of the license may be found
> at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +
> +#ifndef _OPAL_DRIVER_H_
> +#define _OPAL_DRIVER_H_
> +
> +#include <PiDxe.h>
> +
> +#include <IndustryStandard/Pci.h>
> +
> +#include <Protocol/PciIo.h>
> +#include <Protocol/SmmCommunication.h>
> +#include <Protocol/BlockIo.h>
> +#include <Protocol/LoadedImage.h>
> +#include <Protocol/DevicePath.h>
> +#include <Protocol/DevicePathToText.h>
> +#include <Protocol/StorageSecurityCommand.h>
> +
> +#include <Guid/EventGroup.h>
> +
> +#include <Library/UefiLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiRuntimeServicesTableLib.h>
> +#include <Library/DxeServicesTableLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/PrintLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/HiiLib.h>
> +#include <Library/UefiHiiServicesLib.h>
> +#include <Library/PciLib.h>
> +#include <Library/S3BootScriptLib.h>
> +#include <Library/LockBoxLib.h>
> +#include <Library/TcgStorageOpalLib.h>
> +#include <Library/Tcg2PhysicalPresenceLib.h>
> +
> +#include "OpalPasswordCommon.h"
> +#include "OpalHiiFormValues.h"
> +
> +#define EFI_DRIVER_NAME_UNICODE L"1.0 UEFI Opal Driver"
> +
> +// UEFI 2.1
> +#define LANGUAGE_RFC_3066_ENGLISH ((CHAR8*)"en")
> +
> +// UEFI/EFI < 2.1
> +#define LANGUAGE_ISO_639_2_ENGLISH ((CHAR8*)"eng")
> +
> +#define CONCAT_(x, y) x ## y
> +#define CONCAT(x, y) CONCAT_(x, y)
> +
> +#define UNICODE_STR(x) CONCAT( L, x )
> +
> +extern EFI_DRIVER_BINDING_PROTOCOL gOpalDriverBinding;
> +extern EFI_COMPONENT_NAME_PROTOCOL gOpalComponentName;
> +extern EFI_COMPONENT_NAME2_PROTOCOL gOpalComponentName2;
> +
> +#define OPAL_MSID_LENGHT 128
> +
> +#define MAX_PASSWORD_SIZE 32
> +#define MAX_PASSWORD_TRY_COUNT 5
> +
> +// PSID Length
> +#define PSID_CHARACTER_LENGTH 0x20
> +#define MAX_PSID_TRY_COUNT 5
> +
> +#pragma pack(1)
> +
> +//
> +// Structure that is used to represent the available actions for an OpalDisk.
> +// The data can then be utilized to expose/hide certain actions available to an
> end user
> +// by the consumer of this library.
> +//
> +typedef struct {
> + //
> + // Indicates if the disk can support PSID Revert action. should verify disk
> supports PSID authority
> + //
> + UINT16 PsidRevert : 1;
> +
> + //
> + // Indicates if the disk can support Revert action
> + //
> + UINT16 Revert : 1;
> +
> + //
> + // Indicates if the user must keep data for revert action. It is true if no
> media encryption is supported.
> + //
> + UINT16 RevertKeepDataForced : 1;
> +
> + //
> + // Indicates if the disk can support set Admin password
> + //
> + UINT16 AdminPass : 1;
> +
> + //
> + // Indicates if the disk can support set User password. This action
> requires that a user
> + // password is first enabled.
> + //
> + UINT16 UserPass : 1;
> +
> + //
> + // Indicates if unlock action is available. Requires disk to be currently
> locked.
> + //
> + UINT16 Unlock : 1;
> +
> + //
> + // Indicates if Secure Erase action is available. Action requires admin
> credentials and media encryption support.
> + //
> + UINT16 SecureErase : 1;
> +
> + //
> + // Indicates if Disable User action is available. Action requires admin
> credentials.
> + //
> + UINT16 DisableUser : 1;
> +} OPAL_DISK_ACTIONS;
> +
> +//
> +// Structure that is used to represent an OPAL_DISK.
> +//
> +typedef struct {
> + UINT32 MsidLength;
> // Byte length of MSID Pin for device
> + UINT8
> Msid[OPAL_MSID_LENGHT]; // MSID Pin for device
> + EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *Sscp;
> + UINT32 MediaId;
> // MediaId is used by Ssc Protocol.
> + EFI_DEVICE_PATH_PROTOCOL *OpalDevicePath;
> + UINT16 OpalBaseComId;
> // Opal SSC 1 base com id.
> + OPAL_OWNER_SHIP Owner;
> + OPAL_DISK_SUPPORT_ATTRIBUTE
> SupportedAttributes;
> + TCG_LOCKING_FEATURE_DESCRIPTOR LockingFeature;
> // Locking Feature Descriptor retrieved from performing a Level 0 Discovery
> + UINT8 PasswordLength;
> + UINT8
> Password[MAX_PASSWORD_SIZE];
> +} OPAL_DISK;
> +
> +//
> +// Device with block IO protocol
> +//
> +typedef struct _OPAL_DRIVER_DEVICE OPAL_DRIVER_DEVICE;
> +
> +struct _OPAL_DRIVER_DEVICE {
> + OPAL_DRIVER_DEVICE *Next;
> ///< Linked list pointer
> + EFI_HANDLE Handle;
> ///< Device handle
> + OPAL_DISK OpalDisk;
> ///< User context
> + CHAR16 *Name16;
> ///< Allocated/freed by UEFI Filter Driver at device creation/removal
> + CHAR8 *NameZ;
> ///< Allocated/freed by UEFI Filter Driver at device creation/removal
> + UINT32 MediaId;
> ///< Required parameter for EFI_STORAGE_SECURITY_COMMAND_PROTOCOL,
> from BLOCK_IO_MEDIA
> +
> + EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *Sscp;
> /// Device protocols consumed
> + EFI_DEVICE_PATH_PROTOCOL *OpalDevicePath;
> +};
> +
> +//
> +// Opal Driver UEFI Driver Model
> +//
> +typedef struct {
> + EFI_HANDLE Handle; ///< Driver image handle
> + OPAL_DRIVER_DEVICE *DeviceList; ///< Linked list of controllers
> owned by this Driver
> +} OPAL_DRIVER;
> +
> +#pragma pack()
> +
> +//
> +// Retrieves a OPAL_DRIVER_DEVICE based on the pointer to its StorageSecurity
> protocol.
> +//
> +#define DRIVER_DEVICE_FROM_OPALDISK(OpalDiskPointer)
> (OPAL_DRIVER_DEVICE*)(BASE_CR(OpalDiskPointer, OPAL_DRIVER_DEVICE,
> OpalDisk))
> +
> +/**
> + Get devcie list info.
> +
> + @retval return the device list pointer.
> +**/
> +OPAL_DRIVER_DEVICE*
> +OpalDriverGetDeviceList(
> + VOID
> + );
> +
> +/**
> + Get devcie name through the component name protocol.
> +
> + @param[in] Dev The device which need to get
> name.
> +
> + @retval TRUE Find the name for this device.
> + @retval FALSE Not found the name for this device.
> +**/
> +BOOLEAN
> +OpalDriverGetDriverDeviceName(
> + OPAL_DRIVER_DEVICE *Dev
> + );
> +
> +/**
> + Get current device count.
> +
> + @retval return the current created device count.
> +
> +**/
> +UINT8
> +GetDeviceCount (
> + VOID
> + );
> +
> +/**
> + Update password for the Opal disk.
> +
> + @param[in, out] OpalDisk The disk to update password.
> + @param[in] Password The input password.
> + @param[in] PasswordLength The input password length.
> +
> +**/
> +VOID
> +OpalSupportUpdatePassword (
> + IN OUT OPAL_DISK *OpalDisk,
> + IN VOID *Password,
> + IN UINT32 PasswordLength
> + );
> +
> +/**
> +
> + The function performs determines the available actions for the OPAL_DISK
> provided.
> +
> + @param[in] SupportedAttributes The support attribute for the device.
> + @param[in] LockingFeature The locking status for the device.
> + @param[in] OwnerShip The ownership for the device.
> + @param[out] AvalDiskActions Pointer to fill-out with appropriate
> disk actions.
> +
> +**/
> +TCG_RESULT
> +EFIAPI
> +OpalSupportGetAvailableActions(
> + IN OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes,
> + IN TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature,
> + IN UINT16 OwnerShip,
> + OUT OPAL_DISK_ACTIONS *AvalDiskActions
> + );
> +
> +/**
> + Enable Opal Feature for the input device.
> +
> + @param[in] Session The opal session for the opal device.
> + @param[in] Msid Msid
> + @param[in] MsidLength Msid Length
> + @param[in] Password Admin password
> + @param[in] PassLength Length of password in bytes
> +
> +**/
> +TCG_RESULT
> +EFIAPI
> +OpalSupportEnableOpalFeature (
> + IN OPAL_SESSION *Session,
> + IN VOID *Msid,
> + IN UINT32 MsidLength,
> + IN VOID *Password,
> + IN UINT32 PassLength
> + );
> +
> +/**
> + Unloads UEFI Driver. Very useful for debugging and testing.
> +
> + @param ImageHandle Image handle this driver.
> +
> + @retval EFI_SUCCESS This function always complete
> successfully.
> + @retval EFI_INVALID_PARAMETER The input ImageHandle is not valid.
> +**/
> +EFI_STATUS
> +EFIAPI
> +EfiDriverUnload(
> + EFI_HANDLE ImageHandle
> + );
> +
> +
> +/**
> + Test to see if this driver supports Controller.
> +
> + @param This Protocol instance pointer.
> + @param ControllerHandle Handle of device to test
> + @param RemainingDevicePath Optional parameter use to pick a specific
> child
> + device to start.
> +
> + @retval EFI_SUCCESS This driver supports this device.
> + @retval EFI_ALREADY_STARTED This driver is already running on this device.
> + @retval other This driver does not support this device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +OpalEfiDriverBindingSupported(
> + EFI_DRIVER_BINDING_PROTOCOL* This,
> + EFI_HANDLE Controller,
> + EFI_DEVICE_PATH_PROTOCOL* RemainingDevicePath
> + );
> +
> +/**
> + Enables Opal Management on a supported device if available.
> +
> + The start function is designed to be called after the Opal UEFI Driver has
> confirmed the
> + "controller", which is a child handle, contains the
> EF_STORAGE_SECURITY_COMMAND protocols.
> + This function will complete the other necessary checks, such as verifying the
> device supports
> + the correct version of Opal. Upon verification, it will add the device to the
> + Opal HII list in order to expose Opal managmeent options.
> +
> + @param[in] This A pointer to the
> EFI_DRIVER_BINDING_PROTOCOL instance.
> + @param[in] ControllerHandle The handle of the controller to start.
> This handle
> + must support a protocol interface
> that supplies
> + an I/O abstraction to the driver.
> + @param[in] RemainingDevicePath A pointer to the remaining portion of
> a device path. This
> + parameter is ignored by device
> drivers, and is optional for bus
> + drivers. For a bus driver, if this
> parameter is NULL, then handles
> + for all the children of Controller are
> created by this driver.
> + If this parameter is not NULL and the
> first Device Path Node is
> + not the End of Device Path Node,
> then only the handle for the
> + child device specified by the first
> Device Path Node of
> + RemainingDevicePath is created by
> this driver.
> + If the first Device Path Node of
> RemainingDevicePath is
> + the End of Device Path Node, no
> child handle is created by this
> + driver.
> +
> + @retval EFI_SUCCESS Opal management was enabled.
> + @retval EFI_DEVICE_ERROR The device could not be started due
> to a device error.Currently not implemented.
> + @retval EFI_OUT_OF_RESOURCES The request could not be
> completed due to a lack of resources.
> + @retval Others The driver failed to start the device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +OpalEfiDriverBindingStart(
> + EFI_DRIVER_BINDING_PROTOCOL* This,
> + EFI_HANDLE Controller,
> + EFI_DEVICE_PATH_PROTOCOL* RemainingDevicePath
> + );
> +
> +/**
> + Stop this driver on Controller.
> +
> + @param This Protocol instance pointer.
> + @param Controller Handle of device to stop driver on
> + @param NumberOfChildren Number of Handles in ChildHandleBuffer. If
> number of
> + children is zero stop the entire bus driver.
> + @param ChildHandleBuffer List of Child Handles to Stop.
> +
> + @retval EFI_SUCCESS This driver is removed Controller.
> + @retval other This driver could not be removed from this
> device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +OpalEfiDriverBindingStop(
> + EFI_DRIVER_BINDING_PROTOCOL* This,
> + EFI_HANDLE Controller,
> + UINTN NumberOfChildren,
> + EFI_HANDLE* ChildHandleBuffer
> + );
> +
> +/**
> + Retrieves a Unicode string that is the user readable name of the driver.
> +
> + This function retrieves the user readable name of a driver in the form of a
> + Unicode string. If the driver specified by This has a user readable name in
> + the language specified by Language, then a pointer to the driver name is
> + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
> + by This does not support the language specified by Language,
> + then EFI_UNSUPPORTED is returned.
> +
> + @param This[in] A pointer to the
> EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL
> instance.
> +
> + @param Language[in] A pointer to a Null-terminated ASCII
> string
> + array indicating the language. This is the
> + language of the driver name that the
> caller is
> + requesting, and it must match one of the
> + languages specified in
> SupportedLanguages. The
> + number of languages supported by a
> driver is up
> + to the driver writer. Language is specified
> + in RFC 4646 or ISO 639-2 language code
> format.
> +
> + @param DriverName[out] A pointer to the Unicode string to
> return.
> + This Unicode string is the name of the
> + driver specified by This in the language
> + specified by Language.
> +
> + @retval EFI_SUCCESS The Unicode string for the Driver specified
> by
> + This and the language specified by
> Language was
> + returned in DriverName.
> +
> + @retval EFI_INVALID_PARAMETER Language is NULL.
> +
> + @retval EFI_INVALID_PARAMETER DriverName is NULL.
> +
> + @retval EFI_UNSUPPORTED The driver specified by This does not
> support
> + the language specified by Language.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +OpalEfiDriverComponentNameGetDriverName(
> + EFI_COMPONENT_NAME_PROTOCOL* This,
> + CHAR8* Language,
> + CHAR16** DriverName
> + );
> +
> +/**
> + Retrieves a Unicode string that is the user readable name of the controller
> + that is being managed by a driver.
> +
> + This function retrieves the user readable name of the controller specified by
> + ControllerHandle and ChildHandle in the form of a Unicode string. If the
> + driver specified by This has a user readable name in the language specified by
> + Language, then a pointer to the controller name is returned in
> ControllerName,
> + and EFI_SUCCESS is returned. If the driver specified by This is not currently
> + managing the controller specified by ControllerHandle and ChildHandle,
> + then EFI_UNSUPPORTED is returned. If the driver specified by This does not
> + support the language specified by Language, then EFI_UNSUPPORTED is
> returned.
> +
> + @param This[in] A pointer to the
> EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL
> instance.
> +
> + @param ControllerHandle[in] The handle of a controller that the driver
> + specified by This is managing. This
> handle
> + specifies the controller whose name is to
> be
> + returned.
> +
> + @param ChildHandle[in] The handle of the child controller to
> retrieve
> + the name of. This is an optional
> parameter that
> + may be NULL. It will be NULL for device
> + drivers. It will also be NULL for a bus
> drivers
> + that wish to retrieve the name of the bus
> + controller. It will not be NULL for a bus
> + driver that wishes to retrieve the name of
> a
> + child controller.
> +
> + @param Language[in] A pointer to a Null-terminated ASCII
> string
> + array indicating the language. This is the
> + language of the driver name that the
> caller is
> + requesting, and it must match one of the
> + languages specified in
> SupportedLanguages. The
> + number of languages supported by a
> driver is up
> + to the driver writer. Language is specified
> in
> + RFC 4646 or ISO 639-2 language code
> format.
> +
> + @param ControllerName[out] A pointer to the Unicode string to return.
> + This Unicode string is the name of the
> + controller specified by ControllerHandle
> and
> + ChildHandle in the language specified by
> + Language from the point of view of the
> driver
> + specified by This.
> +
> + @retval EFI_SUCCESS The Unicode string for the user readable
> name in
> + the language specified by Language for
> the
> + driver specified by This was returned in
> + DriverName.
> +
> + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
> +
> + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a
> valid
> + EFI_HANDLE.
> +
> + @retval EFI_INVALID_PARAMETER Language is NULL.
> +
> + @retval EFI_INVALID_PARAMETER ControllerName is NULL.
> +
> + @retval EFI_UNSUPPORTED The driver specified by This is not
> currently
> + managing the controller specified by
> + ControllerHandle and ChildHandle.
> +
> + @retval EFI_UNSUPPORTED The driver specified by This does not
> support
> + the language specified by Language.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +OpalEfiDriverComponentNameGetControllerName(
> + EFI_COMPONENT_NAME_PROTOCOL* This,
> + EFI_HANDLE ControllerHandle,
> + EFI_HANDLE ChildHandle,
> + CHAR8* Language,
> + CHAR16** ControllerName
> + );
> +
> +/**
> + Retrieves a Unicode string that is the user readable name of the driver.
> +
> + This function retrieves the user readable name of a driver in the form of a
> + Unicode string. If the driver specified by This has a user readable name in
> + the language specified by Language, then a pointer to the driver name is
> + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
> + by This does not support the language specified by Language,
> + then EFI_UNSUPPORTED is returned.
> +
> + @param This[in] A pointer to the
> EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL
> instance.
> +
> + @param Language[in] A pointer to a Null-terminated ASCII
> string
> + array indicating the language. This is the
> + language of the driver name that the
> caller is
> + requesting, and it must match one of the
> + languages specified in
> SupportedLanguages. The
> + number of languages supported by a
> driver is up
> + to the driver writer. Language is specified
> + in RFC 4646 or ISO 639-2 language code
> format.
> +
> + @param DriverName[out] A pointer to the Unicode string to
> return.
> + This Unicode string is the name of the
> + driver specified by This in the language
> + specified by Language.
> +
> + @retval EFI_SUCCESS The Unicode string for the Driver specified
> by
> + This and the language specified by
> Language was
> + returned in DriverName.
> +
> + @retval EFI_INVALID_PARAMETER Language is NULL.
> +
> + @retval EFI_INVALID_PARAMETER DriverName is NULL.
> +
> + @retval EFI_UNSUPPORTED The driver specified by This does not
> support
> + the language specified by Language.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +OpalEfiDriverComponentName2GetDriverName(
> + EFI_COMPONENT_NAME2_PROTOCOL* This,
> + CHAR8* Language,
> + CHAR16** DriverName
> + );
> +
> +/**
> + Retrieves a Unicode string that is the user readable name of the controller
> + that is being managed by a driver.
> +
> + This function retrieves the user readable name of the controller specified by
> + ControllerHandle and ChildHandle in the form of a Unicode string. If the
> + driver specified by This has a user readable name in the language specified by
> + Language, then a pointer to the controller name is returned in
> ControllerName,
> + and EFI_SUCCESS is returned. If the driver specified by This is not currently
> + managing the controller specified by ControllerHandle and ChildHandle,
> + then EFI_UNSUPPORTED is returned. If the driver specified by This does not
> + support the language specified by Language, then EFI_UNSUPPORTED is
> returned.
> +
> + @param This[in] A pointer to the
> EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL
> instance.
> +
> + @param ControllerHandle[in] The handle of a controller that the driver
> + specified by This is managing. This
> handle
> + specifies the controller whose name is to
> be
> + returned.
> +
> + @param ChildHandle[in] The handle of the child controller to
> retrieve
> + the name of. This is an optional
> parameter that
> + may be NULL. It will be NULL for device
> + drivers. It will also be NULL for a bus
> drivers
> + that wish to retrieve the name of the bus
> + controller. It will not be NULL for a bus
> + driver that wishes to retrieve the name of
> a
> + child controller.
> +
> + @param Language[in] A pointer to a Null-terminated ASCII
> string
> + array indicating the language. This is the
> + language of the driver name that the
> caller is
> + requesting, and it must match one of the
> + languages specified in
> SupportedLanguages. The
> + number of languages supported by a
> driver is up
> + to the driver writer. Language is specified
> in
> + RFC 4646 or ISO 639-2 language code
> format.
> +
> + @param ControllerName[out] A pointer to the Unicode string to return.
> + This Unicode string is the name of the
> + controller specified by ControllerHandle
> and
> + ChildHandle in the language specified by
> + Language from the point of view of the
> driver
> + specified by This.
> +
> + @retval EFI_SUCCESS The Unicode string for the user readable
> name in
> + the language specified by Language for
> the
> + driver specified by This was returned in
> + DriverName.
> +
> + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
> +
> + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a
> valid
> + EFI_HANDLE.
> +
> + @retval EFI_INVALID_PARAMETER Language is NULL.
> +
> + @retval EFI_INVALID_PARAMETER ControllerName is NULL.
> +
> + @retval EFI_UNSUPPORTED The driver specified by This is not
> currently
> + managing the controller specified by
> + ControllerHandle and ChildHandle.
> +
> + @retval EFI_UNSUPPORTED The driver specified by This does not
> support
> + the language specified by Language.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +OpalEfiDriverComponentName2GetControllerName(
> + EFI_COMPONENT_NAME2_PROTOCOL* This,
> + EFI_HANDLE ControllerHandle,
> + EFI_HANDLE ChildHandle,
> + CHAR8* Language,
> + CHAR16** ControllerName
> + );
> +
> +#endif //_OPAL_DRIVER_H_
> diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.c
> b/SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.c
> new file mode 100644
> index 000000000000..e4972227b669
> --- /dev/null
> +++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.c
> @@ -0,0 +1,1178 @@
> +/** @file
> + Implementation of the HII for the Opal UEFI Driver.
> +
> +Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution. The full text of the license may be found
> at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +
> +#include "OpalHii.h"
> +
> +//
> +// This is the generated IFR binary Data for each formset defined in VFR.
> +// This Data array is ready to be used as input of HiiAddPackages() to
> +// create a packagelist (which contains Form packages, String packages, etc).
> +//
> +extern UINT8 OpalPasswordFormBin[];
> +
> +//
> +// This is the generated String package Data for all .UNI files.
> +// This Data array is ready to be used as input of HiiAddPackages() to
> +// create a packagelist (which contains Form packages, String packages, etc).
> +//
> +extern UINT8 OpalPasswordDxeStrings[];
> +
> +CHAR16 OpalPasswordStorageName[] = L"OpalHiiConfig";
> +
> +EFI_HII_CONFIG_ACCESS_PROTOCOL gHiiConfigAccessProtocol;
> +
> +//
> +// Handle to the list of HII packages (forms and strings) for this driver
> +//
> +EFI_HII_HANDLE gHiiPackageListHandle = NULL;
> +
> +//
> +// Package List GUID containing all form and string packages
> +//
> +const EFI_GUID gHiiPackageListGuid = PACKAGE_LIST_GUID;
> +const EFI_GUID gHiiSetupVariableGuid = SETUP_VARIABLE_GUID;
> +
> +//
> +// Structure that contains state of the HII
> +// This structure is updated by Hii.cpp and its contents
> +// is rendered in the HII.
> +//
> +OPAL_HII_CONFIGURATION gHiiConfiguration;
> +
> +//
> +// The device path containing the VENDOR_DEVICE_PATH and
> EFI_DEVICE_PATH_PROTOCOL
> +//
> +HII_VENDOR_DEVICE_PATH gHiiVendorDevicePath = {
> + {
> + {
> + HARDWARE_DEVICE_PATH,
> + HW_VENDOR_DP,
> + {
> + (UINT8)(sizeof(VENDOR_DEVICE_PATH)),
> + (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8)
> + }
> + },
> + OPAL_PASSWORD_CONFIG_GUID
> + },
> + {
> + END_DEVICE_PATH_TYPE,
> + END_ENTIRE_DEVICE_PATH_SUBTYPE,
> + {
> + (UINT8)(END_DEVICE_PATH_LENGTH),
> + (UINT8)((END_DEVICE_PATH_LENGTH) >> 8)
> + }
> + }
> +};
> +
> +/**
> + Get saved OPAL request.
> +
> + @param[in] OpalDisk The disk needs to get the saved OPAL request.
> + @param[out] OpalRequest OPAL request got.
> +
> +**/
> +VOID
> +GetSavedOpalRequest (
> + IN OPAL_DISK *OpalDisk,
> + OUT OPAL_REQUEST *OpalRequest
> + )
> +{
> + EFI_STATUS Status;
> + OPAL_REQUEST_VARIABLE *TempVariable;
> + OPAL_REQUEST_VARIABLE *Variable;
> + UINTN VariableSize;
> + EFI_DEVICE_PATH_PROTOCOL *DevicePathInVariable;
> + UINTN DevicePathSizeInVariable;
> + EFI_DEVICE_PATH_PROTOCOL *DevicePath;
> + UINTN DevicePathSize;
> +
> + DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));
> +
> + Variable = NULL;
> + VariableSize = 0;
> +
> + Status = GetVariable2 (
> + OPAL_REQUEST_VARIABLE_NAME,
> + &gHiiSetupVariableGuid,
> + (VOID **) &Variable,
> + &VariableSize
> + );
> + if (EFI_ERROR (Status) || (Variable == NULL)) {
> + return;
> + }
> +
> + TempVariable = Variable;
> + while ((VariableSize > sizeof (OPAL_REQUEST_VARIABLE)) &&
> + (VariableSize >= TempVariable->Length) &&
> + (TempVariable->Length > sizeof (OPAL_REQUEST_VARIABLE))) {
> + DevicePathInVariable = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN)
> TempVariable + sizeof (OPAL_REQUEST_VARIABLE));
> + DevicePathSizeInVariable = GetDevicePathSize (DevicePathInVariable);
> + DevicePath = OpalDisk->OpalDevicePath;
> + DevicePathSize = GetDevicePathSize (DevicePath);
> + if ((DevicePathSize == DevicePathSizeInVariable) &&
> + (CompareMem (DevicePath, DevicePathInVariable, DevicePathSize)
> == 0)) {
> + //
> + // Found the node for the OPAL device.
> + // Get the OPAL request.
> + //
> + CopyMem (OpalRequest, &TempVariable->OpalRequest, sizeof
> (OPAL_REQUEST));
> + DEBUG ((
> + DEBUG_INFO,
> + "OpalRequest got: 0x%x\n",
> + *OpalRequest
> + ));
> + break;
> + }
> + VariableSize -= TempVariable->Length;
> + TempVariable = (OPAL_REQUEST_VARIABLE *) ((UINTN) TempVariable +
> TempVariable->Length);
> + }
> +
> + FreePool (Variable);
> +
> + DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));
> +}
> +
> +/**
> + Save OPAL request.
> +
> + @param[in] OpalDisk The disk has OPAL request to save.
> + @param[in] OpalRequest OPAL request to save.
> +
> +**/
> +VOID
> +SaveOpalRequest (
> + IN OPAL_DISK *OpalDisk,
> + IN OPAL_REQUEST OpalRequest
> + )
> +{
> + EFI_STATUS Status;
> + OPAL_REQUEST_VARIABLE *TempVariable;
> + UINTN TempVariableSize;
> + OPAL_REQUEST_VARIABLE *Variable;
> + UINTN VariableSize;
> + OPAL_REQUEST_VARIABLE *NewVariable;
> + UINTN NewVariableSize;
> + EFI_DEVICE_PATH_PROTOCOL *DevicePathInVariable;
> + UINTN DevicePathSizeInVariable;
> + EFI_DEVICE_PATH_PROTOCOL *DevicePath;
> + UINTN DevicePathSize;
> +
> + DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));
> +
> + DEBUG ((
> + DEBUG_INFO,
> + "OpalRequest to save: 0x%x\n",
> + OpalRequest
> + ));
> +
> + Variable = NULL;
> + VariableSize = 0;
> + NewVariable = NULL;
> + NewVariableSize = 0;
> +
> + Status = GetVariable2 (
> + OPAL_REQUEST_VARIABLE_NAME,
> + &gHiiSetupVariableGuid,
> + (VOID **) &Variable,
> + &VariableSize
> + );
> + if (!EFI_ERROR (Status) && (Variable != NULL)) {
> + TempVariable = Variable;
> + TempVariableSize = VariableSize;
> + while ((TempVariableSize > sizeof (OPAL_REQUEST_VARIABLE)) &&
> + (TempVariableSize >= TempVariable->Length) &&
> + (TempVariable->Length > sizeof (OPAL_REQUEST_VARIABLE))) {
> + DevicePathInVariable = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN)
> TempVariable + sizeof (OPAL_REQUEST_VARIABLE));
> + DevicePathSizeInVariable = GetDevicePathSize (DevicePathInVariable);
> + DevicePath = OpalDisk->OpalDevicePath;
> + DevicePathSize = GetDevicePathSize (DevicePath);
> + if ((DevicePathSize == DevicePathSizeInVariable) &&
> + (CompareMem (DevicePath, DevicePathInVariable, DevicePathSize)
> == 0)) {
> + //
> + // Found the node for the OPAL device.
> + // Update the OPAL request.
> + //
> + CopyMem (&TempVariable->OpalRequest, &OpalRequest, sizeof
> (OPAL_REQUEST));
> + NewVariable = Variable;
> + NewVariableSize = VariableSize;
> + break;
> + }
> + TempVariableSize -= TempVariable->Length;
> + TempVariable = (OPAL_REQUEST_VARIABLE *) ((UINTN) TempVariable +
> TempVariable->Length);
> + }
> + if (NewVariable == NULL) {
> + //
> + // The node for the OPAL device is not found.
> + // Create node for the OPAL device.
> + //
> + DevicePath = OpalDisk->OpalDevicePath;
> + DevicePathSize = GetDevicePathSize (DevicePath);
> + NewVariableSize = VariableSize + sizeof (OPAL_REQUEST_VARIABLE) +
> DevicePathSize;
> + NewVariable = AllocatePool (NewVariableSize);
> + ASSERT (NewVariable != NULL);
> + CopyMem (NewVariable, Variable, VariableSize);
> + TempVariable = (OPAL_REQUEST_VARIABLE *) ((UINTN) NewVariable +
> VariableSize);
> + TempVariable->Length = (UINT32) (sizeof (OPAL_REQUEST_VARIABLE) +
> DevicePathSize);
> + CopyMem (&TempVariable->OpalRequest, &OpalRequest, sizeof
> (OPAL_REQUEST));
> + DevicePathInVariable = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN)
> TempVariable + sizeof (OPAL_REQUEST_VARIABLE));
> + CopyMem (DevicePathInVariable, DevicePath, DevicePathSize);
> + }
> + } else {
> + DevicePath = OpalDisk->OpalDevicePath;
> + DevicePathSize = GetDevicePathSize (DevicePath);
> + NewVariableSize = sizeof (OPAL_REQUEST_VARIABLE) + DevicePathSize;
> + NewVariable = AllocatePool (NewVariableSize);
> + ASSERT (NewVariable != NULL);
> + NewVariable->Length = (UINT32) (sizeof (OPAL_REQUEST_VARIABLE) +
> DevicePathSize);
> + CopyMem (&NewVariable->OpalRequest, &OpalRequest, sizeof
> (OPAL_REQUEST));
> + DevicePathInVariable = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN)
> NewVariable + sizeof (OPAL_REQUEST_VARIABLE));
> + CopyMem (DevicePathInVariable, DevicePath, DevicePathSize);
> + }
> + Status = gRT->SetVariable (
> + OPAL_REQUEST_VARIABLE_NAME,
> + (EFI_GUID *) &gHiiSetupVariableGuid,
> + EFI_VARIABLE_NON_VOLATILE |
> EFI_VARIABLE_BOOTSERVICE_ACCESS,
> + NewVariableSize,
> + NewVariable
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_INFO, "OpalRequest variable set failed (%r)\n", Status));
> + }
> + if (NewVariable != Variable) {
> + FreePool (NewVariable);
> + }
> + if (Variable != NULL) {
> + FreePool (Variable);
> + }
> +
> + DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));
> +}
> +
> +/**
> + Sets the current system state of global config variables.
> +
> +**/
> +VOID
> +HiiSetCurrentConfiguration(
> + VOID
> + )
> +{
> + UINT32 PpStorageFlag;
> + EFI_STRING NewString;
> +
> + gHiiConfiguration.NumDisks = GetDeviceCount();
> +
> + //
> + // Update the BlockSID status string.
> + //
> + PpStorageFlag = Tcg2PhysicalPresenceLibGetManagementFlags ();
> +
> + if ((PpStorageFlag &
> TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID) != 0) {
> + NewString = HiiGetString (gHiiPackageListHandle,
> STRING_TOKEN(STR_ENABLED), NULL);
> + if (NewString == NULL) {
> + DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( )
> failed\n"));
> + return;
> + }
> + } else {
> + NewString = HiiGetString (gHiiPackageListHandle,
> STRING_TOKEN(STR_DISABLED), NULL);
> + if (NewString == NULL) {
> + DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( )
> failed\n"));
> + return;
> + }
> + }
> + HiiSetString(gHiiPackageListHandle,
> STRING_TOKEN(STR_BLOCKSID_STATUS1), NewString, NULL);
> + FreePool (NewString);
> +
> + if ((PpStorageFlag &
> TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_ENABLE_BL
> OCK_SID) != 0) {
> + NewString = HiiGetString (gHiiPackageListHandle,
> STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_TRUE), NULL);
> + if (NewString == NULL) {
> + DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( )
> failed\n"));
> + return;
> + }
> + } else {
> + NewString = HiiGetString (gHiiPackageListHandle,
> STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_FALSE), NULL);
> + if (NewString == NULL) {
> + DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( )
> failed\n"));
> + return;
> + }
> + }
> + HiiSetString(gHiiPackageListHandle,
> STRING_TOKEN(STR_BLOCKSID_STATUS2), NewString, NULL);
> + FreePool (NewString);
> +
> + if ((PpStorageFlag &
> TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_DISABLE_BL
> OCK_SID) != 0) {
> + NewString = HiiGetString (gHiiPackageListHandle,
> STRING_TOKEN(STR_DISK_INFO_DISABLE_BLOCKSID_TRUE), NULL);
> + if (NewString == NULL) {
> + DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( )
> failed\n"));
> + return;
> + }
> + } else {
> + NewString = HiiGetString (gHiiPackageListHandle,
> STRING_TOKEN(STR_DISK_INFO_DISABLE_BLOCKSID_FALSE), NULL);
> + if (NewString == NULL) {
> + DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( )
> failed\n"));
> + return;
> + }
> + }
> + HiiSetString(gHiiPackageListHandle,
> STRING_TOKEN(STR_BLOCKSID_STATUS3), NewString, NULL);
> + FreePool (NewString);
> +}
> +
> +/**
> + Install the HII related resources.
> +
> + @retval EFI_SUCCESS Install all the resources success.
> + @retval other Error occur when install the resources.
> +**/
> +EFI_STATUS
> +HiiInstall(
> + VOID
> + )
> +{
> + EFI_STATUS Status;
> + EFI_HANDLE DriverHandle;
> +
> + //
> + // Clear the global configuration.
> + //
> + ZeroMem(&gHiiConfiguration, sizeof(gHiiConfiguration));
> +
> + //
> + // Obtain the driver handle that the BIOS assigned us
> + //
> + DriverHandle = HiiGetDriverImageHandleCB();
> +
> + //
> + // Populate the config access protocol with the three functions we are
> publishing
> + //
> + gHiiConfigAccessProtocol.ExtractConfig = ExtractConfig;
> + gHiiConfigAccessProtocol.RouteConfig = RouteConfig;
> + gHiiConfigAccessProtocol.Callback = DriverCallback;
> +
> + //
> + // Associate the required protocols with our driver handle
> + //
> + Status = gBS->InstallMultipleProtocolInterfaces(
> + &DriverHandle,
> + &gEfiHiiConfigAccessProtocolGuid,
> + &gHiiConfigAccessProtocol, // HII callback
> + &gEfiDevicePathProtocolGuid,
> + &gHiiVendorDevicePath, // required for HII callback
> allow all disks to be shown in same hii
> + NULL
> + );
> +
> + if (EFI_ERROR(Status)) {
> + return Status;
> + }
> +
> + return OpalHiiAddPackages();
> +}
> +
> +/**
> + Install the HII form and string packages.
> +
> + @retval EFI_SUCCESS Install all the resources success.
> + @retval EFI_OUT_OF_RESOURCES Out of resource error.
> +**/
> +EFI_STATUS
> +OpalHiiAddPackages(
> + VOID
> + )
> +{
> + EFI_HANDLE DriverHandle;
> + CHAR16 *NewString;
> +
> + DriverHandle = HiiGetDriverImageHandleCB();
> +
> + //
> + // Publish the HII form and HII string packages
> + //
> + gHiiPackageListHandle = HiiAddPackages(
> + &gHiiPackageListGuid,
> + DriverHandle,
> + OpalPasswordDxeStrings,
> + OpalPasswordFormBin,
> + (VOID*)NULL
> + );
> +
> + //
> + // Make sure the packages installed successfully
> + //
> + if (gHiiPackageListHandle == NULL) {
> + DEBUG ((DEBUG_INFO, "OpalHiiAddPackages failed\n"));
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + //
> + // Update Version String in main window
> + //
> + NewString = HiiGetDriverNameCB ();
> + if (HiiSetString(gHiiPackageListHandle,
> STRING_TOKEN(STR_MAIN_OPAL_VERSION), NewString, NULL) == 0) {
> + DEBUG ((DEBUG_INFO, "OpalHiiAddPackages: HiiSetString( ) failed\n"));
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Uninstall the HII capability.
> +
> + @retval EFI_SUCCESS Uninstall all the resources success.
> + @retval others Other errors occur when unistall the hii
> resource.
> +**/
> +EFI_STATUS
> +HiiUninstall(
> + VOID
> + )
> +{
> + EFI_STATUS Status;
> +
> + //
> + // Remove the packages we've provided to the BIOS
> + //
> + HiiRemovePackages(gHiiPackageListHandle);
> +
> + //
> + // Remove the protocols from our driver handle
> + //
> + Status = gBS->UninstallMultipleProtocolInterfaces(
> + HiiGetDriverImageHandleCB(),
> + &gEfiHiiConfigAccessProtocolGuid,
> + &gHiiConfigAccessProtocol, // HII
> callback
> + &gEfiDevicePathProtocolGuid,
> + &gHiiVendorDevicePath, //
> required for HII callback
> + NULL
> + );
> + if (EFI_ERROR(Status)) {
> + DEBUG ((DEBUG_INFO, "Cannot uninstall Hii Protocols: %r\n", Status));
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Updates the main menu form.
> +
> + @retval EFI_SUCCESS update the main form success.
> +**/
> +EFI_STATUS
> +HiiPopulateMainMenuForm (
> + VOID
> + )
> +{
> + UINT8 Index;
> + CHAR8 *DiskName;
> + EFI_STRING_ID DiskNameId;
> + OPAL_DISK *OpalDisk;
> +
> + HiiSetCurrentConfiguration();
> +
> + gHiiConfiguration.SupportedDisks = 0;
> +
> + for (Index = 0; Index < gHiiConfiguration.NumDisks; Index++) {
> + OpalDisk = HiiGetOpalDiskCB (Index);
> + if ((OpalDisk != NULL) && OpalFeatureSupported
> (&OpalDisk->SupportedAttributes)) {
> + gHiiConfiguration.SupportedDisks |= (1 << Index);
> + DiskNameId = GetDiskNameStringId (Index);
> + DiskName = HiiDiskGetNameCB (Index);
> + if ((DiskName == NULL) || (DiskNameId == 0)) {
> + return EFI_UNSUPPORTED;
> + }
> + HiiSetFormString(DiskNameId, DiskName);
> + }
> + }
> +
> + OpalHiiSetBrowserData ();
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Get disk name string id.
> +
> + @param DiskIndex The input disk index info.
> +
> + @retval The disk name string id.
> +
> +**/
> +EFI_STRING_ID
> +GetDiskNameStringId(
> + UINT8 DiskIndex
> + )
> +{
> + switch (DiskIndex) {
> + case 0: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_0);
> + case 1: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_1);
> + case 2: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_2);
> + case 3: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_3);
> + case 4: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_4);
> + case 5: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_5);
> + }
> + return 0;
> +}
> +
> +/**
> + This function processes the results of changes in configuration.
> +
> + @param This Points to the
> EFI_HII_CONFIG_ACCESS_PROTOCOL.
> + @param Action Specifies the type of action taken by the
> browser.
> + @param QuestionId A unique value which is sent to the
> original
> + exporting driver so that it can identify
> the type
> + of data to expect.
> + @param Type The type of value for the question.
> + @param Value A pointer to the data being sent to the
> original
> + exporting driver.
> + @param ActionRequest On return, points to the action
> requested by the
> + callback function.
> +
> + @retval EFI_SUCCESS The callback successfully handled the
> action.
> + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold
> the
> + variable and its data.
> + @retval EFI_DEVICE_ERROR The variable could not be saved.
> + @retval EFI_UNSUPPORTED The specified Action is not supported
> by the
> + callback.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DriverCallback(
> + CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
> + EFI_BROWSER_ACTION Action,
> + EFI_QUESTION_ID QuestionId,
> + UINT8 Type,
> + EFI_IFR_TYPE_VALUE *Value,
> + EFI_BROWSER_ACTION_REQUEST *ActionRequest
> + )
> +{
> + HII_KEY HiiKey;
> + UINT8 HiiKeyId;
> + UINT32 PpRequest;
> + OPAL_DISK *OpalDisk;
> +
> + if (ActionRequest != NULL) {
> + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
> + } else {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + //
> + // If QuestionId is an auto-generated key (label, empty line, etc.), ignore it.
> + //
> + if ((QuestionId & HII_KEY_FLAG) == 0) {
> + return EFI_SUCCESS;
> + }
> +
> + HiiKey.Raw = QuestionId;
> + HiiKeyId = (UINT8) HiiKey.KeyBits.Id;
> +
> + if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {
> + switch (HiiKeyId) {
> + case HII_KEY_ID_VAR_SUPPORTED_DISKS:
> + DEBUG ((DEBUG_INFO, "HII_KEY_ID_VAR_SUPPORTED_DISKS\n"));
> + return HiiPopulateMainMenuForm ();
> +
> + case HII_KEY_ID_VAR_SELECTED_DISK_AVAILABLE_ACTIONS:
> + DEBUG ((DEBUG_INFO,
> "HII_KEY_ID_VAR_SELECTED_DISK_AVAILABLE_ACTIONS\n"));
> + return HiiPopulateDiskInfoForm();
> + }
> + } else if (Action == EFI_BROWSER_ACTION_CHANGING) {
> + switch (HiiKeyId) {
> + case HII_KEY_ID_GOTO_DISK_INFO:
> + return HiiSelectDisk((UINT8)HiiKey.KeyBits.Index);
> + }
> + } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
> + switch (HiiKeyId) {
> + case HII_KEY_ID_BLOCKSID:
> + switch (Value->u8) {
> + case 0:
> + PpRequest = TCG2_PHYSICAL_PRESENCE_NO_ACTION;
> + break;
> +
> + case 1:
> + PpRequest = TCG2_PHYSICAL_PRESENCE_ENABLE_BLOCK_SID;
> + break;
> +
> + case 2:
> + PpRequest = TCG2_PHYSICAL_PRESENCE_DISABLE_BLOCK_SID;
> + break;
> +
> + case 3:
> + PpRequest =
> TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FU
> NC_TRUE;
> + break;
> +
> + case 4:
> + PpRequest =
> TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FU
> NC_FALSE;
> + break;
> +
> + case 5:
> + PpRequest =
> TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FU
> NC_TRUE;
> + break;
> +
> + case 6:
> + PpRequest =
> TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FU
> NC_FALSE;
> + break;
> +
> + default:
> + PpRequest = TCG2_PHYSICAL_PRESENCE_NO_ACTION;
> + DEBUG ((DEBUG_ERROR, "Invalid value input!\n"));
> + break;
> + }
> + HiiSetBlockSidAction(PpRequest);
> +
> + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
> + return EFI_SUCCESS;
> +
> + case HII_KEY_ID_SET_ADMIN_PWD:
> + DEBUG ((DEBUG_INFO, "HII_KEY_ID_SET_ADMIN_PWD\n"));
> + gHiiConfiguration.OpalRequest.SetAdminPwd = Value->b;
> + OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);
> + if (OpalDisk != NULL) {
> + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);
> + }
> + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
> + return EFI_SUCCESS;
> +
> + case HII_KEY_ID_SET_USER_PWD:
> + DEBUG ((DEBUG_INFO, "HII_KEY_ID_SET_USER_PWD\n"));
> + gHiiConfiguration.OpalRequest.SetUserPwd = Value->b;
> + OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);
> + if (OpalDisk != NULL) {
> + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);
> + }
> + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
> + return EFI_SUCCESS;
> +
> + case HII_KEY_ID_SECURE_ERASE:
> + DEBUG ((DEBUG_INFO, "HII_KEY_ID_SECURE_ERASE\n"));
> + gHiiConfiguration.OpalRequest.SecureErase = Value->b;
> + OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);
> + if (OpalDisk != NULL) {
> + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);
> + }
> + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
> + return EFI_SUCCESS;
> +
> + case HII_KEY_ID_REVERT:
> + DEBUG ((DEBUG_INFO, "HII_KEY_ID_REVERT\n"));
> + gHiiConfiguration.OpalRequest.Revert = Value->b;
> + OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);
> + if (OpalDisk != NULL) {
> + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);
> + }
> + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
> + return EFI_SUCCESS;
> + case HII_KEY_ID_KEEP_USER_DATA:
> + DEBUG ((DEBUG_INFO, "HII_KEY_ID_KEEP_USER_DATA\n"));
> + gHiiConfiguration.OpalRequest.KeepUserData = Value->b;
> + OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);
> + if (OpalDisk != NULL) {
> + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);
> + }
> + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
> + return EFI_SUCCESS;
> +
> + case HII_KEY_ID_PSID_REVERT:
> + DEBUG ((DEBUG_INFO, "HII_KEY_ID_PSID_REVERT\n"));
> + gHiiConfiguration.OpalRequest.PsidRevert = Value->b;
> + OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);
> + if (OpalDisk != NULL) {
> + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);
> + }
> + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
> + return EFI_SUCCESS;
> +
> + case HII_KEY_ID_DISABLE_USER:
> + DEBUG ((DEBUG_INFO, "HII_KEY_ID_DISABLE_USER\n"));
> + gHiiConfiguration.OpalRequest.DisableUser = Value->b;
> + OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);
> + if (OpalDisk != NULL) {
> + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);
> + }
> + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
> + return EFI_SUCCESS;
> +
> + case HII_KEY_ID_ENABLE_FEATURE:
> + DEBUG ((DEBUG_INFO, "HII_KEY_ID_ENABLE_FEATURE\n"));
> + gHiiConfiguration.OpalRequest.EnableFeature = Value->b;
> + OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);
> + if (OpalDisk != NULL) {
> + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);
> + }
> + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
> + return EFI_SUCCESS;
> +
> + default:
> + break;
> + }
> + }
> +
> + return EFI_UNSUPPORTED;
> +}
> +
> +/**
> + Update the global Disk index info.
> +
> + @param Index The input disk index info.
> +
> + @retval EFI_SUCCESS Update the disk index info success.
> +
> +**/
> +EFI_STATUS
> +HiiSelectDisk(
> + UINT8 Index
> + )
> +{
> + OpalHiiGetBrowserData();
> + gHiiConfiguration.SelectedDiskIndex = Index;
> + OpalHiiSetBrowserData ();
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Draws the disk info form.
> +
> + @retval EFI_SUCCESS Draw the disk info success.
> +
> +**/
> +EFI_STATUS
> +HiiPopulateDiskInfoForm(
> + VOID
> + )
> +{
> + OPAL_DISK* OpalDisk;
> + OPAL_DISK_ACTIONS AvailActions;
> + TCG_RESULT Ret;
> + CHAR8 *DiskName;
> +
> + OpalHiiGetBrowserData();
> +
> + DiskName = HiiDiskGetNameCB (gHiiConfiguration.SelectedDiskIndex);
> + if (DiskName == NULL) {
> + return EFI_UNSUPPORTED;
> + }
> + HiiSetFormString(STRING_TOKEN(STR_DISK_INFO_SELECTED_DISK_NAME),
> DiskName);
> +
> + gHiiConfiguration.SelectedDiskAvailableActions = HII_ACTION_NONE;
> + ZeroMem (&gHiiConfiguration.OpalRequest, sizeof (OPAL_REQUEST));
> + gHiiConfiguration.KeepUserDataForced = FALSE;
> +
> + OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);
> +
> + if (OpalDisk != NULL) {
> + OpalDiskUpdateStatus (OpalDisk);
> + Ret = OpalSupportGetAvailableActions(&OpalDisk->SupportedAttributes,
> &OpalDisk->LockingFeature, OpalDisk->Owner, &AvailActions);
> + if (Ret == TcgResultSuccess) {
> + //
> + // Update actions, always allow PSID Revert
> + //
> + gHiiConfiguration.SelectedDiskAvailableActions |=
> (AvailActions.PsidRevert == 1) ? HII_ACTION_PSID_REVERT :
> HII_ACTION_NONE;
> +
> + //
> + // Always allow unlock to handle device migration
> + //
> + gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.Unlock
> == 1) ? HII_ACTION_UNLOCK : HII_ACTION_NONE;
> +
> + if (!OpalFeatureEnabled (&OpalDisk->SupportedAttributes,
> &OpalDisk->LockingFeature)) {
> + if (OpalDisk->Owner == OpalOwnershipNobody) {
> + gHiiConfiguration.SelectedDiskAvailableActions |=
> HII_ACTION_ENABLE_FEATURE;
> +
> + //
> + // Update strings
> + //
> + HiiSetFormString( STRING_TOKEN(STR_DISK_INFO_PSID_REVERT),
> "PSID Revert to factory default");
> + } else {
> + DEBUG ((DEBUG_INFO, "Feature disabled but ownership !=
> nobody\n"));
> + }
> + } else {
> + gHiiConfiguration.SelectedDiskAvailableActions |=
> (AvailActions.Revert == 1) ? HII_ACTION_REVERT : HII_ACTION_NONE;
> + gHiiConfiguration.SelectedDiskAvailableActions |=
> (AvailActions.AdminPass == 1) ? HII_ACTION_SET_ADMIN_PWD :
> HII_ACTION_NONE;
> + gHiiConfiguration.SelectedDiskAvailableActions |=
> (AvailActions.UserPass == 1) ? HII_ACTION_SET_USER_PWD :
> HII_ACTION_NONE;
> + gHiiConfiguration.SelectedDiskAvailableActions |=
> (AvailActions.SecureErase == 1) ? HII_ACTION_SECURE_ERASE :
> HII_ACTION_NONE;
> + gHiiConfiguration.SelectedDiskAvailableActions |=
> (AvailActions.DisableUser == 1) ? HII_ACTION_DISABLE_USER :
> HII_ACTION_NONE;
> +
> + HiiSetFormString (STRING_TOKEN(STR_DISK_INFO_PSID_REVERT),
> "PSID Revert to factory default and Disable");
> +
> + //
> + // Determine revert options for disk
> + // Default initialize keep user Data to be true
> + //
> + gHiiConfiguration.OpalRequest.KeepUserData = 1;
> + if (AvailActions.RevertKeepDataForced) {
> + gHiiConfiguration.KeepUserDataForced = TRUE;
> + }
> + }
> + }
> +
> + GetSavedOpalRequest (OpalDisk, &gHiiConfiguration.OpalRequest);
> + }
> +
> + //
> + // Pass the current configuration to the BIOS
> + //
> + OpalHiiSetBrowserData ();
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Send BlockSid request through TPM physical presence module.
> +
> + @param PpRequest TPM physical presence operation request.
> +
> + @retval EFI_SUCCESS Do the required action success.
> + @retval Others Other error occur.
> +
> +**/
> +EFI_STATUS
> +HiiSetBlockSidAction (
> + IN UINT32 PpRequest
> + )
> +{
> + UINT32 ReturnCode;
> + EFI_STATUS Status;
> +
> + ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction
> (PpRequest, 0);
> + if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS) {
> + Status = EFI_SUCCESS;
> + } else if (ReturnCode ==
> TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE) {
> + Status = EFI_OUT_OF_RESOURCES;
> + } else if (ReturnCode ==
> TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED) {
> + Status = EFI_UNSUPPORTED;
> + } else {
> + Status = EFI_DEVICE_ERROR;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + This function processes the results of changes in configuration.
> +
> + @param This Points to the
> EFI_HII_CONFIG_ACCESS_PROTOCOL.
> + @param Configuration A null-terminated Unicode string in
> <ConfigResp>
> + format.
> + @param Progress A pointer to a string filled in with the
> offset of
> + the most recent '&' before the first
> failing
> + name/value pair (or the beginning of the
> string if
> + the failure is in the first name/value pair)
> or
> + the terminating NULL if all was
> successful.
> +
> + @retval EFI_SUCCESS The Results is processed successfully.
> + @retval EFI_INVALID_PARAMETER Configuration is NULL.
> + @retval EFI_NOT_FOUND Routing data doesn't match any
> storage in this
> + driver.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RouteConfig(
> + CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
> + CONST EFI_STRING Configuration,
> + EFI_STRING *Progress
> + )
> +{
> + if (Configuration == NULL || Progress == NULL) {
> + return (EFI_INVALID_PARAMETER);
> + }
> +
> + *Progress = Configuration;
> + if (!HiiIsConfigHdrMatch (Configuration, &gHiiSetupVariableGuid,
> OpalPasswordStorageName)) {
> + return EFI_NOT_FOUND;
> + }
> +
> + *Progress = Configuration + StrLen (Configuration);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function allows a caller to extract the current configuration for one
> + or more named elements from the target driver.
> +
> + @param This Points to the
> EFI_HII_CONFIG_ACCESS_PROTOCOL.
> + @param Request A null-terminated Unicode string in
> + <ConfigRequest> format.
> + @param Progress On return, points to a character in the
> Request
> + string. Points to the string's null
> terminator if
> + request was successful. Points to the
> most recent
> + '&' before the first failing name/value
> pair (or
> + the beginning of the string if the failure
> is in
> + the first name/value pair) if the request
> was not
> + successful.
> + @param Results A null-terminated Unicode string in
> + <ConfigAltResp> format which has all
> values filled
> + in for the names in the Request string.
> String to
> + be allocated by the called function.
> +
> + @retval EFI_SUCCESS The Results is filled with the requested
> values.
> + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the
> results.
> + @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown
> name.
> + @retval EFI_NOT_FOUND Routing data doesn't match any
> storage in this
> + driver.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ExtractConfig(
> + CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
> + CONST EFI_STRING Request,
> + EFI_STRING *Progress,
> + EFI_STRING *Results
> + )
> +{
> + EFI_STATUS Status;
> + EFI_STRING ConfigRequest;
> + EFI_STRING ConfigRequestHdr;
> + UINTN BufferSize;
> + UINTN Size;
> + BOOLEAN AllocatedRequest;
> + EFI_HANDLE DriverHandle;
> +
> + //
> + // Check for valid parameters
> + //
> + if (Progress == NULL || Results == NULL) {
> + return (EFI_INVALID_PARAMETER);
> + }
> +
> + *Progress = Request;
> + if ((Request != NULL) &&
> + !HiiIsConfigHdrMatch (Request, &gHiiSetupVariableGuid,
> OpalPasswordStorageName)) {
> + return EFI_NOT_FOUND;
> + }
> +
> + AllocatedRequest = FALSE;
> + BufferSize = sizeof (OPAL_HII_CONFIGURATION);
> + ConfigRequest = Request;
> + if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
> + //
> + // Request has no request element, construct full request string.
> + // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
> + // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW"
> followed by a Null-terminator
> + //
> + DriverHandle = HiiGetDriverImageHandleCB();
> + ConfigRequestHdr = HiiConstructConfigHdr (&gHiiSetupVariableGuid,
> OpalPasswordStorageName, DriverHandle);
> + Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
> + ConfigRequest = AllocateZeroPool (Size);
> + if (ConfigRequest == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> + AllocatedRequest = TRUE;
> + UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX",
> ConfigRequestHdr, (UINT64)BufferSize);
> + FreePool (ConfigRequestHdr);
> + }
> +
> + //
> + // Convert Buffer Data to <ConfigResp> by helper function BlockToConfig( )
> + //
> + Status = gHiiConfigRouting->BlockToConfig(
> + gHiiConfigRouting,
> + ConfigRequest,
> + (UINT8*)&gHiiConfiguration,
> + sizeof(OPAL_HII_CONFIGURATION),
> + Results,
> + Progress
> + );
> +
> + //
> + // Free the allocated config request string.
> + //
> + if (AllocatedRequest) {
> + FreePool (ConfigRequest);
> + ConfigRequest = NULL;
> + }
> +
> + //
> + // Set Progress string to the original request string.
> + //
> + if (Request == NULL) {
> + *Progress = NULL;
> + } else if (StrStr (Request, L"OFFSET") == NULL) {
> + *Progress = Request + StrLen (Request);
> + }
> +
> + return (Status);
> +}
> +
> +
> +/**
> +
> + Pass the current system state to the bios via the hii_G_Configuration.
> +
> +**/
> +VOID
> +OpalHiiSetBrowserData (
> + VOID
> + )
> +{
> + HiiSetBrowserData(
> + &gHiiSetupVariableGuid,
> + (CHAR16*)L"OpalHiiConfig",
> + sizeof(gHiiConfiguration),
> + (UINT8*)&gHiiConfiguration,
> + NULL
> + );
> +}
> +
> +
> +/**
> +
> + Populate the hii_g_Configuraton with the browser Data.
> +
> +**/
> +VOID
> +OpalHiiGetBrowserData (
> + VOID
> + )
> +{
> + HiiGetBrowserData(
> + &gHiiSetupVariableGuid,
> + (CHAR16*)L"OpalHiiConfig",
> + sizeof(gHiiConfiguration),
> + (UINT8*)&gHiiConfiguration
> + );
> +}
> +
> +/**
> + Set a string Value in a form.
> +
> + @param DestStringId The stringid which need to update.
> + @param SrcAsciiStr The string nned to update.
> +
> + @retval EFI_SUCCESS Do the required action success.
> + @retval Others Other error occur.
> +
> +**/
> +EFI_STATUS
> +HiiSetFormString(
> + EFI_STRING_ID DestStringId,
> + CHAR8 *SrcAsciiStr
> + )
> +{
> + UINT32 Len;
> + UINT32 UniSize;
> + CHAR16* UniStr;
> +
> + //
> + // Determine the Length of the sting
> + //
> + Len = ( UINT32 )AsciiStrLen( SrcAsciiStr );
> +
> + //
> + // Allocate space for the unicode string, including terminator
> + //
> + UniSize = (Len + 1) * sizeof(CHAR16);
> + UniStr = (CHAR16*)AllocateZeroPool(UniSize);
> +
> + //
> + // Copy into unicode string, then copy into string id
> + //
> + AsciiStrToUnicodeStrS ( SrcAsciiStr, UniStr, Len + 1);
> +
> + //
> + // Update the string in the form
> + //
> + if (HiiSetString(gHiiPackageListHandle, DestStringId, UniStr, NULL) == 0) {
> + DEBUG ((DEBUG_INFO, "HiiSetFormString( ) failed\n"));
> + FreePool(UniStr);
> + return (EFI_OUT_OF_RESOURCES);
> + }
> +
> + //
> + // Free the memory
> + //
> + FreePool(UniStr);
> +
> + return (EFI_SUCCESS);
> +}
> +
> +/**
> + Initialize the Opal disk base on the hardware info get from device.
> +
> + @param Dev The Opal device.
> +
> + @retval EFI_SUCESS Initialize the device success.
> + @retval EFI_DEVICE_ERROR Get info from device failed.
> +
> +**/
> +EFI_STATUS
> +OpalDiskInitialize (
> + IN OPAL_DRIVER_DEVICE *Dev
> + )
> +{
> + TCG_RESULT TcgResult;
> + OPAL_SESSION Session;
> +
> + ZeroMem(&Dev->OpalDisk, sizeof(OPAL_DISK));
> + Dev->OpalDisk.Sscp = Dev->Sscp;
> + Dev->OpalDisk.MediaId = Dev->MediaId;
> + Dev->OpalDisk.OpalDevicePath = Dev->OpalDevicePath;
> +
> + ZeroMem(&Session, sizeof(Session));
> + Session.Sscp = Dev->Sscp;
> + Session.MediaId = Dev->MediaId;
> +
> + TcgResult = OpalGetSupportedAttributesInfo (&Session,
> &Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.OpalBaseComId);
> + if (TcgResult != TcgResultSuccess) {
> + return EFI_DEVICE_ERROR;
> + }
> + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;
> +
> + TcgResult = OpalUtilGetMsid (&Session, Dev->OpalDisk.Msid,
> OPAL_MSID_LENGHT, &Dev->OpalDisk.MsidLength);
> + if (TcgResult != TcgResultSuccess) {
> + return EFI_DEVICE_ERROR;
> + }
> +
> + return OpalDiskUpdateStatus (&Dev->OpalDisk);
> +}
> +
> +/**
> + Update the device info.
> +
> + @param OpalDisk The Opal device.
> +
> + @retval EFI_SUCESS Initialize the device success.
> + @retval EFI_DEVICE_ERROR Get info from device failed.
> + @retval EFI_INVALID_PARAMETER Not get Msid info before get ownership
> info.
> +
> +**/
> +EFI_STATUS
> +OpalDiskUpdateStatus (
> + OPAL_DISK *OpalDisk
> + )
> +{
> + TCG_RESULT TcgResult;
> + OPAL_SESSION Session;
> +
> + ZeroMem(&Session, sizeof(Session));
> + Session.Sscp = OpalDisk->Sscp;
> + Session.MediaId = OpalDisk->MediaId;
> + Session.OpalBaseComId = OpalDisk->OpalBaseComId;
> +
> + TcgResult = OpalGetLockingInfo(&Session, &OpalDisk->LockingFeature);
> + if (TcgResult != TcgResultSuccess) {
> + return EFI_DEVICE_ERROR;
> + }
> +
> + if (OpalDisk->MsidLength == 0) {
> + return EFI_INVALID_PARAMETER;
> + } else {
> + //
> + // Base on the Msid info to get the ownership, so Msid info must get first.
> + //
> + OpalDisk->Owner = OpalUtilDetermineOwnership(&Session,
> OpalDisk->Msid, OpalDisk->MsidLength);
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.h
> b/SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.h
> new file mode 100644
> index 000000000000..a1b1131c1380
> --- /dev/null
> +++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.h
> @@ -0,0 +1,380 @@
> +/** @file
> + Public Header file of HII library used by Opal UEFI Driver.
> + Defines required callbacks of Opal HII library.
> +
> +Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution. The full text of the license may be found
> at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +
> +#ifndef _OPAL_HII_H_
> +#define _OPAL_HII_H_
> +
> +#include <Protocol/HiiConfigAccess.h>
> +
> +#include "OpalDriver.h"
> +#include "OpalHiiFormValues.h"
> +
> +#define OPAL_PASSWORD_CONFIG_GUID \
> + { \
> + 0x0d510a4f, 0xa81b, 0x473f, { 0x87, 0x07, 0xb7, 0xfd, 0xfb, 0xc0, 0x45,
> 0xba } \
> + }
> +
> +#pragma pack(1)
> +
> +typedef struct {
> + UINT16 Id: HII_KEY_ID_BITS;
> + UINT16 Index: HII_KEY_INDEX_BITS;
> + UINT16 Flag: HII_KEY_FLAG_BITS;
> +} KEY_BITS;
> +
> +typedef union {
> + UINT16 Raw;
> + KEY_BITS KeyBits;
> +} HII_KEY;
> +
> +typedef struct {
> + VENDOR_DEVICE_PATH VendorDevicePath;
> + EFI_DEVICE_PATH_PROTOCOL End;
> +} HII_VENDOR_DEVICE_PATH;
> +
> +#pragma pack()
> +
> +extern const EFI_GUID gHiiSetupVariableGuid;
> +
> +/**
> + This function processes the results of changes in configuration.
> +
> + @param This Points to the
> EFI_HII_CONFIG_ACCESS_PROTOCOL.
> + @param Configuration A null-terminated Unicode string in
> <ConfigResp>
> + format.
> + @param Progress A pointer to a string filled in with the
> offset of
> + the most recent '&' before the first
> failing
> + name/value pair (or the beginning of the
> string if
> + the failure is in the first name/value pair)
> or
> + the terminating NULL if all was
> successful.
> +
> + @retval EFI_SUCCESS The Results is processed successfully.
> + @retval EFI_INVALID_PARAMETER Configuration is NULL.
> + @retval EFI_NOT_FOUND Routing data doesn't match any
> storage in this
> + driver.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RouteConfig(
> + CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
> + CONST EFI_STRING Configuration,
> + EFI_STRING *Progress
> + );
> +
> +/**
> + This function allows a caller to extract the current configuration for one
> + or more named elements from the target driver.
> +
> + @param This Points to the
> EFI_HII_CONFIG_ACCESS_PROTOCOL.
> + @param Request A null-terminated Unicode string in
> + <ConfigRequest> format.
> + @param Progress On return, points to a character in the
> Request
> + string. Points to the string's null
> terminator if
> + request was successful. Points to the
> most recent
> + '&' before the first failing name/value
> pair (or
> + the beginning of the string if the failure
> is in
> + the first name/value pair) if the request
> was not
> + successful.
> + @param Results A null-terminated Unicode string in
> + <ConfigAltResp> format which has all
> values filled
> + in for the names in the Request string.
> String to
> + be allocated by the called function.
> +
> + @retval EFI_SUCCESS The Results is filled with the requested
> values.
> + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the
> results.
> + @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown
> name.
> + @retval EFI_NOT_FOUND Routing data doesn't match any
> storage in this
> + driver.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ExtractConfig(
> + CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
> + CONST EFI_STRING Request,
> + EFI_STRING *Progress,
> + EFI_STRING *Results
> + );
> +
> +/**
> + This function processes the results of changes in configuration.
> +
> + @param This Points to the
> EFI_HII_CONFIG_ACCESS_PROTOCOL.
> + @param Action Specifies the type of action taken by the
> browser.
> + @param QuestionId A unique value which is sent to the
> original
> + exporting driver so that it can identify
> the type
> + of data to expect.
> + @param Type The type of value for the question.
> + @param Value A pointer to the data being sent to the
> original
> + exporting driver.
> + @param ActionRequest On return, points to the action
> requested by the
> + callback function.
> +
> + @retval EFI_SUCCESS The callback successfully handled the
> action.
> + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold
> the
> + variable and its data.
> + @retval EFI_DEVICE_ERROR The variable could not be saved.
> + @retval EFI_UNSUPPORTED The specified Action is not supported
> by the
> + callback.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DriverCallback(
> + CONST EFI_HII_CONFIG_ACCESS_PROTOCOL* This,
> + EFI_BROWSER_ACTION Action,
> + EFI_QUESTION_ID QuestionId,
> + UINT8 Type,
> + EFI_IFR_TYPE_VALUE* Value,
> + EFI_BROWSER_ACTION_REQUEST* ActionRequest
> + );
> +
> +/**
> +
> + Pass the current system state to the bios via the hii_G_Configuration.
> +
> +**/
> +VOID
> +OpalHiiSetBrowserData (
> + VOID
> + );
> +
> +/**
> +
> + Populate the hii_g_Configuraton with the browser Data.
> +
> +**/
> +VOID
> +OpalHiiGetBrowserData (
> + VOID
> + );
> +
> +/**
> + Draws the disk info form.
> +
> + @retval EFI_SUCCESS Draw the disk info success.
> +
> +**/
> +EFI_STATUS
> +HiiPopulateDiskInfoForm(
> + VOID
> + );
> +
> +/**
> + Update the global Disk index info.
> +
> + @param Index The input disk index info.
> +
> + @retval EFI_SUCCESS Update the disk index info success.
> +
> +**/
> +EFI_STATUS
> +HiiSelectDisk(
> + UINT8 Index
> + );
> +
> +/**
> + Use the input password to do the specified action.
> +
> + @param Str The input password saved in.
> +
> + @retval EFI_SUCCESS Do the required action success.
> + @retval Others Other error occur.
> +
> +**/
> +EFI_STATUS
> +HiiPasswordEntered(
> + EFI_STRING_ID Str
> + );
> +
> +/**
> + Update block sid info.
> +
> + @param PpRequest Input the Pp Request.
> +
> + @retval EFI_SUCCESS Do the required action success.
> + @retval Others Other error occur.
> +
> +**/
> +EFI_STATUS
> +HiiSetBlockSidAction (
> + UINT32 PpRequest
> + );
> +
> +/**
> + Reverts the Opal disk to factory default.
> +
> + @param PsidStringId The string id for the PSID info.
> +
> + @retval EFI_SUCCESS Do the required action success.
> +
> +**/
> +EFI_STATUS
> +HiiPsidRevert(
> + EFI_STRING_ID PsidStringId
> + );
> +
> +/**
> + Get disk name string id.
> +
> + @param DiskIndex The input disk index info.
> +
> + @retval The disk name string id.
> +
> +**/
> +EFI_STRING_ID
> +GetDiskNameStringId(
> + UINT8 DiskIndex
> + );
> +
> +/**
> + Update the device info.
> +
> + @param OpalDisk The Opal device.
> +
> + @retval EFI_SUCESS Initialize the device success.
> + @retval EFI_DEVICE_ERROR Get info from device failed.
> + @retval EFI_INVALID_PARAMETER Not get Msid info before get ownership
> info.
> +
> +**/
> +EFI_STATUS
> +OpalDiskUpdateStatus (
> + OPAL_DISK *OpalDisk
> + );
> +
> +/**
> + Get the driver image handle.
> +
> + @retval the driver image handle.
> +
> +**/
> +EFI_HANDLE
> +HiiGetDriverImageHandleCB(
> + VOID
> + );
> +
> +/**
> + Install the HII form and string packages.
> +
> + @retval EFI_SUCCESS Install all the resources success.
> + @retval EFI_OUT_OF_RESOURCES Out of resource error.
> +**/
> +EFI_STATUS
> +OpalHiiAddPackages(
> + VOID
> + );
> +
> +/**
> + Check whether enable feature or not.
> +
> + @retval Return the disk number.
> +
> +**/
> +UINT8
> +HiiGetNumConfigRequiredOpalDisksCB(
> + VOID
> + );
> +
> +/**
> + Returns the driver name.
> +
> + @retval Returns the driver name.
> +
> +**/
> +CHAR16*
> +HiiGetDriverNameCB(
> + VOID
> + );
> +
> +/**
> + Returns the opaque pointer to a physical disk context.
> +
> + @param DiskIndex Input the disk index.
> +
> + @retval The device pointer.
> +
> +**/
> +OPAL_DISK*
> +HiiGetOpalDiskCB(
> + UINT8 DiskIndex
> + );
> +
> +/**
> + Returns the disk name.
> +
> + @param DiskIndex Input the disk index.
> +
> + @retval Returns the disk name.
> +
> +**/
> +CHAR8*
> +HiiDiskGetNameCB(
> + UINT8 DiskIndex
> + );
> +
> +/**
> + Set a string Value in a form.
> +
> + @param DestStringId The stringid which need to update.
> + @param SrcAsciiStr The string nned to update.
> +
> + @retval EFI_SUCCESS Do the required action success.
> + @retval Others Other error occur.
> +
> +**/
> +EFI_STATUS
> +HiiSetFormString(
> + EFI_STRING_ID DestStringId,
> + CHAR8 *SrcAsciiStr
> + );
> +
> +/**
> + Install the HII related resources.
> +
> + @retval EFI_SUCCESS Install all the resources success.
> + @retval other Error occur when install the resources.
> +**/
> +EFI_STATUS
> +HiiInstall(
> + VOID
> + );
> +
> +/**
> + Uninstall the HII capability.
> +
> + @retval EFI_SUCCESS Uninstall all the resources success.
> + @retval others Other errors occur when unistall the hii
> resource.
> +**/
> +EFI_STATUS
> +HiiUninstall(
> + VOID
> + );
> +
> +/**
> + Initialize the Opal disk base on the hardware info get from device.
> +
> + @param Dev The Opal device.
> +
> + @retval EFI_SUCESS Initialize the device success.
> + @retval EFI_DEVICE_ERROR Get info from device failed.
> +
> +**/
> +EFI_STATUS
> +OpalDiskInitialize (
> + IN OPAL_DRIVER_DEVICE *Dev
> + );
> +
> +#endif // _HII_H_
> diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiCallbacks.c
> b/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiCallbacks.c
> new file mode 100644
> index 000000000000..b07e38c1449d
> --- /dev/null
> +++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiCallbacks.c
> @@ -0,0 +1,219 @@
> +/** @file
> + Callbacks required by the HII of the Opal UEFI Driver to help display
> + Opal device information.
> +
> +Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution. The full text of the license may be found
> at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +
> +#include "OpalHii.h"
> +
> +/**
> + Get Opal var name.
> + The return Value must be freed by caller if not NULL
> +
> + @param OpalDisk The disk.
> + @param Prefix The prefix string.
> +
> + @retval The var name string.
> +
> +**/
> +CHAR16*
> +OpalDriverGetOpalVarName(
> + OPAL_DISK *OpalDisk,
> + const CHAR16 *Prefix
> + )
> +{
> + OPAL_DRIVER_DEVICE* Dev;
> + UINTN PrefixLen;
> + UINTN NameLen;
> + UINTN VarNameLen;
> + CHAR16* VarName;
> +
> + Dev = DRIVER_DEVICE_FROM_OPALDISK(OpalDisk);
> + if (Dev == NULL) {
> + return NULL;
> + }
> +
> + PrefixLen = StrLen(Prefix);
> +
> + NameLen = 0;
> + if (Dev->Name16 != NULL) {
> + NameLen = StrLen(Dev->Name16);
> + }
> +
> + VarNameLen = PrefixLen + NameLen;
> +
> + VarName = (CHAR16*)AllocateZeroPool((VarNameLen + 1) *
> sizeof(CHAR16));
> + if (VarName == NULL) {
> + return NULL;
> + }
> +
> + CopyMem(VarName, Prefix, PrefixLen * sizeof(CHAR16));
> + if (Dev->Name16 != NULL) {
> + CopyMem(VarName + PrefixLen, Dev->Name16, NameLen *
> sizeof(CHAR16));
> + }
> + VarName[VarNameLen] = 0;
> +
> + return VarName;
> +}
> +
> +/**
> + Get the driver image handle.
> +
> + @retval the driver image handle.
> +
> +**/
> +EFI_HANDLE
> +HiiGetDriverImageHandleCB(
> + VOID
> + )
> +{
> + return gImageHandle;
> +}
> +
> +/**
> + Check whether enable feature or not.
> +
> + @retval Return the disk number.
> +
> +**/
> +UINT8
> +HiiGetNumConfigRequiredOpalDisksCB(
> + VOID
> + )
> +{
> + UINT8 NumDisks;
> + UINT8 NumLockedOpalDisks;
> + OPAL_DISK *OpalDisk;
> + UINT8 Index;
> +
> + NumLockedOpalDisks = 0;
> +
> + NumDisks = GetDeviceCount();
> +
> + for (Index = 0; Index < NumDisks; Index++) {
> + OpalDisk = HiiGetOpalDiskCB(Index);
> +
> + if (OpalDisk != NULL) {
> + if (!OpalFeatureEnabled (&OpalDisk->SupportedAttributes,
> &OpalDisk->LockingFeature)) {
> + DEBUG ((DEBUG_INFO, "Ignoring disk %u because feature is disabled
> or health has already been inspected\n", Index));
> + } else if (OpalDeviceLocked (&OpalDisk->SupportedAttributes,
> &OpalDisk->LockingFeature)) {
> + NumLockedOpalDisks++;
> + }
> + }
> + }
> +
> + return NumLockedOpalDisks;
> +}
> +
> +
> +
> +/**
> + Returns the opaque pointer to a physical disk context.
> +
> + @param DiskIndex Input the disk index.
> +
> + @retval The device pointer.
> +
> +**/
> +VOID *
> +HiiGetDiskContextCB(
> + UINT8 DiskIndex
> + )
> +{
> + OPAL_DRIVER_DEVICE* Dev;
> + UINT8 CurrentDisk;
> +
> + Dev = OpalDriverGetDeviceList();
> + CurrentDisk = 0;
> +
> + if (DiskIndex >= GetDeviceCount()) {
> + return NULL;
> + }
> +
> + while (Dev != NULL) {
> + if (CurrentDisk == DiskIndex) {
> + return Dev;
> + } else {
> + Dev = Dev->Next;
> + CurrentDisk++;
> + }
> + }
> +
> + return NULL;
> +}
> +
> +/**
> + Returns the opaque pointer to a physical disk context.
> +
> + @param DiskIndex Input the disk index.
> +
> + @retval The device pointer.
> +
> +**/
> +OPAL_DISK*
> +HiiGetOpalDiskCB(
> + UINT8 DiskIndex
> + )
> +{
> + VOID *Ctx;
> + OPAL_DRIVER_DEVICE *Tmp;
> +
> + Ctx = HiiGetDiskContextCB (DiskIndex);
> +
> + if (Ctx == NULL) {
> + return NULL;
> + }
> +
> + Tmp = (OPAL_DRIVER_DEVICE*) Ctx;
> +
> + return &Tmp->OpalDisk;
> +}
> +
> +/**
> + Returns the disk name.
> +
> + @param DiskIndex Input the disk index.
> +
> + @retval Returns the disk name.
> +
> +**/
> +CHAR8*
> +HiiDiskGetNameCB(
> + UINT8 DiskIndex
> + )
> +{
> + OPAL_DRIVER_DEVICE* Ctx;
> +
> + Ctx = (OPAL_DRIVER_DEVICE*) HiiGetDiskContextCB (DiskIndex);
> +
> + if (Ctx != NULL) {
> + if (Ctx->NameZ == NULL) {
> + OpalDriverGetDriverDeviceName (Ctx);
> + }
> + return Ctx->NameZ;
> + }
> + return NULL;
> +}
> +
> +/**
> + Returns the driver name.
> +
> + @retval Returns the driver name.
> +
> +**/
> +CHAR16*
> +HiiGetDriverNameCB(
> + VOID
> + )
> +{
> + return (CHAR16*)EFI_DRIVER_NAME_UNICODE;
> +}
> diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormStrings.uni
> b/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormStrings.uni
> new file mode 100644
> index 000000000000..69abc561cc56
> --- /dev/null
> +++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormStrings.uni
> @@ -0,0 +1,84 @@
> +// /** @file
> +//
> +// String definitions for Setup formset.
> +//
> +// Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
> +//
> +// This program and the accompanying materials
> +// are licensed and made available under the terms and conditions of the BSD
> License
> +// which accompanies this distribution. The full text of the license may be found
> at
> +// http://opensource.org/licenses/bsd-license.php
> +//
> +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +//
> +// **/
> +
> +/=#
> +///////////////////////////////// GENERIC DEFINITIONS
> /////////////////////////////////
> +#langdef en-US "English"
> +#string STR_NULL #language en-US " "
> +
> +///////////////////////////////// FORM SET /////////////////////////////////
> +#string STR_FORM_SET_HELP #language en-US
> "Manage Opal disks"
> +
> +///////////////////////////////// MULTIPLE FORMS
> /////////////////////////////////
> +#string STR_OPAL #language en-US
> "Opal"
> +#string STR_MAIN_OPAL_VERSION #language en-US
> "Version 00.0.0.0000"
> +
> +///////////////////////////////// MAIN MENU FORM
> /////////////////////////////////
> +#string STR_MAIN_PHY_DISKS_LBL #language en-US
> "Physical Disks:"
> +
> +#string STR_MAIN_GOTO_DISK_INFO_0 #language en-US " "
> +#string STR_MAIN_GOTO_DISK_INFO_1 #language en-US " "
> +#string STR_MAIN_GOTO_DISK_INFO_2 #language en-US " "
> +#string STR_MAIN_GOTO_DISK_INFO_3 #language en-US " "
> +#string STR_MAIN_GOTO_DISK_INFO_4 #language en-US " "
> +#string STR_MAIN_GOTO_DISK_INFO_5 #language en-US " "
> +
> +#string STR_MAIN_GOTO_DISK_INFO_HELP #language en-US
> "Select to see Opal disk actions"
> +
> +#string STR_MAIN_NO_DISKS_PRESENT_LBL #language en-US
> "No disks connected to system"
> +
> +///////////////////////////////// DISK INFO MENU FORM
> /////////////////////////////////
> +#string STR_DISK_INFO_SELECTED_DISK_NAME #language en-US " "
> +
> +#string STR_DISK_INFO_LOCK #language en-US
> "Lock"
> +#string STR_DISK_INFO_UNLOCK #language en-US
> "Unlock"
> +#string STR_DISK_INFO_SET_ADMIN_PSWD #language en-US
> "Update Drive Admin Password"
> +#string STR_DISK_INFO_SET_USER_PSWD #language en-US
> "Set Drive User Password"
> +#string STR_DISK_INFO_SECURE_ERASE #language en-US
> "Secure Erase User Data"
> +#string STR_DISK_INFO_PSID_REVERT #language en-US
> "PSID Revert to factory default"
> +#string STR_DISK_INFO_REVERT #language en-US
> "Admin Revert to factory default and Disable"
> +#string STR_DISK_INFO_DISABLE_USER #language en-US
> "Disable User"
> +#string STR_DISK_INFO_ENABLE_FEATURE #language en-US
> "Enable Feature"
> +#string STR_DISK_INFO_ENABLE_BLOCKSID #language en-US
> "TCG Storage Action"
> +#string STR_ENABLED #language en-US
> "Enable BlockSID"
> +#string STR_DISABLED #language en-US
> "Disable BlockSID"
> +
> +#string STR_NONE #language en-US
> "None"
> +#string STR_DISK_INFO_ENABLE_BLOCKSID_TRUE #language en-US
> "Require physical presence when remote enable BlockSID"
> +#string STR_DISK_INFO_ENABLE_BLOCKSID_FALSE #language en-US
> "Not require physical presence when remote enable BlockSID"
> +#string STR_DISK_INFO_DISABLE_BLOCKSID_TRUE #language en-US
> "Require physical presence when remote disable BlockSID"
> +#string STR_DISK_INFO_DISABLE_BLOCKSID_FALSE #language en-US
> "Not require physical presence when remote disable BlockSID"
> +
> +#string STR_BLOCKSID_STATUS_HELP #language en-US
> "BlockSID action change status"
> +#string STR_BLOCKSID_STATUS #language en-US
> "Current BlockSID Status:"
> +#string STR_BLOCKSID_STATUS1 #language en-US ""
> +#string STR_BLOCKSID_STATUS2 #language en-US ""
> +#string STR_BLOCKSID_STATUS3 #language en-US ""
> +
> +#string STR_OPAL_REQUESTS_LBL #language en-US
> "Opal Requests:"
> +#string STR_DISK_INFO_LOCK_HELP #language en-US
> "Lock the disk"
> +#string STR_DISK_INFO_UNLOCK_HELP #language en-US
> "Unlock the disk"
> +#string STR_DISK_INFO_SET_ADMIN_PSWD_HELP #language en-US
> "Set password for the administrator"
> +#string STR_DISK_INFO_SET_USER_PSWD_HELP #language en-US
> "Set password for User 1"
> +#string STR_DISK_INFO_SECURE_ERASE_HELP #language en-US
> "Securely erase the disk"
> +#string STR_DISK_INFO_REVERT_HELP #language en-US
> "Revert the disk to factory defaults"
> +#string STR_DISK_INFO_PSID_REVERT_HELP #language en-US
> "Revert the disk to factory defaults, PSID is a 32 character case sensitive value"
> +#string STR_DISK_INFO_DISABLE_USER_HELP #language en-US
> "Disable User"
> +#string STR_DISK_INFO_ENABLE_FEATURE_HELP #language en-US
> "Enable Feature"
> +#string STR_KEEP_USER_DATA_PROMPT #language en-US "
> Keep User Data"
> +#string STR_KEEP_USER_DATA_HELP #language en-US
> "Check to keep user data, otherwise data will be lost"
> +
> +#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"
> diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormValues.h
> b/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormValues.h
> new file mode 100644
> index 000000000000..3ff7d4726d5e
> --- /dev/null
> +++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormValues.h
> @@ -0,0 +1,123 @@
> +/** @file
> + Defines Opal HII form ids, structures and values.
> +
> +Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution. The full text of the license may be found
> at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +
> +
> +#ifndef _OPAL_HII_FORM_VALUES_H_
> +#define _OPAL_HII_FORM_VALUES_H_
> +
> +// ID's for various forms that will be used by HII
> +#define FORMID_VALUE_MAIN_MENU 0x01
> +#define FORMID_VALUE_DISK_INFO_FORM_MAIN 0x02
> +
> +#define OPAL_REQUEST_VARIABLE_NAME
> L"OpalRequest"
> +
> +#pragma pack(1)
> +typedef struct {
> + UINT16 Lock:1;
> + UINT16 Unlock:1;
> + UINT16 SetAdminPwd:1;
> + UINT16 SetUserPwd:1;
> + UINT16 SecureErase:1;
> + UINT16 Revert:1;
> + UINT16 PsidRevert:1;
> + UINT16 DisableUser:1;
> + UINT16 DisableFeature:1;
> + UINT16 EnableFeature:1;
> + UINT16 Reserved:5;
> + UINT16 KeepUserData:1;
> +} OPAL_REQUEST;
> +
> +typedef struct {
> + UINT8 NumDisks;
> + UINT8 SelectedDiskIndex;
> + UINT16 SelectedDiskAvailableActions;
> + UINT16 SupportedDisks;
> + BOOLEAN KeepUserDataForced;
> + OPAL_REQUEST OpalRequest;
> + UINT8 EnableBlockSid;
> +} OPAL_HII_CONFIGURATION;
> +
> +typedef struct {
> + UINT32 Length;
> + OPAL_REQUEST OpalRequest;
> + //EFI_DEVICE_PATH_PROTOCOL OpalDevicePath;
> +} OPAL_REQUEST_VARIABLE;
> +
> +#pragma pack()
> +
> +/* Action Flags */
> +#define HII_ACTION_NONE
> 0x0000
> +#define HII_ACTION_LOCK
> 0x0001
> +#define HII_ACTION_UNLOCK
> 0x0002
> +#define HII_ACTION_SET_ADMIN_PWD
> 0x0004
> +#define HII_ACTION_SET_USER_PWD
> 0x0008
> +#define HII_ACTION_SECURE_ERASE
> 0x0010
> +#define HII_ACTION_REVERT
> 0x0020
> +#define HII_ACTION_PSID_REVERT
> 0x0040
> +#define HII_ACTION_DISABLE_USER
> 0x0080
> +#define HII_ACTION_DISABLE_FEATURE
> 0x0100
> +#define HII_ACTION_ENABLE_FEATURE
> 0x0200
> +
> +/* Number of bits allocated for each part of a unique key for an HII_ITEM
> + * all bits together must be <= 16 (EFI_QUESTION_ID is UINT16)
> + * 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
> + * | |-----------------------| |---------------------------|
> + * FLG INDEX ID
> + */
> +#define HII_KEY_ID_BITS 8
> +#define HII_KEY_INDEX_BITS 7
> +#define HII_KEY_FLAG_BITS 1
> +
> +#define HII_KEY_FLAG 0x8000
> // bit 15 (zero based)
> +
> +/***********/
> +/* Key IDs */
> +/***********/
> +
> +#define HII_KEY_ID_GOTO_DISK_INFO 1
> +
> +#define HII_KEY_ID_VAR_SUPPORTED_DISKS 2
> +#define HII_KEY_ID_VAR_SELECTED_DISK_AVAILABLE_ACTIONS 3
> +
> +#define HII_KEY_ID_BLOCKSID 4
> +#define HII_KEY_ID_SET_ADMIN_PWD 5
> +#define HII_KEY_ID_SET_USER_PWD 6
> +#define HII_KEY_ID_SECURE_ERASE 7
> +#define HII_KEY_ID_REVERT 8
> +#define HII_KEY_ID_KEEP_USER_DATA 9
> +#define HII_KEY_ID_PSID_REVERT 0xA
> +#define HII_KEY_ID_DISABLE_USER 0xB
> +#define HII_KEY_ID_ENABLE_FEATURE 0xC
> +
> +#define HII_KEY_ID_MAX 0xC
> // !!Update each time a new ID is added!!
> +
> +#define HII_KEY_WITH_INDEX(id, index) \
> + ( \
> + HII_KEY_FLAG | \
> + (id) | \
> + ((index) << HII_KEY_ID_BITS) \
> + )
> +
> +#define HII_KEY(id) HII_KEY_WITH_INDEX(id, 0)
> +
> +#define PACKAGE_LIST_GUID { 0xf0308176, 0x9058, 0x4153, { 0x93, 0x3d,
> 0xda, 0x2f, 0xdc, 0xc8, 0x3e, 0x44 } }
> +
> +/* {410483CF-F4F9-4ece-848A-1958FD31CEB7} */
> +#define SETUP_FORMSET_GUID { 0x410483cf, 0xf4f9, 0x4ece, { 0x84, 0x8a,
> 0x19, 0x58, 0xfd, 0x31, 0xce, 0xb7 } }
> +
> +// {BBF1ACD2-28D8-44ea-A291-58A237FEDF1A}
> +#define SETUP_VARIABLE_GUID { 0xbbf1acd2, 0x28d8, 0x44ea, { 0xa2, 0x91,
> 0x58, 0xa2, 0x37, 0xfe, 0xdf, 0x1a } }
> +
> +#endif //_HII_FORM_VALUES_H_
> +
> diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.c
> b/SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.c
> new file mode 100644
> index 000000000000..7657bb26e23c
> --- /dev/null
> +++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.c
> @@ -0,0 +1,2144 @@
> +/** @file
> + Provide functions to initialize NVME controller and perform NVME
> commands
> +
> +Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution. The full text of the license may be found
> at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +
> +#include "OpalPasswordPei.h"
> +
> +
> +#define ALIGN(v, a) (UINTN)((((v) - 1) | ((a) - 1)) +
> 1)
> +
> +///
> +/// NVME Host controller registers operation
> +///
> +#define NVME_GET_CAP(Nvme, Cap) NvmeMmioRead (Cap,
> Nvme->Nbar + NVME_CAP_OFFSET, sizeof (NVME_CAP))
> +#define NVME_GET_CC(Nvme, Cc) NvmeMmioRead (Cc,
> Nvme->Nbar + NVME_CC_OFFSET, sizeof (NVME_CC))
> +#define NVME_SET_CC(Nvme, Cc) NvmeMmioWrite
> (Nvme->Nbar + NVME_CC_OFFSET, Cc, sizeof (NVME_CC))
> +#define NVME_GET_CSTS(Nvme, Csts) NvmeMmioRead (Csts,
> Nvme->Nbar + NVME_CSTS_OFFSET, sizeof (NVME_CSTS))
> +#define NVME_GET_AQA(Nvme, Aqa) NvmeMmioRead (Aqa,
> Nvme->Nbar + NVME_AQA_OFFSET, sizeof (NVME_AQA))
> +#define NVME_SET_AQA(Nvme, Aqa) NvmeMmioWrite
> (Nvme->Nbar + NVME_AQA_OFFSET, Aqa, sizeof (NVME_AQA))
> +#define NVME_GET_ASQ(Nvme, Asq) NvmeMmioRead (Asq,
> Nvme->Nbar + NVME_ASQ_OFFSET, sizeof (NVME_ASQ))
> +#define NVME_SET_ASQ(Nvme, Asq) NvmeMmioWrite
> (Nvme->Nbar + NVME_ASQ_OFFSET, Asq, sizeof (NVME_ASQ))
> +#define NVME_GET_ACQ(Nvme, Acq) NvmeMmioRead (Acq,
> Nvme->Nbar + NVME_ACQ_OFFSET, sizeof (NVME_ACQ))
> +#define NVME_SET_ACQ(Nvme, Acq) NvmeMmioWrite
> (Nvme->Nbar + NVME_ACQ_OFFSET, Acq, sizeof (NVME_ACQ))
> +#define NVME_GET_VER(Nvme, Ver) NvmeMmioRead (Ver,
> Nvme->Nbar + NVME_VER_OFFSET, sizeof (NVME_VER))
> +#define NVME_SET_SQTDBL(Nvme, Qid, Sqtdbl) NvmeMmioWrite
> (Nvme->Nbar + NVME_SQTDBL_OFFSET(Qid, Nvme->Cap.Dstrd), Sqtdbl, sizeof
> (NVME_SQTDBL))
> +#define NVME_SET_CQHDBL(Nvme, Qid, Cqhdbl) NvmeMmioWrite
> (Nvme->Nbar + NVME_CQHDBL_OFFSET(Qid, Nvme->Cap.Dstrd), Cqhdbl, sizeof
> (NVME_CQHDBL))
> +
> +///
> +/// Base memory address
> +///
> +enum {
> + BASEMEM_CONTROLLER_DATA,
> + BASEMEM_IDENTIFY_DATA,
> + BASEMEM_ASQ,
> + BASEMEM_ACQ,
> + BASEMEM_SQ,
> + BASEMEM_CQ,
> + BASEMEM_PRP,
> + BASEMEM_SECURITY,
> + MAX_BASEMEM_COUNT
> +};
> +
> +///
> +/// All of base memories are 4K(0x1000) alignment
> +///
> +#define NVME_MEM_BASE(Nvme)
> ((UINTN)(Nvme->BaseMem))
> +#define NVME_CONTROL_DATA_BASE(Nvme) (ALIGN
> (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages
> (BASEMEM_CONTROLLER_DATA)) * EFI_PAGE_SIZE),
> EFI_PAGE_SIZE))
> +#define NVME_NAMESPACE_DATA_BASE(Nvme) (ALIGN
> (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages
> (BASEMEM_IDENTIFY_DATA)) * EFI_PAGE_SIZE),
> EFI_PAGE_SIZE))
> +#define NVME_ASQ_BASE(Nvme) (ALIGN
> (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_ASQ))
> * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
> +#define NVME_ACQ_BASE(Nvme) (ALIGN
> (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_ACQ))
> * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
> +#define NVME_SQ_BASE(Nvme, index) (ALIGN
> (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_SQ) +
> ((index)*(NVME_MAX_IO_QUEUES-1))) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
> +#define NVME_CQ_BASE(Nvme, index) (ALIGN
> (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_CQ) +
> ((index)*(NVME_MAX_IO_QUEUES-1))) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
> +#define NVME_PRP_BASE(Nvme, index) (ALIGN
> (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_PRP) +
> ((index)*NVME_PRP_SIZE)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
> +#define NVME_SEC_BASE(Nvme) (ALIGN
> (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_SECURITY))
> * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
> +
> +/**
> + Transfer MMIO Data to memory.
> +
> + @param[in,out] MemBuffer - Destination: Memory address
> + @param[in] MmioAddr - Source: MMIO address
> + @param[in] Size - Size for read
> +
> + @retval EFI_SUCCESS - MMIO read sucessfully
> +**/
> +EFI_STATUS
> +NvmeMmioRead (
> + IN OUT VOID *MemBuffer,
> + IN UINTN MmioAddr,
> + IN UINTN Size
> + )
> +{
> + UINTN Offset;
> + UINT8 Data;
> + UINT8 *Ptr;
> +
> + // priority has adjusted
> + switch (Size) {
> + case 4:
> + *((UINT32 *)MemBuffer) = MmioRead32 (MmioAddr);
> + break;
> +
> + case 8:
> + *((UINT64 *)MemBuffer) = MmioRead64 (MmioAddr);
> + break;
> +
> + case 2:
> + *((UINT16 *)MemBuffer) = MmioRead16 (MmioAddr);
> + break;
> +
> + case 1:
> + *((UINT8 *)MemBuffer) = MmioRead8 (MmioAddr);
> + break;
> +
> + default:
> + Ptr = (UINT8 *)MemBuffer;
> + for (Offset = 0; Offset < Size; Offset += 1) {
> + Data = MmioRead8 (MmioAddr + Offset);
> + Ptr[Offset] = Data;
> + }
> + break;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Transfer memory data to MMIO.
> +
> + @param[in,out] MmioAddr - Destination: MMIO address
> + @param[in] MemBuffer - Source: Memory address
> + @param[in] Size - Size for write
> +
> + @retval EFI_SUCCESS - MMIO write sucessfully
> +**/
> +EFI_STATUS
> +NvmeMmioWrite (
> + IN OUT UINTN MmioAddr,
> + IN VOID *MemBuffer,
> + IN UINTN Size
> + )
> +{
> + UINTN Offset;
> + UINT8 Data;
> + UINT8 *Ptr;
> +
> + // priority has adjusted
> + switch (Size) {
> + case 4:
> + MmioWrite32 (MmioAddr, *((UINT32 *)MemBuffer));
> + break;
> +
> + case 8:
> + MmioWrite64 (MmioAddr, *((UINT64 *)MemBuffer));
> + break;
> +
> + case 2:
> + MmioWrite16 (MmioAddr, *((UINT16 *)MemBuffer));
> + break;
> +
> + case 1:
> + MmioWrite8 (MmioAddr, *((UINT8 *)MemBuffer));
> + break;
> +
> + default:
> + Ptr = (UINT8 *)MemBuffer;
> + for (Offset = 0; Offset < Size; Offset += 1) {
> + Data = Ptr[Offset];
> + MmioWrite8 (MmioAddr + Offset, Data);
> + }
> + break;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Transfer MMIO data to memory.
> +
> + @param[in,out] MemBuffer - Destination: Memory address
> + @param[in] MmioAddr - Source: MMIO address
> + @param[in] Size - Size for read
> +
> + @retval EFI_SUCCESS - MMIO read sucessfully
> +**/
> +EFI_STATUS
> +OpalPciRead (
> + IN OUT VOID *MemBuffer,
> + IN UINTN MmioAddr,
> + IN UINTN Size
> + )
> +{
> + UINTN Offset;
> + UINT8 Data;
> + UINT8 *Ptr;
> +
> + // priority has adjusted
> + switch (Size) {
> + case 4:
> + *((UINT32 *)MemBuffer) = PciRead32 (MmioAddr);
> + break;
> +
> + case 2:
> + *((UINT16 *)MemBuffer) = PciRead16 (MmioAddr);
> + break;
> +
> + case 1:
> + *((UINT8 *)MemBuffer) = PciRead8 (MmioAddr);
> + break;
> +
> + default:
> + Ptr = (UINT8 *)MemBuffer;
> + for (Offset = 0; Offset < Size; Offset += 1) {
> + Data = PciRead8 (MmioAddr + Offset);
> + Ptr[Offset] = Data;
> + }
> + break;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Transfer memory data to MMIO.
> +
> + @param[in,out] MmioAddr - Destination: MMIO address
> + @param[in] MemBuffer - Source: Memory address
> + @param[in] Size - Size for write
> +
> + @retval EFI_SUCCESS - MMIO write sucessfully
> +**/
> +EFI_STATUS
> +OpalPciWrite (
> + IN OUT UINTN MmioAddr,
> + IN VOID *MemBuffer,
> + IN UINTN Size
> + )
> +{
> + UINTN Offset;
> + UINT8 Data;
> + UINT8 *Ptr;
> +
> + // priority has adjusted
> + switch (Size) {
> + case 4:
> + PciWrite32 (MmioAddr, *((UINT32 *)MemBuffer));
> + break;
> +
> + case 2:
> + PciWrite16 (MmioAddr, *((UINT16 *)MemBuffer));
> + break;
> +
> + case 1:
> + PciWrite8 (MmioAddr, *((UINT8 *)MemBuffer));
> + break;
> +
> + default:
> + Ptr = (UINT8 *)MemBuffer;
> + for (Offset = 0; Offset < Size; Offset += 1) {
> + Data = Ptr[Offset];
> + PciWrite8 (MmioAddr + Offset, Data);
> + }
> + break;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Get total pages for specific NVME based memory.
> +
> + @param[in] BaseMemIndex - The Index of BaseMem (0-based).
> +
> + @retval - The page count for specific BaseMem Index
> +
> +**/
> +UINT32
> +NvmeGetBaseMemPages (
> + IN UINTN BaseMemIndex
> + )
> +{
> + UINT32 Pages;
> + UINTN Index;
> + UINT32 PageSizeList[8];
> +
> + PageSizeList[0] = 1; /* Controller Data */
> + PageSizeList[1] = 1; /* Identify Data */
> + PageSizeList[2] = 1; /* ASQ */
> + PageSizeList[3] = 1; /* ACQ */
> + PageSizeList[4] = 1; /* SQs */
> + PageSizeList[5] = 1; /* CQs */
> + PageSizeList[6] = NVME_PRP_SIZE * NVME_CSQ_DEPTH; /* PRPs */
> + PageSizeList[7] = 1; /* Security Commands */
> +
> + if (BaseMemIndex > MAX_BASEMEM_COUNT) {
> + ASSERT (FALSE);
> + return 0;
> + }
> +
> + Pages = 0;
> + for (Index = 0; Index < BaseMemIndex; Index++) {
> + Pages += PageSizeList[Index];
> + }
> +
> + return Pages;
> +}
> +
> +/**
> + Wait for NVME controller status to be ready or not.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> + @param[in] WaitReady - Flag for waitting status ready or not
> +
> + @return EFI_SUCCESS - Successfully to wait specific status.
> + @return others - Fail to wait for specific controller
> status.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +NvmeWaitController (
> + IN NVME_CONTEXT *Nvme,
> + IN BOOLEAN WaitReady
> + )
> +{
> + NVME_CSTS Csts;
> + EFI_STATUS Status;
> + UINT32 Index;
> + UINT8 Timeout;
> +
> + //
> + // Cap.To specifies max delay time in 500ms increments for Csts.Rdy to set
> after
> + // Cc.Enable. Loop produces a 1 millisecond delay per itteration, up to 500 *
> Cap.To.
> + //
> + if (Nvme->Cap.To == 0) {
> + Timeout = 1;
> + } else {
> + Timeout = Nvme->Cap.To;
> + }
> +
> + Status = EFI_SUCCESS;
> + for(Index = (Timeout * 500); Index != 0; --Index) {
> + MicroSecondDelay (1000);
> +
> + //
> + // Check if the controller is initialized
> + //
> + Status = NVME_GET_CSTS (Nvme, &Csts);
> + if (EFI_ERROR(Status)) {
> + DEBUG ((DEBUG_ERROR, "NVME_GET_CSTS fail, Status = %r\n",
> Status));
> + return Status;
> + }
> +
> + if ((BOOLEAN) Csts.Rdy == WaitReady) {
> + break;
> + }
> + }
> +
> + if (Index == 0) {
> + Status = EFI_TIMEOUT;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Disable the Nvm Express controller.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> +
> + @return EFI_SUCCESS - Successfully disable the controller.
> + @return others - Fail to disable the controller.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +NvmeDisableController (
> + IN NVME_CONTEXT *Nvme
> + )
> +{
> + NVME_CC Cc;
> + NVME_CSTS Csts;
> + EFI_STATUS Status;
> +
> + Status = NVME_GET_CSTS (Nvme, &Csts);
> +
> + ///
> + /// Read Controller Configuration Register.
> + ///
> + Status = NVME_GET_CC (Nvme, &Cc);
> + if (EFI_ERROR(Status)) {
> + DEBUG ((DEBUG_ERROR, "NVME_GET_CC fail, Status = %r\n", Status));
> + goto Done;
> + }
> +
> + if (Cc.En == 1) {
> + Cc.En = 0;
> + ///
> + /// Disable the controller.
> + ///
> + Status = NVME_SET_CC (Nvme, &Cc);
> + if (EFI_ERROR(Status)) {
> + DEBUG ((DEBUG_ERROR, "NVME_SET_CC fail, Status = %r\n", Status));
> + goto Done;
> + }
> + }
> +
> + Status = NvmeWaitController (Nvme, FALSE);
> + if (EFI_ERROR(Status)) {
> + DEBUG ((DEBUG_ERROR, "NvmeWaitController fail, Status = %r\n",
> Status));
> + goto Done;
> + }
> +
> + return EFI_SUCCESS;
> +
> +Done:
> + DEBUG ((DEBUG_INFO, "NvmeDisableController fail, Status: %r\n", Status));
> + return Status;
> +}
> +
> +/**
> + Enable the Nvm Express controller.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> +
> + @return EFI_SUCCESS - Successfully enable the controller.
> + @return EFI_DEVICE_ERROR - Fail to enable the controller.
> + @return EFI_TIMEOUT - Fail to enable the controller in
> given time slot.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +NvmeEnableController (
> + IN NVME_CONTEXT *Nvme
> + )
> +{
> + NVME_CC Cc;
> + EFI_STATUS Status;
> +
> + //
> + // Enable the controller
> + //
> + ZeroMem (&Cc, sizeof (NVME_CC));
> + Cc.En = 1;
> + Cc.Iosqes = 6;
> + Cc.Iocqes = 4;
> + Status = NVME_SET_CC (Nvme, &Cc);
> + if (EFI_ERROR(Status)) {
> + DEBUG ((DEBUG_ERROR, "NVME_SET_CC fail, Status = %r\n", Status));
> + goto Done;
> + }
> +
> + Status = NvmeWaitController (Nvme, TRUE);
> + if (EFI_ERROR(Status)) {
> + DEBUG ((DEBUG_ERROR, "NvmeWaitController fail, Status = %r\n",
> Status));
> + goto Done;
> + }
> +
> + return EFI_SUCCESS;
> +
> +Done:
> + DEBUG ((DEBUG_INFO, "NvmeEnableController fail, Status: %r\n", Status));
> + return Status;
> +}
> +
> +/**
> + Shutdown the Nvm Express controller.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> +
> + @return EFI_SUCCESS - Successfully shutdown the
> controller.
> + @return EFI_DEVICE_ERROR - Fail to shutdown the controller.
> + @return EFI_TIMEOUT - Fail to shutdown the controller in
> given time slot.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +NvmeShutdownController (
> + IN NVME_CONTEXT *Nvme
> + )
> +{
> + NVME_CC Cc;
> + NVME_CSTS Csts;
> + EFI_STATUS Status;
> + UINT32 Index;
> + UINTN Timeout;
> +
> + Status = NVME_GET_CC (Nvme, &Cc);
> + if (EFI_ERROR(Status)) {
> + DEBUG ((DEBUG_ERROR, "NVME_GET_CC fail, Status = %r\n", Status));
> + return Status;
> + }
> +
> + Cc.Shn = 1; // Normal shutdown
> +
> + Status = NVME_SET_CC (Nvme, &Cc);
> + if (EFI_ERROR(Status)) {
> + DEBUG ((DEBUG_ERROR, "NVME_SET_CC fail, Status = %r\n", Status));
> + return Status;
> + }
> +
> + Timeout = NVME_GENERIC_TIMEOUT/1000; // ms
> + for(Index = (UINT32)(Timeout); Index != 0; --Index) {
> + MicroSecondDelay (1000);
> +
> + Status = NVME_GET_CSTS (Nvme, &Csts);
> + if (EFI_ERROR(Status)) {
> + DEBUG ((DEBUG_ERROR, "NVME_GET_CSTS fail, Status = %r\n",
> Status));
> + return Status;
> + }
> +
> + if (Csts.Shst == 2) { // Shutdown processing complete
> + break;
> + }
> + }
> +
> + if (Index == 0) {
> + Status = EFI_TIMEOUT;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Check the execution status from a given completion queue entry.
> +
> + @param[in] Cq - A pointer to the NVME_CQ item.
> +
> +**/
> +EFI_STATUS
> +NvmeCheckCqStatus (
> + IN NVME_CQ *Cq
> + )
> +{
> + if (Cq->Sct == 0x0 && Cq->Sc == 0x0) {
> + return EFI_SUCCESS;
> + }
> +
> + DEBUG ((DEBUG_INFO, "Dump NVMe Completion Entry Status from
> [0x%x]:\n", (UINTN)Cq));
> + DEBUG ((DEBUG_INFO, " SQ Identifier : [0x%x], Phase Tag : [%d], Cmd
> Identifier : [0x%x]\n", Cq->Sqid, Cq->Pt, Cq->Cid));
> + DEBUG ((DEBUG_INFO, " NVMe Cmd Execution Result - "));
> +
> + switch (Cq->Sct) {
> + case 0x0:
> + switch (Cq->Sc) {
> + case 0x0:
> + DEBUG ((DEBUG_INFO, "Successful Completion\n"));
> + return EFI_SUCCESS;
> + case 0x1:
> + DEBUG ((DEBUG_INFO, "Invalid Command Opcode\n"));
> + break;
> + case 0x2:
> + DEBUG ((DEBUG_INFO, "Invalid Field in Command\n"));
> + break;
> + case 0x3:
> + DEBUG ((DEBUG_INFO, "Command ID Conflict\n"));
> + break;
> + case 0x4:
> + DEBUG ((DEBUG_INFO, "Data Transfer Error\n"));
> + break;
> + case 0x5:
> + DEBUG ((DEBUG_INFO, "Commands Aborted due to Power Loss
> Notification\n"));
> + break;
> + case 0x6:
> + DEBUG ((DEBUG_INFO, "Internal Device Error\n"));
> + break;
> + case 0x7:
> + DEBUG ((DEBUG_INFO, "Command Abort Requested\n"));
> + break;
> + case 0x8:
> + DEBUG ((DEBUG_INFO, "Command Aborted due to SQ
> Deletion\n"));
> + break;
> + case 0x9:
> + DEBUG ((DEBUG_INFO, "Command Aborted due to Failed Fused
> Command\n"));
> + break;
> + case 0xA:
> + DEBUG ((DEBUG_INFO, "Command Aborted due to Missing Fused
> Command\n"));
> + break;
> + case 0xB:
> + DEBUG ((DEBUG_INFO, "Invalid Namespace or Format\n"));
> + break;
> + case 0xC:
> + DEBUG ((DEBUG_INFO, "Command Sequence Error\n"));
> + break;
> + case 0xD:
> + DEBUG ((DEBUG_INFO, "Invalid SGL Last Segment Descriptor\n"));
> + break;
> + case 0xE:
> + DEBUG ((DEBUG_INFO, "Invalid Number of SGL Descriptors\n"));
> + break;
> + case 0xF:
> + DEBUG ((DEBUG_INFO, "Data SGL Length Invalid\n"));
> + break;
> + case 0x10:
> + DEBUG ((DEBUG_INFO, "Metadata SGL Length Invalid\n"));
> + break;
> + case 0x11:
> + DEBUG ((DEBUG_INFO, "SGL Descriptor Type Invalid\n"));
> + break;
> + case 0x80:
> + DEBUG ((DEBUG_INFO, "LBA Out of Range\n"));
> + break;
> + case 0x81:
> + DEBUG ((DEBUG_INFO, "Capacity Exceeded\n"));
> + break;
> + case 0x82:
> + DEBUG ((DEBUG_INFO, "Namespace Not Ready\n"));
> + break;
> + case 0x83:
> + DEBUG ((DEBUG_INFO, "Reservation Conflict\n"));
> + break;
> + }
> + break;
> +
> + case 0x1:
> + switch (Cq->Sc) {
> + case 0x0:
> + DEBUG ((DEBUG_INFO, "Completion Queue Invalid\n"));
> + break;
> + case 0x1:
> + DEBUG ((DEBUG_INFO, "Invalid Queue Identifier\n"));
> + break;
> + case 0x2:
> + DEBUG ((DEBUG_INFO, "Maximum Queue Size Exceeded\n"));
> + break;
> + case 0x3:
> + DEBUG ((DEBUG_INFO, "Abort Command Limit Exceeded\n"));
> + break;
> + case 0x5:
> + DEBUG ((DEBUG_INFO, "Asynchronous Event Request Limit
> Exceeded\n"));
> + break;
> + case 0x6:
> + DEBUG ((DEBUG_INFO, "Invalid Firmware Slot\n"));
> + break;
> + case 0x7:
> + DEBUG ((DEBUG_INFO, "Invalid Firmware Image\n"));
> + break;
> + case 0x8:
> + DEBUG ((DEBUG_INFO, "Invalid Interrupt Vector\n"));
> + break;
> + case 0x9:
> + DEBUG ((DEBUG_INFO, "Invalid Log Page\n"));
> + break;
> + case 0xA:
> + DEBUG ((DEBUG_INFO, "Invalid Format\n"));
> + break;
> + case 0xB:
> + DEBUG ((DEBUG_INFO, "Firmware Application Requires
> Conventional Reset\n"));
> + break;
> + case 0xC:
> + DEBUG ((DEBUG_INFO, "Invalid Queue Deletion\n"));
> + break;
> + case 0xD:
> + DEBUG ((DEBUG_INFO, "Feature Identifier Not Saveable\n"));
> + break;
> + case 0xE:
> + DEBUG ((DEBUG_INFO, "Feature Not Changeable\n"));
> + break;
> + case 0xF:
> + DEBUG ((DEBUG_INFO, "Feature Not Namespace Specific\n"));
> + break;
> + case 0x10:
> + DEBUG ((DEBUG_INFO, "Firmware Application Requires NVM
> Subsystem Reset\n"));
> + break;
> + case 0x80:
> + DEBUG ((DEBUG_INFO, "Conflicting Attributes\n"));
> + break;
> + case 0x81:
> + DEBUG ((DEBUG_INFO, "Invalid Protection Information\n"));
> + break;
> + case 0x82:
> + DEBUG ((DEBUG_INFO, "Attempted Write to Read Only Range\n"));
> + break;
> + }
> + break;
> +
> + case 0x2:
> + switch (Cq->Sc) {
> + case 0x80:
> + DEBUG ((DEBUG_INFO, "Write Fault\n"));
> + break;
> + case 0x81:
> + DEBUG ((DEBUG_INFO, "Unrecovered Read Error\n"));
> + break;
> + case 0x82:
> + DEBUG ((DEBUG_INFO, "End-to-end Guard Check Error\n"));
> + break;
> + case 0x83:
> + DEBUG ((DEBUG_INFO, "End-to-end Application Tag Check
> Error\n"));
> + break;
> + case 0x84:
> + DEBUG ((DEBUG_INFO, "End-to-end Reference Tag Check
> Error\n"));
> + break;
> + case 0x85:
> + DEBUG ((DEBUG_INFO, "Compare Failure\n"));
> + break;
> + case 0x86:
> + DEBUG ((DEBUG_INFO, "Access Denied\n"));
> + break;
> + }
> + break;
> +
> + default:
> + DEBUG ((DEBUG_INFO, "Unknown error\n"));
> + break;
> + }
> +
> + return EFI_DEVICE_ERROR;
> +}
> +
> +/**
> + Create PRP lists for Data transfer which is larger than 2 memory pages.
> + Note here we calcuate the number of required PRP lists and allocate them at
> one time.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> + @param[in] SqId - The SQ index for this PRP
> + @param[in] PhysicalAddr - The physical base address of Data
> Buffer.
> + @param[in] Pages - The number of pages to be
> transfered.
> + @param[out] PrpListHost - The host base address of PRP lists.
> + @param[in,out] PrpListNo - The number of PRP List.
> +
> + @retval The pointer Value to the first PRP List of the PRP lists.
> +
> +**/
> +STATIC
> +UINT64
> +NvmeCreatePrpList (
> + IN NVME_CONTEXT *Nvme,
> + IN UINT16 SqId,
> + IN EFI_PHYSICAL_ADDRESS PhysicalAddr,
> + IN UINTN Pages,
> + OUT VOID **PrpListHost,
> + IN OUT UINTN *PrpListNo
> + )
> +{
> + UINTN PrpEntryNo;
> + UINT64 PrpListBase;
> + UINTN PrpListIndex;
> + UINTN PrpEntryIndex;
> + UINT64 Remainder;
> + EFI_PHYSICAL_ADDRESS PrpListPhyAddr;
> + UINTN Bytes;
> + UINT8 *PrpEntry;
> + EFI_PHYSICAL_ADDRESS NewPhyAddr;
> +
> + ///
> + /// The number of Prp Entry in a memory page.
> + ///
> + PrpEntryNo = EFI_PAGE_SIZE / sizeof (UINT64);
> +
> + ///
> + /// Calculate total PrpList number.
> + ///
> + *PrpListNo = (UINTN) DivU64x64Remainder ((UINT64)Pages,
> (UINT64)PrpEntryNo, &Remainder);
> + if (Remainder != 0) {
> + *PrpListNo += 1;
> + }
> +
> + if (*PrpListNo > NVME_PRP_SIZE) {
> + DEBUG ((DEBUG_INFO, "NvmeCreatePrpList (PhysicalAddr: %lx, Pages: %x)
> PrpEntryNo: %x\n",
> + PhysicalAddr, Pages, PrpEntryNo));
> + DEBUG ((DEBUG_INFO, "*PrpListNo: %x, Remainder: %lx", *PrpListNo,
> Remainder));
> + ASSERT (FALSE);
> + }
> + *PrpListHost = (VOID *)(UINTN) NVME_PRP_BASE (Nvme, SqId);
> +
> + Bytes = EFI_PAGES_TO_SIZE (*PrpListNo);
> + PrpListPhyAddr = (UINT64)(UINTN)(*PrpListHost);
> +
> + ///
> + /// Fill all PRP lists except of last one.
> + ///
> + ZeroMem (*PrpListHost, Bytes);
> + for (PrpListIndex = 0; PrpListIndex < *PrpListNo - 1; ++PrpListIndex) {
> + PrpListBase = *(UINT64*)PrpListHost + PrpListIndex * EFI_PAGE_SIZE;
> +
> + for (PrpEntryIndex = 0; PrpEntryIndex < PrpEntryNo; ++PrpEntryIndex) {
> + PrpEntry = (UINT8 *)(UINTN) (PrpListBase + PrpEntryIndex *
> sizeof(UINT64));
> + if (PrpEntryIndex != PrpEntryNo - 1) {
> + ///
> + /// Fill all PRP entries except of last one.
> + ///
> + CopyMem (PrpEntry, (VOID *)(UINTN) (&PhysicalAddr), sizeof
> (UINT64));
> + PhysicalAddr += EFI_PAGE_SIZE;
> + } else {
> + ///
> + /// Fill last PRP entries with next PRP List pointer.
> + ///
> + NewPhyAddr = (PrpListPhyAddr + (PrpListIndex + 1) *
> EFI_PAGE_SIZE);
> + CopyMem (PrpEntry, (VOID *)(UINTN) (&NewPhyAddr), sizeof
> (UINT64));
> + }
> + }
> + }
> +
> + ///
> + /// Fill last PRP list.
> + ///
> + PrpListBase = *(UINT64*)PrpListHost + PrpListIndex * EFI_PAGE_SIZE;
> + for (PrpEntryIndex = 0; PrpEntryIndex < ((Remainder != 0) ? Remainder :
> PrpEntryNo); ++PrpEntryIndex) {
> + PrpEntry = (UINT8 *)(UINTN) (PrpListBase + PrpEntryIndex *
> sizeof(UINT64));
> + CopyMem (PrpEntry, (VOID *)(UINTN) (&PhysicalAddr), sizeof (UINT64));
> +
> + PhysicalAddr += EFI_PAGE_SIZE;
> + }
> +
> + return PrpListPhyAddr;
> +}
> +
> +/**
> + Check whether there are available command slots.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> + @param[in] Qid - Queue index
> +
> + @retval EFI_SUCCESS - Available command slot is found
> + @retval EFI_NOT_READY - No available command slot is found
> + @retval EFI_DEVICE_ERROR - Error occurred on device side.
> +
> +**/
> +EFI_STATUS
> +NvmeHasFreeCmdSlot (
> + IN NVME_CONTEXT *Nvme,
> + IN UINT8 Qid
> + )
> +{
> + return TRUE;
> +}
> +
> +/**
> + Check whether all command slots are clean.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> + @param[in] Qid - Queue index
> +
> + @retval EFI_SUCCESS - All command slots are clean
> + @retval EFI_NOT_READY - Not all command slots are clean
> + @retval EFI_DEVICE_ERROR - Error occurred on device side.
> +
> +**/
> +EFI_STATUS
> +NvmeIsAllCmdSlotClean (
> + IN NVME_CONTEXT *Nvme,
> + IN UINT8 Qid
> + )
> +{
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Waits until all NVME commands completed.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> + @param[in] Qid - Queue index
> +
> + @retval EFI_SUCCESS - All NVME commands have
> completed
> + @retval EFI_TIMEOUT - Timeout occured
> + @retval EFI_NOT_READY - Not all NVME commands have
> completed
> + @retval others - Error occurred on device side.
> +**/
> +EFI_STATUS
> +NvmeWaitAllComplete (
> + IN NVME_CONTEXT *Nvme,
> + IN UINT8 Qid
> + )
> +{
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Sends an NVM Express Command Packet to an NVM Express controller or
> namespace. This function supports
> + both blocking I/O and nonblocking I/O. The blocking I/O functionality is
> required, and the nonblocking
> + I/O functionality is optional.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> + @param[in] NamespaceId - Is a 32 bit Namespace ID to which
> the Express HCI command packet will be sent.
> + A Value of 0 denotes the NVM
> Express controller, a Value of all 0FFh in the namespace
> + ID specifies that the command
> packet should be sent to all valid namespaces.
> + @param[in] NamespaceUuid - Is a 64 bit Namespace UUID to
> which the Express HCI command packet will be sent.
> + A Value of 0 denotes the NVM
> Express controller, a Value of all 0FFh in the namespace
> + UUID specifies that the command
> packet should be sent to all valid namespaces.
> + @param[in,out] Packet - A pointer to the NVM Express HCI
> Command Packet to send to the NVMe namespace specified
> + by NamespaceId.
> +
> + @retval EFI_SUCCESS - The NVM Express Command Packet
> was sent by the host. TransferLength bytes were transferred
> + to, or from DataBuffer.
> + @retval EFI_NOT_READY - The NVM Express Command Packet
> could not be sent because the controller is not ready. The caller
> + may retry again later.
> + @retval EFI_DEVICE_ERROR - A device error occurred while
> attempting to send the NVM Express Command Packet.
> + @retval EFI_INVALID_PARAMETER - Namespace, or the contents of
> NVM_EXPRESS_PASS_THRU_COMMAND_PACKET are invalid. The NVM
> + Express Command Packet was not
> sent, so no additional status information is available.
> + @retval EFI_UNSUPPORTED - The command described by the
> NVM Express Command Packet is not supported by the host adapter.
> + The NVM Express Command
> Packet was not sent, so no additional status information is available.
> + @retval EFI_TIMEOUT - A timeout occurred while waiting
> for the NVM Express Command Packet to execute.
> +
> +**/
> +EFI_STATUS
> +NvmePassThru (
> + IN NVME_CONTEXT *Nvme,
> + IN UINT32 NamespaceId,
> + IN UINT64 NamespaceUuid,
> + IN OUT NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet
> + )
> +{
> + EFI_STATUS Status;
> + NVME_SQ *Sq;
> + NVME_CQ *Cq;
> + UINT8 Qid;
> + UINT32 Bytes;
> + UINT32 Offset;
> + EFI_PHYSICAL_ADDRESS PhyAddr;
> + VOID *PrpListHost;
> + UINTN PrpListNo;
> + UINT32 Timer;
> + UINTN SqSize;
> + UINTN CqSize;
> +
> + ///
> + /// check the Data fields in Packet parameter.
> + ///
> + if ((Nvme == NULL) || (Packet == NULL)) {
> + DEBUG ((DEBUG_ERROR, "NvmePassThru, invalid parameter:
> Nvme(%x)/Packet(%x)\n",
> + (UINTN)Nvme, (UINTN)Packet));
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if ((Packet->NvmeCmd == NULL) || (Packet->NvmeResponse == NULL)) {
> + DEBUG ((DEBUG_ERROR, "NvmePassThru, invalid parameter:
> NvmeCmd(%x)/NvmeResponse(%x)\n",
> + (UINTN)Packet->NvmeCmd, (UINTN)Packet->NvmeResponse));
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (Packet->QueueId != NVME_ADMIN_QUEUE && Packet->QueueId !=
> NVME_IO_QUEUE) {
> + DEBUG ((DEBUG_ERROR, "NvmePassThru, invalid parameter:
> QueueId(%x)\n",
> + Packet->QueueId));
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + PrpListHost = NULL;
> + PrpListNo = 0;
> + Status = EFI_SUCCESS;
> +
> + Qid = Packet->QueueId;
> + Sq = Nvme->SqBuffer[Qid] + Nvme->SqTdbl[Qid].Sqt;
> + Cq = Nvme->CqBuffer[Qid] + Nvme->CqHdbl[Qid].Cqh;
> + if (Qid == NVME_ADMIN_QUEUE) {
> + SqSize = NVME_ASQ_SIZE + 1;
> + CqSize = NVME_ACQ_SIZE + 1;
> + } else {
> + SqSize = NVME_CSQ_DEPTH;
> + CqSize = NVME_CCQ_DEPTH;
> + }
> +
> + if (Packet->NvmeCmd->Nsid != NamespaceId) {
> + DEBUG ((DEBUG_ERROR, "NvmePassThru: Nsid mismatch (%x, %x)\n",
> + Packet->NvmeCmd->Nsid, NamespaceId));
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + ZeroMem (Sq, sizeof (NVME_SQ));
> + Sq->Opc = Packet->NvmeCmd->Cdw0.Opcode;
> + Sq->Fuse = Packet->NvmeCmd->Cdw0.FusedOperation;
> + Sq->Cid = Packet->NvmeCmd->Cdw0.Cid;
> + Sq->Nsid = Packet->NvmeCmd->Nsid;
> +
> + ///
> + /// Currently we only support PRP for Data transfer, SGL is NOT supported.
> + ///
> + ASSERT (Sq->Psdt == 0);
> + if (Sq->Psdt != 0) {
> + DEBUG ((DEBUG_ERROR, "NvmePassThru: doesn't support SGL
> mechanism\n"));
> + return EFI_UNSUPPORTED;
> + }
> +
> + Sq->Prp[0] = Packet->TransferBuffer;
> + Sq->Prp[1] = 0;
> +
> + if(Packet->MetadataBuffer != (UINT64)(UINTN)NULL) {
> + Sq->Mptr = Packet->MetadataBuffer;
> + }
> +
> + ///
> + /// If the Buffer Size spans more than two memory pages (page Size as
> defined in CC.Mps),
> + /// then build a PRP list in the second PRP submission queue entry.
> + ///
> + Offset = ((UINT32)Sq->Prp[0]) & (EFI_PAGE_SIZE - 1);
> + Bytes = Packet->TransferLength;
> +
> + if ((Offset + Bytes) > (EFI_PAGE_SIZE * 2)) {
> + ///
> + /// Create PrpList for remaining Data Buffer.
> + ///
> + PhyAddr = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1);
> + Sq->Prp[1] = NvmeCreatePrpList (Nvme, Nvme->SqTdbl[Qid].Sqt, PhyAddr,
> EFI_SIZE_TO_PAGES(Offset + Bytes) - 1, &PrpListHost, &PrpListNo);
> + if (Sq->Prp[1] == 0) {
> + Status = EFI_OUT_OF_RESOURCES;
> + DEBUG ((DEBUG_ERROR, "NvmeCreatePrpList fail, Status: %r\n",
> Status));
> + goto EXIT;
> + }
> +
> + } else if ((Offset + Bytes) > EFI_PAGE_SIZE) {
> + Sq->Prp[1] = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1);
> + }
> +
> + if(Packet->NvmeCmd->Flags & CDW10_VALID) {
> + Sq->Payload.Raw.Cdw10 = Packet->NvmeCmd->Cdw10;
> + }
> + if(Packet->NvmeCmd->Flags & CDW11_VALID) {
> + Sq->Payload.Raw.Cdw11 = Packet->NvmeCmd->Cdw11;
> + }
> + if(Packet->NvmeCmd->Flags & CDW12_VALID) {
> + Sq->Payload.Raw.Cdw12 = Packet->NvmeCmd->Cdw12;
> + }
> + if(Packet->NvmeCmd->Flags & CDW13_VALID) {
> + Sq->Payload.Raw.Cdw13 = Packet->NvmeCmd->Cdw13;
> + }
> + if(Packet->NvmeCmd->Flags & CDW14_VALID) {
> + Sq->Payload.Raw.Cdw14 = Packet->NvmeCmd->Cdw14;
> + }
> + if(Packet->NvmeCmd->Flags & CDW15_VALID) {
> + Sq->Payload.Raw.Cdw15 = Packet->NvmeCmd->Cdw15;
> + }
> +
> + ///
> + /// Ring the submission queue doorbell.
> + ///
> + Nvme->SqTdbl[Qid].Sqt++;
> + if(Nvme->SqTdbl[Qid].Sqt == SqSize) {
> + Nvme->SqTdbl[Qid].Sqt = 0;
> + }
> + Status = NVME_SET_SQTDBL (Nvme, Qid, &Nvme->SqTdbl[Qid]);
> + if (EFI_ERROR(Status)) {
> + DEBUG ((DEBUG_ERROR, "NVME_SET_SQTDBL fail, Status: %r\n",
> Status));
> + goto EXIT;
> + }
> +
> + ///
> + /// Wait for completion queue to get filled in.
> + ///
> + Status = EFI_TIMEOUT;
> + Timer = 0;
> + while (Timer < NVME_CMD_TIMEOUT) {
> + //DEBUG ((DEBUG_VERBOSE, "Timer: %x, Cq:\n", Timer));
> + //DumpMem (Cq, sizeof (NVME_CQ));
> + if (Cq->Pt != Nvme->Pt[Qid]) {
> + Status = EFI_SUCCESS;
> + break;
> + }
> +
> + MicroSecondDelay (NVME_CMD_WAIT);
> + Timer += NVME_CMD_WAIT;
> + }
> +
> + Nvme->CqHdbl[Qid].Cqh++;
> + if (Nvme->CqHdbl[Qid].Cqh == CqSize) {
> + Nvme->CqHdbl[Qid].Cqh = 0;
> + Nvme->Pt[Qid] ^= 1;
> + }
> +
> + ///
> + /// Copy the Respose Queue entry for this command to the callers response
> Buffer
> + ///
> + CopyMem (Packet->NvmeResponse, Cq, sizeof(NVM_EXPRESS_RESPONSE));
> +
> + if (!EFI_ERROR(Status)) { // We still need to check CQ status if no timeout
> error occured
> + Status = NvmeCheckCqStatus (Cq);
> + }
> + NVME_SET_CQHDBL (Nvme, Qid, &Nvme->CqHdbl[Qid]);
> +
> +EXIT:
> + return Status;
> +}
> +
> +/**
> + Get identify controller Data.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> + @param[in] Buffer - The Buffer used to store the identify
> controller Data.
> +
> + @return EFI_SUCCESS - Successfully get the identify
> controller Data.
> + @return others - Fail to get the identify controller
> Data.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +NvmeIdentifyController (
> + IN NVME_CONTEXT *Nvme,
> + IN VOID *Buffer
> + )
> +{
> + NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
> + NVM_EXPRESS_COMMAND Command;
> + NVM_EXPRESS_RESPONSE Response;
> + EFI_STATUS Status;
> +
> + ZeroMem (&CommandPacket,
> sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
> + ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
> + ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
> +
> + Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_OPC;
> + Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++;
> + //
> + // According to Nvm Express 1.1 spec Figure 38, When not used, the field
> shall be cleared to 0h.
> + // For the Identify command, the Namespace Identifier is only used for the
> Namespace Data structure.
> + //
> + Command.Nsid = 0;
> +
> + CommandPacket.NvmeCmd = &Command;
> + CommandPacket.NvmeResponse = &Response;
> + CommandPacket.TransferBuffer = (UINT64)(UINTN)Buffer;
> + CommandPacket.TransferLength = sizeof
> (NVME_ADMIN_CONTROLLER_DATA);
> + CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
> + CommandPacket.QueueId = NVME_ADMIN_QUEUE;
> + //
> + // Set bit 0 (Cns bit) to 1 to identify a controller
> + //
> + Command.Cdw10 = 1;
> + Command.Flags = CDW10_VALID;
> +
> + Status = NvmePassThru (
> + Nvme,
> + NVME_CONTROLLER_ID,
> + 0,
> + &CommandPacket
> + );
> + if (!EFI_ERROR (Status)) {
> + Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Get specified identify namespace Data.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> + @param[in] NamespaceId - The specified namespace identifier.
> + @param[in] Buffer - The Buffer used to store the identify
> namespace Data.
> +
> + @return EFI_SUCCESS - Successfully get the identify
> namespace Data.
> + @return others - Fail to get the identify namespace
> Data.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +NvmeIdentifyNamespace (
> + IN NVME_CONTEXT *Nvme,
> + IN UINT32 NamespaceId,
> + IN VOID *Buffer
> + )
> +{
> + NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
> + NVM_EXPRESS_COMMAND Command;
> + NVM_EXPRESS_RESPONSE Response;
> + EFI_STATUS Status;
> +
> + ZeroMem (&CommandPacket,
> sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
> + ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
> + ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
> +
> + CommandPacket.NvmeCmd = &Command;
> + CommandPacket.NvmeResponse = &Response;
> +
> + Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_OPC;
> + Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++;
> + Command.Nsid = NamespaceId;
> + CommandPacket.TransferBuffer = (UINT64)(UINTN)Buffer;
> + CommandPacket.TransferLength = sizeof
> (NVME_ADMIN_NAMESPACE_DATA);
> + CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
> + CommandPacket.QueueId = NVME_ADMIN_QUEUE;
> + //
> + // Set bit 0 (Cns bit) to 1 to identify a namespace
> + //
> + CommandPacket.NvmeCmd->Cdw10 = 0;
> + CommandPacket.NvmeCmd->Flags = CDW10_VALID;
> +
> + Status = NvmePassThru (
> + Nvme,
> + NamespaceId,
> + 0,
> + &CommandPacket
> + );
> + if (!EFI_ERROR (Status)) {
> + Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Get Block Size for specific namespace of NVME.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> +
> + @return - Block Size in bytes
> +
> +**/
> +STATIC
> +UINT32
> +NvmeGetBlockSize (
> + IN NVME_CONTEXT *Nvme
> + )
> +{
> + UINT32 BlockSize;
> + UINT32 Lbads;
> + UINT32 Flbas;
> + UINT32 LbaFmtIdx;
> +
> + Flbas = Nvme->NamespaceData->Flbas;
> + LbaFmtIdx = Flbas & 3;
> + Lbads = Nvme->NamespaceData->LbaFormat[LbaFmtIdx].Lbads;
> +
> + BlockSize = (UINT32)1 << Lbads;
> + return BlockSize;
> +}
> +
> +/**
> + Get last LBA for specific namespace of NVME.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> +
> + @return - Last LBA address
> +
> +**/
> +STATIC
> +EFI_LBA
> +NvmeGetLastLba (
> + IN NVME_CONTEXT *Nvme
> + )
> +{
> + EFI_LBA LastBlock;
> + LastBlock = Nvme->NamespaceData->Nsze - 1;
> + return LastBlock;
> +}
> +
> +/**
> + Create io completion queue.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> +
> + @return EFI_SUCCESS - Successfully create io completion
> queue.
> + @return others - Fail to create io completion queue.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +NvmeCreateIoCompletionQueue (
> + IN NVME_CONTEXT *Nvme
> + )
> +{
> + NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
> + NVM_EXPRESS_COMMAND Command;
> + NVM_EXPRESS_RESPONSE Response;
> + EFI_STATUS Status;
> + NVME_ADMIN_CRIOCQ CrIoCq;
> +
> + ZeroMem (&CommandPacket,
> sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
> + ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
> + ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
> + ZeroMem (&CrIoCq, sizeof(NVME_ADMIN_CRIOCQ));
> +
> + CommandPacket.NvmeCmd = &Command;
> + CommandPacket.NvmeResponse = &Response;
> +
> + Command.Cdw0.Opcode = NVME_ADMIN_CRIOCQ_OPC;
> + Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++;
> + CommandPacket.TransferBuffer =
> (UINT64)(UINTN)Nvme->CqBuffer[NVME_IO_QUEUE];
> + CommandPacket.TransferLength = EFI_PAGE_SIZE;
> + CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
> + CommandPacket.QueueId = NVME_ADMIN_QUEUE;
> +
> + CrIoCq.Qid = NVME_IO_QUEUE;
> + CrIoCq.Qsize = NVME_CCQ_SIZE;
> + CrIoCq.Pc = 1;
> + CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoCq, sizeof
> (NVME_ADMIN_CRIOCQ));
> + CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
> +
> + Status = NvmePassThru (
> + Nvme,
> + NVME_CONTROLLER_ID,
> + 0,
> + &CommandPacket
> + );
> + if (!EFI_ERROR (Status)) {
> + Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Create io submission queue.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> +
> + @return EFI_SUCCESS - Successfully create io submission
> queue.
> + @return others - Fail to create io submission queue.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +NvmeCreateIoSubmissionQueue (
> + IN NVME_CONTEXT *Nvme
> + )
> +{
> + NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
> + NVM_EXPRESS_COMMAND Command;
> + NVM_EXPRESS_RESPONSE Response;
> + EFI_STATUS Status;
> + NVME_ADMIN_CRIOSQ CrIoSq;
> +
> + ZeroMem (&CommandPacket,
> sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
> + ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
> + ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
> + ZeroMem (&CrIoSq, sizeof(NVME_ADMIN_CRIOSQ));
> +
> + CommandPacket.NvmeCmd = &Command;
> + CommandPacket.NvmeResponse = &Response;
> +
> + Command.Cdw0.Opcode = NVME_ADMIN_CRIOSQ_OPC;
> + Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++;
> + CommandPacket.TransferBuffer =
> (UINT64)(UINTN)Nvme->SqBuffer[NVME_IO_QUEUE];
> + CommandPacket.TransferLength = EFI_PAGE_SIZE;
> + CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
> + CommandPacket.QueueId = NVME_ADMIN_QUEUE;
> +
> + CrIoSq.Qid = NVME_IO_QUEUE;
> + CrIoSq.Qsize = NVME_CSQ_SIZE;
> + CrIoSq.Pc = 1;
> + CrIoSq.Cqid = NVME_IO_QUEUE;
> + CrIoSq.Qprio = 0;
> + CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoSq, sizeof
> (NVME_ADMIN_CRIOSQ));
> + CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
> +
> + Status = NvmePassThru (
> + Nvme,
> + NVME_CONTROLLER_ID,
> + 0,
> + &CommandPacket
> + );
> + if (!EFI_ERROR (Status)) {
> + Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Security send and receive commands.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> + @param[in] SendCommand - The flag to indicate the
> command type, TRUE for Send command and FALSE for receive command
> + @param[in] SecurityProtocol - Security Protocol
> + @param[in] SpSpecific - Security Protocol Specific
> + @param[in] TransferLength - Transfer Length of Buffer (in
> bytes) - always a multiple of 512
> + @param[in,out] TransferBuffer - Address of Data to transfer
> +
> + @return EFI_SUCCESS - Successfully create io submission
> queue.
> + @return others - Fail to send/receive commands.
> +
> +**/
> +EFI_STATUS
> +NvmeSecuritySendReceive (
> + IN NVME_CONTEXT *Nvme,
> + IN BOOLEAN SendCommand,
> + IN UINT8 SecurityProtocol,
> + IN UINT16 SpSpecific,
> + IN UINTN TransferLength,
> + IN OUT VOID *TransferBuffer
> + )
> +{
> + NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
> + NVM_EXPRESS_COMMAND Command;
> + NVM_EXPRESS_RESPONSE Response;
> + EFI_STATUS Status;
> + NVME_ADMIN_SECSEND SecSend;
> + OACS *Oacs;
> + UINT8 Opcode;
> + VOID* *SecBuff;
> +
> + Oacs = (OACS *)&Nvme->ControllerData->Oacs;
> +
> + //
> + // Verify security bit for Security Send/Receive commands
> + //
> + if (Oacs->Security == 0) {
> + DEBUG ((DEBUG_ERROR, "Security command doesn't support.\n"));
> + return EFI_NOT_READY;
> + }
> +
> + SecBuff = (VOID *)(UINTN) NVME_SEC_BASE (Nvme);
> +
> + //
> + // Actions for sending security command
> + //
> + if (SendCommand) {
> + CopyMem (SecBuff, TransferBuffer, TransferLength);
> + }
> +
> + ZeroMem (&CommandPacket,
> sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
> + ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
> + ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
> + ZeroMem (&SecSend, sizeof(NVME_ADMIN_SECSEND));
> +
> + CommandPacket.NvmeCmd = &Command;
> + CommandPacket.NvmeResponse = &Response;
> +
> + Opcode = (UINT8)(SendCommand ? NVME_ADMIN_SECURITY_SEND_OPC :
> NVME_ADMIN_SECURITY_RECV_OPC);
> + Command.Cdw0.Opcode = Opcode;
> + Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++;
> + CommandPacket.TransferBuffer = (UINT64)(UINTN)SecBuff;
> + CommandPacket.TransferLength = (UINT32)TransferLength;
> + CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
> + CommandPacket.QueueId = NVME_ADMIN_QUEUE;
> +
> + SecSend.Spsp = SpSpecific;
> + SecSend.Secp = SecurityProtocol;
> + SecSend.Tl = (UINT32)TransferLength;
> +
> + CopyMem (&CommandPacket.NvmeCmd->Cdw10, &SecSend, sizeof
> (NVME_ADMIN_SECSEND));
> + CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
> +
> + Status = NvmePassThru (
> + Nvme,
> + NVME_CONTROLLER_ID,
> + 0,
> + &CommandPacket
> + );
> + if (!EFI_ERROR (Status)) {
> + Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);
> + }
> +
> + //
> + // Actions for receiving security command
> + //
> + if (!SendCommand) {
> + CopyMem (TransferBuffer, SecBuff, TransferLength);
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Destroy io completion queue.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> +
> + @return EFI_SUCCESS - Successfully destroy io completion
> queue.
> + @return others - Fail to destroy io completion queue.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +NvmeDestroyIoCompletionQueue (
> + IN NVME_CONTEXT *Nvme
> + )
> +{
> + NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
> + NVM_EXPRESS_COMMAND Command;
> + NVM_EXPRESS_RESPONSE Response;
> + EFI_STATUS Status;
> + NVME_ADMIN_DEIOCQ DelIoCq;
> +
> + ZeroMem (&CommandPacket,
> sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
> + ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
> + ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
> + ZeroMem (&DelIoCq, sizeof(NVME_ADMIN_DEIOCQ));
> +
> + CommandPacket.NvmeCmd = &Command;
> + CommandPacket.NvmeResponse = &Response;
> +
> + Command.Cdw0.Opcode = NVME_ADMIN_DELIOCQ_OPC;
> + Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++;
> + CommandPacket.TransferBuffer =
> (UINT64)(UINTN)Nvme->CqBuffer[NVME_IO_QUEUE];
> + CommandPacket.TransferLength = EFI_PAGE_SIZE;
> + CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
> + CommandPacket.QueueId = NVME_ADMIN_QUEUE;
> +
> + DelIoCq.Qid = NVME_IO_QUEUE;
> + CopyMem (&CommandPacket.NvmeCmd->Cdw10, &DelIoCq, sizeof
> (NVME_ADMIN_DEIOCQ));
> + CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
> +
> + Status = NvmePassThru (
> + Nvme,
> + NVME_CONTROLLER_ID,
> + 0,
> + &CommandPacket
> + );
> + if (!EFI_ERROR (Status)) {
> + Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Destroy io submission queue.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> +
> + @return EFI_SUCCESS - Successfully destroy io submission
> queue.
> + @return others - Fail to destroy io submission queue.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +NvmeDestroyIoSubmissionQueue (
> + IN NVME_CONTEXT *Nvme
> + )
> +{
> + NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
> + NVM_EXPRESS_COMMAND Command;
> + NVM_EXPRESS_RESPONSE Response;
> + EFI_STATUS Status;
> + NVME_ADMIN_DEIOSQ DelIoSq;
> +
> + ZeroMem (&CommandPacket,
> sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
> + ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
> + ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
> + ZeroMem (&DelIoSq, sizeof(NVME_ADMIN_DEIOSQ));
> +
> + CommandPacket.NvmeCmd = &Command;
> + CommandPacket.NvmeResponse = &Response;
> +
> + Command.Cdw0.Opcode = NVME_ADMIN_DELIOSQ_OPC;
> + Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++;
> + CommandPacket.TransferBuffer =
> (UINT64)(UINTN)Nvme->SqBuffer[NVME_IO_QUEUE];
> + CommandPacket.TransferLength = EFI_PAGE_SIZE;
> + CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
> + CommandPacket.QueueId = NVME_ADMIN_QUEUE;
> +
> + DelIoSq.Qid = NVME_IO_QUEUE;
> + CopyMem (&CommandPacket.NvmeCmd->Cdw10, &DelIoSq, sizeof
> (NVME_ADMIN_DEIOSQ));
> + CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
> +
> + Status = NvmePassThru (
> + Nvme,
> + NVME_CONTROLLER_ID,
> + 0,
> + &CommandPacket
> + );
> + if (!EFI_ERROR (Status)) {
> + Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Allocate transfer-related Data struct which is used at Nvme.
> +
> + @param[in, out] Nvme The pointer to the NVME_CONTEXT Data
> structure.
> +
> + @retval EFI_OUT_OF_RESOURCE No enough resource.
> + @retval EFI_SUCCESS Successful to allocate resource.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +NvmeAllocateResource (
> + IN OUT NVME_CONTEXT *Nvme
> + )
> +{
> + EFI_STATUS Status;
> + EFI_PHYSICAL_ADDRESS DeviceAddress;
> + VOID *Base;
> + VOID *Mapping;
> +
> + //
> + // Allocate resources for DMA.
> + //
> + Status = IoMmuAllocateBuffer (
> + EFI_SIZE_TO_PAGES (NVME_MEM_MAX_SIZE),
> + &Base,
> + &DeviceAddress,
> + &Mapping
> + );
> + if (EFI_ERROR (Status)) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> + ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
> + Nvme->BaseMemMapping = Mapping;
> + Nvme->BaseMem = Base;
> + ZeroMem (Nvme->BaseMem, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES
> (NVME_MEM_MAX_SIZE));
> +
> + DEBUG ((
> + DEBUG_INFO,
> + "%a() NvmeContext 0x%x\n",
> + __FUNCTION__,
> + Nvme->BaseMem
> + ));
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Free allocated transfer-related Data struct which is used at NVMe.
> +
> + @param[in, out] Nvme The pointer to the NVME_CONTEXT Data
> structure.
> +
> +**/
> +VOID
> +EFIAPI
> +NvmeFreeResource (
> + IN OUT NVME_CONTEXT *Nvme
> + )
> +{
> + if (Nvme->BaseMem != NULL) {
> + IoMmuFreeBuffer (
> + EFI_SIZE_TO_PAGES (NVME_MEM_MAX_SIZE),
> + Nvme->BaseMem,
> + Nvme->BaseMemMapping
> + );
> + Nvme->BaseMem = NULL;
> + }
> +}
> +
> +/**
> + Initialize the Nvm Express controller.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> +
> + @retval EFI_SUCCESS - The NVM Express Controller is
> initialized successfully.
> + @retval Others - A device error occurred while
> initializing the controller.
> +
> +**/
> +EFI_STATUS
> +NvmeControllerInit (
> + IN NVME_CONTEXT *Nvme
> + )
> +{
> + EFI_STATUS Status;
> + NVME_AQA Aqa;
> + NVME_ASQ Asq;
> + NVME_ACQ Acq;
> + NVME_VER Ver;
> +
> + UINT32 MlBAR;
> + UINT32 MuBAR;
> +
> + ///
> + /// Update PCIE BAR0/1 for NVME device
> + ///
> + MlBAR = Nvme->Nbar;
> + MuBAR = 0;
> + PciWrite32 (Nvme->PciBase + 0x10, MlBAR); // MLBAR (BAR0)
> + PciWrite32 (Nvme->PciBase + 0x14, MuBAR); // MUBAR (BAR1)
> +
> + ///
> + /// Enable PCIE decode
> + ///
> + PciWrite8 (Nvme->PciBase + NVME_PCIE_PCICMD, 0x6);
> +
> + // Version
> + NVME_GET_VER (Nvme, &Ver);
> + if (!(Ver.Mjr == 0x0001) && (Ver.Mnr == 0x0000)) {
> + DEBUG ((DEBUG_INFO, "\n!!!\n!!! NVME Version mismatch for the
> implementation !!!\n!!!\n"));
> + }
> +
> + ///
> + /// Read the Controller Capabilities register and verify that the NVM
> command set is supported
> + ///
> + Status = NVME_GET_CAP (Nvme, &Nvme->Cap);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "NVME_GET_CAP fail, Status: %r\n", Status));
> + goto Done;
> + }
> +
> + if (Nvme->Cap.Css != 0x01) {
> + DEBUG ((DEBUG_ERROR, "NvmeControllerInit fail: the controller doesn't
> support NVMe command set\n"));
> + Status = EFI_UNSUPPORTED;
> + goto Done;
> + }
> +
> + ///
> + /// Currently the driver only supports 4k page Size.
> + ///
> + if ((Nvme->Cap.Mpsmin + 12) > EFI_PAGE_SHIFT) {
> + DEBUG ((DEBUG_ERROR, "NvmeControllerInit fail: only supports 4k page
> Size\n"));
> + ASSERT (FALSE);
> + Status = EFI_UNSUPPORTED;
> + goto Done;
> + }
> +
> + Nvme->Cid[0] = 0;
> + Nvme->Cid[1] = 0;
> +
> + Nvme->Pt[0] = 0;
> + Nvme->Pt[1] = 0;
> +
> + ZeroMem ((VOID *)(UINTN)(&(Nvme->SqTdbl[0])), sizeof (NVME_SQTDBL) *
> NVME_MAX_IO_QUEUES);
> + ZeroMem ((VOID *)(UINTN)(&(Nvme->CqHdbl[0])), sizeof (NVME_CQHDBL)
> * NVME_MAX_IO_QUEUES);
> +
> + ZeroMem (Nvme->BaseMem, NVME_MEM_MAX_SIZE);
> +
> + Status = NvmeDisableController (Nvme);
> + if (EFI_ERROR(Status)) {
> + DEBUG ((DEBUG_ERROR, "NvmeDisableController fail, Status: %r\n",
> Status));
> + goto Done;
> + }
> +
> + ///
> + /// set number of entries admin submission & completion queues.
> + ///
> + Aqa.Asqs = NVME_ASQ_SIZE;
> + Aqa.Rsvd1 = 0;
> + Aqa.Acqs = NVME_ACQ_SIZE;
> + Aqa.Rsvd2 = 0;
> +
> + ///
> + /// Address of admin submission queue.
> + ///
> + Asq = (UINT64)(UINTN)(NVME_ASQ_BASE (Nvme) & ~0xFFF);
> +
> + ///
> + /// Address of admin completion queue.
> + ///
> + Acq = (UINT64)(UINTN)(NVME_ACQ_BASE (Nvme) & ~0xFFF);
> +
> + ///
> + /// Address of I/O submission & completion queue.
> + ///
> + Nvme->SqBuffer[0] = (NVME_SQ *)(UINTN)NVME_ASQ_BASE (Nvme); //
> NVME_ADMIN_QUEUE
> + Nvme->CqBuffer[0] = (NVME_CQ *)(UINTN)NVME_ACQ_BASE (Nvme); //
> NVME_ADMIN_QUEUE
> + Nvme->SqBuffer[1] = (NVME_SQ *)(UINTN)NVME_SQ_BASE (Nvme, 0); //
> NVME_IO_QUEUE
> + Nvme->CqBuffer[1] = (NVME_CQ *)(UINTN)NVME_CQ_BASE (Nvme, 0); //
> NVME_IO_QUEUE
> +
> + DEBUG ((DEBUG_INFO, "Admin Submission Queue Size (Aqa.Asqs) =
> [%08X]\n", Aqa.Asqs));
> + DEBUG ((DEBUG_INFO, "Admin Completion Queue Size (Aqa.Acqs) =
> [%08X]\n", Aqa.Acqs));
> + DEBUG ((DEBUG_INFO, "Admin Submission Queue (SqBuffer[0]) =
> [%08X]\n", Nvme->SqBuffer[0]));
> + DEBUG ((DEBUG_INFO, "Admin Completion Queue (CqBuffer[0]) =
> [%08X]\n", Nvme->CqBuffer[0]));
> + DEBUG ((DEBUG_INFO, "I/O Submission Queue (SqBuffer[1]) =
> [%08X]\n", Nvme->SqBuffer[1]));
> + DEBUG ((DEBUG_INFO, "I/O Completion Queue (CqBuffer[1]) =
> [%08X]\n", Nvme->CqBuffer[1]));
> +
> + ///
> + /// Program admin queue attributes.
> + ///
> + Status = NVME_SET_AQA (Nvme, &Aqa);
> + if (EFI_ERROR(Status)) {
> + goto Done;
> + }
> +
> + ///
> + /// Program admin submission queue address.
> + ///
> + Status = NVME_SET_ASQ (Nvme, &Asq);
> + if (EFI_ERROR(Status)) {
> + goto Done;
> + }
> +
> + ///
> + /// Program admin completion queue address.
> + ///
> + Status = NVME_SET_ACQ (Nvme, &Acq);
> + if (EFI_ERROR(Status)) {
> + goto Done;
> + }
> +
> + Status = NvmeEnableController (Nvme);
> + if (EFI_ERROR(Status)) {
> + goto Done;
> + }
> +
> + ///
> + /// Create one I/O completion queue.
> + ///
> + Status = NvmeCreateIoCompletionQueue (Nvme);
> + if (EFI_ERROR(Status)) {
> + goto Done;
> + }
> +
> + ///
> + /// Create one I/O Submission queue.
> + ///
> + Status = NvmeCreateIoSubmissionQueue (Nvme);
> + if (EFI_ERROR(Status)) {
> + goto Done;
> + }
> +
> + ///
> + /// Get current Identify Controller Data
> + ///
> + Nvme->ControllerData = (NVME_ADMIN_CONTROLLER_DATA *)(UINTN)
> NVME_CONTROL_DATA_BASE (Nvme);
> + Status = NvmeIdentifyController (Nvme, Nvme->ControllerData);
> + if (EFI_ERROR(Status)) {
> + goto Done;
> + }
> +
> + ///
> + /// Dump NvmExpress Identify Controller Data
> + ///
> + Nvme->ControllerData->Sn[19] = 0;
> + Nvme->ControllerData->Mn[39] = 0;
> + //NvmeDumpIdentifyController (Nvme->ControllerData);
> +
> + ///
> + /// Get current Identify Namespace Data
> + ///
> + Nvme->NamespaceData = (NVME_ADMIN_NAMESPACE_DATA
> *)NVME_NAMESPACE_DATA_BASE (Nvme);
> + Status = NvmeIdentifyNamespace (Nvme, Nvme->Nsid,
> Nvme->NamespaceData);
> + if (EFI_ERROR(Status)) {
> + DEBUG ((DEBUG_ERROR, "NvmeIdentifyNamespace fail, Status = %r\n",
> Status));
> + goto Done;
> + }
> +
> + ///
> + /// Dump NvmExpress Identify Namespace Data
> + ///
> + if (Nvme->NamespaceData->Ncap == 0) {
> + DEBUG ((DEBUG_ERROR, "Invalid Namespace, Ncap: %lx\n",
> Nvme->NamespaceData->Ncap));
> + Status = EFI_DEVICE_ERROR;
> + goto Done;
> + }
> +
> + Nvme->BlockSize = NvmeGetBlockSize (Nvme);
> + Nvme->LastBlock = NvmeGetLastLba (Nvme);
> +
> + Nvme->State = NvmeStatusInit;
> +
> + return EFI_SUCCESS;
> +
> +Done:
> + return Status;
> +}
> +
> +/**
> + Un-initialize the Nvm Express controller.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> +
> + @retval EFI_SUCCESS - The NVM Express Controller is
> un-initialized successfully.
> + @retval Others - A device error occurred while
> un-initializing the controller.
> +
> +**/
> +EFI_STATUS
> +NvmeControllerExit (
> + IN NVME_CONTEXT *Nvme
> + )
> +{
> + EFI_STATUS Status;
> +
> + Status = EFI_SUCCESS;
> + if (Nvme->State == NvmeStatusInit || Nvme->State == NvmeStatusMax) {
> + ///
> + /// Destroy I/O Submission queue.
> + ///
> + Status = NvmeDestroyIoSubmissionQueue (Nvme);
> + if (EFI_ERROR(Status)) {
> + DEBUG ((DEBUG_ERROR, "NvmeDestroyIoSubmissionQueue fail, Status
> = %r\n", Status));
> + return Status;
> + }
> +
> + ///
> + /// Destroy I/O completion queue.
> + ///
> + Status = NvmeDestroyIoCompletionQueue (Nvme);
> + if (EFI_ERROR(Status)) {
> + DEBUG ((DEBUG_ERROR, "NvmeDestroyIoCompletionQueue fail, Status
> = %r\n", Status));
> + return Status;
> + }
> +
> + Status = NvmeShutdownController (Nvme);
> + if (EFI_ERROR(Status)) {
> + DEBUG ((DEBUG_ERROR, "NvmeShutdownController fail, Status: %r\n",
> Status));
> + }
> + }
> +
> + ///
> + /// Disable PCIE decode
> + ///
> + PciWrite8 (Nvme->PciBase + NVME_PCIE_PCICMD, 0x0);
> + PciWrite32 (Nvme->PciBase + 0x10, 0); // MLBAR (BAR0)
> + PciWrite32 (Nvme->PciBase + 0x14, 0); // MUBAR (BAR1)
> +
> + Nvme->State = NvmeStatusUnknown;
> + return Status;
> +}
> +
> +/**
> + Read sector Data from the NVMe device.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> + @param[in,out] Buffer - The Buffer used to store the Data
> read from the device.
> + @param[in] Lba - The start block number.
> + @param[in] Blocks - Total block number to be read.
> +
> + @retval EFI_SUCCESS - Datum are read from the device.
> + @retval Others - Fail to read all the datum.
> +
> +**/
> +EFI_STATUS
> +NvmeReadSectors (
> + IN NVME_CONTEXT *Nvme,
> + IN OUT UINT64 Buffer,
> + IN UINT64 Lba,
> + IN UINT32 Blocks
> + )
> +{
> + UINT32 Bytes;
> + NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
> + NVM_EXPRESS_COMMAND Command;
> + NVM_EXPRESS_RESPONSE Response;
> + EFI_STATUS Status;
> + UINT32 BlockSize;
> +
> + BlockSize = Nvme->BlockSize;
> + Bytes = Blocks * BlockSize;
> +
> + ZeroMem (&CommandPacket,
> sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
> + ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
> + ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
> +
> + CommandPacket.NvmeCmd = &Command;
> + CommandPacket.NvmeResponse = &Response;
> +
> + CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_READ_OPC;
> + CommandPacket.NvmeCmd->Cdw0.Cid =
> Nvme->Cid[NVME_IO_QUEUE]++;
> + CommandPacket.NvmeCmd->Nsid = Nvme->Nsid;
> + CommandPacket.TransferBuffer = Buffer;
> +
> + CommandPacket.TransferLength = Bytes;
> + CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
> + CommandPacket.QueueId = NVME_IO_QUEUE;
> +
> + CommandPacket.NvmeCmd->Cdw10 = (UINT32)Lba;
> + CommandPacket.NvmeCmd->Cdw11 = (UINT32)(RShiftU64 (Lba, 32));
> + CommandPacket.NvmeCmd->Cdw12 = (Blocks - 1) & 0xFFFF;
> +
> + CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID |
> CDW12_VALID;
> +
> + Status = NvmePassThru (
> + Nvme,
> + Nvme->Nsid,
> + 0,
> + &CommandPacket
> + );
> +
> + return Status;
> +}
> +
> +/**
> + Write sector Data to the NVMe device.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> + @param[in] Buffer - The Buffer to be written into the
> device.
> + @param[in] Lba - The start block number.
> + @param[in] Blocks - Total block number to be written.
> +
> + @retval EFI_SUCCESS - Datum are written into the Buffer.
> + @retval Others - Fail to write all the datum.
> +
> +**/
> +EFI_STATUS
> +NvmeWriteSectors (
> + IN NVME_CONTEXT *Nvme,
> + IN UINT64 Buffer,
> + IN UINT64 Lba,
> + IN UINT32 Blocks
> + )
> +{
> + NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
> + NVM_EXPRESS_COMMAND Command;
> + NVM_EXPRESS_RESPONSE Response;
> + EFI_STATUS Status;
> + UINT32 Bytes;
> + UINT32 BlockSize;
> +
> + BlockSize = Nvme->BlockSize;
> + Bytes = Blocks * BlockSize;
> +
> + ZeroMem (&CommandPacket,
> sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
> + ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
> + ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
> +
> + CommandPacket.NvmeCmd = &Command;
> + CommandPacket.NvmeResponse = &Response;
> +
> + CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_WRITE_OPC;
> + CommandPacket.NvmeCmd->Cdw0.Cid =
> Nvme->Cid[NVME_IO_QUEUE]++;
> + CommandPacket.NvmeCmd->Nsid = Nvme->Nsid;
> + CommandPacket.TransferBuffer = Buffer;
> +
> + CommandPacket.TransferLength = Bytes;
> + CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
> + CommandPacket.QueueId = NVME_IO_QUEUE;
> +
> + CommandPacket.NvmeCmd->Cdw10 = (UINT32)Lba;
> + CommandPacket.NvmeCmd->Cdw11 = (UINT32)(RShiftU64 (Lba, 32));
> + CommandPacket.NvmeCmd->Cdw12 = (Blocks - 1) & 0xFFFF;
> +
> + CommandPacket.MetadataBuffer = (UINT64)(UINTN)NULL;
> + CommandPacket.MetadataLength = 0;
> +
> + CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID |
> CDW12_VALID;
> +
> + Status = NvmePassThru (
> + Nvme,
> + Nvme->Nsid,
> + 0,
> + &CommandPacket
> + );
> +
> + return Status;
> +}
> +
> +/**
> + Flushes all modified Data to the device.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> +
> + @retval EFI_SUCCESS - Datum are written into the Buffer.
> + @retval Others - Fail to write all the datum.
> +
> +**/
> +EFI_STATUS
> +NvmeFlush (
> + IN NVME_CONTEXT *Nvme
> + )
> +{
> + NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
> + NVM_EXPRESS_COMMAND Command;
> + NVM_EXPRESS_RESPONSE Response;
> + EFI_STATUS Status;
> +
> + ZeroMem (&CommandPacket,
> sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
> + ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
> + ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
> +
> + CommandPacket.NvmeCmd = &Command;
> + CommandPacket.NvmeResponse = &Response;
> +
> + CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_FLUSH_OPC;
> + CommandPacket.NvmeCmd->Cdw0.Cid =
> Nvme->Cid[NVME_IO_QUEUE]++;
> + CommandPacket.NvmeCmd->Nsid = Nvme->Nsid;
> + CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
> + CommandPacket.QueueId = NVME_IO_QUEUE;
> +
> + Status = NvmePassThru (
> + Nvme,
> + Nvme->Nsid,
> + 0,
> + &CommandPacket
> + );
> + if (!EFI_ERROR (Status)) {
> + Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Read some blocks from the device.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> + @param[out] Buffer - The Buffer used to store the Data
> read from the device.
> + @param[in] Lba - The start block number.
> + @param[in] Blocks - Total block number to be read.
> +
> + @retval EFI_SUCCESS - Datum are read from the device.
> + @retval Others - Fail to read all the datum.
> +
> +**/
> +EFI_STATUS
> +NvmeRead (
> + IN NVME_CONTEXT *Nvme,
> + OUT UINT64 Buffer,
> + IN UINT64 Lba,
> + IN UINTN Blocks
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 BlockSize;
> + UINT32 MaxTransferBlocks;
> +
> + ASSERT (Blocks <= NVME_MAX_SECTORS);
> + Status = EFI_SUCCESS;
> + BlockSize = Nvme->BlockSize;
> + if (Nvme->ControllerData->Mdts != 0) {
> + MaxTransferBlocks = (1 << (Nvme->ControllerData->Mdts)) * (1 <<
> (Nvme->Cap.Mpsmin + 12)) / BlockSize;
> + } else {
> + MaxTransferBlocks = 1024;
> + }
> +
> + while (Blocks > 0) {
> + if (Blocks > MaxTransferBlocks) {
> + Status = NvmeReadSectors (Nvme, Buffer, Lba, MaxTransferBlocks);
> +
> + Blocks -= MaxTransferBlocks;
> + Buffer += (MaxTransferBlocks * BlockSize);
> + Lba += MaxTransferBlocks;
> + } else {
> + Status = NvmeReadSectors (Nvme, Buffer, Lba, (UINT32) Blocks);
> + Blocks = 0;
> + }
> +
> + if (EFI_ERROR(Status)) {
> + DEBUG ((DEBUG_ERROR, "NvmeRead fail, Status = %r\n", Status));
> + break;
> + }
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Write some blocks to the device.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> + @param[in] Buffer - The Buffer to be written into the
> device.
> + @param[in] Lba - The start block number.
> + @param[in] Blocks - Total block number to be written.
> +
> + @retval EFI_SUCCESS - Datum are written into the Buffer.
> + @retval Others - Fail to write all the datum.
> +
> +**/
> +EFI_STATUS
> +NvmeWrite (
> + IN NVME_CONTEXT *Nvme,
> + IN UINT64 Buffer,
> + IN UINT64 Lba,
> + IN UINTN Blocks
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 BlockSize;
> + UINT32 MaxTransferBlocks;
> +
> + ASSERT (Blocks <= NVME_MAX_SECTORS);
> + Status = EFI_SUCCESS;
> + BlockSize = Nvme->BlockSize;
> +
> + if (Nvme->ControllerData->Mdts != 0) {
> + MaxTransferBlocks = (1 << (Nvme->ControllerData->Mdts)) * (1 <<
> (Nvme->Cap.Mpsmin + 12)) / BlockSize;
> + } else {
> + MaxTransferBlocks = 1024;
> + }
> +
> + while (Blocks > 0) {
> + if (Blocks > MaxTransferBlocks) {
> + Status = NvmeWriteSectors (Nvme, Buffer, Lba, MaxTransferBlocks);
> +
> + Blocks -= MaxTransferBlocks;
> + Buffer += (MaxTransferBlocks * BlockSize);
> + Lba += MaxTransferBlocks;
> + } else {
> + Status = NvmeWriteSectors (Nvme, Buffer, Lba, (UINT32) Blocks);
> + Blocks = 0;
> + }
> +
> + if (EFI_ERROR(Status)) {
> + DEBUG ((DEBUG_ERROR, "NvmeWrite fail, Status = %r\n", Status));
> + break;
> + }
> + }
> +
> + return Status;
> +}
> diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.h
> b/SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.h
> new file mode 100644
> index 000000000000..3fef3dbc1c0d
> --- /dev/null
> +++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeMode.h
> @@ -0,0 +1,455 @@
> +/** @file
> + Header file for NVMe function definitions
> +
> +Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution. The full text of the license may be found
> at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +
> +#ifndef __OPAL_PASSWORD_NVME_MODE_H__
> +#define __OPAL_PASSWORD_NVME_MODE_H__
> +
> +
> +#include "OpalNvmeReg.h"
> +
> +#define NVME_MAX_SECTORS 0x10000
> +//
> +// QueueId
> +//
> +#define NVME_ADMIN_QUEUE 0x00
> +#define NVME_IO_QUEUE 0x01
> +
> +typedef struct {
> + UINT8 Opcode;
> + UINT8 FusedOperation;
> + #define NORMAL_CMD 0x00
> + #define FUSED_FIRST_CMD 0x01
> + #define FUSED_SECOND_CMD 0x02
> + UINT16 Cid;
> +} NVME_CDW0;
> +
> +typedef struct {
> + NVME_CDW0 Cdw0;
> + UINT8 Flags;
> + #define CDW10_VALID 0x01
> + #define CDW11_VALID 0x02
> + #define CDW12_VALID 0x04
> + #define CDW13_VALID 0x08
> + #define CDW14_VALID 0x10
> + #define CDW15_VALID 0x20
> + UINT32 Nsid;
> + UINT32 Cdw10;
> + UINT32 Cdw11;
> + UINT32 Cdw12;
> + UINT32 Cdw13;
> + UINT32 Cdw14;
> + UINT32 Cdw15;
> +} NVM_EXPRESS_COMMAND;
> +
> +typedef struct {
> + UINT32 Cdw0;
> + UINT32 Cdw1;
> + UINT32 Cdw2;
> + UINT32 Cdw3;
> +} NVM_EXPRESS_RESPONSE;
> +
> +typedef struct {
> + UINT64 CommandTimeout;
> + UINT64 TransferBuffer;
> + UINT32 TransferLength;
> + UINT64 MetadataBuffer;
> + UINT32 MetadataLength;
> + UINT8 QueueId;
> + NVM_EXPRESS_COMMAND *NvmeCmd;
> + NVM_EXPRESS_RESPONSE *NvmeResponse;
> +} NVM_EXPRESS_PASS_THRU_COMMAND_PACKET;
> +
> +
> +#pragma pack(1)
> +
> +// Internal fields
> +typedef enum {
> + NvmeStatusUnknown,
> + NvmeStatusInit,
> + NvmeStatusInuse,
> + NvmeStatusMax,
> +} NVME_STATUS;
> +
> +typedef struct {
> + UINT32 Nbar;
> + VOID *BaseMem;
> + VOID *BaseMemMapping;
> + BOOLEAN PollCancellation;
> + UINT16 NvmeInitWaitTime;
> +
> + NVME_STATUS State;
> + UINT8 BusID;
> + UINT8 DeviceID;
> + UINT8 FuncID;
> + UINTN PciBase;
> +
> + UINT32 Nsid;
> + UINT64 Nsuuid;
> + UINT32 BlockSize;
> + EFI_LBA LastBlock;
> +
> + //
> + // Pointers to 4kB aligned submission & completion queues.
> + //
> + NVME_SQ
> *SqBuffer[NVME_MAX_IO_QUEUES];
> + NVME_CQ
> *CqBuffer[NVME_MAX_IO_QUEUES];
> + UINT16 Cid[NVME_MAX_IO_QUEUES];
> +
> + //
> + // Submission and completion queue indices.
> + //
> + NVME_SQTDBL
> SqTdbl[NVME_MAX_IO_QUEUES];
> + NVME_CQHDBL
> CqHdbl[NVME_MAX_IO_QUEUES];
> + UINT8 Pt[NVME_MAX_IO_QUEUES];
> +
> + UINTN
> SqeCount[NVME_MAX_IO_QUEUES];
> +
> + //
> + // Nvme controller capabilities
> + //
> + NVME_CAP Cap;
> +
> + //
> + // pointer to identify controller Data
> + //
> + NVME_ADMIN_CONTROLLER_DATA *ControllerData;
> + NVME_ADMIN_NAMESPACE_DATA *NamespaceData;
> +} NVME_CONTEXT;
> +
> +#pragma pack()
> +
> +/**
> + Transfer MMIO Data to memory.
> +
> + @param[in,out] MemBuffer - Destination: Memory address
> + @param[in] MmioAddr - Source: MMIO address
> + @param[in] Size - Size for read
> +
> + @retval EFI_SUCCESS - MMIO read sucessfully
> +**/
> +EFI_STATUS
> +NvmeMmioRead (
> + IN OUT VOID *MemBuffer,
> + IN UINTN MmioAddr,
> + IN UINTN Size
> + );
> +
> +/**
> + Transfer memory Data to MMIO.
> +
> + @param[in,out] MmioAddr - Destination: MMIO address
> + @param[in] MemBuffer - Source: Memory address
> + @param[in] Size - Size for write
> +
> + @retval EFI_SUCCESS - MMIO write sucessfully
> +**/
> +EFI_STATUS
> +NvmeMmioWrite (
> + IN OUT UINTN MmioAddr,
> + IN VOID *MemBuffer,
> + IN UINTN Size
> + );
> +
> +/**
> + Transfer memory data to MMIO.
> +
> + @param[in,out] MmioAddr - Destination: MMIO address
> + @param[in] MemBuffer - Source: Memory address
> + @param[in] Size - Size for write
> +
> + @retval EFI_SUCCESS - MMIO write sucessfully
> +**/
> +EFI_STATUS
> +OpalPciWrite (
> + IN OUT UINTN MmioAddr,
> + IN VOID *MemBuffer,
> + IN UINTN Size
> + );
> +
> +/**
> + Transfer MMIO data to memory.
> +
> + @param[in,out] MemBuffer - Destination: Memory address
> + @param[in] MmioAddr - Source: MMIO address
> + @param[in] Size - Size for read
> +
> + @retval EFI_SUCCESS - MMIO read sucessfully
> +**/
> +EFI_STATUS
> +OpalPciRead (
> + IN OUT VOID *MemBuffer,
> + IN UINTN MmioAddr,
> + IN UINTN Size
> + );
> +
> +/**
> + Allocate transfer-related Data struct which is used at Nvme.
> +
> + @param[in, out] Nvme The pointer to the NVME_CONTEXT Data
> structure.
> +
> + @retval EFI_OUT_OF_RESOURCE No enough resource.
> + @retval EFI_SUCCESS Successful to allocate resource.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +NvmeAllocateResource (
> + IN OUT NVME_CONTEXT *Nvme
> + );
> +
> +/**
> + Free allocated transfer-related Data struct which is used at NVMe.
> +
> + @param[in, out] Nvme The pointer to the NVME_CONTEXT Data
> structure.
> +
> +**/
> +VOID
> +EFIAPI
> +NvmeFreeResource (
> + IN OUT NVME_CONTEXT *Nvme
> + );
> +
> +/**
> + Sends an NVM Express Command Packet to an NVM Express controller or
> namespace. This function supports
> + both blocking I/O and nonblocking I/O. The blocking I/O functionality is
> required, and the nonblocking
> + I/O functionality is optional.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> + @param[in] NamespaceId - Is a 32 bit Namespace ID to which
> the Express HCI command packet will be sent.
> + A Value of 0 denotes the NVM
> Express controller, a Value of all 0FFh in the namespace
> + ID specifies that the command
> packet should be sent to all valid namespaces.
> + @param[in] NamespaceUuid - Is a 64 bit Namespace UUID to
> which the Express HCI command packet will be sent.
> + A Value of 0 denotes the NVM
> Express controller, a Value of all 0FFh in the namespace
> + UUID specifies that the command
> packet should be sent to all valid namespaces.
> + @param[in,out] Packet - A pointer to the NVM Express HCI
> Command Packet to send to the NVMe namespace specified
> + by NamespaceId.
> +
> + @retval EFI_SUCCESS - The NVM Express Command Packet
> was sent by the host. TransferLength bytes were transferred
> + to, or from DataBuffer.
> + @retval EFI_NOT_READY - The NVM Express Command Packet
> could not be sent because the controller is not ready. The caller
> + may retry again later.
> + @retval EFI_DEVICE_ERROR - A device error occurred while
> attempting to send the NVM Express Command Packet.
> + @retval EFI_INVALID_PARAMETER - Namespace, or the contents of
> NVM_EXPRESS_PASS_THRU_COMMAND_PACKET are invalid. The NVM
> + Express Command Packet was not
> sent, so no additional status information is available.
> + @retval EFI_UNSUPPORTED - The command described by the
> NVM Express Command Packet is not supported by the host adapter.
> + The NVM Express Command
> Packet was not sent, so no additional status information is available.
> + @retval EFI_TIMEOUT - A timeout occurred while waiting
> for the NVM Express Command Packet to execute.
> +
> +**/
> +EFI_STATUS
> +NvmePassThru (
> + IN NVME_CONTEXT *Nvme,
> + IN UINT32 NamespaceId,
> + IN UINT64 NamespaceUuid,
> + IN OUT NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet
> + );
> +
> +/**
> + Waits until all NVME commands completed.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> + @param[in] Qid - Queue index
> +
> + @retval EFI_SUCCESS - All NVME commands have
> completed
> + @retval EFI_TIMEOUT - Timeout occured
> + @retval EFI_NOT_READY - Not all NVME commands have
> completed
> + @retval others - Error occurred on device side.
> +**/
> +EFI_STATUS
> +NvmeWaitAllComplete (
> + IN NVME_CONTEXT *Nvme,
> + IN UINT8 Qid
> + );
> +
> +/**
> + Initialize the Nvm Express controller.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> +
> + @retval EFI_SUCCESS - The NVM Express Controller is
> initialized successfully.
> + @retval Others - A device error occurred while
> initializing the controller.
> +
> +**/
> +EFI_STATUS
> +NvmeControllerInit (
> + IN NVME_CONTEXT *Nvme
> + );
> +
> +/**
> + Un-initialize the Nvm Express controller.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> +
> + @retval EFI_SUCCESS - The NVM Express Controller is
> un-initialized successfully.
> + @retval Others - A device error occurred while
> un-initializing the controller.
> +
> +**/
> +EFI_STATUS
> +NvmeControllerExit (
> + IN NVME_CONTEXT *Nvme
> + );
> +
> +/**
> + Check whether there are available command slots.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> + @param[in] Qid - Queue index
> +
> + @retval EFI_SUCCESS - Available command slot is found
> + @retval EFI_NOT_READY - No available command slot is found
> + @retval EFI_DEVICE_ERROR - Error occurred on device side.
> +
> +**/
> +EFI_STATUS
> +NvmeHasFreeCmdSlot (
> + IN NVME_CONTEXT *Nvme,
> + IN UINT8 Qid
> + );
> +
> +/**
> + Check whether all command slots are clean.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> + @param[in] Qid - Queue index
> +
> + @retval EFI_SUCCESS - All command slots are clean
> + @retval EFI_NOT_READY - Not all command slots are clean
> + @retval EFI_DEVICE_ERROR - Error occurred on device side.
> +
> +**/
> +EFI_STATUS
> +NvmeIsAllCmdSlotClean (
> + IN NVME_CONTEXT *Nvme,
> + IN UINT8 Qid
> + );
> +
> +/**
> + Read sector Data from the NVMe device.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> + @param[in,out] Buffer - The Buffer used to store the Data
> read from the device.
> + @param[in] Lba - The start block number.
> + @param[in] Blocks - Total block number to be read.
> +
> + @retval EFI_SUCCESS - Datum are read from the device.
> + @retval Others - Fail to read all the datum.
> +
> +**/
> +EFI_STATUS
> +NvmeReadSectors (
> + IN NVME_CONTEXT *Nvme,
> + IN OUT UINT64 Buffer,
> + IN UINT64 Lba,
> + IN UINT32 Blocks
> + );
> +
> +/**
> + Write sector Data to the NVMe device.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> + @param[in] Buffer - The Buffer to be written into the
> device.
> + @param[in] Lba - The start block number.
> + @param[in] Blocks - Total block number to be written.
> +
> + @retval EFI_SUCCESS - Datum are written into the Buffer.
> + @retval Others - Fail to write all the datum.
> +
> +**/
> +EFI_STATUS
> +NvmeWriteSectors (
> + IN NVME_CONTEXT *Nvme,
> + IN UINT64 Buffer,
> + IN UINT64 Lba,
> + IN UINT32 Blocks
> + );
> +
> +/**
> + Flushes all modified Data to the device.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> +
> + @retval EFI_SUCCESS - Datum are written into the Buffer.
> + @retval Others - Fail to write all the datum.
> +
> +**/
> +EFI_STATUS
> +NvmeFlush (
> + IN NVME_CONTEXT *Nvme
> + );
> +
> +/**
> + Read some blocks from the device.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> + @param[out] Buffer - The Buffer used to store the Data
> read from the device.
> + @param[in] Lba - The start block number.
> + @param[in] Blocks - Total block number to be read.
> +
> + @retval EFI_SUCCESS - Datum are read from the device.
> + @retval Others - Fail to read all the datum.
> +
> +**/
> +EFI_STATUS
> +NvmeRead (
> + IN NVME_CONTEXT *Nvme,
> + OUT UINT64 Buffer,
> + IN UINT64 Lba,
> + IN UINTN Blocks
> + );
> +
> +/**
> + Write some blocks to the device.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> + @param[in] Buffer - The Buffer to be written into the
> device.
> + @param[in] Lba - The start block number.
> + @param[in] Blocks - Total block number to be written.
> +
> + @retval EFI_SUCCESS - Datum are written into the Buffer.
> + @retval Others - Fail to write all the datum.
> +
> +**/
> +EFI_STATUS
> +NvmeWrite (
> + IN NVME_CONTEXT *Nvme,
> + IN UINT64 Buffer,
> + IN UINT64 Lba,
> + IN UINTN Blocks
> + );
> +
> +/**
> + Security send and receive commands.
> +
> + @param[in] Nvme - The pointer to the
> NVME_CONTEXT Data structure.
> + @param[in] SendCommand - The flag to indicate the
> command type, TRUE for Send command and FALSE for receive command
> + @param[in] SecurityProtocol - Security Protocol
> + @param[in] SpSpecific - Security Protocol Specific
> + @param[in] TransferLength - Transfer Length of Buffer (in
> bytes) - always a multiple of 512
> + @param[in,out] TransferBuffer - Address of Data to transfer
> +
> + @return EFI_SUCCESS - Successfully create io submission
> queue.
> + @return others - Fail to send/receive commands.
> +
> +**/
> +EFI_STATUS
> +NvmeSecuritySendReceive (
> + IN NVME_CONTEXT *Nvme,
> + IN BOOLEAN SendCommand,
> + IN UINT8 SecurityProtocol,
> + IN UINT16 SpSpecific,
> + IN UINTN TransferLength,
> + IN OUT VOID *TransferBuffer
> + );
> +
> +#endif
> diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeReg.h
> b/SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeReg.h
> new file mode 100644
> index 000000000000..03376b9e6c9a
> --- /dev/null
> +++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalNvmeReg.h
> @@ -0,0 +1,815 @@
> +/** @file
> + Header file for Registers and Structure definitions
> +
> +Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution. The full text of the license may be found
> at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +#ifndef __OPAL_PASSWORD_NVME_REG_H__
> +#define __OPAL_PASSWORD_NVME_REG_H__
> +
> +//
> +// PCI Header for PCIe root port configuration
> +//
> +#define NVME_PCIE_PCICMD 0x04
> +#define NVME_PCIE_BNUM 0x18
> +#define NVME_PCIE_SEC_BNUM 0x19
> +#define NVME_PCIE_IOBL 0x1C
> +#define NVME_PCIE_MBL 0x20
> +#define NVME_PCIE_PMBL 0x24
> +#define NVME_PCIE_PMBU32 0x28
> +#define NVME_PCIE_PMLU32 0x2C
> +#define NVME_PCIE_INTR 0x3C
> +
> +//
> +// NVMe related definitions
> +//
> +#define PCI_CLASS_MASS_STORAGE_NVM 0x08 // mass
> storage sub-class non-volatile memory.
> +#define PCI_IF_NVMHCI 0x02 // mass
> storage programming interface NVMHCI.
> +
> +#define NVME_ASQ_SIZE 1 //
> Number of admin submission queue entries, which is 0-based
> +#define NVME_ACQ_SIZE 1 //
> Number of admin completion queue entries, which is 0-based
> +
> +#define NVME_CSQ_SIZE 63 //
> Number of I/O submission queue entries, which is 0-based
> +#define NVME_CCQ_SIZE 63 //
> Number of I/O completion queue entries, which is 0-based
> +
> +#define NVME_MAX_IO_QUEUES 2 //
> Number of I/O queues supported by the driver, 1 for AQ, 1 for CQ
> +
> +#define NVME_CSQ_DEPTH
> (NVME_CSQ_SIZE+1)
> +#define NVME_CCQ_DEPTH
> (NVME_CCQ_SIZE+1)
> +#define NVME_PRP_SIZE (4) //
> Pages of PRP list
> +
> +#define NVME_CONTROLLER_ID 0
> +
> +//
> +// Time out Value for Nvme transaction execution
> +//
> +#define NVME_GENERIC_TIMEOUT 5000000
> ///< us
> +#define NVME_CMD_WAIT 100
> ///< us
> +#define NVME_CMD_TIMEOUT
> 20000000 ///< us
> +
> +
> +
> +#define NVME_MEM_MAX_SIZE \
> + (( \
> + 1 /* Controller Data */ + \
> + 1 /* Identify Data */ + \
> + 1 /* ASQ */ +
> \
> + 1 /* ACQ */ +
> \
> + 1 /* SQs */ +
> \
> + 1 /* CQs */ +
> \
> + NVME_PRP_SIZE * NVME_CSQ_DEPTH /* PRPs */
> + \
> + 1 /* SECURITY */
> \
> + ) * EFI_PAGE_SIZE)
> +
> +
> +//
> +// controller register offsets
> +//
> +#define NVME_CAP_OFFSET 0x0000 // Controller Capabilities
> +#define NVME_VER_OFFSET 0x0008 // Version
> +#define NVME_INTMS_OFFSET 0x000c // Interrupt Mask Set
> +#define NVME_INTMC_OFFSET 0x0010 // Interrupt Mask Clear
> +#define NVME_CC_OFFSET 0x0014 // Controller Configuration
> +#define NVME_CSTS_OFFSET 0x001c // Controller Status
> +#define NVME_AQA_OFFSET 0x0024 // Admin Queue Attributes
> +#define NVME_ASQ_OFFSET 0x0028 // Admin Submission Queue
> Base Address
> +#define NVME_ACQ_OFFSET 0x0030 // Admin Completion Queue
> Base Address
> +#define NVME_SQ0_OFFSET 0x1000 // Submission Queue 0
> (admin) Tail Doorbell
> +#define NVME_CQ0_OFFSET 0x1004 // Completion Queue 0
> (admin) Head Doorbell
> +
> +//
> +// These register offsets are defined as 0x1000 + (N * (4 << CAP.DSTRD))
> +// Get the doorbell stride bit shift Value from the controller capabilities.
> +//
> +#define NVME_SQTDBL_OFFSET(QID, DSTRD) 0x1000 + ((2 * (QID)) * (4
> << (DSTRD))) // Submission Queue y (NVM) Tail Doorbell
> +#define NVME_CQHDBL_OFFSET(QID, DSTRD) 0x1000 + (((2 * (QID)) + 1)
> * (4 << (DSTRD))) // Completion Queue y (NVM) Head Doorbell
> +
> +
> +#pragma pack(1)
> +
> +//
> +// 3.1.1 Offset 00h: CAP - Controller Capabilities
> +//
> +typedef struct {
> + UINT16 Mqes; // Maximum Queue Entries Supported
> + UINT8 Cqr:1; // Contiguous Queues Required
> + UINT8 Ams:2; // Arbitration Mechanism Supported
> + UINT8 Rsvd1:5;
> + UINT8 To; // Timeout
> + UINT16 Dstrd:4;
> + UINT16 Rsvd2:1;
> + UINT16 Css:4; // Command Sets Supported
> + UINT16 Rsvd3:7;
> + UINT8 Mpsmin:4;
> + UINT8 Mpsmax:4;
> + UINT8 Rsvd4;
> +} NVME_CAP;
> +
> +//
> +// 3.1.2 Offset 08h: VS - Version
> +//
> +typedef struct {
> + UINT16 Mnr; // Minor version number
> + UINT16 Mjr; // Major version number
> +} NVME_VER;
> +
> +//
> +// 3.1.5 Offset 14h: CC - Controller Configuration
> +//
> +typedef struct {
> + UINT16 En:1; // Enable
> + UINT16 Rsvd1:3;
> + UINT16 Css:3; // Command Set Selected
> + UINT16 Mps:4; // Memory Page Size
> + UINT16 Ams:3; // Arbitration Mechanism Selected
> + UINT16 Shn:2; // Shutdown Notification
> + UINT8 Iosqes:4; // I/O Submission Queue Entry Size
> + UINT8 Iocqes:4; // I/O Completion Queue Entry Size
> + UINT8 Rsvd2;
> +} NVME_CC;
> +
> +//
> +// 3.1.6 Offset 1Ch: CSTS - Controller Status
> +//
> +typedef struct {
> + UINT32 Rdy:1; // Ready
> + UINT32 Cfs:1; // Controller Fatal Status
> + UINT32 Shst:2; // Shutdown Status
> + UINT32 Nssro:1; // NVM Subsystem Reset Occurred
> + UINT32 Rsvd1:27;
> +} NVME_CSTS;
> +
> +//
> +// 3.1.8 Offset 24h: AQA - Admin Queue Attributes
> +//
> +typedef struct {
> + UINT16 Asqs:12; // Submission Queue Size
> + UINT16 Rsvd1:4;
> + UINT16 Acqs:12; // Completion Queue Size
> + UINT16 Rsvd2:4;
> +} NVME_AQA;
> +
> +//
> +// 3.1.9 Offset 28h: ASQ - Admin Submission Queue Base Address
> +//
> +#define NVME_ASQ UINT64
> +
> +//
> +// 3.1.10 Offset 30h: ACQ - Admin Completion Queue Base Address
> +//
> +#define NVME_ACQ UINT64
> +
> +//
> +// 3.1.11 Offset (1000h + ((2y) * (4 << CAP.DSTRD))): SQyTDBL - Submission
> Queue y Tail Doorbell
> +//
> +typedef struct {
> + UINT16 Sqt;
> + UINT16 Rsvd1;
> +} NVME_SQTDBL;
> +
> +//
> +// 3.1.12 Offset (1000h + ((2y + 1) * (4 << CAP.DSTRD))): CQyHDBL -
> Completion Queue y Head Doorbell
> +//
> +typedef struct {
> + UINT16 Cqh;
> + UINT16 Rsvd1;
> +} NVME_CQHDBL;
> +
> +//
> +// NVM command set structures
> +//
> +// Read Command
> +//
> +typedef struct {
> + //
> + // CDW 10, 11
> + //
> + UINT64 Slba; /* Starting Sector Address */
> + //
> + // CDW 12
> + //
> + UINT16 Nlb; /* Number of Sectors */
> + UINT16 Rsvd1:10;
> + UINT16 Prinfo:4; /* Protection Info Check */
> + UINT16 Fua:1; /* Force Unit Access */
> + UINT16 Lr:1; /* Limited Retry */
> + //
> + // CDW 13
> + //
> + UINT32 Af:4; /* Access Frequency */
> + UINT32 Al:2; /* Access Latency */
> + UINT32 Sr:1; /* Sequential Request */
> + UINT32 In:1; /* Incompressible */
> + UINT32 Rsvd2:24;
> + //
> + // CDW 14
> + //
> + UINT32 Eilbrt; /* Expected Initial Logical Block Reference Tag
> */
> + //
> + // CDW 15
> + //
> + UINT16 Elbat; /* Expected Logical Block Application Tag */
> + UINT16 Elbatm; /* Expected Logical Block Application Tag
> Mask */
> +} NVME_READ;
> +
> +//
> +// Write Command
> +//
> +typedef struct {
> + //
> + // CDW 10, 11
> + //
> + UINT64 Slba; /* Starting Sector Address */
> + //
> + // CDW 12
> + //
> + UINT16 Nlb; /* Number of Sectors */
> + UINT16 Rsvd1:10;
> + UINT16 Prinfo:4; /* Protection Info Check */
> + UINT16 Fua:1; /* Force Unit Access */
> + UINT16 Lr:1; /* Limited Retry */
> + //
> + // CDW 13
> + //
> + UINT32 Af:4; /* Access Frequency */
> + UINT32 Al:2; /* Access Latency */
> + UINT32 Sr:1; /* Sequential Request */
> + UINT32 In:1; /* Incompressible */
> + UINT32 Rsvd2:24;
> + //
> + // CDW 14
> + //
> + UINT32 Ilbrt; /* Initial Logical Block Reference Tag */
> + //
> + // CDW 15
> + //
> + UINT16 Lbat; /* Logical Block Application Tag */
> + UINT16 Lbatm; /* Logical Block Application Tag Mask */
> +} NVME_WRITE;
> +
> +//
> +// Flush
> +//
> +typedef struct {
> + //
> + // CDW 10
> + //
> + UINT32 Flush; /* Flush */
> +} NVME_FLUSH;
> +
> +//
> +// Write Uncorrectable command
> +//
> +typedef struct {
> + //
> + // CDW 10, 11
> + //
> + UINT64 Slba; /* Starting LBA */
> + //
> + // CDW 12
> + //
> + UINT32 Nlb:16; /* Number of Logical Blocks */
> + UINT32 Rsvd1:16;
> +} NVME_WRITE_UNCORRECTABLE;
> +
> +//
> +// Write Zeroes command
> +//
> +typedef struct {
> + //
> + // CDW 10, 11
> + //
> + UINT64 Slba; /* Starting LBA */
> + //
> + // CDW 12
> + //
> + UINT16 Nlb; /* Number of Logical Blocks */
> + UINT16 Rsvd1:10;
> + UINT16 Prinfo:4; /* Protection Info Check */
> + UINT16 Fua:1; /* Force Unit Access */
> + UINT16 Lr:1; /* Limited Retry */
> + //
> + // CDW 13
> + //
> + UINT32 Rsvd2;
> + //
> + // CDW 14
> + //
> + UINT32 Ilbrt; /* Initial Logical Block Reference Tag */
> + //
> + // CDW 15
> + //
> + UINT16 Lbat; /* Logical Block Application Tag */
> + UINT16 Lbatm; /* Logical Block Application Tag Mask */
> +} NVME_WRITE_ZEROES;
> +
> +//
> +// Compare command
> +//
> +typedef struct {
> + //
> + // CDW 10, 11
> + //
> + UINT64 Slba; /* Starting LBA */
> + //
> + // CDW 12
> + //
> + UINT16 Nlb; /* Number of Logical Blocks */
> + UINT16 Rsvd1:10;
> + UINT16 Prinfo:4; /* Protection Info Check */
> + UINT16 Fua:1; /* Force Unit Access */
> + UINT16 Lr:1; /* Limited Retry */
> + //
> + // CDW 13
> + //
> + UINT32 Rsvd2;
> + //
> + // CDW 14
> + //
> + UINT32 Eilbrt; /* Expected Initial Logical Block Reference Tag
> */
> + //
> + // CDW 15
> + //
> + UINT16 Elbat; /* Expected Logical Block Application Tag */
> + UINT16 Elbatm; /* Expected Logical Block Application Tag
> Mask */
> +} NVME_COMPARE;
> +
> +typedef union {
> + NVME_READ Read;
> + NVME_WRITE Write;
> + NVME_FLUSH Flush;
> + NVME_WRITE_UNCORRECTABLE WriteUncorrectable;
> + NVME_WRITE_ZEROES WriteZeros;
> + NVME_COMPARE Compare;
> +} NVME_CMD;
> +
> +typedef struct {
> + UINT16 Mp; /* Maximum Power */
> + UINT8 Rsvd1; /* Reserved as of Nvm Express 1.1 Spec */
> + UINT8 Mps:1; /* Max Power Scale */
> + UINT8 Nops:1; /* Non-Operational State */
> + UINT8 Rsvd2:6; /* Reserved as of Nvm Express 1.1 Spec */
> + UINT32 Enlat; /* Entry Latency */
> + UINT32 Exlat; /* Exit Latency */
> + UINT8 Rrt:5; /* Relative Read Throughput */
> + UINT8 Rsvd3:3; /* Reserved as of Nvm Express 1.1 Spec */
> + UINT8 Rrl:5; /* Relative Read Leatency */
> + UINT8 Rsvd4:3; /* Reserved as of Nvm Express 1.1 Spec */
> + UINT8 Rwt:5; /* Relative Write Throughput */
> + UINT8 Rsvd5:3; /* Reserved as of Nvm Express 1.1 Spec */
> + UINT8 Rwl:5; /* Relative Write Leatency */
> + UINT8 Rsvd6:3; /* Reserved as of Nvm Express 1.1 Spec */
> + UINT8 Rsvd7[16]; /* Reserved as of Nvm Express 1.1 Spec */
> +} NVME_PSDESCRIPTOR;
> +
> +//
> +// Identify Controller Data
> +//
> +typedef struct {
> + //
> + // Controller Capabilities and Features 0-255
> + //
> + UINT16 Vid; /* PCI Vendor ID */
> + UINT16 Ssvid; /* PCI sub-system vendor ID */
> + UINT8 Sn[20]; /* Produce serial number */
> +
> + UINT8 Mn[40]; /* Proeduct model number */
> + UINT8 Fr[8]; /* Firmware Revision */
> + UINT8 Rab; /* Recommended Arbitration Burst */
> + UINT8 Ieee_oiu[3]; /* Organization Unique Identifier */
> + UINT8 Cmic; /* Multi-interface Capabilities */
> + UINT8 Mdts; /* Maximum Data Transfer Size */
> + UINT8 Cntlid[2]; /* Controller ID */
> + UINT8 Rsvd1[176]; /* Reserved as of Nvm Express 1.1 Spec */
> + //
> + // Admin Command Set Attributes
> + //
> + UINT16 Oacs; /* Optional Admin Command Support */
> + UINT8 Acl; /* Abort Command Limit */
> + UINT8 Aerl; /* Async Event Request Limit */
> + UINT8 Frmw; /* Firmware updates */
> + UINT8 Lpa; /* Log Page Attributes */
> + UINT8 Elpe; /* Error Log Page Entries */
> + UINT8 Npss; /* Number of Power States Support */
> + UINT8 Avscc; /* Admin Vendor Specific Command
> Configuration */
> + UINT8 Apsta; /* Autonomous Power State Transition
> Attributes */
> + UINT8 Rsvd2[246]; /* Reserved as of Nvm Express 1.1 Spec */
> + //
> + // NVM Command Set Attributes
> + //
> + UINT8 Sqes; /* Submission Queue Entry Size */
> + UINT8 Cqes; /* Completion Queue Entry Size */
> + UINT16 Rsvd3; /* Reserved as of Nvm Express 1.1 Spec */
> + UINT32 Nn; /* Number of Namespaces */
> + UINT16 Oncs; /* Optional NVM Command Support */
> + UINT16 Fuses; /* Fused Operation Support */
> + UINT8 Fna; /* Format NVM Attributes */
> + UINT8 Vwc; /* Volatile Write Cache */
> + UINT16 Awun; /* Atomic Write Unit Normal */
> + UINT16 Awupf; /* Atomic Write Unit Power Fail */
> + UINT8 Nvscc; /* NVM Vendor Specific Command
> Configuration */
> + UINT8 Rsvd4; /* Reserved as of Nvm Express 1.1 Spec */
> + UINT16 Acwu; /* Atomic Compare & Write Unit */
> + UINT16 Rsvd5; /* Reserved as of Nvm Express 1.1 Spec */
> + UINT32 Sgls; /* SGL Support */
> + UINT8 Rsvd6[164]; /* Reserved as of Nvm Express 1.1 Spec */
> + //
> + // I/O Command set Attributes
> + //
> + UINT8 Rsvd7[1344]; /* Reserved as of Nvm Express 1.1 Spec */
> + //
> + // Power State Descriptors
> + //
> + NVME_PSDESCRIPTOR PsDescriptor[32];
> +
> + UINT8 VendorData[1024]; /* Vendor specific Data */
> +} NVME_ADMIN_CONTROLLER_DATA;
> +
> +typedef struct {
> + UINT16 Security : 1; /* supports security send/receive
> commands */
> + UINT16 Format : 1; /* supports format nvm command */
> + UINT16 Firmware : 1; /* supports firmware
> activate/download commands */
> + UINT16 Oacs_rsvd : 13;
> + } OACS; // optional admin command support:
> NVME_ADMIN_CONTROLLER_DATA.Oacs
> +
> +typedef struct {
> + UINT16 Ms; /* Metadata Size */
> + UINT8 Lbads; /* LBA Data Size */
> + UINT8 Rp:2; /* Relative Performance */
> + #define LBAF_RP_BEST 00b
> + #define LBAF_RP_BETTER 01b
> + #define LBAF_RP_GOOD 10b
> + #define LBAF_RP_DEGRADED 11b
> + UINT8 Rsvd1:6; /* Reserved as of Nvm Express 1.1 Spec */
> +} NVME_LBAFORMAT;
> +
> +//
> +// Identify Namespace Data
> +//
> +typedef struct {
> + //
> + // NVM Command Set Specific
> + //
> + UINT64 Nsze; /* Namespace Size (total number of blocks
> in formatted namespace) */
> + UINT64 Ncap; /* Namespace Capacity (max number of
> logical blocks) */
> + UINT64 Nuse; /* Namespace Utilization */
> + UINT8 Nsfeat; /* Namespace Features */
> + UINT8 Nlbaf; /* Number of LBA Formats */
> + UINT8 Flbas; /* Formatted LBA Size */
> + UINT8 Mc; /* Metadata Capabilities */
> + UINT8 Dpc; /* End-to-end Data Protection capabilities
> */
> + UINT8 Dps; /* End-to-end Data Protection Type Settings
> */
> + UINT8 Nmic; /* Namespace Multi-path I/O and
> Namespace Sharing Capabilities */
> + UINT8 Rescap; /* Reservation Capabilities */
> + UINT8 Rsvd1[88]; /* Reserved as of Nvm Express 1.1 Spec */
> + UINT64 Eui64; /* IEEE Extended Unique Identifier */
> + //
> + // LBA Format
> + //
> + NVME_LBAFORMAT LbaFormat[16];
> +
> + UINT8 Rsvd2[192]; /* Reserved as of Nvm Express 1.1 Spec */
> + UINT8 VendorData[3712]; /* Vendor specific Data */
> +} NVME_ADMIN_NAMESPACE_DATA;
> +
> +//
> +// NvmExpress Admin Identify Cmd
> +//
> +typedef struct {
> + //
> + // CDW 10
> + //
> + UINT32 Cns:2;
> + UINT32 Rsvd1:30;
> +} NVME_ADMIN_IDENTIFY;
> +
> +//
> +// NvmExpress Admin Create I/O Completion Queue
> +//
> +typedef struct {
> + //
> + // CDW 10
> + //
> + UINT32 Qid:16; /* Queue Identifier */
> + UINT32 Qsize:16; /* Queue Size */
> +
> + //
> + // CDW 11
> + //
> + UINT32 Pc:1; /* Physically Contiguous */
> + UINT32 Ien:1; /* Interrupts Enabled */
> + UINT32 Rsvd1:14; /* reserved as of Nvm Express 1.1 Spec */
> + UINT32 Iv:16; /* Interrupt Vector */
> +} NVME_ADMIN_CRIOCQ;
> +
> +//
> +// NvmExpress Admin Create I/O Submission Queue
> +//
> +typedef struct {
> + //
> + // CDW 10
> + //
> + UINT32 Qid:16; /* Queue Identifier */
> + UINT32 Qsize:16; /* Queue Size */
> +
> + //
> + // CDW 11
> + //
> + UINT32 Pc:1; /* Physically Contiguous */
> + UINT32 Qprio:2; /* Queue Priority */
> + UINT32 Rsvd1:13; /* Reserved as of Nvm Express 1.1 Spec */
> + UINT32 Cqid:16; /* Completion Queue ID */
> +} NVME_ADMIN_CRIOSQ;
> +
> +//
> +// NvmExpress Admin Delete I/O Completion Queue
> +//
> +typedef struct {
> + //
> + // CDW 10
> + //
> + UINT16 Qid;
> + UINT16 Rsvd1;
> +} NVME_ADMIN_DEIOCQ;
> +
> +//
> +// NvmExpress Admin Delete I/O Submission Queue
> +//
> +typedef struct {
> + //
> + // CDW 10
> + //
> + UINT16 Qid;
> + UINT16 Rsvd1;
> +} NVME_ADMIN_DEIOSQ;
> +
> +//
> +// NvmExpress Admin Security Send
> +//
> +typedef struct {
> + //
> + // CDW 10
> + //
> + UINT32 Resv:8; /* Reserve */
> + UINT32 Spsp:16; /* SP Specific */
> + UINT32 Secp:8; /* Security Protocol */
> +
> + //
> + // CDW 11
> + //
> + UINT32 Tl; /* Transfer Length */
> +} NVME_ADMIN_SECSEND;
> +
> +//
> +// NvmExpress Admin Abort Command
> +//
> +typedef struct {
> + //
> + // CDW 10
> + //
> + UINT32 Sqid:16; /* Submission Queue identifier */
> + UINT32 Cid:16; /* Command Identifier */
> +} NVME_ADMIN_ABORT;
> +
> +//
> +// NvmExpress Admin Firmware Activate Command
> +//
> +typedef struct {
> + //
> + // CDW 10
> + //
> + UINT32 Fs:3; /* Submission Queue identifier */
> + UINT32 Aa:2; /* Command Identifier */
> + UINT32 Rsvd1:27;
> +} NVME_ADMIN_FIRMWARE_ACTIVATE;
> +
> +//
> +// NvmExpress Admin Firmware Image Download Command
> +//
> +typedef struct {
> + //
> + // CDW 10
> + //
> + UINT32 Numd; /* Number of Dwords */
> + //
> + // CDW 11
> + //
> + UINT32 Ofst; /* Offset */
> +} NVME_ADMIN_FIRMWARE_IMAGE_DOWNLOAD;
> +
> +//
> +// NvmExpress Admin Get Features Command
> +//
> +typedef struct {
> + //
> + // CDW 10
> + //
> + UINT32 Fid:8; /* Feature Identifier */
> + UINT32 Sel:3; /* Select */
> + UINT32 Rsvd1:21;
> +} NVME_ADMIN_GET_FEATURES;
> +
> +//
> +// NvmExpress Admin Get Log Page Command
> +//
> +typedef struct {
> + //
> + // CDW 10
> + //
> + UINT32 Lid:8; /* Log Page Identifier */
> + #define LID_ERROR_INFO
> + #define LID_SMART_INFO
> + #define LID_FW_SLOT_INFO
> + UINT32 Rsvd1:8;
> + UINT32 Numd:12; /* Number of Dwords */
> + UINT32 Rsvd2:4; /* Reserved as of Nvm Express 1.1 Spec */
> +} NVME_ADMIN_GET_LOG_PAGE;
> +
> +//
> +// NvmExpress Admin Set Features Command
> +//
> +typedef struct {
> + //
> + // CDW 10
> + //
> + UINT32 Fid:8; /* Feature Identifier */
> + UINT32 Rsvd1:23;
> + UINT32 Sv:1; /* Save */
> +} NVME_ADMIN_SET_FEATURES;
> +
> +//
> +// NvmExpress Admin Format NVM Command
> +//
> +typedef struct {
> + //
> + // CDW 10
> + //
> + UINT32 Lbaf:4; /* LBA Format */
> + UINT32 Ms:1; /* Metadata Settings */
> + UINT32 Pi:3; /* Protection Information */
> + UINT32 Pil:1; /* Protection Information Location */
> + UINT32 Ses:3; /* Secure Erase Settings */
> + UINT32 Rsvd1:20;
> +} NVME_ADMIN_FORMAT_NVM;
> +
> +//
> +// NvmExpress Admin Security Receive Command
> +//
> +typedef struct {
> + //
> + // CDW 10
> + //
> + UINT32 Rsvd1:8;
> + UINT32 Spsp:16; /* SP Specific */
> + UINT32 Secp:8; /* Security Protocol */
> + //
> + // CDW 11
> + //
> + UINT32 Al; /* Allocation Length */
> +} NVME_ADMIN_SECURITY_RECEIVE;
> +
> +//
> +// NvmExpress Admin Security Send Command
> +//
> +typedef struct {
> + //
> + // CDW 10
> + //
> + UINT32 Rsvd1:8;
> + UINT32 Spsp:16; /* SP Specific */
> + UINT32 Secp:8; /* Security Protocol */
> + //
> + // CDW 11
> + //
> + UINT32 Tl; /* Transfer Length */
> +} NVME_ADMIN_SECURITY_SEND;
> +
> +typedef union {
> + NVME_ADMIN_IDENTIFY Identify;
> + NVME_ADMIN_CRIOCQ CrIoCq;
> + NVME_ADMIN_CRIOSQ CrIoSq;
> + NVME_ADMIN_DEIOCQ DeIoCq;
> + NVME_ADMIN_DEIOSQ DeIoSq;
> + NVME_ADMIN_ABORT Abort;
> + NVME_ADMIN_FIRMWARE_ACTIVATE Activate;
> + NVME_ADMIN_FIRMWARE_IMAGE_DOWNLOAD
> FirmwareImageDownload;
> + NVME_ADMIN_GET_FEATURES GetFeatures;
> + NVME_ADMIN_GET_LOG_PAGE GetLogPage;
> + NVME_ADMIN_SET_FEATURES SetFeatures;
> + NVME_ADMIN_FORMAT_NVM FormatNvm;
> + NVME_ADMIN_SECURITY_RECEIVE SecurityReceive;
> + NVME_ADMIN_SECURITY_SEND SecuritySend;
> +} NVME_ADMIN_CMD;
> +
> +typedef struct {
> + UINT32 Cdw10;
> + UINT32 Cdw11;
> + UINT32 Cdw12;
> + UINT32 Cdw13;
> + UINT32 Cdw14;
> + UINT32 Cdw15;
> +} NVME_RAW;
> +
> +typedef union {
> + NVME_ADMIN_CMD Admin; // Union of Admin commands
> + NVME_CMD Nvm; // Union of Nvm commands
> + NVME_RAW Raw;
> +} NVME_PAYLOAD;
> +
> +//
> +// Submission Queue
> +//
> +typedef struct {
> + //
> + // CDW 0, Common to all comnmands
> + //
> + UINT8 Opc; // Opcode
> + UINT8 Fuse:2; // Fused Operation
> + UINT8 Rsvd1:5;
> + UINT8 Psdt:1; // PRP or SGL for Data Transfer
> + UINT16 Cid; // Command Identifier
> +
> + //
> + // CDW 1
> + //
> + UINT32 Nsid; // Namespace Identifier
> +
> + //
> + // CDW 2,3
> + //
> + UINT64 Rsvd2;
> +
> + //
> + // CDW 4,5
> + //
> + UINT64 Mptr; // Metadata Pointer
> +
> + //
> + // CDW 6-9
> + //
> + UINT64 Prp[2]; // First and second PRP entries
> +
> + NVME_PAYLOAD Payload;
> +
> +} NVME_SQ;
> +
> +//
> +// Completion Queue
> +//
> +typedef struct {
> + //
> + // CDW 0
> + //
> + UINT32 Dword0;
> + //
> + // CDW 1
> + //
> + UINT32 Rsvd1;
> + //
> + // CDW 2
> + //
> + UINT16 Sqhd; // Submission Queue Head Pointer
> + UINT16 Sqid; // Submission Queue Identifier
> + //
> + // CDW 3
> + //
> + UINT16 Cid; // Command Identifier
> + UINT16 Pt:1; // Phase Tag
> + UINT16 Sc:8; // Status Code
> + UINT16 Sct:3; // Status Code Type
> + UINT16 Rsvd2:2;
> + UINT16 Mo:1; // More
> + UINT16 Dnr:1; // Retry
> +} NVME_CQ;
> +
> +//
> +// Nvm Express Admin cmd opcodes
> +//
> +#define NVME_ADMIN_DELIOSQ_OPC 0
> +#define NVME_ADMIN_CRIOSQ_OPC 1
> +#define NVME_ADMIN_DELIOCQ_OPC 4
> +#define NVME_ADMIN_CRIOCQ_OPC 5
> +#define NVME_ADMIN_IDENTIFY_OPC 6
> +#define NVME_ADMIN_SECURITY_SEND_OPC 0x81
> +#define NVME_ADMIN_SECURITY_RECV_OPC 0x82
> +
> +#define NVME_IO_FLUSH_OPC 0
> +#define NVME_IO_WRITE_OPC 1
> +#define NVME_IO_READ_OPC 2
> +
> +//
> +// Offset from the beginning of private Data queue Buffer
> +//
> +#define NVME_ASQ_BUF_OFFSET EFI_PAGE_SIZE
> +
> +#pragma pack()
> +
> +#endif
> +
> diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordCommon.h
> b/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordCommon.h
> new file mode 100644
> index 000000000000..17fda410dc54
> --- /dev/null
> +++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordCommon.h
> @@ -0,0 +1,65 @@
> +/** @file
> + Opal Password common header file.
> +
> +Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution. The full text of the license may be found
> at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +
> +#ifndef _OPAL_PASSWORD_COMMON_H_
> +#define _OPAL_PASSWORD_COMMON_H_
> +
> +#define OPAL_DEVICE_TYPE_UNKNOWN 0x0
> +#define OPAL_DEVICE_TYPE_ATA 0x1
> +#define OPAL_DEVICE_TYPE_NVME 0x2
> +
> +typedef struct {
> + UINT16 Segment;
> + UINT8 Bus;
> + UINT8 Device;
> + UINT8 Function;
> + UINT8 Reserved;
> +} OPAL_PCI_DEVICE;
> +
> +typedef struct {
> + UINT16 Length;
> + OPAL_PCI_DEVICE Device;
> + UINT8 PasswordLength;
> + UINT8 Password[32];
> + UINT16 OpalBaseComId;
> + UINT32 BarAddr;
> +} OPAL_DEVICE_COMMON;
> +
> +#define OPAL_DEVICE_ATA_GUID { 0xcb934fe1, 0xb8cd, 0x46b1, { 0xa0, 0x58,
> 0xdd, 0xcb, 0x7, 0xb7, 0xb4, 0x17 } }
> +
> +typedef struct {
> + UINT16 Length;
> + OPAL_PCI_DEVICE Device;
> + UINT8 PasswordLength;
> + UINT8 Password[32];
> + UINT16 OpalBaseComId;
> + UINT32 BarAddr;
> + UINT16 Port;
> + UINT16 PortMultiplierPort;
> +} OPAL_DEVICE_ATA;
> +
> +#define OPAL_DEVICE_NVME_GUID { 0xde116925, 0xaf7f, 0x42d9, { 0x83,
> 0xc0, 0x7e, 0xd6, 0x26, 0x59, 0x0, 0xfb } }
> +
> +typedef struct {
> + UINT16 Length;
> + OPAL_PCI_DEVICE Device;
> + UINT8 PasswordLength;
> + UINT8 Password[32];
> + UINT16 OpalBaseComId;
> + UINT32 BarAddr;
> + UINT32 NvmeNamespaceId;
> + OPAL_PCI_DEVICE PciBridgeNode[0];
> +} OPAL_DEVICE_NVME;
> +
> +#endif // _OPAL_PASSWORD_COMMON_H_
> diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordDxe.inf
> b/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordDxe.inf
> new file mode 100644
> index 000000000000..0ac550a72873
> --- /dev/null
> +++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordDxe.inf
> @@ -0,0 +1,81 @@
> +## @file
> +# This is a OpalPasswordDxe driver.
> +#
> +# This module is used to Management the Opal feature
> +# for Opal supported devices.
> +#
> +# Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
> +# This program and the accompanying materials
> +# are licensed and made available under the terms and conditions of the BSD
> License
> +# which accompanies this distribution. The full text of the license may be found
> at
> +# http://opensource.org/licenses/bsd-license.php
> +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +#
> +##
> +[Defines]
> + INF_VERSION = 0x00010007
> + BASE_NAME = OpalPasswordDxe
> + FILE_GUID =
> E3E4048D-6C0C-43E4-AE1C-FFB579D8EF41
> + MODULE_TYPE = DXE_DRIVER
> + VERSION_STRING = 1.0
> + ENTRY_POINT = EfiDriverEntryPoint
> + UNLOAD_IMAGE = OpalEfiDriverUnload
> +
> +#
> +# The following information is for reference only and not required by the build
> tools.
> +#
> +# VALID_ARCHITECTURES = IA32 X64 IPF EBC
> +#
> +
> +[Sources]
> + OpalDriver.c
> + OpalDriver.h
> + OpalPasswordCommon.h
> + OpalHii.c
> + OpalHii.h
> + OpalHiiCallbacks.c
> + OpalHiiFormValues.h
> + OpalHiiFormStrings.uni
> + OpalPasswordForm.vfr
> + ComponentName.c
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> + MdeModulePkg/MdeModulePkg.dec
> + SecurityPkg/SecurityPkg.dec
> +
> +[LibraryClasses]
> + BaseLib
> + MemoryAllocationLib
> + UefiBootServicesTableLib
> + UefiDriverEntryPoint
> + UefiRuntimeServicesTableLib
> + DxeServicesTableLib
> + UefiHiiServicesLib
> + BaseMemoryLib
> + DebugLib
> + HiiLib
> + PrintLib
> + DevicePathLib
> + UefiLib
> + TcgStorageOpalLib
> + Tcg2PhysicalPresenceLib
> + PciLib
> + S3BootScriptLib
> + LockBoxLib
> +
> +[Protocols]
> + gEfiHiiConfigAccessProtocolGuid ## PRODUCES
> + gEfiStorageSecurityCommandProtocolGuid ## CONSUMES
> + gEfiComponentNameProtocolGuid ## PRODUCES
> + gEfiComponentName2ProtocolGuid ## PRODUCES
> + gEfiBlockIoProtocolGuid ## CONSUMES
> + gEfiPciIoProtocolGuid ## CONSUMES
> + gEfiDevicePathToTextProtocolGuid ## CONSUMES
> +
> +[Guids]
> + gEfiEndOfDxeEventGroupGuid ## CONSUMES
> ## Event
> +
> +[Depex]
> + gEfiHiiStringProtocolGuid AND gEfiHiiDatabaseProtocolGuid
> diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordForm.vfr
> b/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordForm.vfr
> new file mode 100644
> index 000000000000..cba388723305
> --- /dev/null
> +++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordForm.vfr
> @@ -0,0 +1,309 @@
> +/** @file
> +
> +Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution. The full text of the license may be found
> at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +#include "OpalHiiFormValues.h"
> +
> +
> +#define EFI_HII_PLATFORM_SETUP_FORMSET_GUID \
> + { 0x93039971, 0x8545, 0x4b04, { 0xb4, 0x5e, 0x32, 0xeb, 0x83, 0x26, 0x4,
> 0xe } }
> +
> +formset
> + guid = SETUP_FORMSET_GUID,
> + title = STRING_TOKEN(STR_OPAL),
> + help = STRING_TOKEN(STR_FORM_SET_HELP),
> + classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,
> +
> + // Define a Buffer Storage (EFI_IFR_VARSTORE) that will be filled
> + // out initially through extractConfig call
> + varstore OPAL_HII_CONFIGURATION, // This is the Data
> structure type
> + name = OpalHiiConfig, // Define referenced name
> in vfr
> + guid = SETUP_VARIABLE_GUID; // GUID of this Buffer
> storage
> +
> +form formid = FORMID_VALUE_MAIN_MENU,
> + title = STRING_TOKEN(STR_OPAL);
> +
> + //CONFIG_VARIABLE(HII_KEY(HII_KEY_ID_VAR_SUPPORTED_DISKS),
> SupportedDisks, 0x0, 0xFFFF);
> + suppressif TRUE;
> + numeric
> + name = SupportedDisks,
> + varid = OpalHiiConfig.SupportedDisks,
> + prompt = STRING_TOKEN(STR_NULL),
> + help = STRING_TOKEN(STR_NULL),
> + flags = INTERACTIVE,
> + key = 0x8002,
> + minimum = 0x0,
> + maximum = 0xFFFF,
> + endnumeric;
> + endif;
> +
> + subtitle text = STRING_TOKEN(STR_MAIN_OPAL_VERSION);
> +
> + subtitle text = STRING_TOKEN(STR_NULL);
> +
> + subtitle text = STRING_TOKEN(STR_MAIN_PHY_DISKS_LBL);
> +
> + //DISK( 0 );
> + suppressif ( questionref(SupportedDisks) & ( 0x1 ) ) == 0;
> + goto FORMID_VALUE_DISK_INFO_FORM_MAIN,
> + prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_0 ),
> + help =
> STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP),
> + flags = INTERACTIVE,
> + key = 0x8001;
> + endif;
> +
> + //DISK( 1 );
> + suppressif ( questionref(SupportedDisks) & ( 0x2 ) ) == 0;
> + goto FORMID_VALUE_DISK_INFO_FORM_MAIN,
> + prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_1 ),
> + help =
> STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP),
> + flags = INTERACTIVE,
> + key = 0x8101;
> + endif;
> +
> + //DISK( 2 );
> + suppressif ( questionref(SupportedDisks) & ( 0x4 ) ) == 0;
> + goto FORMID_VALUE_DISK_INFO_FORM_MAIN,
> + prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_2 ),
> + help =
> STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP),
> + flags = INTERACTIVE,
> + key = 0x8201;
> + endif;
> +
> + //DISK( 3 );
> + suppressif ( questionref(SupportedDisks) & ( 0x8 ) ) == 0;
> + goto FORMID_VALUE_DISK_INFO_FORM_MAIN,
> + prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_3 ),
> + help =
> STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP),
> + flags = INTERACTIVE,
> + key = 0x8301;
> + endif;
> +
> + //DISK( 4 );
> + suppressif ( questionref(SupportedDisks) & ( 0x10 ) ) == 0;
> + goto FORMID_VALUE_DISK_INFO_FORM_MAIN,
> + prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_4 ),
> + help =
> STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP),
> + flags = INTERACTIVE,
> + key = 0x8401;
> + endif;
> +
> + //DISK( 5 );
> + suppressif ( questionref(SupportedDisks) & ( 0x20 ) ) == 0;
> + goto FORMID_VALUE_DISK_INFO_FORM_MAIN,
> + prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_5 ),
> + help =
> STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP),
> + flags = INTERACTIVE,
> + key = 0x8501;
> + endif;
> +
> + //No disks on system
> + suppressif ideqval OpalHiiConfig.NumDisks > 0;
> + text
> + help = STRING_TOKEN(STR_NULL),
> + text =
> STRING_TOKEN(STR_MAIN_NO_DISKS_PRESENT_LBL);
> + endif;
> +
> + subtitle text = STRING_TOKEN(STR_NULL);
> +
> + grayoutif TRUE;
> + text
> + help = STRING_TOKEN(STR_BLOCKSID_STATUS_HELP),
> + text = STRING_TOKEN(STR_BLOCKSID_STATUS);
> + text
> + help = STRING_TOKEN(STR_BLOCKSID_STATUS_HELP),
> + text = STRING_TOKEN(STR_BLOCKSID_STATUS1);
> + text
> + help = STRING_TOKEN(STR_BLOCKSID_STATUS_HELP),
> + text = STRING_TOKEN(STR_BLOCKSID_STATUS2);
> + text
> + help = STRING_TOKEN(STR_BLOCKSID_STATUS_HELP),
> + text = STRING_TOKEN(STR_BLOCKSID_STATUS3);
> + subtitle text = STRING_TOKEN(STR_NULL);
> + endif;
> +
> + oneof varid = OpalHiiConfig.EnableBlockSid,
> + questionid = 0x8004,
> + prompt = STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID),
> + help =
> STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_HELP),
> + flags = INTERACTIVE,
> + option text = STRING_TOKEN(STR_NONE), value = 0, flags = DEFAULT |
> MANUFACTURING | RESET_REQUIRED;
> + option text = STRING_TOKEN(STR_ENABLED), value = 1, flags =
> RESET_REQUIRED;
> + option text = STRING_TOKEN(STR_DISABLED), value = 2, flags =
> RESET_REQUIRED;
> + option text =
> STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_TRUE), value = 3, flags =
> RESET_REQUIRED;
> + option text =
> STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_FALSE), value = 4, flags =
> RESET_REQUIRED;
> + option text =
> STRING_TOKEN(STR_DISK_INFO_DISABLE_BLOCKSID_TRUE), value = 5, flags =
> RESET_REQUIRED;
> + option text =
> STRING_TOKEN(STR_DISK_INFO_DISABLE_BLOCKSID_FALSE), value = 6, flags =
> RESET_REQUIRED;
> + endoneof;
> +
> +
> +
> +endform; // MAIN MENU FORM
> +
> +//
> +///////////////// DISK INFO FORM /////////////////
> +//
> +form formid = FORMID_VALUE_DISK_INFO_FORM_MAIN,
> + title = STRING_TOKEN(STR_OPAL);
> +
> + suppressif TRUE;
> + numeric
> + name = SelectedDiskAvailableActions,
> + varid = OpalHiiConfig.SelectedDiskAvailableActions,
> + prompt = STRING_TOKEN(STR_NULL),
> + help = STRING_TOKEN(STR_NULL),
> + flags = INTERACTIVE,
> + key = 0x8003,
> + minimum = 0x0,
> + maximum = 0xFFFF,
> + endnumeric;
> + endif;
> +
> + suppressif TRUE;
> + checkbox varid = OpalHiiConfig.KeepUserDataForced,
> + prompt = STRING_TOKEN(STR_NULL),
> + help = STRING_TOKEN(STR_NULL),
> + endcheckbox;
> + endif;
> +
> + subtitle text = STRING_TOKEN(STR_MAIN_OPAL_VERSION);
> +
> + subtitle text = STRING_TOKEN(STR_NULL);
> +
> + text
> + help = STRING_TOKEN(STR_NULL),
> + text = STRING_TOKEN(STR_DISK_INFO_SELECTED_DISK_NAME);
> +
> + subtitle text = STRING_TOKEN(STR_NULL);
> +
> + subtitle text = STRING_TOKEN(STR_OPAL_REQUESTS_LBL);
> +
> + suppressif ( questionref(SelectedDiskAvailableActions) &
> HII_ACTION_SET_ADMIN_PWD ) == 0;
> + grayoutif ideqval OpalHiiConfig.OpalRequest.Revert == 1;
> + grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert == 1;
> + checkbox varid = OpalHiiConfig.OpalRequest.SetAdminPwd,
> + prompt =
> STRING_TOKEN(STR_DISK_INFO_SET_ADMIN_PSWD),
> + help =
> STRING_TOKEN(STR_DISK_INFO_SET_ADMIN_PSWD_HELP),
> + flags = INTERACTIVE | RESET_REQUIRED,
> + key = 0x8005,
> + endcheckbox;
> + endif;
> + endif;
> + endif;
> +
> + suppressif ( questionref(SelectedDiskAvailableActions) &
> HII_ACTION_SET_USER_PWD ) == 0;
> + grayoutif ideqval OpalHiiConfig.OpalRequest.DisableUser == 1;
> + grayoutif ideqval OpalHiiConfig.OpalRequest.Revert == 1;
> + grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert == 1;
> + checkbox varid = OpalHiiConfig.OpalRequest.SetUserPwd,
> + prompt = STRING_TOKEN(STR_DISK_INFO_SET_USER_PSWD),
> + help =
> STRING_TOKEN(STR_DISK_INFO_SET_USER_PSWD_HELP),
> + flags = INTERACTIVE | RESET_REQUIRED,
> + key = 0x8006,
> + endcheckbox;
> + endif;
> + endif;
> + endif;
> + endif;
> +
> + suppressif ( questionref(SelectedDiskAvailableActions) &
> HII_ACTION_SECURE_ERASE ) == 0;
> + grayoutif ideqval OpalHiiConfig.OpalRequest.Revert == 1;
> + grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert == 1;
> + checkbox varid = OpalHiiConfig.OpalRequest.SecureErase,
> + prompt = STRING_TOKEN(STR_DISK_INFO_SECURE_ERASE),
> + help =
> STRING_TOKEN(STR_DISK_INFO_SECURE_ERASE_HELP),
> + flags = INTERACTIVE | RESET_REQUIRED,
> + key = 0x8007,
> + endcheckbox;
> + endif;
> + endif;
> + endif;
> +
> + suppressif ( questionref(SelectedDiskAvailableActions) &
> HII_ACTION_REVERT ) == 0;
> + grayoutif ideqval OpalHiiConfig.OpalRequest.SetAdminPwd == 1;
> + grayoutif ideqval OpalHiiConfig.OpalRequest.SetUserPwd == 1;
> + grayoutif ideqval OpalHiiConfig.OpalRequest.SecureErase == 1;
> + grayoutif ideqval OpalHiiConfig.OpalRequest.DisableUser == 1;
> + grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert == 1;
> + checkbox varid = OpalHiiConfig.OpalRequest.Revert,
> + prompt = STRING_TOKEN(STR_DISK_INFO_REVERT),
> + help = STRING_TOKEN(STR_DISK_INFO_REVERT_HELP),
> + flags = INTERACTIVE | RESET_REQUIRED,
> + key = 0x8008,
> + endcheckbox;
> + endif;
> + endif;
> + endif;
> + endif;
> + endif;
> + endif;
> +
> + suppressif ideqval OpalHiiConfig.OpalRequest.Revert == 0;
> + grayoutif ideqval OpalHiiConfig.KeepUserDataForced == 1;
> + checkbox varid = OpalHiiConfig.OpalRequest.KeepUserData,
> + prompt =
> STRING_TOKEN(STR_KEEP_USER_DATA_PROMPT),
> + help = STRING_TOKEN(STR_KEEP_USER_DATA_HELP),
> + flags = INTERACTIVE | RESET_REQUIRED,
> + key = 0x8009,
> + endcheckbox;
> + endif;
> + endif;
> +
> + suppressif ( questionref(SelectedDiskAvailableActions) &
> HII_ACTION_PSID_REVERT ) == 0;
> + grayoutif ideqval OpalHiiConfig.OpalRequest.SetAdminPwd == 1;
> + grayoutif ideqval OpalHiiConfig.OpalRequest.SetUserPwd == 1;
> + grayoutif ideqval OpalHiiConfig.OpalRequest.SecureErase == 1;
> + grayoutif ideqval OpalHiiConfig.OpalRequest.DisableUser == 1;
> + grayoutif ideqval OpalHiiConfig.OpalRequest.EnableFeature == 1;
> + grayoutif ideqval OpalHiiConfig.OpalRequest.Revert == 1;
> + checkbox varid = OpalHiiConfig.OpalRequest.PsidRevert,
> + prompt = STRING_TOKEN(STR_DISK_INFO_PSID_REVERT),
> + help =
> STRING_TOKEN(STR_DISK_INFO_PSID_REVERT_HELP),
> + flags = INTERACTIVE | RESET_REQUIRED,
> + key = 0x800A,
> + endcheckbox;
> + endif;
> + endif;
> + endif;
> + endif;
> + endif;
> + endif;
> + endif;
> +
> + suppressif ( questionref(SelectedDiskAvailableActions) &
> HII_ACTION_DISABLE_USER ) == 0;
> + grayoutif ideqval OpalHiiConfig.OpalRequest.SetUserPwd == 1;
> + grayoutif ideqval OpalHiiConfig.OpalRequest.Revert == 1;
> + grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert == 1;
> + checkbox varid = OpalHiiConfig.OpalRequest.DisableUser,
> + prompt = STRING_TOKEN(STR_DISK_INFO_DISABLE_USER),
> + help =
> STRING_TOKEN(STR_DISK_INFO_DISABLE_USER_HELP),
> + flags = INTERACTIVE | RESET_REQUIRED,
> + key = 0x800B,
> + endcheckbox;
> + endif;
> + endif;
> + endif;
> + endif;
> +
> + suppressif ( questionref(SelectedDiskAvailableActions) &
> HII_ACTION_ENABLE_FEATURE ) == 0;
> + grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert == 1;
> + checkbox varid = OpalHiiConfig.OpalRequest.EnableFeature,
> + prompt = STRING_TOKEN(STR_DISK_INFO_ENABLE_FEATURE),
> + help =
> STRING_TOKEN(STR_DISK_INFO_ENABLE_FEATURE_HELP),
> + flags = INTERACTIVE | RESET_REQUIRED,
> + key = 0x800C,
> + endcheckbox;
> + endif;
> + endif;
> +
> +endform; // DISK INFO FORM
> +
> +endformset;
> diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.c
> b/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.c
> new file mode 100644
> index 000000000000..1788b2ad3339
> --- /dev/null
> +++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.c
> @@ -0,0 +1,940 @@
> +/** @file
> + Opal Password PEI driver which is used to unlock Opal Password for S3.
> +
> +Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution. The full text of the license may be found
> at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +
> +#include "OpalPasswordPei.h"
> +
> +EFI_GUID mOpalDeviceAtaGuid = OPAL_DEVICE_ATA_GUID;
> +EFI_GUID mOpalDeviceNvmeGuid = OPAL_DEVICE_NVME_GUID;
> +
> +#define OPAL_PCIE_ROOTPORT_SAVESIZE (0x40)
> +#define STORE_INVALID_ROOTPORT_INDEX ((UINT8) -1)
> +
> +/**
> + Get IOMMU PPI.
> +
> + @return Pointer to IOMMU PPI.
> +
> +**/
> +EDKII_IOMMU_PPI *
> +GetIoMmu (
> + VOID
> + )
> +{
> + EFI_STATUS Status;
> + EDKII_IOMMU_PPI *IoMmu;
> +
> + IoMmu = NULL;
> + Status = PeiServicesLocatePpi (
> + &gEdkiiIoMmuPpiGuid,
> + 0,
> + NULL,
> + (VOID **) &IoMmu
> + );
> + if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
> + return IoMmu;
> + }
> +
> + return NULL;
> +}
> +
> +/**
> + Allocates pages that are suitable for an OperationBusMasterCommonBuffer
> or
> + OperationBusMasterCommonBuffer64 mapping.
> +
> + @param Pages The number of pages to allocate.
> + @param HostAddress A pointer to store the base system
> memory address of the
> + allocated range.
> + @param DeviceAddress The resulting map address for the bus
> master PCI controller to use to
> + access the hosts HostAddress.
> + @param Mapping A resulting value to pass to Unmap().
> +
> + @retval EFI_SUCCESS The requested memory pages were
> allocated.
> + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal
> attribute bits are
> + MEMORY_WRITE_COMBINE and
> MEMORY_CACHED.
> + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> + @retval EFI_OUT_OF_RESOURCES The memory pages could not be
> allocated.
> +
> +**/
> +EFI_STATUS
> +IoMmuAllocateBuffer (
> + IN UINTN Pages,
> + OUT VOID **HostAddress,
> + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
> + OUT VOID **Mapping
> + )
> +{
> + EFI_STATUS Status;
> + UINTN NumberOfBytes;
> + EFI_PHYSICAL_ADDRESS HostPhyAddress;
> + EDKII_IOMMU_PPI *IoMmu;
> +
> + *HostAddress = NULL;
> + *DeviceAddress = 0;
> + *Mapping = NULL;
> +
> + IoMmu = GetIoMmu ();
> +
> + if (IoMmu != NULL) {
> + Status = IoMmu->AllocateBuffer (
> + IoMmu,
> + EfiBootServicesData,
> + Pages,
> + HostAddress,
> + 0
> + );
> + if (EFI_ERROR (Status)) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + NumberOfBytes = EFI_PAGES_TO_SIZE (Pages);
> + Status = IoMmu->Map (
> + IoMmu,
> + EdkiiIoMmuOperationBusMasterCommonBuffer,
> + *HostAddress,
> + &NumberOfBytes,
> + DeviceAddress,
> + Mapping
> + );
> + if (EFI_ERROR (Status)) {
> + IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
> + *HostAddress = NULL;
> + return EFI_OUT_OF_RESOURCES;
> + }
> + Status = IoMmu->SetAttribute (
> + IoMmu,
> + *Mapping,
> + EDKII_IOMMU_ACCESS_READ |
> EDKII_IOMMU_ACCESS_WRITE
> + );
> + if (EFI_ERROR (Status)) {
> + IoMmu->Unmap (IoMmu, *Mapping);
> + IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
> + *Mapping = NULL;
> + *HostAddress = NULL;
> + return Status;
> + }
> + } else {
> + Status = PeiServicesAllocatePages (
> + EfiBootServicesData,
> + Pages,
> + &HostPhyAddress
> + );
> + if (EFI_ERROR (Status)) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> + *HostAddress = (VOID *) (UINTN) HostPhyAddress;
> + *DeviceAddress = HostPhyAddress;
> + *Mapping = NULL;
> + }
> + return Status;
> +}
> +
> +/**
> + Frees memory that was allocated with AllocateBuffer().
> +
> + @param Pages The number of pages to free.
> + @param HostAddress The base system memory address of the
> allocated range.
> + @param Mapping The mapping value returned from Map().
> +
> +**/
> +VOID
> +IoMmuFreeBuffer (
> + IN UINTN Pages,
> + IN VOID *HostAddress,
> + IN VOID *Mapping
> + )
> +{
> + EDKII_IOMMU_PPI *IoMmu;
> +
> + IoMmu = GetIoMmu ();
> +
> + if (IoMmu != NULL) {
> + IoMmu->SetAttribute (IoMmu, Mapping, 0);
> + IoMmu->Unmap (IoMmu, Mapping);
> + IoMmu->FreeBuffer (IoMmu, Pages, HostAddress);
> + } else {
> + PeiServicesFreePages (
> + (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress,
> + Pages
> + );
> + }
> +}
> +
> +/**
> + Provide IO action support.
> +
> + @param[in] PeiDev The opal device need to perform
> trusted IO.
> + @param[in] IoType OPAL_IO_TYPE indicating whether to
> perform a Trusted Send or Trusted Receive.
> + @param[in] SecurityProtocol Security Protocol
> + @param[in] SpSpecific Security Protocol Specific
> + @param[in] TransferLength Transfer Length of Buffer (in bytes) -
> always a multiple of 512
> + @param[in] Buffer Address of Data to transfer
> +
> + @retval EFI_SUCCESS Perform the IO action success.
> + @retval Others Perform the IO action failed.
> +
> +**/
> +EFI_STATUS
> +PerformTrustedIo (
> + OPAL_PEI_DEVICE *PeiDev,
> + OPAL_IO_TYPE IoType,
> + UINT8 SecurityProtocol,
> + UINT16 SpSpecific,
> + UINTN TransferLength,
> + VOID *Buffer
> + )
> +{
> + EFI_STATUS Status;
> + UINTN BufferSizeBlocks;
> + EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
> + OPAL_DEVICE_ATA *DevInfoAta;
> + AHCI_CONTEXT *AhciContext;
> + NVME_CONTEXT *NvmeContext;
> +
> + Status = EFI_DEVICE_ERROR;
> + if (PeiDev->DeviceType == OPAL_DEVICE_TYPE_ATA) {
> + DevInfoAta = (OPAL_DEVICE_ATA *) PeiDev->Device;
> + AhciContext = (AHCI_CONTEXT *) PeiDev->Context;
> +
> + BufferSizeBlocks = TransferLength / 512;
> +
> + ZeroMem( &AtaCommandBlock, sizeof( EFI_ATA_COMMAND_BLOCK ) );
> + AtaCommandBlock.AtaCommand = ( IoType == OpalSend ) ?
> ATA_COMMAND_TRUSTED_SEND : ATA_COMMAND_TRUSTED_RECEIVE;
> + AtaCommandBlock.AtaSectorCount = ( UINT8 )BufferSizeBlocks;
> + AtaCommandBlock.AtaSectorNumber = ( UINT8 )( BufferSizeBlocks >> 8 );
> + AtaCommandBlock.AtaFeatures = SecurityProtocol;
> + AtaCommandBlock.AtaCylinderLow = ( UINT8 )( SpSpecific >> 8 );
> + AtaCommandBlock.AtaCylinderHigh = ( UINT8 )( SpSpecific );
> + AtaCommandBlock.AtaDeviceHead = ATA_DEVICE_LBA;
> +
> +
> + ZeroMem( AhciContext->Buffer, HDD_PAYLOAD );
> + ASSERT( TransferLength <= HDD_PAYLOAD );
> +
> + if (IoType == OpalSend) {
> + CopyMem( AhciContext->Buffer, Buffer, TransferLength );
> + }
> +
> + Status = AhciPioTransfer(
> + AhciContext,
> + (UINT8) DevInfoAta->Port,
> + (UINT8) DevInfoAta->PortMultiplierPort,
> + NULL,
> + 0,
> + ( IoType == OpalSend ) ? FALSE : TRUE, // i/o direction
> + &AtaCommandBlock,
> + NULL,
> + AhciContext->Buffer,
> + (UINT32)TransferLength,
> + ATA_TIMEOUT
> + );
> +
> + if (IoType == OpalRecv) {
> + CopyMem( Buffer, AhciContext->Buffer, TransferLength );
> + }
> + } else if (PeiDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
> + NvmeContext = (NVME_CONTEXT *) PeiDev->Context;
> + Status = NvmeSecuritySendReceive (
> + NvmeContext,
> + IoType == OpalSend,
> + SecurityProtocol,
> + SwapBytes16(SpSpecific),
> + TransferLength,
> + Buffer
> + );
> + } else {
> + DEBUG((DEBUG_ERROR, "DeviceType(%x) not support.\n",
> PeiDev->DeviceType));
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Send a security protocol command to a device that receives data and/or the
> result
> + of one or more commands sent by SendData.
> +
> + The ReceiveData function sends a security protocol command to the given
> MediaId.
> + The security protocol command sent is defined by SecurityProtocolId and
> contains
> + the security protocol specific data SecurityProtocolSpecificData. The function
> + returns the data from the security protocol command in PayloadBuffer.
> +
> + For devices supporting the SCSI command set, the security protocol
> command is sent
> + using the SECURITY PROTOCOL IN command defined in SPC-4.
> +
> + For devices supporting the ATA command set, the security protocol
> command is sent
> + using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if
> PayloadBufferSize
> + is non-zero.
> +
> + If the PayloadBufferSize is zero, the security protocol command is sent using
> the
> + Trusted Non-Data command defined in ATA8-ACS.
> +
> + If PayloadBufferSize is too small to store the available data from the security
> + protocol command, the function shall copy PayloadBufferSize bytes into the
> + PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
> +
> + If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is
> non-zero,
> + the function shall return EFI_INVALID_PARAMETER.
> +
> + If the given MediaId does not support security protocol commands, the
> function shall
> + return EFI_UNSUPPORTED. If there is no media in the device, the function
> returns
> + EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
> device,
> + the function returns EFI_MEDIA_CHANGED.
> +
> + If the security protocol fails to complete within the Timeout period, the
> function
> + shall return EFI_TIMEOUT.
> +
> + If the security protocol command completes without an error, the function
> shall
> + return EFI_SUCCESS. If the security protocol command completes with an
> error, the
> + function shall return EFI_DEVICE_ERROR.
> +
> + @param This Indicates a pointer to the calling
> context.
> + @param MediaId ID of the medium to receive
> data from.
> + @param Timeout The timeout, in 100ns units, to
> use for the execution
> + of the security protocol
> command. A Timeout value of 0
> + means that this function will wait
> indefinitely for the
> + security protocol command to
> execute. If Timeout is greater
> + than zero, then this function will
> return EFI_TIMEOUT
> + if the time required to execute
> the receive data command
> + is greater than Timeout.
> + @param SecurityProtocolId The value of the "Security
> Protocol" parameter of
> + the security protocol command
> to be sent.
> + @param SecurityProtocolSpecificData The value of the "Security Protocol
> Specific" parameter
> + of the security protocol
> command to be sent.
> + @param PayloadBufferSize Size in bytes of the payload data
> buffer.
> + @param PayloadBuffer A pointer to a destination buffer
> to store the security
> + protocol command specific
> payload data for the security
> + protocol command. The caller is
> responsible for having
> + either implicit or explicit
> ownership of the buffer.
> + @param PayloadTransferSize A pointer to a buffer to store the
> size in bytes of the
> + data written to the payload data
> buffer.
> +
> + @retval EFI_SUCCESS The security protocol command
> completed successfully.
> + @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was
> too small to store the available
> + data from the device. The
> PayloadBuffer contains the truncated data.
> + @retval EFI_UNSUPPORTED The given MediaId does not
> support security protocol commands.
> + @retval EFI_DEVICE_ERROR The security protocol command
> completed with an error.
> + @retval EFI_NO_MEDIA There is no media in the device.
> + @retval EFI_MEDIA_CHANGED The MediaId is not for the
> current media.
> + @retval EFI_INVALID_PARAMETER The PayloadBuffer or
> PayloadTransferSize is NULL and
> + PayloadBufferSize is non-zero.
> + @retval EFI_TIMEOUT A timeout occurred while waiting
> for the security
> + protocol command to execute.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SecurityReceiveData (
> + IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
> + IN UINT32 MediaId,
> + IN UINT64 Timeout,
> + IN UINT8 SecurityProtocolId,
> + IN UINT16
> SecurityProtocolSpecificData,
> + IN UINTN PayloadBufferSize,
> + OUT VOID *PayloadBuffer,
> + OUT UINTN *PayloadTransferSize
> + )
> +{
> + OPAL_PEI_DEVICE *PeiDev;
> +
> + PeiDev = OPAL_PEI_DEVICE_FROM_THIS (This);
> + if (PeiDev == NULL) {
> + return EFI_DEVICE_ERROR;
> + }
> +
> + return PerformTrustedIo (
> + PeiDev,
> + OpalRecv,
> + SecurityProtocolId,
> + SecurityProtocolSpecificData,
> + PayloadBufferSize,
> + PayloadBuffer
> + );
> +}
> +
> +/**
> + Send a security protocol command to a device.
> +
> + The SendData function sends a security protocol command containing the
> payload
> + PayloadBuffer to the given MediaId. The security protocol command sent is
> + defined by SecurityProtocolId and contains the security protocol specific data
> + SecurityProtocolSpecificData. If the underlying protocol command requires a
> + specific padding for the command payload, the SendData function shall add
> padding
> + bytes to the command payload to satisfy the padding requirements.
> +
> + For devices supporting the SCSI command set, the security protocol
> command is sent
> + using the SECURITY PROTOCOL OUT command defined in SPC-4.
> +
> + For devices supporting the ATA command set, the security protocol
> command is sent
> + using one of the TRUSTED SEND commands defined in ATA8-ACS if
> PayloadBufferSize
> + is non-zero. If the PayloadBufferSize is zero, the security protocol command
> is
> + sent using the Trusted Non-Data command defined in ATA8-ACS.
> +
> + If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
> + return EFI_INVALID_PARAMETER.
> +
> + If the given MediaId does not support security protocol commands, the
> function
> + shall return EFI_UNSUPPORTED. If there is no media in the device, the
> function
> + returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in
> the
> + device, the function returns EFI_MEDIA_CHANGED.
> +
> + If the security protocol fails to complete within the Timeout period, the
> function
> + shall return EFI_TIMEOUT.
> +
> + If the security protocol command completes without an error, the function
> shall return
> + EFI_SUCCESS. If the security protocol command completes with an error, the
> function
> + shall return EFI_DEVICE_ERROR.
> +
> + @param This Indicates a pointer to the calling
> context.
> + @param MediaId ID of the medium to receive
> data from.
> + @param Timeout The timeout, in 100ns units, to
> use for the execution
> + of the security protocol
> command. A Timeout value of 0
> + means that this function will wait
> indefinitely for the
> + security protocol command to
> execute. If Timeout is greater
> + than zero, then this function will
> return EFI_TIMEOUT
> + if the time required to execute
> the send data command
> + is greater than Timeout.
> + @param SecurityProtocolId The value of the "Security
> Protocol" parameter of
> + the security protocol command
> to be sent.
> + @param SecurityProtocolSpecificData The value of the "Security Protocol
> Specific" parameter
> + of the security protocol
> command to be sent.
> + @param PayloadBufferSize Size in bytes of the payload data
> buffer.
> + @param PayloadBuffer A pointer to a destination buffer
> to store the security
> + protocol command specific
> payload data for the security
> + protocol command.
> +
> + @retval EFI_SUCCESS The security protocol command
> completed successfully.
> + @retval EFI_UNSUPPORTED The given MediaId does not
> support security protocol commands.
> + @retval EFI_DEVICE_ERROR The security protocol command
> completed with an error.
> + @retval EFI_NO_MEDIA There is no media in the device.
> + @retval EFI_MEDIA_CHANGED The MediaId is not for the
> current media.
> + @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and
> PayloadBufferSize is non-zero.
> + @retval EFI_TIMEOUT A timeout occurred while waiting
> for the security
> + protocol command to execute.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SecuritySendData (
> + IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
> + IN UINT32 MediaId,
> + IN UINT64 Timeout,
> + IN UINT8 SecurityProtocolId,
> + IN UINT16
> SecurityProtocolSpecificData,
> + IN UINTN PayloadBufferSize,
> + IN VOID *PayloadBuffer
> + )
> +{
> + OPAL_PEI_DEVICE *PeiDev;
> +
> + PeiDev = OPAL_PEI_DEVICE_FROM_THIS (This);
> + if (PeiDev == NULL) {
> + return EFI_DEVICE_ERROR;
> + }
> +
> + return PerformTrustedIo (
> + PeiDev,
> + OpalSend,
> + SecurityProtocolId,
> + SecurityProtocolSpecificData,
> + PayloadBufferSize,
> + PayloadBuffer
> + );
> +
> +}
> +
> +/**
> + Save/Restore RootPort configuration space.
> +
> + @param[in] DevInfoNvme Pointer to NVMe device info.
> + @param[in] SaveAction TRUE: Save, FALSE: Restore
> + @param[in,out] PcieConfBufferList Configuration space data buffer for
> save/restore
> +
> + @return PCIE base address of this RootPort
> +**/
> +UINTN
> +SaveRestoreRootportConfSpace (
> + IN OPAL_DEVICE_NVME *DevInfoNvme,
> + IN BOOLEAN SaveAction,
> + IN OUT UINT8 **PcieConfBufferList
> + )
> +{
> + UINTN RpBase;
> + UINTN Length;
> + OPAL_PCI_DEVICE *DevNode;
> + UINT8 *StorePcieConfData;
> + UINTN Index;
> +
> + Length = 0;
> + Index = 0;
> + RpBase = 0;
> +
> + while (sizeof (OPAL_DEVICE_NVME) + Length < DevInfoNvme->Length) {
> + DevNode = (OPAL_PCI_DEVICE *)((UINT8*)DevInfoNvme->PciBridgeNode
> + Length);
> + RpBase = PCI_LIB_ADDRESS (DevNode->Bus, DevNode->Device,
> DevNode->Function, 0x0);
> +
> + if (PcieConfBufferList != NULL) {
> + if (SaveAction) {
> + StorePcieConfData = (UINT8 *) AllocateZeroPool
> (OPAL_PCIE_ROOTPORT_SAVESIZE);
> + ASSERT (StorePcieConfData != NULL);
> + OpalPciRead (StorePcieConfData, RpBase,
> OPAL_PCIE_ROOTPORT_SAVESIZE);
> + PcieConfBufferList[Index] = StorePcieConfData;
> + } else {
> + // Skip PCIe Command & Status registers
> + StorePcieConfData = PcieConfBufferList[Index];
> + OpalPciWrite (RpBase, StorePcieConfData, 4);
> + OpalPciWrite (RpBase + 8, StorePcieConfData + 8,
> OPAL_PCIE_ROOTPORT_SAVESIZE - 8);
> +
> + FreePool (StorePcieConfData);
> + }
> + }
> +
> + Length += sizeof (OPAL_PCI_DEVICE);
> + Index ++;
> + }
> +
> + return RpBase;
> +}
> +
> +/**
> + Configure RootPort for downstream PCIe NAND devices.
> +
> + @param[in] RpBase - PCIe configuration space address of this
> RootPort
> + @param[in] BusNumber - Bus number
> + @param[in] MemoryBase - Memory base address
> + @param[in] MemoryLength - Memory size
> +
> +**/
> +VOID
> +ConfigureRootPortForPcieNand (
> + IN UINTN RpBase,
> + IN UINTN BusNumber,
> + IN UINT32 MemoryBase,
> + IN UINT32 MemoryLength
> + )
> +{
> + UINT32 MemoryLimit;
> +
> + DEBUG ((DEBUG_INFO, "ConfigureRootPortForPcieNand, BusNumber: %x,
> MemoryBase: %x, MemoryLength: %x\n",
> + BusNumber, MemoryBase, MemoryLength));
> +
> + if (MemoryLength == 0) {
> + MemoryLimit = MemoryBase;
> + } else {
> + MemoryLimit = MemoryBase + MemoryLength + 0xFFFFF; // 1M
> + }
> +
> + ///
> + /// Configue PCIE configuration space for RootPort
> + ///
> + PciWrite8 (RpBase + NVME_PCIE_BNUM + 1, (UINT8) BusNumber);
> // Secondary Bus Number registers
> + PciWrite8 (RpBase + NVME_PCIE_BNUM + 2, (UINT8) BusNumber);
> // Subordinate Bus Number registers
> + PciWrite8 (RpBase + NVME_PCIE_IOBL, 0xFF);
> // I/O Base registers
> + PciWrite8 (RpBase + NVME_PCIE_IOBL + 1, 0x00);
> // I/O Limit registers
> + PciWrite16 (RpBase + NVME_PCIE_MBL, (UINT16) RShiftU64
> ((UINTN)MemoryBase, 16)); // Memory Base register
> + PciWrite16 (RpBase + NVME_PCIE_MBL + 2, (UINT16) RShiftU64
> ((UINTN)MemoryLimit, 16)); // Memory Limit register
> + PciWrite16 (RpBase + NVME_PCIE_PMBL, 0xFFFF);
> // Prefetchable Memory Base registers
> + PciWrite16 (RpBase + NVME_PCIE_PMBL + 2, 0x0000);
> // Prefetchable Memory Limit registers
> + PciWrite32 (RpBase + NVME_PCIE_PMBU32, 0xFFFFFFFF);
> // Prefetchable Memory Upper Base registers
> + PciWrite32 (RpBase + NVME_PCIE_PMLU32, 0x00000000);
> // Prefetchable Memory Upper Limit registers
> +}
> +
> +/**
> +
> + The function returns whether or not the device is Opal Locked.
> + TRUE means that the device is partially or fully locked.
> + This will perform a Level 0 Discovery and parse the locking feature descriptor
> +
> + @param[in] OpalDev Opal object to determine if
> locked.
> + @param[out] BlockSidSupported Whether device support BlockSid
> feature.
> +
> +**/
> +BOOLEAN
> +IsOpalDeviceLocked(
> + OPAL_PEI_DEVICE *OpalDev,
> + BOOLEAN *BlockSidSupported
> + )
> +{
> + OPAL_SESSION Session;
> + OPAL_DISK_SUPPORT_ATTRIBUTE SupportedAttributes;
> + TCG_LOCKING_FEATURE_DESCRIPTOR LockingFeature;
> + UINT16 OpalBaseComId;
> + TCG_RESULT Ret;
> +
> + Session.Sscp = &OpalDev->Sscp;
> + Session.MediaId = 0;
> +
> + Ret = OpalGetSupportedAttributesInfo (&Session, &SupportedAttributes,
> &OpalBaseComId);
> + if (Ret != TcgResultSuccess) {
> + return FALSE;
> + }
> +
> + Session.OpalBaseComId = OpalBaseComId;
> + *BlockSidSupported = SupportedAttributes.BlockSid == 1 ? TRUE :
> FALSE;
> +
> + Ret = OpalGetLockingInfo(&Session, &LockingFeature);
> + if (Ret != TcgResultSuccess) {
> + return FALSE;
> + }
> +
> + return OpalDeviceLocked (&SupportedAttributes, &LockingFeature);
> +}
> +
> +/**
> + Unlock OPAL password for S3.
> +
> + @param[in] OpalDev Opal object to unlock.
> +
> +**/
> +VOID
> +UnlockOpalPassword (
> + IN OPAL_PEI_DEVICE *OpalDev
> + )
> +{
> + TCG_RESULT Result;
> + OPAL_SESSION Session;
> + BOOLEAN BlockSidSupport;
> + UINT32 PpStorageFlags;
> + BOOLEAN BlockSIDEnabled;
> +
> + BlockSidSupport = FALSE;
> + if (IsOpalDeviceLocked (OpalDev, &BlockSidSupport)) {
> + ZeroMem(&Session, sizeof (Session));
> + Session.Sscp = &OpalDev->Sscp;
> + Session.MediaId = 0;
> + Session.OpalBaseComId = OpalDev->Device->OpalBaseComId;
> +
> + Result = OpalUtilUpdateGlobalLockingRange (
> + &Session,
> + OpalDev->Device->Password,
> + OpalDev->Device->PasswordLength,
> + FALSE,
> + FALSE
> + );
> + DEBUG ((
> + DEBUG_INFO,
> + "%a() OpalUtilUpdateGlobalLockingRange() Result = 0x%x\n",
> + __FUNCTION__,
> + Result
> + ));
> + }
> +
> + PpStorageFlags = Tcg2PhysicalPresenceLibGetManagementFlags ();
> + if ((PpStorageFlags &
> TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID) != 0) {
> + BlockSIDEnabled = TRUE;
> + } else {
> + BlockSIDEnabled = FALSE;
> + }
> + if (BlockSIDEnabled && BlockSidSupport) {
> + Result = OpalBlockSid (&Session, TRUE);
> + DEBUG ((
> + DEBUG_INFO,
> + "%a() OpalBlockSid() Result = 0x%x\n",
> + __FUNCTION__,
> + Result
> + ));
> + }
> +}
> +
> +/**
> + Unlock ATA OPAL password for S3.
> +
> +**/
> +VOID
> +UnlockOpalPasswordAta (
> + VOID
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 *DevInfo;
> + OPAL_DEVICE_ATA TempDevInfoAta;
> + OPAL_DEVICE_ATA *DevInfoAta;
> + UINTN DevInfoLengthAta;
> + UINT8 Bus;
> + UINT8 Device;
> + UINT8 Function;
> + OPAL_PEI_DEVICE OpalDev;
> + UINT8 BaseClassCode;
> + UINT8 SubClassCode;
> + UINT8 SataCmdSt;
> + AHCI_CONTEXT AhciContext;
> + UINT32 AhciBar;
> +
> + DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));
> +
> + //
> + // Get ATA OPAL device info from LockBox.
> + //
> + DevInfo = (UINT8 *) &TempDevInfoAta;
> + DevInfoLengthAta = sizeof (OPAL_DEVICE_ATA);
> + Status = RestoreLockBox (&mOpalDeviceAtaGuid, DevInfo,
> &DevInfoLengthAta);
> + if (Status == EFI_BUFFER_TOO_SMALL) {
> + DevInfo = AllocatePages (EFI_SIZE_TO_PAGES (DevInfoLengthAta));
> + if (DevInfo != NULL) {
> + Status = RestoreLockBox (&mOpalDeviceAtaGuid, DevInfo,
> &DevInfoLengthAta);
> + }
> + }
> + if (EFI_ERROR (Status) || (DevInfo == NULL)) {
> + return;
> + }
> +
> + for (DevInfoAta = (OPAL_DEVICE_ATA *) DevInfo;
> + (UINTN) DevInfoAta < ((UINTN) DevInfo + DevInfoLengthAta);
> + DevInfoAta = (OPAL_DEVICE_ATA *) ((UINTN) DevInfoAta +
> DevInfoAta->Length)) {
> + Bus = DevInfoAta->Device.Bus;
> + Device = DevInfoAta->Device.Device;
> + Function = DevInfoAta->Device.Function;
> +
> + SataCmdSt = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function,
> PCI_COMMAND_OFFSET));
> + PciWrite8 (PCI_LIB_ADDRESS (Bus, Device, Function,
> PCI_COMMAND_OFFSET), 0x6);
> +
> + BaseClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function,
> 0x0B));
> + SubClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function,
> 0x0A));
> + if ((BaseClassCode != PCI_CLASS_MASS_STORAGE) ||
> + ((SubClassCode != PCI_CLASS_MASS_STORAGE_SATADPA) &&
> (SubClassCode != PCI_CLASS_MASS_STORAGE_RAID))) {
> + DEBUG ((DEBUG_ERROR, "%a() ClassCode/SubClassCode are not
> supported\n", __FUNCTION__));
> + } else {
> + AhciBar = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24));
> + PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24),
> DevInfoAta->BarAddr);
> +
> + ZeroMem (&AhciContext, sizeof (AHCI_CONTEXT));
> + AhciContext.AhciBar = DevInfoAta->BarAddr;
> + AhciAllocateResource (&AhciContext);
> + Status = AhciModeInitialize (&AhciContext, (UINT8)DevInfoAta->Port);
> + ASSERT_EFI_ERROR (Status);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a() AhciModeInitialize() error,
> Status: %r\n", __FUNCTION__, Status));
> + }
> +
> + OpalDev.Signature = OPAL_PEI_DEVICE_SIGNATURE;
> + OpalDev.Sscp.ReceiveData = SecurityReceiveData;
> + OpalDev.Sscp.SendData = SecuritySendData;
> + OpalDev.DeviceType = OPAL_DEVICE_TYPE_ATA;
> + OpalDev.Device = (OPAL_DEVICE_COMMON *) DevInfoAta;
> + OpalDev.Context = &AhciContext;
> +
> + UnlockOpalPassword (&OpalDev);
> +
> + AhciFreeResource (&AhciContext);
> + PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24), AhciBar);
> + }
> + PciWrite8 (PCI_LIB_ADDRESS (Bus, Device, Function,
> PCI_COMMAND_OFFSET), SataCmdSt);
> + }
> +
> + ZeroMem (DevInfo, DevInfoLengthAta);
> + if ((UINTN) DevInfo != (UINTN) &TempDevInfoAta) {
> + FreePages (DevInfo, EFI_SIZE_TO_PAGES (DevInfoLengthAta));
> + }
> +
> + DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));
> +}
> +
> +/**
> + Unlock NVMe OPAL password for S3.
> +
> +**/
> +VOID
> +UnlockOpalPasswordNvme (
> + VOID
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 *DevInfo;
> + OPAL_DEVICE_NVME TempDevInfoNvme;
> + OPAL_DEVICE_NVME *DevInfoNvme;
> + UINTN DevInfoLengthNvme;
> + UINT8 Bus;
> + UINT8 Device;
> + UINT8 Function;
> + OPAL_PEI_DEVICE OpalDev;
> + UINT8 BaseClassCode;
> + UINT8 SubClassCode;
> + UINT8 ProgInt;
> + UINT8 NvmeCmdSt;
> + UINT8 *StorePcieConfDataList[16];
> + UINTN RpBase;
> + UINTN MemoryBase;
> + UINTN MemoryLength;
> + NVME_CONTEXT NvmeContext;
> +
> + DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));
> +
> + //
> + // Get NVMe OPAL device info from LockBox.
> + //
> + DevInfo = (UINT8 *) &TempDevInfoNvme;
> + DevInfoLengthNvme = sizeof (OPAL_DEVICE_NVME);
> + Status = RestoreLockBox (&mOpalDeviceNvmeGuid, DevInfo,
> &DevInfoLengthNvme);
> + if (Status == EFI_BUFFER_TOO_SMALL) {
> + DevInfo = AllocatePages (EFI_SIZE_TO_PAGES (DevInfoLengthNvme));
> + if (DevInfo != NULL) {
> + Status = RestoreLockBox (&mOpalDeviceNvmeGuid, DevInfo,
> &DevInfoLengthNvme);
> + }
> + }
> + if (EFI_ERROR (Status) || (DevInfo == NULL)) {
> + return;
> + }
> +
> + for (DevInfoNvme = (OPAL_DEVICE_NVME *) DevInfo;
> + (UINTN) DevInfoNvme < ((UINTN) DevInfo + DevInfoLengthNvme);
> + DevInfoNvme = (OPAL_DEVICE_NVME *) ((UINTN) DevInfoNvme +
> DevInfoNvme->Length)) {
> + Bus = DevInfoNvme->Device.Bus;
> + Device = DevInfoNvme->Device.Device;
> + Function = DevInfoNvme->Device.Function;
> +
> + RpBase = 0;
> + NvmeCmdSt = 0;
> +
> + ///
> + /// Save original RootPort configuration space to heap
> + ///
> + RpBase = SaveRestoreRootportConfSpace (
> + DevInfoNvme,
> + TRUE, // save
> + StorePcieConfDataList
> + );
> + MemoryBase = DevInfoNvme->BarAddr;
> + MemoryLength = 0;
> + ConfigureRootPortForPcieNand (RpBase, Bus, (UINT32) MemoryBase,
> (UINT32) MemoryLength);
> +
> + ///
> + /// Enable PCIE decode for RootPort
> + ///
> + NvmeCmdSt = PciRead8 (RpBase + NVME_PCIE_PCICMD);
> + PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0x6);
> +
> + BaseClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function,
> 0x0B));
> + SubClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function,
> 0x0A));
> + ProgInt = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function,
> 0x09));
> + if ((BaseClassCode != PCI_CLASS_MASS_STORAGE) ||
> + (SubClassCode != PCI_CLASS_MASS_STORAGE_NVM) ||
> + (ProgInt != PCI_IF_NVMHCI)) {
> + DEBUG ((DEBUG_ERROR, "%a() ClassCode/SubClassCode/PI are not
> supported\n", __FUNCTION__));
> + } else {
> + ZeroMem (&NvmeContext, sizeof (NVME_CONTEXT));
> + NvmeContext.Nbar = DevInfoNvme->BarAddr;
> + NvmeContext.PciBase = PCI_LIB_ADDRESS (Bus, Device, Function, 0x0);
> + NvmeContext.NvmeInitWaitTime = 0;
> + NvmeContext.Nsid = DevInfoNvme->NvmeNamespaceId;
> + NvmeAllocateResource (&NvmeContext);
> + Status = NvmeControllerInit (&NvmeContext);
> +
> + OpalDev.Signature = OPAL_PEI_DEVICE_SIGNATURE;
> + OpalDev.Sscp.ReceiveData = SecurityReceiveData;
> + OpalDev.Sscp.SendData = SecuritySendData;
> + OpalDev.DeviceType = OPAL_DEVICE_TYPE_NVME;
> + OpalDev.Device = (OPAL_DEVICE_COMMON *) DevInfoNvme;
> + OpalDev.Context = &NvmeContext;
> +
> + UnlockOpalPassword (&OpalDev);
> +
> + Status = NvmeControllerExit (&NvmeContext);
> + NvmeFreeResource (&NvmeContext);
> + }
> +
> + ASSERT (RpBase != 0);
> + PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0);
> + RpBase = SaveRestoreRootportConfSpace (
> + DevInfoNvme,
> + FALSE, // restore
> + StorePcieConfDataList
> + );
> + PciWrite8 (RpBase + NVME_PCIE_PCICMD, NvmeCmdSt);
> + }
> +
> + ZeroMem (DevInfo, DevInfoLengthNvme);
> + if ((UINTN) DevInfo != (UINTN) &TempDevInfoNvme) {
> + FreePages (DevInfo, EFI_SIZE_TO_PAGES (DevInfoLengthNvme));
> + }
> +
> + DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));
> +}
> +
> +/**
> + Unlock OPAL password for S3.
> +
> +**/
> +VOID
> +OpalPasswordS3 (
> + VOID
> + )
> +{
> + UnlockOpalPasswordAta ();
> + UnlockOpalPasswordNvme ();
> +}
> +
> +/**
> + Entry point of the notification callback function itself within the PEIM.
> + It is to unlock OPAL password for S3.
> +
> + @param PeiServices Indirect reference to the PEI Services Table.
> + @param NotifyDescriptor Address of the notification descriptor data
> structure.
> + @param Ppi Address of the PPI that was installed.
> +
> + @return Status of the notification.
> + The status code returned from this function is ignored.
> +**/
> +EFI_STATUS
> +EFIAPI
> +OpalPasswordEndOfPeiNotify(
> + IN EFI_PEI_SERVICES **PeiServices,
> + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
> + IN VOID *Ppi
> + )
> +{
> + EFI_STATUS Status;
> + EFI_BOOT_MODE BootMode;
> +
> + Status = PeiServicesGetBootMode (&BootMode);
> + ASSERT_EFI_ERROR (Status);
> + if (BootMode != BOOT_ON_S3_RESUME) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + DEBUG ((DEBUG_INFO, "%a() - enter at S3 resume\n", __FUNCTION__));
> +
> + OpalPasswordS3 ();
> +
> + DEBUG ((DEBUG_INFO, "%a() - exit at S3 resume\n", __FUNCTION__));
> +
> + return EFI_SUCCESS;
> +}
> +
> +EFI_PEI_NOTIFY_DESCRIPTOR mOpalPasswordEndOfPeiNotifyDesc = {
> + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |
> EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
> + &gEfiEndOfPeiSignalPpiGuid,
> + OpalPasswordEndOfPeiNotify
> +};
> +
> +/**
> + Main entry for this module.
> +
> + @param FileHandle Handle of the file being invoked.
> + @param PeiServices Pointer to PEI Services table.
> +
> + @return Status from PeiServicesNotifyPpi.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +OpalPasswordPeiInit (
> + IN EFI_PEI_FILE_HANDLE FileHandle,
> + IN CONST EFI_PEI_SERVICES **PeiServices
> + )
> +{
> + EFI_STATUS Status;
> +
> + Status = PeiServicesNotifyPpi (&mOpalPasswordEndOfPeiNotifyDesc);
> + ASSERT_EFI_ERROR (Status);
> + return Status;
> +}
> +
> diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.h
> b/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.h
> new file mode 100644
> index 000000000000..31aab37f5d91
> --- /dev/null
> +++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.h
> @@ -0,0 +1,133 @@
> +/** @file
> + Opal Password PEI driver which is used to unlock Opal Password for S3.
> +
> +Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution. The full text of the license may be found
> at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +
> +#ifndef _OPAL_PASSWORD_PEI_H_
> +#define _OPAL_PASSWORD_PEI_H_
> +
> +#include <PiPei.h>
> +#include <IndustryStandard/Atapi.h>
> +#include <IndustryStandard/Pci.h>
> +
> +#include <Library/DebugLib.h>
> +#include <Library/IoLib.h>
> +#include <Library/PciLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/PeimEntryPoint.h>
> +#include <Library/PeiServicesLib.h>
> +#include <Library/HobLib.h>
> +#include <Library/TimerLib.h>
> +#include <Library/LockBoxLib.h>
> +#include <Library/TcgStorageOpalLib.h>
> +#include <Library/Tcg2PhysicalPresenceLib.h>
> +
> +#include <Protocol/StorageSecurityCommand.h>
> +
> +#include <Ppi/IoMmu.h>
> +
> +#include "OpalPasswordCommon.h"
> +#include "OpalAhciMode.h"
> +#include "OpalNvmeMode.h"
> +
> +//
> +// Time out Value for ATA pass through protocol
> +//
> +#define ATA_TIMEOUT 30000000
> +
> +//
> +// The payload Length of HDD related ATA commands
> +//
> +#define HDD_PAYLOAD 512
> +//
> +// According to ATA spec, the max Length of hdd password is 32 bytes
> +//
> +#define OPAL_PASSWORD_MAX_LENGTH 32
> +
> +#pragma pack(1)
> +
> +/**
> +* Opal I/O Type utilized by the Trusted IO callback
> +*
> +* The type indicates if the I/O is a send or receive
> +*/
> +typedef enum {
> + //
> + // I/O is a TCG Trusted Send command
> + //
> + OpalSend,
> +
> + //
> + // I/O is a TCG Trusted Receive command
> + //
> + OpalRecv
> +} OPAL_IO_TYPE;
> +
> +#define OPAL_PEI_DEVICE_SIGNATURE SIGNATURE_32 ('o', 'p', 'd', 's')
> +
> +typedef struct {
> + UINTN Signature;
> + EFI_STORAGE_SECURITY_COMMAND_PROTOCOL Sscp;
> + UINT8 DeviceType;
> + OPAL_DEVICE_COMMON *Device;
> + VOID *Context;
> +} OPAL_PEI_DEVICE;
> +
> +#define OPAL_PEI_DEVICE_FROM_THIS(a) CR (a, OPAL_PEI_DEVICE, Sscp,
> OPAL_PEI_DEVICE_SIGNATURE)
> +
> +#pragma pack()
> +
> +/**
> + Allocates pages that are suitable for an OperationBusMasterCommonBuffer
> or
> + OperationBusMasterCommonBuffer64 mapping.
> +
> + @param Pages The number of pages to allocate.
> + @param HostAddress A pointer to store the base system
> memory address of the
> + allocated range.
> + @param DeviceAddress The resulting map address for the bus
> master PCI controller to use to
> + access the hosts HostAddress.
> + @param Mapping A resulting value to pass to Unmap().
> +
> + @retval EFI_SUCCESS The requested memory pages were
> allocated.
> + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal
> attribute bits are
> + MEMORY_WRITE_COMBINE and
> MEMORY_CACHED.
> + @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
> + @retval EFI_OUT_OF_RESOURCES The memory pages could not be
> allocated.
> +
> +**/
> +EFI_STATUS
> +IoMmuAllocateBuffer (
> + IN UINTN Pages,
> + OUT VOID **HostAddress,
> + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
> + OUT VOID **Mapping
> + );
> +
> +/**
> + Frees memory that was allocated with AllocateBuffer().
> +
> + @param Pages The number of pages to free.
> + @param HostAddress The base system memory address of the
> allocated range.
> + @param Mapping The mapping value returned from Map().
> +
> +**/
> +VOID
> +IoMmuFreeBuffer (
> + IN UINTN Pages,
> + IN VOID *HostAddress,
> + IN VOID *Mapping
> + );
> +
> +#endif // _OPAL_PASSWORD_PEI_H_
> +
> diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.inf
> b/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.inf
> new file mode 100644
> index 000000000000..81c57c36d2aa
> --- /dev/null
> +++ b/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.inf
> @@ -0,0 +1,63 @@
> +## @file
> +# This is a Opal Password PEI driver.
> +#
> +# Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
> +# This program and the accompanying materials
> +# are licensed and made available under the terms and conditions of the BSD
> License
> +# which accompanies this distribution. The full text of the license may be found
> at
> +# http://opensource.org/licenses/bsd-license.php
> +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +#
> +##
> +
> +[Defines]
> + INF_VERSION = 0x00010005
> + BASE_NAME = OpalPasswordPei
> + FILE_GUID =
> DED60489-979C-4B5A-8EE4-4068B0CC38DC
> + MODULE_TYPE = PEIM
> + VERSION_STRING = 1.0
> + ENTRY_POINT = OpalPasswordPeiInit
> +
> +#
> +# The following information is for reference only and not required by the build
> tools.
> +#
> +# VALID_ARCHITECTURES = IA32 X64
> +#
> +
> +[Sources]
> + OpalPasswordPei.c
> + OpalPasswordPei.h
> + OpalPasswordCommon.h
> + OpalAhciMode.c
> + OpalAhciMode.h
> + OpalNvmeMode.c
> + OpalNvmeMode.h
> + OpalNvmeReg.h
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> + SecurityPkg/SecurityPkg.dec
> + MdeModulePkg/MdeModulePkg.dec
> +
> +[LibraryClasses]
> + PeimEntryPoint
> + PeiServicesLib
> + DebugLib
> + IoLib
> + PciLib
> + BaseLib
> + BaseMemoryLib
> + MemoryAllocationLib
> + TimerLib
> + HobLib
> + LockBoxLib
> + TcgStorageOpalLib
> + Tcg2PhysicalPresenceLib
> +
> +[Ppis]
> + gEdkiiIoMmuPpiGuid ##
> SOMETIMES_CONSUMES
> + gEfiEndOfPeiSignalPpiGuid ## NOTIFY
> +
> +[Depex]
> + gEfiPeiMasterBootModePpiGuid
> --
> 2.7.0.windows.1
next prev parent reply other threads:[~2018-03-08 11:38 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-03-07 13:19 [PATCH V2 0/7] OpalPassword: New solution without SMM device code Star Zeng
2018-03-07 13:19 ` [PATCH V2 1/7] MdeModulePkg LockBoxLib: Support LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY Star Zeng
2018-03-07 13:19 ` [PATCH V2 2/7] SecurityPkg TcgStorageOpalLib: Make it be base type really Star Zeng
2018-03-07 13:19 ` [PATCH V2 3/7] SecurityPkg TcgStorageCoreLib: " Star Zeng
2018-03-07 13:19 ` [PATCH V2 4/7] SecurityPkg OpalPassword: Add solution without SMM device code Star Zeng
2018-03-08 11:44 ` Yao, Jiewen [this message]
2018-03-08 11:48 ` Zeng, Star
2018-03-07 13:19 ` [PATCH V2 5/7] SecurityPkg OpalPassword: Remove old solution Star Zeng
2018-03-07 13:19 ` [PATCH V2 6/7] SecurityPkg OpalPasswordSupportLib: Remove it Star Zeng
2018-03-07 13:19 ` [PATCH V2 7/7] SecurityPkg OpalPasswordExtraInfoVariable.h: " Star Zeng
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=74D8A39837DF1E4DA445A8C0B3885C503AAE2D98@shsmsx102.ccr.corp.intel.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox