From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=134.134.136.31; helo=mga06.intel.com; envelope-from=star.zeng@intel.com; receiver=edk2-devel@lists.01.org Received: from mga06.intel.com (mga06.intel.com [134.134.136.31]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 498B9224DCA2E for ; Thu, 8 Mar 2018 03:42:39 -0800 (PST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 08 Mar 2018 03:48:54 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.47,440,1515484800"; d="scan'208";a="209880901" Received: from fmsmsx103.amr.corp.intel.com ([10.18.124.201]) by fmsmga006.fm.intel.com with ESMTP; 08 Mar 2018 03:48:53 -0800 Received: from fmsmsx115.amr.corp.intel.com (10.18.116.19) by FMSMSX103.amr.corp.intel.com (10.18.124.201) with Microsoft SMTP Server (TLS) id 14.3.319.2; Thu, 8 Mar 2018 03:48:53 -0800 Received: from shsmsx101.ccr.corp.intel.com (10.239.4.153) by fmsmsx115.amr.corp.intel.com (10.18.116.19) with Microsoft SMTP Server (TLS) id 14.3.319.2; Thu, 8 Mar 2018 03:48:51 -0800 Received: from shsmsx102.ccr.corp.intel.com ([169.254.2.124]) by SHSMSX101.ccr.corp.intel.com ([169.254.1.253]) with mapi id 14.03.0319.002; Thu, 8 Mar 2018 19:48:48 +0800 From: "Zeng, Star" To: "Yao, Jiewen" , "edk2-devel@lists.01.org" CC: "Dong, Eric" , "Zhang, Chao B" , "Zeng, Star" Thread-Topic: [PATCH V2 4/7] SecurityPkg OpalPassword: Add solution without SMM device code Thread-Index: AQHTthb47nDdcHAA8EGCYwvmrHucOKPFs1CAgACHNGA= Date: Thu, 8 Mar 2018 11:48:47 +0000 Message-ID: <0C09AFA07DD0434D9E2A0C6AEB0483103BA4822A@shsmsx102.ccr.corp.intel.com> References: <1520428757-69040-1-git-send-email-star.zeng@intel.com> <1520428757-69040-5-git-send-email-star.zeng@intel.com> <74D8A39837DF1E4DA445A8C0B3885C503AAE2D98@shsmsx102.ccr.corp.intel.com> In-Reply-To: <74D8A39837DF1E4DA445A8C0B3885C503AAE2D98@shsmsx102.ccr.corp.intel.com> Accept-Language: zh-CN, en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.239.127.40] MIME-Version: 1.0 Subject: Re: [PATCH V2 4/7] SecurityPkg OpalPassword: Add solution without SMM device code X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 08 Mar 2018 11:42:39 -0000 Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Got the point and agree. Thanks for the good comment. :) Star -----Original Message----- From: Yao, Jiewen=20 Sent: Thursday, March 8, 2018 7:44 PM To: Zeng, Star ; edk2-devel@lists.01.org Cc: Dong, Eric ; Zhang, Chao B Subject: RE: [PATCH V2 4/7] SecurityPkg OpalPassword: Add solution without = SMM device code One minor: > + if (InputLength =3D=3D 0 || InputKey.ScanCode =3D=3D SCAN_ESC) { I prefer we also zero Unicode here. ESC just means exit, the Unicode buffer= might already be filled. > + return NULL; > + } > + > + Ascii =3D AllocateZeroPool (PSID_CHARACTER_LENGTH + 1); > + if (Ascii =3D=3D 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 ; Yao, Jiewen ; > Dong, Eric ; Zhang, Chao B > Subject: [PATCH V2 4/7] SecurityPkg OpalPassword: Add solution without SM= M > device code >=20 > 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. >=20 > Cc: Jiewen Yao > Cc: Eric Dong > Cc: Chao Zhang > Contributed-under: TianoCore Contribution Agreement 1.1 > Signed-off-by: Star Zeng > --- > 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 >=20 > 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 >=20 > [Components.IPF] > SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSa= l.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.
> +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BS= D > License > +which accompanies this distribution. The full text of the license may b= e 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 =3D { > + OpalEfiDriverComponentNameGetDriverName, > + OpalEfiDriverComponentNameGetControllerName, > + "eng" > +}; > + > +// > +// EFI Component Name 2 Protocol > +// > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL > gOpalComponentName2 =3D { > + OpalEfiDriverComponentName2GetDriverName, > + OpalEfiDriverComponentName2GetControllerName, > + "en" > +}; > + > + > +/// The name of the driver in all the languages we support. > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE > mOpalDriverNameTable[] =3D { > + { 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 drive= r. > + > + 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 na= me 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 spe= cified > + 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 t= he > + 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 specif= ied > + 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 specif= ied > 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 drive= r. > + > + 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 na= me 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 spe= cified > + 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 t= he > + 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 specif= ied > + 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 specif= ied > 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 contr= oller > + that is being managed by a driver. > + > + This function retrieves the user readable name of the controller speci= fied by > + ControllerHandle and ChildHandle in the form of a Unicode string. If t= he > + driver specified by This has a user readable name in the language spec= ified 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 c= urrently > + managing the controller specified by ControllerHandle and ChildHandle, > + then EFI_UNSUPPORTED is returned. If the driver specified by This doe= s not > + support the language specified by Language, then EFI_UNSUPPORTED is > returned. > + > + @param ControllerHandle[in] The handle of a controller that the driv= er > + specified by This is managing. This > handle > + specifies the controller whose name is t= o > 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 bu= s > + controller. It will not be NULL for a b= us > + 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 specif= ied > in > + RFC 4646 or ISO 639-2 language code > format. > + > + @param ControllerName[out] A pointer to the Unicode string to retur= n. > + 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 =3D=3D NULL || ControllerName =3D=3D NULL || ControllerHa= ndle =3D=3D > 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 contr= oller > + that is being managed by a driver. > + > + This function retrieves the user readable name of the controller speci= fied by > + ControllerHandle and ChildHandle in the form of a Unicode string. If t= he > + driver specified by This has a user readable name in the language spec= ified 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 c= urrently > + managing the controller specified by ControllerHandle and ChildHandle, > + then EFI_UNSUPPORTED is returned. If the driver specified by This doe= s 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 driv= er > + specified by This is managing. This > handle > + specifies the controller whose name is t= o > 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 bu= s > + controller. It will not be NULL for a b= us > + 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 specif= ied > in > + RFC 4646 or ISO 639-2 language code > format. > + > + @param ControllerName[out] A pointer to the Unicode string to retur= n. > + 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 contr= oller > + that is being managed by a driver. > + > + This function retrieves the user readable name of the controller speci= fied by > + ControllerHandle and ChildHandle in the form of a Unicode string. If t= he > + driver specified by This has a user readable name in the language spec= ified 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 c= urrently > + managing the controller specified by ControllerHandle and ChildHandle, > + then EFI_UNSUPPORTED is returned. If the driver specified by This doe= s 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 driv= er > + specified by This is managing. This > handle > + specifies the controller whose name is t= o > 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 bu= s > + controller. It will not be NULL for a b= us > + 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 specif= ied > in > + RFC 4646 or ISO 639-2 language code > format. > + > + @param ControllerName[out] A pointer to the Unicode string to retur= n. > + 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.
> +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BS= D > License > +which accompanies this distribution. The full text of the license may b= e 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 =3D 0; > + > + Data =3D 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 =3D AhciReadReg (AhciBar, Offset); > + > + Data &=3D 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 =3D AhciReadReg (AhciBar, Offset); > + > + Data |=3D 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 =3D (UINT32) (DivU64x32(Timeout, 1000) + 1); > + > + do { > + Value =3D AhciReadReg (AhciBar, Offset) & MaskValue; > + > + if (Value =3D=3D 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 Valu= e. > + > + @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 =3D (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 =3D *(volatile UINT32 *) (UINTN) Address; > + Value &=3D MaskValue; > + > + if (Value =3D=3D 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 !=3D NULL) { > + (*RetryTimes)--; > + } > + > + Value =3D *(volatile UINT32 *) Address; > + Value &=3D MaskValue; > + > + if (Value =3D=3D TestValue) { > + return EFI_SUCCESS; > + } > + > + if ((RetryTimes !=3D NULL) && (*RetryTimes =3D=3D 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 =3D 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 =3D 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 =3D 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 =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + > EFI_AHCI_PORT_CMD; > + Data =3D 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)) !=3D 0) { > + return EFI_UNSUPPORTED; > + } > + > + // > + // Check if the Fis receive DMA engine for the port is running. > + // > + if ((Data & EFI_AHCI_PORT_CMD_FR) !=3D 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 =3D &AhciContext->AhciRegisters; > + AhciBar =3D AhciContext->AhciBar; > + > + // > + // Filling the PRDT > + // > + PrdtNumber =3D 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 com= mand > table > + // is 65535. > + // > + ASSERT (PrdtNumber <=3D 1); > + > + Data64.Uint64 =3D (UINTN) (AhciRegisters->AhciRFis); > + > + BaseAddr =3D Data64.Uint64; > + > + ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS)); > + > + ZeroMem (AhciRegisters->AhciCommandTable, sizeof > (EFI_AHCI_COMMAND_TABLE)); > + > + CommandFis->AhciCFisPmNum =3D PortMultiplier; > + > + CopyMem (&AhciRegisters->AhciCommandTable->CommandFis, > CommandFis, sizeof (EFI_AHCI_COMMAND_FIS)); > + > + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + > EFI_AHCI_PORT_CMD; > + if (AtapiCommand !=3D NULL) { > + CopyMem ( > + &AhciRegisters->AhciCommandTable->AtapiCmd, > + AtapiCommand, > + AtapiCommandLength > + ); > + > + CommandList->AhciCmdA =3D 1; > + CommandList->AhciCmdP =3D 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 =3D (UINTN) DataLength; > + MemAddr =3D (UINTN) DataPhysicalAddr; > + CommandList->AhciCmdPrdtl =3D (UINT32)PrdtNumber; > + > + AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDbc =3D > (UINT32)RemainedData - 1; > + > + Data64.Uint64 =3D (UINT64)MemAddr; > + AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDba =3D > Data64.Uint32.Lower32; > + AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDbau =3D > Data64.Uint32.Upper32; > + > + // > + // Set the last PRDT to Interrupt On Complete > + // > + AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtIoc =3D 1; > + > + CopyMem ( > + (VOID *) ((UINTN) AhciRegisters->AhciCmdList + (UINTN) > CommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST)), > + CommandList, > + sizeof (EFI_AHCI_COMMAND_LIST) > + ); > + > + Data64.Uint64 =3D (UINT64)(UINTN) AhciRegisters->AhciCommandTable; > + AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtba =3D > Data64.Uint32.Lower32; > + AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtbau =3D > Data64.Uint32.Upper32; > + AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdPmp =3D > 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 =3D EFI_AHCI_FIS_REGISTER_H2D; > + // > + // Indicator it's a command > + // > + CmdFis->AhciCFisCmdInd =3D 0x1; > + CmdFis->AhciCFisCmd =3D AtaCommandBlock->AtaCommand; > + > + CmdFis->AhciCFisFeature =3D AtaCommandBlock->AtaFeatures; > + CmdFis->AhciCFisFeatureExp =3D AtaCommandBlock->AtaFeaturesExp; > + > + CmdFis->AhciCFisSecNum =3D AtaCommandBlock->AtaSectorNumber; > + CmdFis->AhciCFisSecNumExp =3D > AtaCommandBlock->AtaSectorNumberExp; > + > + CmdFis->AhciCFisClyLow =3D AtaCommandBlock->AtaCylinderLow; > + CmdFis->AhciCFisClyLowExp =3D AtaCommandBlock->AtaCylinderLowExp; > + > + CmdFis->AhciCFisClyHigh =3D AtaCommandBlock->AtaCylinderHigh; > + CmdFis->AhciCFisClyHighExp =3D AtaCommandBlock->AtaCylinderHighExp; > + > + CmdFis->AhciCFisSecCount =3D AtaCommandBlock->AtaSectorCount; > + CmdFis->AhciCFisSecCountExp =3D AtaCommandBlock->AtaSectorCountExp; > + > + CmdFis->AhciCFisDevHead =3D (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 successfull= y. > + > +**/ > +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 =3D &AhciContext->AhciRegisters; > + AhciBar =3D AhciContext->AhciBar; > + > + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + > EFI_AHCI_PORT_FB; > + OldRfisLo =3D AhciReadReg (AhciBar, Offset); > + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + > EFI_AHCI_PORT_FBU; > + OldRfisHi =3D AhciReadReg (AhciBar, Offset); > + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + > EFI_AHCI_PORT_FB; > + AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciRFis)= ; > + Offset =3D 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 =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + > EFI_AHCI_PORT_CLB; > + OldCmdListLo =3D AhciReadReg (AhciBar, Offset); > + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + > EFI_AHCI_PORT_CLBU; > + OldCmdListHi =3D AhciReadReg (AhciBar, Offset); > + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + > EFI_AHCI_PORT_CLB; > + AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciCmdLi= st); > + Offset =3D 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 =3D EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4; > + CmdList.AhciCmdW =3D Read ? 0 : 1; > + > + AhciBuildCommand ( > + AhciContext, > + Port, > + PortMultiplier, > + &CFis, > + &CmdList, > + AtapiCommand, > + AtapiCommandLength, > + 0, > + MemoryAddr, > + DataCount > + ); > + > + Status =3D AhciStartCommand ( > + AhciBar, > + Port, > + 0, > + Timeout > + ); > + if (EFI_ERROR (Status)) { > + goto Exit; > + } > + > + // > + // Checking the status and wait the driver sending Data > + // > + FisBaseAddr =3D (UINT32)(UINTN)AhciRegisters->AhciRFis; > + if (Read && (AtapiCommand =3D=3D 0)) { > + // > + // Wait device sends the PIO setup fis before Data transfer > + // > + Status =3D EFI_TIMEOUT; > + Delay =3D (UINT32) (DivU64x32 (Timeout, 1000) + 1); > + do { > + Offset =3D FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET; > + > + Status =3D AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, > EFI_AHCI_FIS_PIO_SETUP, 0); > + if (!EFI_ERROR (Status)) { > + Offset =3D EFI_AHCI_PORT_START + Port * > EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD; > + PortTfd =3D 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 o= nly > need to check the TFD after receiving a SetupFIS. > + // > + if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) !=3D 0) { > + Status =3D EFI_DEVICE_ERROR; > + break; > + } > + > + PrdCount =3D *(volatile UINT32 *) > (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc)); > + if (PrdCount =3D=3D DataCount) { > + break; > + } > + } > + > + Offset =3D FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET; > + Status =3D AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, > EFI_AHCI_FIS_REGISTER_D2H, 0); > + if (!EFI_ERROR (Status)) { > + Status =3D EFI_DEVICE_ERROR; > + break; > + } > + > + // > + // Stall for 100 microseconds. > + // > + MicroSecondDelay(100); > + > + Delay--; > + } while (Delay > 0); > + } else { > + // > + // Wait for D2H Fis is received > + // > + Offset =3D FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET; > + Status =3D AhciWaitMemSet ( > + Offset, > + EFI_AHCI_FIS_TYPE_MASK, > + EFI_AHCI_FIS_REGISTER_D2H, > + Timeout > + ); > + > + if (EFI_ERROR (Status)) { > + goto Exit; > + } > + > + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + > EFI_AHCI_PORT_TFD; > + PortTfd =3D AhciReadReg (AhciBar, (UINT32) Offset); > + if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) !=3D 0) { > + Status =3D EFI_DEVICE_ERROR; > + } > + } > + > +Exit: > + AhciStopCommand ( > + AhciBar, > + Port, > + Timeout > + ); > + > + AhciDisableFisReceive ( > + AhciBar, > + Port, > + Timeout > + ); > + > + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + > EFI_AHCI_PORT_FB; > + AhciWriteReg (AhciBar, Offset, OldRfisLo); > + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + > EFI_AHCI_PORT_FBU; > + AhciWriteReg (AhciBar, Offset, OldRfisHi); > + > + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + > EFI_AHCI_PORT_CLB; > + AhciWriteReg (AhciBar, Offset, OldCmdListLo); > + Offset =3D 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 =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + > EFI_AHCI_PORT_CMD; > + Data =3D AhciReadReg (AhciBar, Offset); > + > + if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) =3D=3D 0) = { > + return EFI_SUCCESS; > + } > + > + if ((Data & EFI_AHCI_PORT_CMD_ST) !=3D 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 =3D AhciReadReg(AhciBar, EFI_AHCI_CAPABILITY_OFFSET); > + > + CmdSlotBit =3D (UINT32) (1 << CommandSlot); > + > + AhciClearPortStatus ( > + AhciBar, > + Port > + ); > + > + Status =3D AhciEnableFisReceive ( > + AhciBar, > + Port, > + Timeout > + ); > + > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + > EFI_AHCI_PORT_CMD; > + PortStatus =3D AhciReadReg (AhciBar, Offset); > + > + StartCmd =3D 0; > + if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) !=3D 0) { > + StartCmd =3D AhciReadReg (AhciBar, Offset); > + StartCmd &=3D ~EFI_AHCI_PORT_CMD_ICC_MASK; > + StartCmd |=3D EFI_AHCI_PORT_CMD_ACTIVE; > + } > + > + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + > EFI_AHCI_PORT_TFD; > + PortTfd =3D AhciReadReg (AhciBar, Offset); > + > + if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) !=3D 0= ) > { > + if ((Capability & BIT24) !=3D 0) { > + Offset =3D 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 =3D 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 =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + > EFI_AHCI_PORT_SACT; > + AhciAndReg (AhciBar, Offset, 0); > + AhciOrReg (AhciBar, Offset, CmdSlotBit); > + > + Offset =3D 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 =3D 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) =3D=3D 0) { > + AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE); > + } > + > + AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET); > + > + Delay =3D (UINT32) (DivU64x32(Timeout, 1000) + 1); > + > + do { > + Value =3D AhciReadReg(AhciBar, EFI_AHCI_GHC_OFFSET); > + if ((Value & EFI_AHCI_GHC_RESET) =3D=3D 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 =3D=3D NULL || Buffer =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK)); > + > + AtaCommandBlock.AtaCommand =3D ATA_CMD_IDENTIFY_DRIVE; > + AtaCommandBlock.AtaSectorCount =3D 1; > + > + Status =3D 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 =3D &AhciContext->AhciRegisters; > + > + // > + // Allocate resources required by AHCI host controller. > + // > + Status =3D IoMmuAllocateBuffer ( > + EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)), > + &Base, > + &DeviceAddress, > + &Mapping > + ); > + if (EFI_ERROR (Status)) { > + return EFI_OUT_OF_RESOURCES; > + } > + ASSERT (DeviceAddress =3D=3D ((EFI_PHYSICAL_ADDRESS) (UINTN) Base)); > + AhciRegisters->AhciRFisMapping =3D Mapping; > + AhciRegisters->AhciRFis =3D Base; > + ZeroMem (AhciRegisters->AhciRFis, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES > (sizeof (EFI_AHCI_RECEIVED_FIS))); > + > + Status =3D 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 =3D NULL; > + return EFI_OUT_OF_RESOURCES; > + } > + ASSERT (DeviceAddress =3D=3D ((EFI_PHYSICAL_ADDRESS) (UINTN) Base)); > + AhciRegisters->AhciCmdListMapping =3D Mapping; > + AhciRegisters->AhciCmdList =3D Base; > + ZeroMem (AhciRegisters->AhciCmdList, EFI_PAGE_SIZE * > EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST))); > + > + Status =3D 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 =3D NULL; > + IoMmuFreeBuffer ( > + EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)), > + AhciRegisters->AhciCmdList, > + AhciRegisters->AhciCmdListMapping > + ); > + AhciRegisters->AhciCmdList =3D NULL; > + return EFI_OUT_OF_RESOURCES; > + } > + ASSERT (DeviceAddress =3D=3D ((EFI_PHYSICAL_ADDRESS) (UINTN) Base)); > + AhciRegisters->AhciCommandTableMapping =3D Mapping; > + AhciRegisters->AhciCommandTable =3D Base; > + ZeroMem (AhciRegisters->AhciCommandTable, EFI_PAGE_SIZE * > EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE))); > + > + // > + // Allocate resources for data transfer. > + // > + Status =3D 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 =3D NULL; > + IoMmuFreeBuffer ( > + EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)), > + AhciRegisters->AhciCmdList, > + AhciRegisters->AhciCmdListMapping > + ); > + AhciRegisters->AhciCmdList =3D NULL; > + IoMmuFreeBuffer ( > + EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)), > + AhciRegisters->AhciCommandTable, > + AhciRegisters->AhciCommandTableMapping > + ); > + AhciRegisters->AhciCommandTable =3D NULL; > + > + return EFI_OUT_OF_RESOURCES; > + } > + ASSERT (DeviceAddress =3D=3D ((EFI_PHYSICAL_ADDRESS) (UINTN) Base)); > + AhciContext->BufferMapping =3D Mapping; > + AhciContext->Buffer =3D 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 =3D &AhciContext->AhciRegisters; > + > + if (AhciRegisters->AhciRFis !=3D NULL) { > + IoMmuFreeBuffer ( > + EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)), > + AhciRegisters->AhciRFis, > + AhciRegisters->AhciRFisMapping > + ); > + AhciRegisters->AhciRFis =3D NULL; > + } > + > + if (AhciRegisters->AhciCmdList !=3D NULL) { > + IoMmuFreeBuffer ( > + EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)), > + AhciRegisters->AhciCmdList, > + AhciRegisters->AhciCmdListMapping > + ); > + AhciRegisters->AhciCmdList =3D NULL; > + } > + > + if (AhciRegisters->AhciCommandTable !=3D NULL) { > + IoMmuFreeBuffer ( > + EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)), > + AhciRegisters->AhciCommandTable, > + AhciRegisters->AhciCommandTableMapping > + ); > + AhciRegisters->AhciCommandTable =3D NULL; > + } > + > + if (AhciContext->Buffer !=3D NULL) { > + IoMmuFreeBuffer ( > + EFI_SIZE_TO_PAGES (HDD_PAYLOAD), > + AhciContext->Buffer, > + AhciContext->BufferMapping > + ); > + AhciContext->Buffer =3D 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 =3D &AhciContext->AhciRegisters; > + AhciBar =3D AhciContext->AhciBar; > + > + Status =3D AhciReset (AhciBar, ATA_TIMEOUT); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // > + // Collect AHCI controller information > + // > + Capability =3D 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) =3D=3D 0) { > + AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE); > + } > + > + Offset =3D 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 =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + > EFI_AHCI_PORT_CLB; > + AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciCmdLi= st); > + > + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + > EFI_AHCI_PORT_CMD; > + Data =3D AhciReadReg (AhciBar, Offset); > + if ((Data & EFI_AHCI_PORT_CMD_CPD) !=3D 0) { > + AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_POD); > + } > + > + if ((Capability & BIT27) !=3D 0) { > + AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_SUD); > + } > + > + // > + // Disable aggressive power management. > + // > + Offset =3D 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 soft= ware. > + // > + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + > EFI_AHCI_PORT_IE; > + AhciAndReg (AhciBar, Offset, 0); > + > + Status =3D 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.B= SY > and PxTFD.DRQ > + // and PxTFD.ERR to be zero. The maximum wait time is 16s which is def= ined > at ATA spec. > + // > + PhyDetectDelay =3D 16 * 1000; > + do { > + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + > EFI_AHCI_PORT_SERR; > + if (AhciReadReg(AhciBar, Offset) !=3D 0) { > + AhciWriteReg (AhciBar, Offset, AhciReadReg(AhciBar, Offset)); > + } > + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + > EFI_AHCI_PORT_TFD; > + > + Data =3D AhciReadReg (AhciBar, Offset) & EFI_AHCI_PORT_TFD_MASK; > + if (Data =3D=3D 0) { > + break; > + } > + > + MicroSecondDelay (1000); > + PhyDetectDelay--; > + } while (PhyDetectDelay > 0); > + > + if (PhyDetectDelay =3D=3D 0) { > + return EFI_NOT_FOUND; > + } > + > + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + > EFI_AHCI_PORT_SIG; > + Status =3D 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.
> +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BS= D > License > +which accompanies this distribution. The full text of the license may b= e 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 0x= 40 > + 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 successfull= y. > + > +**/ > +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.
> +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BS= D > License > +which accompanies this distribution. The full text of the license may b= e 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 prov= ide a > popup > +// window during boot requesting a user password > + > +#include "OpalDriver.h" > +#include "OpalHii.h" > + > +EFI_GUID mOpalDeviceAtaGuid =3D OPAL_DEVICE_ATA_GUID; > +EFI_GUID mOpalDeviceNvmeGuid =3D OPAL_DEVICE_NVME_GUID; > + > +BOOLEAN mOpalEndOfDxe =3D FALSE; > +OPAL_REQUEST_VARIABLE *mOpalRequestVariable =3D NULL; > +UINTN mOpalRequestVariableSize =3D 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 follow= ing > registers. > +// > +const OPAL_HC_PCI_REGISTER_SAVE mSataHcRegisterSaveTemplate[] =3D { > + {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 =3D { > + OpalEfiDriverBindingSupported, > + OpalEfiDriverBindingStart, > + OpalEfiDriverBindingStop, > + 0x1b, > + NULL, > + NULL > +}; > + > +/** > + > + The function determines the available actions for the OPAL_DISK provid= ed. > + > + @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 appropriat= e > 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 =3D 1; > + AvalDiskActions->UserPass =3D 0; > + AvalDiskActions->DisableUser =3D 0; > + AvalDiskActions->Unlock =3D 0; > + > + // > + // Revert is performed on locking sp, so only allow if locking sp is e= nabled > + // > + if (LockingFeature->LockingEnabled) { > + AvalDiskActions->Revert =3D 1; > + } > + > + // > + // Psid revert is available for any device with media encryption suppo= rt > + // Revert is allowed for any device with media encryption support, how= ever > 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 =3D 1; > + AvalDiskActions->RevertKeepDataForced =3D 0; > + > + // > + // Secure erase is performed by generating a new encryption key > + // this is only available if encryption is supported > + // > + AvalDiskActions->SecureErase =3D 1; > + } else { > + AvalDiskActions->PsidRevert =3D 0; > + AvalDiskActions->SecureErase =3D 0; > + > + // > + // If no media encryption is supported, then a revert (using passwor= d) will > not > + // erase the Data (since you can't generate a new encryption key) > + // > + AvalDiskActions->RevertKeepDataForced =3D 1; > + } > + > + if (LockingFeature->Locked) { > + AvalDiskActions->Unlock =3D 1; > + } else { > + AvalDiskActions->Unlock =3D 0; > + } > + > + // > + // Only allow user to set password if an admin password exists > + // > + ExistingPassword =3D OpalUtilAdminPasswordExists(OwnerShip, > LockingFeature); > + AvalDiskActions->UserPass =3D ExistingPassword; > + > + // > + // This will still show up even if there isn't a user, which is fine > + // > + AvalDiskActions->DisableUser =3D ExistingPassword; > + > + return TcgResultSuccess; > +} > + > +/** > + Enable Opal Feature for the input device. > + > + @param[in] Session The opal session for the opal devic= e. > + @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 =3D OpalUtilSetAdminPasswordAsSid( > + Session, > + Msid, > + MsidLength, > + Password, > + PassLength > + ); > + if (Ret =3D=3D TcgResultSuccess) { > + // > + // Enable global locking range > + // > + Ret =3D 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 =3D (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 !=3D NULL); > + ASSERT (DevInfoLength !=3D NULL); > + > + DeviceType =3D OPAL_DEVICE_TYPE_UNKNOWN; > + *DevInfoLength =3D 0; > + > + TmpDevPath =3D DevicePath; > + > + // > + // Get device type. > + // > + while (!IsDevicePathEnd (TmpDevPath)) { > + if (TmpDevPath->Type =3D=3D MESSAGING_DEVICE_PATH && > TmpDevPath->SubType =3D=3D MSG_SATA_DP) { > + // > + // SATA > + // > + if (DevInfo !=3D NULL) { > + SataDevPath =3D (SATA_DEVICE_PATH *) TmpDevPath; > + DevInfoAta =3D (OPAL_DEVICE_ATA *) DevInfo; > + DevInfoAta->Port =3D SataDevPath->HBAPortNumber; > + DevInfoAta->PortMultiplierPort =3D > SataDevPath->PortMultiplierPortNumber; > + } > + DeviceType =3D OPAL_DEVICE_TYPE_ATA; > + *DevInfoLength =3D sizeof (OPAL_DEVICE_ATA); > + break; > + } else if (TmpDevPath->Type =3D=3D MESSAGING_DEVICE_PATH && > TmpDevPath->SubType =3D=3D MSG_NVME_NAMESPACE_DP) { > + // > + // NVMe > + // > + if (DevInfo !=3D NULL) { > + NvmeDevPath =3D (NVME_NAMESPACE_DEVICE_PATH *) TmpDevPath; > + DevInfoNvme =3D (OPAL_DEVICE_NVME *) DevInfo; > + DevInfoNvme->NvmeNamespaceId =3D NvmeDevPath->NamespaceId; > + } > + DeviceType =3D OPAL_DEVICE_TYPE_NVME; > + *DevInfoLength =3D sizeof (OPAL_DEVICE_NVME); > + break; > + } > + TmpDevPath =3D NextDevicePathNode (TmpDevPath); > + } > + > + // > + // Get device info. > + // > + BusNum =3D 0; > + TmpDevPath =3D DevicePath; > + TmpDevPath2 =3D NextDevicePathNode (DevicePath); > + while (!IsDevicePathEnd (TmpDevPath2)) { > + if (TmpDevPath->Type =3D=3D HARDWARE_DEVICE_PATH && > TmpDevPath->SubType =3D=3D HW_PCI_DP) { > + PciDevPath =3D (PCI_DEVICE_PATH *) TmpDevPath; > + if ((TmpDevPath2->Type =3D=3D MESSAGING_DEVICE_PATH && > TmpDevPath2->SubType =3D=3D MSG_NVME_NAMESPACE_DP)|| > + (TmpDevPath2->Type =3D=3D MESSAGING_DEVICE_PATH && > TmpDevPath2->SubType =3D=3D MSG_SATA_DP)) { > + if (DevInfo !=3D NULL) { > + PciDevice =3D &DevInfo->Device; > + PciDevice->Segment =3D 0; > + PciDevice->Bus =3D BusNum; > + PciDevice->Device =3D PciDevPath->Device; > + PciDevice->Function =3D PciDevPath->Function; > + } > + } else { > + if (DevInfo !=3D NULL) { > + PciDevice =3D (OPAL_PCI_DEVICE *) ((UINTN) DevInfo + > *DevInfoLength); > + PciDevice->Segment =3D 0; > + PciDevice->Bus =3D BusNum; > + PciDevice->Device =3D PciDevPath->Device; > + PciDevice->Function =3D PciDevPath->Function; > + } > + *DevInfoLength +=3D sizeof (OPAL_PCI_DEVICE); > + if (TmpDevPath2->Type =3D=3D HARDWARE_DEVICE_PATH && > TmpDevPath2->SubType =3D=3D HW_PCI_DP) { > + BusNum =3D PciRead8 (PCI_LIB_ADDRESS (BusNum, > PciDevPath->Device, PciDevPath->Function, > PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET)); > + } > + } > + } > + > + TmpDevPath =3D NextDevicePathNode (TmpDevPath); > + TmpDevPath2 =3D NextDevicePathNode (TmpDevPath2); > + } > + > + ASSERT (DeviceType !=3D 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 =3D 0; > + > + Bus =3D DevInfo->Device.Bus; > + Device =3D DevInfo->Device.Device; > + Function =3D DevInfo->Device.Function; > + > + HcRegisterSaveListPtr =3D (OPAL_HC_PCI_REGISTER_SAVE *) > mSataHcRegisterSaveTemplate; > + Count =3D sizeof (mSataHcRegisterSaveTemplate) / sizeof > (OPAL_HC_PCI_REGISTER_SAVE); > + > + for (Index =3D 0; Index < Count; Index++) { > + Offset =3D HcRegisterSaveListPtr[Index].Address; > + Width =3D HcRegisterSaveListPtr[Index].Width; > + > + switch (Width) { > + case S3BootScriptWidthUint8: > + Data =3D (UINT32)PciRead8 > (PCI_LIB_ADDRESS(Bus,Device,Function,Offset)); > + break; > + case S3BootScriptWidthUint16: > + Data =3D (UINT32)PciRead16 > (PCI_LIB_ADDRESS(Bus,Device,Function,Offset)); > + break; > + case S3BootScriptWidthUint32: > + Data =3D PciRead32 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset))= ; > + break; > + default: > + ASSERT (FALSE); > + break; > + } > + > + Address =3D S3_BOOT_SCRIPT_LIB_PCI_ADDRESS (Bus, Device, Function, > Offset); > + Status =3D 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 =3D 0; > + TmpDev =3D mOpalDriver.DeviceList; > + while (TmpDev !=3D NULL) { > + DeviceType =3D ExtractDeviceInfoFromDevicePath ( > + TmpDev->OpalDisk.OpalDevicePath, > + &DevInfoLength, > + NULL > + ); > + if (DeviceType =3D=3D OPAL_DEVICE_TYPE_ATA) { > + DevInfoLengthAta +=3D DevInfoLength; > + } > + > + TmpDev =3D TmpDev->Next; > + } > + > + if (DevInfoLengthAta =3D=3D 0) { > + return; > + } > + > + DevInfoAta =3D AllocateZeroPool (DevInfoLengthAta); > + ASSERT (DevInfoAta !=3D NULL); > + > + TempDevInfoAta =3D DevInfoAta; > + TmpDev =3D mOpalDriver.DeviceList; > + while (TmpDev !=3D NULL) { > + DeviceType =3D ExtractDeviceInfoFromDevicePath ( > + TmpDev->OpalDisk.OpalDevicePath, > + &DevInfoLength, > + NULL > + ); > + if (DeviceType =3D=3D OPAL_DEVICE_TYPE_ATA) { > + ExtractDeviceInfoFromDevicePath ( > + TmpDev->OpalDisk.OpalDevicePath, > + &DevInfoLength, > + (OPAL_DEVICE_COMMON *) TempDevInfoAta > + ); > + TempDevInfoAta->Length =3D DevInfoLength; > + TempDevInfoAta->OpalBaseComId =3D > TmpDev->OpalDisk.OpalBaseComId; > + TempDevInfoAta->BarAddr =3D BarAddr; > + CopyMem ( > + TempDevInfoAta->Password, > + TmpDev->OpalDisk.Password, > + TmpDev->OpalDisk.PasswordLength > + ); > + TempDevInfoAta->PasswordLength =3D > TmpDev->OpalDisk.PasswordLength; > + OpalDeviceAtaSaveBootScript (TempDevInfoAta); > + TempDevInfoAta =3D (OPAL_DEVICE_ATA *) ((UINTN) TempDevInfoAta + > DevInfoLength); > + } > + > + TmpDev =3D TmpDev->Next; > + } > + > + Status =3D SaveLockBox ( > + &mOpalDeviceAtaGuid, > + DevInfoAta, > + DevInfoLengthAta > + ); > + ASSERT_EFI_ERROR (Status); > + > + Status =3D 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 =3D 0; > + TmpDev =3D mOpalDriver.DeviceList; > + while (TmpDev !=3D NULL) { > + DeviceType =3D ExtractDeviceInfoFromDevicePath ( > + TmpDev->OpalDisk.OpalDevicePath, > + &DevInfoLength, > + NULL > + ); > + if (DeviceType =3D=3D OPAL_DEVICE_TYPE_NVME) { > + DevInfoLengthNvme +=3D DevInfoLength; > + } > + > + TmpDev =3D TmpDev->Next; > + } > + > + if (DevInfoLengthNvme =3D=3D 0) { > + return; > + } > + > + DevInfoNvme =3D AllocateZeroPool (DevInfoLengthNvme); > + ASSERT (DevInfoNvme !=3D NULL); > + > + TempDevInfoNvme =3D DevInfoNvme; > + TmpDev =3D mOpalDriver.DeviceList; > + while (TmpDev !=3D NULL) { > + DeviceType =3D ExtractDeviceInfoFromDevicePath ( > + TmpDev->OpalDisk.OpalDevicePath, > + &DevInfoLength, > + NULL > + ); > + if (DeviceType =3D=3D OPAL_DEVICE_TYPE_NVME) { > + ExtractDeviceInfoFromDevicePath ( > + TmpDev->OpalDisk.OpalDevicePath, > + &DevInfoLength, > + (OPAL_DEVICE_COMMON *) TempDevInfoNvme > + ); > + TempDevInfoNvme->Length =3D DevInfoLength; > + TempDevInfoNvme->OpalBaseComId =3D > TmpDev->OpalDisk.OpalBaseComId; > + TempDevInfoNvme->BarAddr =3D BarAddr; > + CopyMem ( > + TempDevInfoNvme->Password, > + TmpDev->OpalDisk.Password, > + TmpDev->OpalDisk.PasswordLength > + ); > + TempDevInfoNvme->PasswordLength =3D > TmpDev->OpalDisk.PasswordLength; > + TempDevInfoNvme =3D (OPAL_DEVICE_NVME *) ((UINTN) > TempDevInfoNvme + DevInfoLength); > + } > + > + TmpDev =3D TmpDev->Next; > + } > + > + Status =3D SaveLockBox ( > + &mOpalDeviceNvmeGuid, > + DevInfoNvme, > + DevInfoLengthNvme > + ); > + ASSERT_EFI_ERROR (Status); > + > + Status =3D 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 invoke= d. > + @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 =3D TRUE; > + > + if (mOpalRequestVariable !=3D NULL) { > + // > + // Free the OPAL request variable buffer here > + // as the OPAL requests should have been processed. > + // > + FreePool (mOpalRequestVariable); > + mOpalRequestVariable =3D NULL; > + mOpalRequestVariableSize =3D 0; > + } > + > + // > + // Assume 64K size and alignment are enough. > + // > + Length =3D 0x10000; > + Address =3D 0xFFFFFFFF; > + Status =3D 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 =3D mOpalDriver.DeviceList; > + while (TmpDev !=3D NULL) { > + ZeroMem (TmpDev->OpalDisk.Password, > TmpDev->OpalDisk.PasswordLength); > + TmpDev =3D 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 =3D FALSE; > + > + gST->ConOut->ClearScreen(gST->ConOut); > + > + InputLength =3D 0; > + while (TRUE) { > + Mask[InputLength] =3D L'_'; > + CreatePopUp ( > + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, > + &InputKey, > + PopUpString, > + L"---------------------", > + Mask, > + NULL > + ); > + > + // > + // Check key. > + // > + if (InputKey.ScanCode =3D=3D SCAN_NULL) { > + // > + // password finished > + // > + if (InputKey.UnicodeChar =3D=3D CHAR_CARRIAGE_RETURN) { > + // > + // Add the null terminator. > + // > + Unicode[InputLength] =3D 0; > + Mask[InputLength] =3D 0; > + break; > + } else if ((InputKey.UnicodeChar =3D=3D CHAR_NULL) || > + (InputKey.UnicodeChar =3D=3D CHAR_TAB) || > + (InputKey.UnicodeChar =3D=3D CHAR_LINEFEED) > + ) { > + continue; > + } else { > + // > + // delete last key entered > + // > + if (InputKey.UnicodeChar =3D=3D CHAR_BACKSPACE) { > + if (InputLength > 0) { > + Unicode[InputLength] =3D 0; > + Mask[InputLength] =3D 0; > + InputLength--; > + } > + } else { > + // > + // add Next key entry > + // > + Unicode[InputLength] =3D InputKey.UnicodeChar; > + Mask[InputLength] =3D InputKey.UnicodeChar; > + InputLength++; > + if (InputLength =3D=3D PSID_CHARACTER_LENGTH) { > + // > + // Add the null terminator. > + // > + Unicode[InputLength] =3D 0; > + Mask[InputLength] =3D 0; > + break; > + } > + } > + } > + } > + > + // > + // exit on ESC > + // > + if (InputKey.ScanCode =3D=3D SCAN_ESC) { > + *PressEsc =3D TRUE; > + break; > + } > + } > + > + gST->ConOut->ClearScreen(gST->ConOut); > + > + if (InputLength =3D=3D 0 || InputKey.ScanCode =3D=3D SCAN_ESC) { > + return NULL; > + } > + > + Ascii =3D AllocateZeroPool (PSID_CHARACTER_LENGTH + 1); > + if (Ascii =3D=3D 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 =3D FALSE; > + > + gST->ConOut->ClearScreen(gST->ConOut); > + > + InputLength =3D 0; > + while (TRUE) { > + Mask[InputLength] =3D L'_'; > + if (PopUpString2 =3D=3D 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 =3D=3D SCAN_NULL) { > + // > + // password finished > + // > + if (InputKey.UnicodeChar =3D=3D CHAR_CARRIAGE_RETURN) { > + // > + // Add the null terminator. > + // > + Unicode[InputLength] =3D 0; > + Mask[InputLength] =3D 0; > + break; > + } else if ((InputKey.UnicodeChar =3D=3D CHAR_NULL) || > + (InputKey.UnicodeChar =3D=3D CHAR_TAB) || > + (InputKey.UnicodeChar =3D=3D CHAR_LINEFEED) > + ) { > + continue; > + } else { > + // > + // delete last key entered > + // > + if (InputKey.UnicodeChar =3D=3D CHAR_BACKSPACE) { > + if (InputLength > 0) { > + Unicode[InputLength] =3D 0; > + Mask[InputLength] =3D 0; > + InputLength--; > + } > + } else { > + // > + // add Next key entry > + // > + Unicode[InputLength] =3D InputKey.UnicodeChar; > + Mask[InputLength] =3D L'*'; > + InputLength++; > + if (InputLength =3D=3D MAX_PASSWORD_SIZE) { > + // > + // Add the null terminator. > + // > + Unicode[InputLength] =3D 0; > + Mask[InputLength] =3D 0; > + break; > + } > + } > + } > + } > + > + // > + // exit on ESC > + // > + if (InputKey.ScanCode =3D=3D SCAN_ESC) { > + *PressEsc =3D TRUE; > + break; > + } > + } > + > + gST->ConOut->ClearScreen(gST->ConOut); > + > + if (InputLength =3D=3D 0 || InputKey.ScanCode =3D=3D SCAN_ESC) { > + return NULL; > + } > + > + Ascii =3D AllocateZeroPool (MAX_PASSWORD_SIZE + 1); > + if (Ascii =3D=3D 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 =3D StrLen (RequestString) + 1 + MAX (StrLen (Dev->Name16), > StrLen (L"Disk")); > + ASSERT (StrLength < sizeof (mPopUpString) / sizeof (CHAR16)); > + > + if (Dev->Name16 =3D=3D NULL) { > + UnicodeSPrint (mPopUpString, StrLength + 1, L"%s Disk", RequestStrin= g); > + } 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 =3D=3D NULL) { > + return; > + } > + > + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); > + > + PopUpString =3D OpalGetPopUpString (Dev, RequestString); > + > + Count =3D 0; > + > + IsEnabled =3D OpalFeatureEnabled (&Dev->OpalDisk.SupportedAttributes, > &Dev->OpalDisk.LockingFeature); > + if (IsEnabled) { > + ZeroMem(&Session, sizeof(Session)); > + Session.Sscp =3D Dev->OpalDisk.Sscp; > + Session.MediaId =3D Dev->OpalDisk.MediaId; > + Session.OpalBaseComId =3D Dev->OpalDisk.OpalBaseComId; > + > + IsLocked =3D OpalDeviceLocked (&Dev->OpalDisk.SupportedAttributes, > &Dev->OpalDisk.LockingFeature); > + > + while (Count < MAX_PASSWORD_TRY_COUNT) { > + Password =3D 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 !=3D SCAN_ESC) && (Key.UnicodeChar !=3D > CHAR_CARRIAGE_RETURN)); > + > + if (Key.UnicodeChar =3D=3D 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 !=3D SCAN_ESC) && (Key.UnicodeChar !=3D > CHAR_CARRIAGE_RETURN)); > + > + if (Key.UnicodeChar =3D=3D CHAR_CARRIAGE_RETURN) { > + gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL); > + } else { > + // > + // Let user input password again. > + // > + continue; > + } > + } > + } > + > + if (Password =3D=3D NULL) { > + Count ++; > + continue; > + } > + PasswordLen =3D (UINT32) AsciiStrLen(Password); > + > + if (IsLocked) { > + Ret =3D OpalUtilUpdateGlobalLockingRange(&Session, Password, > PasswordLen, FALSE, FALSE); > + } else { > + Ret =3D OpalUtilUpdateGlobalLockingRange(&Session, Password, > PasswordLen, TRUE, TRUE); > + if (Ret =3D=3D TcgResultSuccess) { > + Ret =3D OpalUtilUpdateGlobalLockingRange(&Session, Password, > PasswordLen, FALSE, FALSE); > + } > + } > + > + if (Ret =3D=3D TcgResultSuccess) { > + OpalSupportUpdatePassword (&Dev->OpalDisk, Password, > PasswordLen); > + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); > + } else { > + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); > + } > + > + if (Password !=3D NULL) { > + ZeroMem (Password, PasswordLen); > + FreePool (Password); > + } > + > + if (Ret =3D=3D TcgResultSuccess) { > + break; > + } > + > + Count++; > + > + do { > + CreatePopUp ( > + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, > + &Key, > + L"Invalid password.", > + L"Press ENTER to retry", > + NULL > + ); > + } while (Key.UnicodeChar !=3D CHAR_CARRIAGE_RETURN); > + } > + > + if (Count >=3D 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 !=3D 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 =3D=3D NULL) { > + return; > + } > + > + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); > + > + PopUpString =3D OpalGetPopUpString (Dev, RequestString); > + > + Count =3D 0; > + > + ZeroMem(&Session, sizeof(Session)); > + Session.Sscp =3D Dev->OpalDisk.Sscp; > + Session.MediaId =3D Dev->OpalDisk.MediaId; > + Session.OpalBaseComId =3D Dev->OpalDisk.OpalBaseComId; > + > + while (Count < MAX_PASSWORD_TRY_COUNT) { > + Password =3D OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Pleas= e > 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 !=3D SCAN_ESC) && (Key.UnicodeChar !=3D > CHAR_CARRIAGE_RETURN)); > + > + if (Key.UnicodeChar =3D=3D CHAR_CARRIAGE_RETURN) { > + gST->ConOut->ClearScreen(gST->ConOut); > + return; > + } else { > + // > + // Let user input password again. > + // > + continue; > + } > + } > + > + if (Password =3D=3D NULL) { > + Count ++; > + continue; > + } > + PasswordLen =3D (UINT32) AsciiStrLen(Password); > + > + PasswordConfirm =3D OpalDriverPopUpPasswordInput (Dev, PopUpString, > L"Please confirm your new password", &PressEsc); > + if (PasswordConfirm =3D=3D NULL) { > + ZeroMem (Password, PasswordLen); > + FreePool (Password); > + Count ++; > + continue; > + } > + PasswordLenConfirm =3D (UINT32) AsciiStrLen(PasswordConfirm); > + if ((PasswordLen !=3D PasswordLenConfirm) || > + (CompareMem (Password, PasswordConfirm, PasswordLen) !=3D 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 !=3D CHAR_CARRIAGE_RETURN); > + Count ++; > + continue; > + } > + > + if (PasswordConfirm !=3D NULL) { > + ZeroMem (PasswordConfirm, PasswordLenConfirm); > + FreePool (PasswordConfirm); > + } > + > + Ret =3D OpalSupportEnableOpalFeature (&Session, Dev->OpalDisk.Msid, > Dev->OpalDisk.MsidLength, Password, PasswordLen); > + if (Ret =3D=3D TcgResultSuccess) { > + OpalSupportUpdatePassword (&Dev->OpalDisk, Password, > PasswordLen); > + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); > + } else { > + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); > + } > + > + if (Password !=3D NULL) { > + ZeroMem (Password, PasswordLen); > + FreePool (Password); > + } > + > + if (Ret =3D=3D TcgResultSuccess) { > + break; > + } > + > + Count++; > + > + do { > + CreatePopUp ( > + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, > + &Key, > + L"Request failed.", > + L"Press ENTER to retry", > + NULL > + ); > + } while (Key.UnicodeChar !=3D CHAR_CARRIAGE_RETURN); > + } > + > + if (Count >=3D 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 !=3D 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 =3D=3D NULL) { > + return; > + } > + > + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); > + > + PopUpString =3D OpalGetPopUpString (Dev, RequestString); > + > + Count =3D 0; > + > + ZeroMem(&Session, sizeof(Session)); > + Session.Sscp =3D Dev->OpalDisk.Sscp; > + Session.MediaId =3D Dev->OpalDisk.MediaId; > + Session.OpalBaseComId =3D Dev->OpalDisk.OpalBaseComId; > + > + while (Count < MAX_PASSWORD_TRY_COUNT) { > + Password =3D 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 !=3D SCAN_ESC) && (Key.UnicodeChar !=3D > CHAR_CARRIAGE_RETURN)); > + > + if (Key.UnicodeChar =3D=3D CHAR_CARRIAGE_RETURN) { > + gST->ConOut->ClearScreen(gST->ConOut); > + return; > + } else { > + // > + // Let user input password again. > + // > + continue; > + } > + } > + > + if (Password =3D=3D NULL) { > + Count ++; > + continue; > + } > + PasswordLen =3D (UINT32) AsciiStrLen(Password); > + > + Ret =3D OpalUtilDisableUser(&Session, Password, PasswordLen, > &PasswordFailed); > + if (Ret =3D=3D TcgResultSuccess) { > + OpalSupportUpdatePassword (&Dev->OpalDisk, Password, > PasswordLen); > + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); > + } else { > + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); > + } > + > + if (Password !=3D NULL) { > + ZeroMem (Password, PasswordLen); > + FreePool (Password); > + } > + > + if (Ret =3D=3D 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 !=3D CHAR_CARRIAGE_RETURN); > + } > + > + if (Count >=3D 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 !=3D 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 =3D=3D NULL) { > + return; > + } > + > + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); > + > + PopUpString =3D OpalGetPopUpString (Dev, RequestString); > + > + Count =3D 0; > + > + ZeroMem(&Session, sizeof(Session)); > + Session.Sscp =3D Dev->OpalDisk.Sscp; > + Session.MediaId =3D Dev->OpalDisk.MediaId; > + Session.OpalBaseComId =3D Dev->OpalDisk.OpalBaseComId; > + > + while (Count < MAX_PSID_TRY_COUNT) { > + Psid =3D 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 !=3D SCAN_ESC) && (Key.UnicodeChar !=3D > CHAR_CARRIAGE_RETURN)); > + > + if (Key.UnicodeChar =3D=3D CHAR_CARRIAGE_RETURN) { > + gST->ConOut->ClearScreen(gST->ConOut); > + return; > + } else { > + // > + // Let user input Psid again. > + // > + continue; > + } > + } > + > + if (Psid =3D=3D NULL) { > + Count ++; > + continue; > + } > + PsidLen =3D (UINT32) AsciiStrLen(Psid); > + > + Ret =3D OpalUtilPsidRevert(&Session, Psid, PsidLen); > + if (Ret =3D=3D TcgResultSuccess) { > + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); > + } else { > + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); > + } > + > + if (Psid !=3D NULL) { > + ZeroMem (Psid, PsidLen); > + FreePool (Psid); > + } > + > + if (Ret =3D=3D 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 !=3D CHAR_CARRIAGE_RETURN); > + } > + > + if (Count >=3D 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 !=3D 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 =3D=3D NULL) { > + return; > + } > + > + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); > + > + PopUpString =3D OpalGetPopUpString (Dev, RequestString); > + > + Count =3D 0; > + > + ZeroMem(&Session, sizeof(Session)); > + Session.Sscp =3D Dev->OpalDisk.Sscp; > + Session.MediaId =3D Dev->OpalDisk.MediaId; > + Session.OpalBaseComId =3D Dev->OpalDisk.OpalBaseComId; > + > + while (Count < MAX_PASSWORD_TRY_COUNT) { > + Password =3D 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 !=3D SCAN_ESC) && (Key.UnicodeChar !=3D > CHAR_CARRIAGE_RETURN)); > + > + if (Key.UnicodeChar =3D=3D CHAR_CARRIAGE_RETURN) { > + gST->ConOut->ClearScreen(gST->ConOut); > + return; > + } else { > + // > + // Let user input password again. > + // > + continue; > + } > + } > + > + if (Password =3D=3D NULL) { > + Count ++; > + continue; > + } > + PasswordLen =3D (UINT32) AsciiStrLen(Password); > + > + if ((Dev->OpalDisk.SupportedAttributes.PyriteSsc =3D=3D 1) && > + (Dev->OpalDisk.LockingFeature.MediaEncryption =3D=3D 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 =3D OpalUtilRevert( > + &Session, > + FALSE, > + Password, > + PasswordLen, > + &PasswordFailed, > + Dev->OpalDisk.Msid, > + Dev->OpalDisk.MsidLength > + ); > + } else { > + Ret =3D OpalUtilRevert( > + &Session, > + KeepUserData, > + Password, > + PasswordLen, > + &PasswordFailed, > + Dev->OpalDisk.Msid, > + Dev->OpalDisk.MsidLength > + ); > + } > + if (Ret =3D=3D TcgResultSuccess) { > + OpalSupportUpdatePassword (&Dev->OpalDisk, Password, > PasswordLen); > + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); > + } else { > + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); > + } > + > + if (Password !=3D NULL) { > + ZeroMem (Password, PasswordLen); > + FreePool (Password); > + } > + > + if (Ret =3D=3D 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 !=3D CHAR_CARRIAGE_RETURN); > + } > + > + if (Count >=3D 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 !=3D 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 =3D=3D NULL) { > + return; > + } > + > + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); > + > + PopUpString =3D OpalGetPopUpString (Dev, RequestString); > + > + Count =3D 0; > + > + ZeroMem(&Session, sizeof(Session)); > + Session.Sscp =3D Dev->OpalDisk.Sscp; > + Session.MediaId =3D Dev->OpalDisk.MediaId; > + Session.OpalBaseComId =3D Dev->OpalDisk.OpalBaseComId; > + > + while (Count < MAX_PASSWORD_TRY_COUNT) { > + Password =3D 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 !=3D SCAN_ESC) && (Key.UnicodeChar !=3D > CHAR_CARRIAGE_RETURN)); > + > + if (Key.UnicodeChar =3D=3D CHAR_CARRIAGE_RETURN) { > + gST->ConOut->ClearScreen(gST->ConOut); > + return; > + } else { > + // > + // Let user input password again. > + // > + continue; > + } > + } > + > + if (Password =3D=3D NULL) { > + Count ++; > + continue; > + } > + PasswordLen =3D (UINT32) AsciiStrLen(Password); > + > + Ret =3D OpalUtilSecureErase(&Session, Password, PasswordLen, > &PasswordFailed); > + if (Ret =3D=3D TcgResultSuccess) { > + OpalSupportUpdatePassword (&Dev->OpalDisk, Password, > PasswordLen); > + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); > + } else { > + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); > + } > + > + if (Password !=3D NULL) { > + ZeroMem (Password, PasswordLen); > + FreePool (Password); > + } > + > + if (Ret =3D=3D 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 !=3D CHAR_CARRIAGE_RETURN); > + } > + > + if (Count >=3D 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 !=3D 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 =3D=3D NULL) { > + return; > + } > + > + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); > + > + PopUpString =3D OpalGetPopUpString (Dev, RequestString); > + > + Count =3D 0; > + > + while (Count < MAX_PASSWORD_TRY_COUNT) { > + OldPassword =3D 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 !=3D SCAN_ESC) && (Key.UnicodeChar !=3D > CHAR_CARRIAGE_RETURN)); > + > + if (Key.UnicodeChar =3D=3D CHAR_CARRIAGE_RETURN) { > + gST->ConOut->ClearScreen(gST->ConOut); > + return; > + } else { > + // > + // Let user input password again. > + // > + continue; > + } > + } > + > + if (OldPassword =3D=3D NULL) { > + Count ++; > + continue; > + } > + OldPasswordLen =3D (UINT32) AsciiStrLen(OldPassword); > + > + ZeroMem(&Session, sizeof(Session)); > + Session.Sscp =3D Dev->OpalDisk.Sscp; > + Session.MediaId =3D Dev->OpalDisk.MediaId; > + Session.OpalBaseComId =3D Dev->OpalDisk.OpalBaseComId; > + Ret =3D OpalUtilVerifyPassword (&Session, OldPassword, OldPasswordLe= n, > OPAL_LOCKING_SP_USER1_AUTHORITY); > + if (Ret =3D=3D TcgResultSuccess) { > + DEBUG ((DEBUG_INFO, "Verify with USER1 authority : Success\n")); > + } else { > + Ret =3D OpalUtilVerifyPassword (&Session, OldPassword, OldPassword= Len, > OPAL_LOCKING_SP_ADMIN1_AUTHORITY); > + if (Ret =3D=3D 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 !=3D CHAR_CARRIAGE_RETURN); > + Count ++; > + continue; > + } > + } > + > + Password =3D OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Pleas= e > type in your new password", &PressEsc); > + if (Password =3D=3D NULL) { > + ZeroMem (OldPassword, OldPasswordLen); > + FreePool (OldPassword); > + Count ++; > + continue; > + } > + PasswordLen =3D (UINT32) AsciiStrLen(Password); > + > + PasswordConfirm =3D OpalDriverPopUpPasswordInput (Dev, PopUpString, > L"Please confirm your new password", &PressEsc); > + if (PasswordConfirm =3D=3D NULL) { > + ZeroMem (OldPassword, OldPasswordLen); > + FreePool (OldPassword); > + ZeroMem (Password, PasswordLen); > + FreePool (Password); > + Count ++; > + continue; > + } > + PasswordLenConfirm =3D (UINT32) AsciiStrLen(PasswordConfirm); > + if ((PasswordLen !=3D PasswordLenConfirm) || > + (CompareMem (Password, PasswordConfirm, PasswordLen) !=3D 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 !=3D CHAR_CARRIAGE_RETURN); > + Count ++; > + continue; > + } > + > + if (PasswordConfirm !=3D NULL) { > + ZeroMem (PasswordConfirm, PasswordLenConfirm); > + FreePool (PasswordConfirm); > + } > + > + ZeroMem(&Session, sizeof(Session)); > + Session.Sscp =3D Dev->OpalDisk.Sscp; > + Session.MediaId =3D Dev->OpalDisk.MediaId; > + Session.OpalBaseComId =3D Dev->OpalDisk.OpalBaseComId; > + Ret =3D OpalUtilSetUserPassword( > + &Session, > + OldPassword, > + OldPasswordLen, > + Password, > + PasswordLen > + ); > + if (Ret =3D=3D TcgResultSuccess) { > + OpalSupportUpdatePassword (&Dev->OpalDisk, Password, > PasswordLen); > + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); > + } else { > + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); > + } > + > + if (OldPassword !=3D NULL) { > + ZeroMem (OldPassword, OldPasswordLen); > + FreePool (OldPassword); > + } > + > + if (Password !=3D NULL) { > + ZeroMem (Password, PasswordLen); > + FreePool (Password); > + } > + > + if (Ret =3D=3D TcgResultSuccess) { > + break; > + } > + > + Count++; > + > + do { > + CreatePopUp ( > + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, > + &Key, > + L"Request failed.", > + L"Press ENTER to retry", > + NULL > + ); > + } while (Key.UnicodeChar !=3D CHAR_CARRIAGE_RETURN); > + } > + > + if (Count >=3D 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 !=3D 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 =3D=3D NULL) { > + return; > + } > + > + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); > + > + PopUpString =3D OpalGetPopUpString (Dev, RequestString); > + > + Count =3D 0; > + > + while (Count < MAX_PASSWORD_TRY_COUNT) { > + OldPassword =3D 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 !=3D SCAN_ESC) && (Key.UnicodeChar !=3D > CHAR_CARRIAGE_RETURN)); > + > + if (Key.UnicodeChar =3D=3D CHAR_CARRIAGE_RETURN) { > + gST->ConOut->ClearScreen(gST->ConOut); > + return; > + } else { > + // > + // Let user input password again. > + // > + continue; > + } > + } > + > + if (OldPassword =3D=3D NULL) { > + Count ++; > + continue; > + } > + OldPasswordLen =3D (UINT32) AsciiStrLen(OldPassword); > + > + ZeroMem(&Session, sizeof(Session)); > + Session.Sscp =3D Dev->OpalDisk.Sscp; > + Session.MediaId =3D Dev->OpalDisk.MediaId; > + Session.OpalBaseComId =3D Dev->OpalDisk.OpalBaseComId; > + Ret =3D OpalUtilVerifyPassword (&Session, OldPassword, OldPasswordLe= n, > OPAL_LOCKING_SP_ADMIN1_AUTHORITY); > + if (Ret =3D=3D 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 !=3D CHAR_CARRIAGE_RETURN); > + Count ++; > + continue; > + } > + > + Password =3D OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Pleas= e > type in your new password", &PressEsc); > + if (Password =3D=3D NULL) { > + ZeroMem (OldPassword, OldPasswordLen); > + FreePool (OldPassword); > + Count ++; > + continue; > + } > + PasswordLen =3D (UINT32) AsciiStrLen(Password); > + > + PasswordConfirm =3D OpalDriverPopUpPasswordInput (Dev, PopUpString, > L"Please confirm your new password", &PressEsc); > + if (PasswordConfirm =3D=3D NULL) { > + ZeroMem (OldPassword, OldPasswordLen); > + FreePool (OldPassword); > + ZeroMem (Password, PasswordLen); > + FreePool (Password); > + Count ++; > + continue; > + } > + PasswordLenConfirm =3D (UINT32) AsciiStrLen(PasswordConfirm); > + if ((PasswordLen !=3D PasswordLenConfirm) || > + (CompareMem (Password, PasswordConfirm, PasswordLen) !=3D 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 !=3D CHAR_CARRIAGE_RETURN); > + Count ++; > + continue; > + } > + > + if (PasswordConfirm !=3D NULL) { > + ZeroMem (PasswordConfirm, PasswordLenConfirm); > + FreePool (PasswordConfirm); > + } > + > + > + ZeroMem(&Session, sizeof(Session)); > + Session.Sscp =3D Dev->OpalDisk.Sscp; > + Session.MediaId =3D Dev->OpalDisk.MediaId; > + Session.OpalBaseComId =3D Dev->OpalDisk.OpalBaseComId; > + Ret =3D OpalUtilSetAdminPassword( > + &Session, > + OldPassword, > + OldPasswordLen, > + Password, > + PasswordLen > + ); > + if (Ret =3D=3D TcgResultSuccess) { > + OpalSupportUpdatePassword (&Dev->OpalDisk, Password, > PasswordLen); > + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); > + } else { > + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); > + } > + > + if (OldPassword !=3D NULL) { > + ZeroMem (OldPassword, OldPasswordLen); > + FreePool (OldPassword); > + } > + > + if (Password !=3D NULL) { > + ZeroMem (Password, PasswordLen); > + FreePool (Password); > + } > + > + if (Ret =3D=3D TcgResultSuccess) { > + break; > + } > + > + Count++; > + > + do { > + CreatePopUp ( > + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, > + &Key, > + L"Request failed.", > + L"Press ENTER to retry", > + NULL > + ); > + } while (Key.UnicodeChar !=3D CHAR_CARRIAGE_RETURN); > + } > + > + if (Count >=3D 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 !=3D 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 =3D=3D NULL) { > + Status =3D GetVariable2 ( > + OPAL_REQUEST_VARIABLE_NAME, > + &gHiiSetupVariableGuid, > + (VOID **) &Variable, > + &VariableSize > + ); > + if (EFI_ERROR (Status) || (Variable =3D=3D NULL)) { > + return; > + } > + mOpalRequestVariable =3D Variable; > + mOpalRequestVariableSize =3D VariableSize; > + > + // > + // Delete the OPAL request variable. > + // > + Status =3D gRT->SetVariable ( > + OPAL_REQUEST_VARIABLE_NAME, > + (EFI_GUID *) &gHiiSetupVariableGuid, > + 0, > + 0, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > + } else { > + Variable =3D mOpalRequestVariable; > + VariableSize =3D mOpalRequestVariableSize; > + } > + > + // > + // Process the OPAL requests. > + // > + TempVariable =3D Variable; > + while ((VariableSize > sizeof (OPAL_REQUEST_VARIABLE)) && > + (VariableSize >=3D TempVariable->Length) && > + (TempVariable->Length > sizeof (OPAL_REQUEST_VARIABLE))) { > + DevicePathInVariable =3D (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) > TempVariable + sizeof (OPAL_REQUEST_VARIABLE)); > + DevicePathSizeInVariable =3D GetDevicePathSize (DevicePathInVariable= ); > + DevicePath =3D Dev->OpalDisk.OpalDevicePath; > + DevicePathSize =3D GetDevicePathSize (DevicePath); > + if ((DevicePathSize =3D=3D DevicePathSizeInVariable) && > + (CompareMem (DevicePath, DevicePathInVariable, DevicePathSize) > =3D=3D 0)) { > + // > + // Found the node for the OPAL device. > + // > + if (TempVariable->OpalRequest.SetAdminPwd !=3D 0) { > + ProcessOpalRequestSetAdminPwd (Dev, L"Update Admin Pwd:"); > + } > + if (TempVariable->OpalRequest.SetUserPwd !=3D 0) { > + ProcessOpalRequestSetUserPwd (Dev, L"Set User Pwd:"); > + } > + if (TempVariable->OpalRequest.SecureErase!=3D 0) { > + ProcessOpalRequestSecureErase (Dev, L"Secure Erase:"); > + } > + if (TempVariable->OpalRequest.Revert !=3D 0) { > + KeepUserData =3D (BOOLEAN) > TempVariable->OpalRequest.KeepUserData; > + ProcessOpalRequestRevert ( > + Dev, > + KeepUserData, > + KeepUserData ? L"Admin Revert(keep):" : L"Admin Revert:" > + ); > + } > + if (TempVariable->OpalRequest.PsidRevert !=3D 0) { > + ProcessOpalRequestPsidRevert (Dev, L"Psid Revert:"); > + } > + if (TempVariable->OpalRequest.DisableUser !=3D 0) { > + ProcessOpalRequestDisableUser (Dev, L"Disable User:"); > + } > + if (TempVariable->OpalRequest.EnableFeature !=3D 0) { > + ProcessOpalRequestEnableFeature (Dev, L"Enable Feature:"); > + } > + > + break; > + } > + > + VariableSize -=3D TempVariable->Length; > + TempVariable =3D (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 =3D=3D NULL) { > + mOpalDriver.DeviceList =3D Dev; > + } else { > + TmpDev =3D mOpalDriver.DeviceList; > + while (TmpDev->Next !=3D NULL) { > + TmpDev =3D TmpDev->Next; > + } > + > + TmpDev->Next =3D 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 =3D=3D NULL) { > + return; > + } > + > + if (mOpalDriver.DeviceList =3D=3D Dev) { > + mOpalDriver.DeviceList =3D NULL; > + return; > + } > + > + TmpDev =3D mOpalDriver.DeviceList; > + while (TmpDev->Next !=3D NULL) { > + if (TmpDev->Next =3D=3D Dev) { > + TmpDev->Next =3D Dev->Next; > + break; > + } > + } > +} > + > +/** > + Get current device count. > + > + @retval return the current created device count. > + > +**/ > +UINT8 > +GetDeviceCount ( > + VOID > + ) > +{ > + UINT8 Count; > + OPAL_DRIVER_DEVICE *TmpDev; > + > + Count =3D 0; > + TmpDev =3D mOpalDriver.DeviceList; > + > + while (TmpDev !=3D NULL) { > + Count++; > + TmpDev =3D 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 =3D Tcg2PhysicalPresenceLibGetManagementFlags (); > + if ((PpStorageFlag & > TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID) !=3D 0) { > + // > + // Send BlockSID command to each Opal disk > + // > + Itr =3D mOpalDriver.DeviceList; > + while (Itr !=3D NULL) { > + if (Itr->OpalDisk.SupportedAttributes.BlockSid) { > + ZeroMem(&Session, sizeof(Session)); > + Session.Sscp =3D Itr->OpalDisk.Sscp; > + Session.MediaId =3D Itr->OpalDisk.MediaId; > + Session.OpalBaseComId =3D Itr->OpalDisk.OpalBaseComId; > + > + Result =3D OpalBlockSid (&Session, TRUE); // HardwareReset must > always be TRUE > + if (Result !=3D TcgResultSuccess) { > + DEBUG ((DEBUG_ERROR, "OpalBlockSid fail\n")); > + break; > + } > + } > + > + Itr =3D 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 =3D=3D NULL || AllHandlesBuffer =3D=3D NULL || NumAllHandles = =3D=3D 0) { > + return FALSE; > + } > + > + Protocol =3D UseComp1 ? gEfiComponentNameProtocolGuid : > gEfiComponentName2ProtocolGuid; > + > + // > + // Find all EFI_HANDLES with protocol > + // > + Status =3D gBS->LocateHandleBuffer( > + ByProtocol, > + &Protocol, > + NULL, > + &NumProtocolHandles, > + &ProtocolHandlesBuffer > + ); > + if (EFI_ERROR(Status)) { > + return FALSE; > + } > + > + > + // > + // Exit early if no supported devices > + // > + if (NumProtocolHandles =3D=3D 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 inte= rnal list > + // > + Status =3D EFI_DEVICE_ERROR; > + for (Index1 =3D 0; Index1 < NumProtocolHandles; Index1++) { > + DevName =3D NULL; > + > + if (Dev->Name16 !=3D NULL) { > + return TRUE; > + } > + > + TmpHandle =3D ProtocolHandlesBuffer[Index1]; > + > + Status =3D gBS->OpenProtocol( > + TmpHandle, > + &Protocol, > + (VOID**)&Cnp1_2, > + gImageHandle, > + NULL, > + EFI_OPEN_PROTOCOL_GET_PROTOCOL > + ); > + if (EFI_ERROR(Status) || Cnp1_2 =3D=3D NULL) { > + continue; > + } > + > + // > + // Use all handles array as controller handle > + // > + for (Index2 =3D 0; Index2 < NumAllHandles; Index2++) { > + Status =3D Cnp1_2->GetControllerName( > + Cnp1_2, > + AllHandlesBuffer[Index2], > + Dev->Handle, > + LANGUAGE_ISO_639_2_ENGLISH, > + &DevName > + ); > + if (EFI_ERROR(Status)) { > + Status =3D Cnp1_2->GetControllerName( > + Cnp1_2, > + AllHandlesBuffer[Index2], > + Dev->Handle, > + LANGUAGE_RFC_3066_ENGLISH, > + &DevName > + ); > + } > + if (!EFI_ERROR(Status) && DevName !=3D NULL) { > + StrLength =3D StrLen(DevName) + 1; // Add one for NULL > terminator > + Dev->Name16 =3D AllocateZeroPool(StrLength * sizeof (CHAR16)); > + ASSERT (Dev->Name16 !=3D NULL); > + StrCpyS (Dev->Name16, StrLength, DevName); > + Dev->NameZ =3D (CHAR8*)AllocateZeroPool(StrLength); > + UnicodeStrToAsciiStrS (DevName, Dev->NameZ, StrLength); > + > + // > + // Retrieve bridge BDF info and port number or namespace dependi= ng > on type > + // > + TmpDevPath =3D NULL; > + Status =3D gBS->OpenProtocol( > + Dev->Handle, > + &gEfiDevicePathProtocolGuid, > + (VOID**)&TmpDevPath, > + gImageHandle, > + NULL, > + EFI_OPEN_PROTOCOL_GET_PROTOCOL > + ); > + if (!EFI_ERROR(Status)) { > + Dev->OpalDevicePath =3D DuplicateDevicePath (TmpDevPath); > + return TRUE; > + } > + > + if (Dev->Name16 !=3D NULL) { > + FreePool(Dev->Name16); > + Dev->Name16 =3D NULL; > + } > + if (Dev->NameZ !=3D NULL) { > + FreePool(Dev->NameZ); > + Dev->NameZ =3D 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 =3D=3D NULL) { > + DEBUG((DEBUG_ERROR | DEBUG_INIT, "OpalDriverGetDriverDeviceName > Exiting, Dev=3DNULL\n")); > + return FALSE; > + } > + > + // > + // Iterate through ComponentName2 handles to get name, if fails, try > ComponentName > + // > + if (Dev->Name16 =3D=3D NULL) { > + DEBUG((DEBUG_ERROR | DEBUG_INIT, "Name is null, update it\n")); > + // > + // Find all EFI_HANDLES > + // > + Status =3D 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 =3D 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 =3D ImageHandle; > + > + Status =3D 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 =3D 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 requir= es > 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 =3D gBS->OpenProtocol( > + Controller, > + &gEfiStorageSecurityCommandProtocolGuid, > + ( VOID ** )&SecurityCommand, > + This->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_BY_DRIVER > + ); > + > + if (Status =3D=3D 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 =3D 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 verify= ing the > device supports > + the correct version of Opal. Upon verification, it will add the devic= e 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 star= t. > 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 o= f > 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 a= re > created by this driver. > + If this parameter is not NULL and th= e > 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 devic= e. > + > +**/ > +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 =3D mOpalDriver.DeviceList; > + while (Itr !=3D NULL) { > + if (Controller =3D=3D Itr->Handle) { > + return EFI_SUCCESS; > + } > + Itr =3D Itr->Next; > + } > + > + // > + // Create internal device for tracking. This allows all disks to be t= racked > + // by same HII form > + // > + Dev =3D > (OPAL_DRIVER_DEVICE*)AllocateZeroPool(sizeof(OPAL_DRIVER_DEVICE)); > + if (Dev =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + Dev->Handle =3D Controller; > + > + // > + // Open EFI_STORAGE_SECURITY_COMMAND_PROTOCOL to perform Opal > supported checks > + // > + Status =3D 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 =3D 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 =3D BlkIo->Media->MediaId; > + > + gBS->CloseProtocol( > + Controller, > + &gEfiBlockIoProtocolGuid, > + This->DriverBindingHandle, > + Controller > + ); > + > + // > + // Acquire Ascii printable name of child, if not found, then ignore de= vice > + // > + Result =3D OpalDriverGetDriverDeviceName (Dev); > + if (!Result) { > + goto Done; > + } > + > + Status =3D 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 =3D mOpalDriver.DeviceList; > + > + // > + // does Controller match any of the devices we are managing for Opal > + // > + while (Itr !=3D NULL) { > + if (Itr->Handle =3D=3D Controller) { > + OpalDriverStopDevice (Itr); > + return EFI_SUCCESS; > + } > + > + Itr =3D 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 =3D EFI_SUCCESS; > + > + if (ImageHandle !=3D gImageHandle) { > + return (EFI_INVALID_PARAMETER); > + } > + > + // > + // Uninstall any interface added to each device by us > + // > + while (mOpalDriver.DeviceList) { > + Itr =3D mOpalDriver.DeviceList; > + // > + // Remove OPAL_DRIVER_DEVICE from the list > + // it updates the controllerList pointer > + // > + OpalDriverStopDevice(Itr); > + } > + > + // > + // Uninstall the HII capability > + // > + Status =3D 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.
> +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BS= D > License > +which accompanies this distribution. The full text of the license may b= e 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 > + > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#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 Opal= Disk. > +// The data can then be utilized to expose/hide certain actions availabl= e to an > end user > +// by the consumer of this library. > +// > +typedef struct { > + // > + // Indicates if the disk can support PSID Revert action. should ver= ify 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 tr= ue 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 cur= rently > locked. > + // > + UINT16 Unlock : 1; > + > + // > + // Indicates if Secure Erase action is available. Action requires a= dmin > credentials and media encryption support. > + // > + UINT16 SecureErase : 1; > + > + // > + // Indicates if Disable User action is available. Action requires a= dmin > 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 Discove= ry > + 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 controll= ers > owned by this Driver > +} OPAL_DRIVER; > + > +#pragma pack() > + > +// > +// Retrieves a OPAL_DRIVER_DEVICE based on the pointer to its StorageSec= urity > 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_DI= SK > provided. > + > + @param[in] SupportedAttributes The support attribute for the devic= e. > + @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 appropriat= e > 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 devic= e. > + @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 dev= ice. > + @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 verify= ing the > device supports > + the correct version of Opal. Upon verification, it will add the devic= e 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 star= t. > 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 o= f > 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 a= re > created by this driver. > + If this parameter is not NULL and th= e > 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 devic= e. > + > +**/ > +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 drive= r. > + > + 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 na= me 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 spe= cified > + 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 t= he > + 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 specif= ied > + 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 specif= ied > 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 contr= oller > + that is being managed by a driver. > + > + This function retrieves the user readable name of the controller speci= fied by > + ControllerHandle and ChildHandle in the form of a Unicode string. If t= he > + driver specified by This has a user readable name in the language spec= ified 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 c= urrently > + managing the controller specified by ControllerHandle and ChildHandle, > + then EFI_UNSUPPORTED is returned. If the driver specified by This doe= s 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 driv= er > + specified by This is managing. This > handle > + specifies the controller whose name is t= o > 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 bu= s > + controller. It will not be NULL for a b= us > + 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 specif= ied > in > + RFC 4646 or ISO 639-2 language code > format. > + > + @param ControllerName[out] A pointer to the Unicode string to retur= n. > + 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 drive= r. > + > + 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 na= me 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 spe= cified > + 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 t= he > + 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 specif= ied > + 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 specif= ied > 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 contr= oller > + that is being managed by a driver. > + > + This function retrieves the user readable name of the controller speci= fied by > + ControllerHandle and ChildHandle in the form of a Unicode string. If t= he > + driver specified by This has a user readable name in the language spec= ified 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 c= urrently > + managing the controller specified by ControllerHandle and ChildHandle, > + then EFI_UNSUPPORTED is returned. If the driver specified by This doe= s 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 driv= er > + specified by This is managing. This > handle > + specifies the controller whose name is t= o > 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 bu= s > + controller. It will not be NULL for a b= us > + 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 specif= ied > in > + RFC 4646 or ISO 639-2 language code > format. > + > + @param ControllerName[out] A pointer to the Unicode string to retur= n. > + 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.
> +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BS= D > License > +which accompanies this distribution. The full text of the license may b= e 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[] =3D L"OpalHiiConfig"; > + > +EFI_HII_CONFIG_ACCESS_PROTOCOL gHiiConfigAccessProtocol; > + > +// > +// Handle to the list of HII packages (forms and strings) for this drive= r > +// > +EFI_HII_HANDLE gHiiPackageListHandle =3D NULL; > + > +// > +// Package List GUID containing all form and string packages > +// > +const EFI_GUID gHiiPackageListGuid =3D PACKAGE_LIST_GUID; > +const EFI_GUID gHiiSetupVariableGuid =3D 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 =3D { > + { > + { > + 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 =3D NULL; > + VariableSize =3D 0; > + > + Status =3D GetVariable2 ( > + OPAL_REQUEST_VARIABLE_NAME, > + &gHiiSetupVariableGuid, > + (VOID **) &Variable, > + &VariableSize > + ); > + if (EFI_ERROR (Status) || (Variable =3D=3D NULL)) { > + return; > + } > + > + TempVariable =3D Variable; > + while ((VariableSize > sizeof (OPAL_REQUEST_VARIABLE)) && > + (VariableSize >=3D TempVariable->Length) && > + (TempVariable->Length > sizeof (OPAL_REQUEST_VARIABLE))) { > + DevicePathInVariable =3D (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) > TempVariable + sizeof (OPAL_REQUEST_VARIABLE)); > + DevicePathSizeInVariable =3D GetDevicePathSize (DevicePathInVariable= ); > + DevicePath =3D OpalDisk->OpalDevicePath; > + DevicePathSize =3D GetDevicePathSize (DevicePath); > + if ((DevicePathSize =3D=3D DevicePathSizeInVariable) && > + (CompareMem (DevicePath, DevicePathInVariable, DevicePathSize) > =3D=3D 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 -=3D TempVariable->Length; > + TempVariable =3D (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 =3D NULL; > + VariableSize =3D 0; > + NewVariable =3D NULL; > + NewVariableSize =3D 0; > + > + Status =3D GetVariable2 ( > + OPAL_REQUEST_VARIABLE_NAME, > + &gHiiSetupVariableGuid, > + (VOID **) &Variable, > + &VariableSize > + ); > + if (!EFI_ERROR (Status) && (Variable !=3D NULL)) { > + TempVariable =3D Variable; > + TempVariableSize =3D VariableSize; > + while ((TempVariableSize > sizeof (OPAL_REQUEST_VARIABLE)) && > + (TempVariableSize >=3D TempVariable->Length) && > + (TempVariable->Length > sizeof (OPAL_REQUEST_VARIABLE))) { > + DevicePathInVariable =3D (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) > TempVariable + sizeof (OPAL_REQUEST_VARIABLE)); > + DevicePathSizeInVariable =3D GetDevicePathSize (DevicePathInVariab= le); > + DevicePath =3D OpalDisk->OpalDevicePath; > + DevicePathSize =3D GetDevicePathSize (DevicePath); > + if ((DevicePathSize =3D=3D DevicePathSizeInVariable) && > + (CompareMem (DevicePath, DevicePathInVariable, DevicePathSize) > =3D=3D 0)) { > + // > + // Found the node for the OPAL device. > + // Update the OPAL request. > + // > + CopyMem (&TempVariable->OpalRequest, &OpalRequest, sizeof > (OPAL_REQUEST)); > + NewVariable =3D Variable; > + NewVariableSize =3D VariableSize; > + break; > + } > + TempVariableSize -=3D TempVariable->Length; > + TempVariable =3D (OPAL_REQUEST_VARIABLE *) ((UINTN) TempVariable + > TempVariable->Length); > + } > + if (NewVariable =3D=3D NULL) { > + // > + // The node for the OPAL device is not found. > + // Create node for the OPAL device. > + // > + DevicePath =3D OpalDisk->OpalDevicePath; > + DevicePathSize =3D GetDevicePathSize (DevicePath); > + NewVariableSize =3D VariableSize + sizeof (OPAL_REQUEST_VARIABLE) = + > DevicePathSize; > + NewVariable =3D AllocatePool (NewVariableSize); > + ASSERT (NewVariable !=3D NULL); > + CopyMem (NewVariable, Variable, VariableSize); > + TempVariable =3D (OPAL_REQUEST_VARIABLE *) ((UINTN) NewVariable + > VariableSize); > + TempVariable->Length =3D (UINT32) (sizeof (OPAL_REQUEST_VARIABLE) = + > DevicePathSize); > + CopyMem (&TempVariable->OpalRequest, &OpalRequest, sizeof > (OPAL_REQUEST)); > + DevicePathInVariable =3D (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) > TempVariable + sizeof (OPAL_REQUEST_VARIABLE)); > + CopyMem (DevicePathInVariable, DevicePath, DevicePathSize); > + } > + } else { > + DevicePath =3D OpalDisk->OpalDevicePath; > + DevicePathSize =3D GetDevicePathSize (DevicePath); > + NewVariableSize =3D sizeof (OPAL_REQUEST_VARIABLE) + DevicePathSize; > + NewVariable =3D AllocatePool (NewVariableSize); > + ASSERT (NewVariable !=3D NULL); > + NewVariable->Length =3D (UINT32) (sizeof (OPAL_REQUEST_VARIABLE) + > DevicePathSize); > + CopyMem (&NewVariable->OpalRequest, &OpalRequest, sizeof > (OPAL_REQUEST)); > + DevicePathInVariable =3D (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) > NewVariable + sizeof (OPAL_REQUEST_VARIABLE)); > + CopyMem (DevicePathInVariable, DevicePath, DevicePathSize); > + } > + Status =3D 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 !=3D Variable) { > + FreePool (NewVariable); > + } > + if (Variable !=3D 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 =3D GetDeviceCount(); > + > + // > + // Update the BlockSID status string. > + // > + PpStorageFlag =3D Tcg2PhysicalPresenceLibGetManagementFlags (); > + > + if ((PpStorageFlag & > TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID) !=3D 0) { > + NewString =3D HiiGetString (gHiiPackageListHandle, > STRING_TOKEN(STR_ENABLED), NULL); > + if (NewString =3D=3D NULL) { > + DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( ) > failed\n")); > + return; > + } > + } else { > + NewString =3D HiiGetString (gHiiPackageListHandle, > STRING_TOKEN(STR_DISABLED), NULL); > + if (NewString =3D=3D 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) !=3D 0) { > + NewString =3D HiiGetString (gHiiPackageListHandle, > STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_TRUE), NULL); > + if (NewString =3D=3D NULL) { > + DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( ) > failed\n")); > + return; > + } > + } else { > + NewString =3D HiiGetString (gHiiPackageListHandle, > STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_FALSE), NULL); > + if (NewString =3D=3D 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) !=3D 0) { > + NewString =3D HiiGetString (gHiiPackageListHandle, > STRING_TOKEN(STR_DISK_INFO_DISABLE_BLOCKSID_TRUE), NULL); > + if (NewString =3D=3D NULL) { > + DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( ) > failed\n")); > + return; > + } > + } else { > + NewString =3D HiiGetString (gHiiPackageListHandle, > STRING_TOKEN(STR_DISK_INFO_DISABLE_BLOCKSID_FALSE), NULL); > + if (NewString =3D=3D 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 =3D HiiGetDriverImageHandleCB(); > + > + // > + // Populate the config access protocol with the three functions we are > publishing > + // > + gHiiConfigAccessProtocol.ExtractConfig =3D ExtractConfig; > + gHiiConfigAccessProtocol.RouteConfig =3D RouteConfig; > + gHiiConfigAccessProtocol.Callback =3D DriverCallback; > + > + // > + // Associate the required protocols with our driver handle > + // > + Status =3D gBS->InstallMultipleProtocolInterfaces( > + &DriverHandle, > + &gEfiHiiConfigAccessProtocolGuid, > + &gHiiConfigAccessProtocol, // HII callback > + &gEfiDevicePathProtocolGuid, > + &gHiiVendorDevicePath, // required for HII callbac= k > 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 =3D HiiGetDriverImageHandleCB(); > + > + // > + // Publish the HII form and HII string packages > + // > + gHiiPackageListHandle =3D HiiAddPackages( > + &gHiiPackageListGuid, > + DriverHandle, > + OpalPasswordDxeStrings, > + OpalPasswordFormBin, > + (VOID*)NULL > + ); > + > + // > + // Make sure the packages installed successfully > + // > + if (gHiiPackageListHandle =3D=3D NULL) { > + DEBUG ((DEBUG_INFO, "OpalHiiAddPackages failed\n")); > + return EFI_OUT_OF_RESOURCES; > + } > + > + // > + // Update Version String in main window > + // > + NewString =3D HiiGetDriverNameCB (); > + if (HiiSetString(gHiiPackageListHandle, > STRING_TOKEN(STR_MAIN_OPAL_VERSION), NewString, NULL) =3D=3D 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 hi= i > 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 =3D 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 =3D 0; > + > + for (Index =3D 0; Index < gHiiConfiguration.NumDisks; Index++) { > + OpalDisk =3D HiiGetOpalDiskCB (Index); > + if ((OpalDisk !=3D NULL) && OpalFeatureSupported > (&OpalDisk->SupportedAttributes)) { > + gHiiConfiguration.SupportedDisks |=3D (1 << Index); > + DiskNameId =3D GetDiskNameStringId (Index); > + DiskName =3D HiiDiskGetNameCB (Index); > + if ((DiskName =3D=3D NULL) || (DiskNameId =3D=3D 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 t= he > browser. > + @param QuestionId A unique value which is sent to the > original > + exporting driver so that it can identif= y > 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 !=3D NULL) { > + *ActionRequest =3D EFI_BROWSER_ACTION_REQUEST_NONE; > + } else { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // If QuestionId is an auto-generated key (label, empty line, etc.), i= gnore it. > + // > + if ((QuestionId & HII_KEY_FLAG) =3D=3D 0) { > + return EFI_SUCCESS; > + } > + > + HiiKey.Raw =3D QuestionId; > + HiiKeyId =3D (UINT8) HiiKey.KeyBits.Id; > + > + if (Action =3D=3D 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 =3D=3D EFI_BROWSER_ACTION_CHANGING) { > + switch (HiiKeyId) { > + case HII_KEY_ID_GOTO_DISK_INFO: > + return HiiSelectDisk((UINT8)HiiKey.KeyBits.Index); > + } > + } else if (Action =3D=3D EFI_BROWSER_ACTION_CHANGED) { > + switch (HiiKeyId) { > + case HII_KEY_ID_BLOCKSID: > + switch (Value->u8) { > + case 0: > + PpRequest =3D TCG2_PHYSICAL_PRESENCE_NO_ACTION; > + break; > + > + case 1: > + PpRequest =3D TCG2_PHYSICAL_PRESENCE_ENABLE_BLOCK_SID; > + break; > + > + case 2: > + PpRequest =3D TCG2_PHYSICAL_PRESENCE_DISABLE_BLOCK_SID; > + break; > + > + case 3: > + PpRequest =3D > TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FU > NC_TRUE; > + break; > + > + case 4: > + PpRequest =3D > TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FU > NC_FALSE; > + break; > + > + case 5: > + PpRequest =3D > TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FU > NC_TRUE; > + break; > + > + case 6: > + PpRequest =3D > TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FU > NC_FALSE; > + break; > + > + default: > + PpRequest =3D TCG2_PHYSICAL_PRESENCE_NO_ACTION; > + DEBUG ((DEBUG_ERROR, "Invalid value input!\n")); > + break; > + } > + HiiSetBlockSidAction(PpRequest); > + > + *ActionRequest =3D 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 =3D Value->b; > + OpalDisk =3D HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskInde= x); > + if (OpalDisk !=3D NULL) { > + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest); > + } > + *ActionRequest =3D 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 =3D Value->b; > + OpalDisk =3D HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskInde= x); > + if (OpalDisk !=3D NULL) { > + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest); > + } > + *ActionRequest =3D 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 =3D Value->b; > + OpalDisk =3D HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskInde= x); > + if (OpalDisk !=3D NULL) { > + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest); > + } > + *ActionRequest =3D 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 =3D Value->b; > + OpalDisk =3D HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskInde= x); > + if (OpalDisk !=3D NULL) { > + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest); > + } > + *ActionRequest =3D 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 =3D Value->b; > + OpalDisk =3D HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskInde= x); > + if (OpalDisk !=3D NULL) { > + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest); > + } > + *ActionRequest =3D 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 =3D Value->b; > + OpalDisk =3D HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskInde= x); > + if (OpalDisk !=3D NULL) { > + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest); > + } > + *ActionRequest =3D 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 =3D Value->b; > + OpalDisk =3D HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskInde= x); > + if (OpalDisk !=3D NULL) { > + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest); > + } > + *ActionRequest =3D 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 =3D Value->b; > + OpalDisk =3D HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskInde= x); > + if (OpalDisk !=3D NULL) { > + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest); > + } > + *ActionRequest =3D 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 =3D 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 =3D HiiDiskGetNameCB (gHiiConfiguration.SelectedDiskIndex); > + if (DiskName =3D=3D NULL) { > + return EFI_UNSUPPORTED; > + } > + HiiSetFormString(STRING_TOKEN(STR_DISK_INFO_SELECTED_DISK_NAME), > DiskName); > + > + gHiiConfiguration.SelectedDiskAvailableActions =3D HII_ACTION_NONE; > + ZeroMem (&gHiiConfiguration.OpalRequest, sizeof (OPAL_REQUEST)); > + gHiiConfiguration.KeepUserDataForced =3D FALSE; > + > + OpalDisk =3D HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex); > + > + if (OpalDisk !=3D NULL) { > + OpalDiskUpdateStatus (OpalDisk); > + Ret =3D OpalSupportGetAvailableActions(&OpalDisk->SupportedAttribute= s, > &OpalDisk->LockingFeature, OpalDisk->Owner, &AvailActions); > + if (Ret =3D=3D TcgResultSuccess) { > + // > + // Update actions, always allow PSID Revert > + // > + gHiiConfiguration.SelectedDiskAvailableActions |=3D > (AvailActions.PsidRevert =3D=3D 1) ? HII_ACTION_PSID_REVERT : > HII_ACTION_NONE; > + > + // > + // Always allow unlock to handle device migration > + // > + gHiiConfiguration.SelectedDiskAvailableActions |=3D (AvailActions.= Unlock > =3D=3D 1) ? HII_ACTION_UNLOCK : HII_ACTION_NONE; > + > + if (!OpalFeatureEnabled (&OpalDisk->SupportedAttributes, > &OpalDisk->LockingFeature)) { > + if (OpalDisk->Owner =3D=3D OpalOwnershipNobody) { > + gHiiConfiguration.SelectedDiskAvailableActions |=3D > 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 !=3D > nobody\n")); > + } > + } else { > + gHiiConfiguration.SelectedDiskAvailableActions |=3D > (AvailActions.Revert =3D=3D 1) ? HII_ACTION_REVERT : HII_ACTION_NONE; > + gHiiConfiguration.SelectedDiskAvailableActions |=3D > (AvailActions.AdminPass =3D=3D 1) ? HII_ACTION_SET_ADMIN_PWD : > HII_ACTION_NONE; > + gHiiConfiguration.SelectedDiskAvailableActions |=3D > (AvailActions.UserPass =3D=3D 1) ? HII_ACTION_SET_USER_PWD : > HII_ACTION_NONE; > + gHiiConfiguration.SelectedDiskAvailableActions |=3D > (AvailActions.SecureErase =3D=3D 1) ? HII_ACTION_SECURE_ERASE : > HII_ACTION_NONE; > + gHiiConfiguration.SelectedDiskAvailableActions |=3D > (AvailActions.DisableUser =3D=3D 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 =3D 1; > + if (AvailActions.RevertKeepDataForced) { > + gHiiConfiguration.KeepUserDataForced =3D 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 =3D Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction > (PpRequest, 0); > + if (ReturnCode =3D=3D TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS) { > + Status =3D EFI_SUCCESS; > + } else if (ReturnCode =3D=3D > TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE) { > + Status =3D EFI_OUT_OF_RESOURCES; > + } else if (ReturnCode =3D=3D > TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED) { > + Status =3D EFI_UNSUPPORTED; > + } else { > + Status =3D 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 > > + format. > + @param Progress A pointer to a string filled in with th= e > offset of > + the most recent '&' before the first > failing > + name/value pair (or the beginning of th= e > 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 =3D=3D NULL || Progress =3D=3D NULL) { > + return (EFI_INVALID_PARAMETER); > + } > + > + *Progress =3D Configuration; > + if (!HiiIsConfigHdrMatch (Configuration, &gHiiSetupVariableGuid, > OpalPasswordStorageName)) { > + return EFI_NOT_FOUND; > + } > + > + *Progress =3D 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 > + 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 fail= ure > is in > + the first name/value pair) if the reque= st > was not > + successful. > + @param Results A null-terminated Unicode string in > + 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 requeste= d > 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 =3D=3D NULL || Results =3D=3D NULL) { > + return (EFI_INVALID_PARAMETER); > + } > + > + *Progress =3D Request; > + if ((Request !=3D NULL) && > + !HiiIsConfigHdrMatch (Request, &gHiiSetupVariableGuid, > OpalPasswordStorageName)) { > + return EFI_NOT_FOUND; > + } > + > + AllocatedRequest =3D FALSE; > + BufferSize =3D sizeof (OPAL_HII_CONFIGURATION); > + ConfigRequest =3D Request; > + if ((Request =3D=3D NULL) || (StrStr (Request, L"OFFSET") =3D=3D NULL)= ) { > + // > + // Request has no request element, construct full request string. > + // Allocate and fill a buffer large enough to hold the t= emplate > + // followed by "&OFFSET=3D0&WIDTH=3DWWWWWWWWWWWWWWWW" > followed by a Null-terminator > + // > + DriverHandle =3D HiiGetDriverImageHandleCB(); > + ConfigRequestHdr =3D HiiConstructConfigHdr (&gHiiSetupVariableGuid, > OpalPasswordStorageName, DriverHandle); > + Size =3D (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16); > + ConfigRequest =3D AllocateZeroPool (Size); > + if (ConfigRequest =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + AllocatedRequest =3D TRUE; > + UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=3D0&WIDTH=3D%016LX", > ConfigRequestHdr, (UINT64)BufferSize); > + FreePool (ConfigRequestHdr); > + } > + > + // > + // Convert Buffer Data to by helper function BlockToConfi= g( ) > + // > + Status =3D gHiiConfigRouting->BlockToConfig( > + gHiiConfigRouting, > + ConfigRequest, > + (UINT8*)&gHiiConfiguration, > + sizeof(OPAL_HII_CONFIGURATION), > + Results, > + Progress > + ); > + > + // > + // Free the allocated config request string. > + // > + if (AllocatedRequest) { > + FreePool (ConfigRequest); > + ConfigRequest =3D NULL; > + } > + > + // > + // Set Progress string to the original request string. > + // > + if (Request =3D=3D NULL) { > + *Progress =3D NULL; > + } else if (StrStr (Request, L"OFFSET") =3D=3D NULL) { > + *Progress =3D 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 =3D ( UINT32 )AsciiStrLen( SrcAsciiStr ); > + > + // > + // Allocate space for the unicode string, including terminator > + // > + UniSize =3D (Len + 1) * sizeof(CHAR16); > + UniStr =3D (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) = =3D=3D 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 =3D Dev->Sscp; > + Dev->OpalDisk.MediaId =3D Dev->MediaId; > + Dev->OpalDisk.OpalDevicePath =3D Dev->OpalDevicePath; > + > + ZeroMem(&Session, sizeof(Session)); > + Session.Sscp =3D Dev->Sscp; > + Session.MediaId =3D Dev->MediaId; > + > + TcgResult =3D OpalGetSupportedAttributesInfo (&Session, > &Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.OpalBaseComId); > + if (TcgResult !=3D TcgResultSuccess) { > + return EFI_DEVICE_ERROR; > + } > + Session.OpalBaseComId =3D Dev->OpalDisk.OpalBaseComId; > + > + TcgResult =3D OpalUtilGetMsid (&Session, Dev->OpalDisk.Msid, > OPAL_MSID_LENGHT, &Dev->OpalDisk.MsidLength); > + if (TcgResult !=3D 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 =3D OpalDisk->Sscp; > + Session.MediaId =3D OpalDisk->MediaId; > + Session.OpalBaseComId =3D OpalDisk->OpalBaseComId; > + > + TcgResult =3D OpalGetLockingInfo(&Session, &OpalDisk->LockingFeature); > + if (TcgResult !=3D TcgResultSuccess) { > + return EFI_DEVICE_ERROR; > + } > + > + if (OpalDisk->MsidLength =3D=3D 0) { > + return EFI_INVALID_PARAMETER; > + } else { > + // > + // Base on the Msid info to get the ownership, so Msid info must get= first. > + // > + OpalDisk->Owner =3D 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.
> +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BS= D > License > +which accompanies this distribution. The full text of the license may b= e 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 > + > +#include "OpalDriver.h" > +#include "OpalHiiFormValues.h" > + > +#define OPAL_PASSWORD_CONFIG_GUID \ > + { \ > + 0x0d510a4f, 0xa81b, 0x473f, { 0x87, 0x07, 0xb7, 0xfd, 0xfb, 0xc0, 0x= 45, > 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 > > + format. > + @param Progress A pointer to a string filled in with th= e > offset of > + the most recent '&' before the first > failing > + name/value pair (or the beginning of th= e > 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 > + 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 fail= ure > is in > + the first name/value pair) if the reque= st > was not > + successful. > + @param Results A null-terminated Unicode string in > + 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 requeste= d > 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 t= he > browser. > + @param QuestionId A unique value which is sent to the > original > + exporting driver so that it can identif= y > 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 hi= i > 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.
> +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BS= D > License > +which accompanies this distribution. The full text of the license may b= e 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 =3D DRIVER_DEVICE_FROM_OPALDISK(OpalDisk); > + if (Dev =3D=3D NULL) { > + return NULL; > + } > + > + PrefixLen =3D StrLen(Prefix); > + > + NameLen =3D 0; > + if (Dev->Name16 !=3D NULL) { > + NameLen =3D StrLen(Dev->Name16); > + } > + > + VarNameLen =3D PrefixLen + NameLen; > + > + VarName =3D (CHAR16*)AllocateZeroPool((VarNameLen + 1) * > sizeof(CHAR16)); > + if (VarName =3D=3D NULL) { > + return NULL; > + } > + > + CopyMem(VarName, Prefix, PrefixLen * sizeof(CHAR16)); > + if (Dev->Name16 !=3D NULL) { > + CopyMem(VarName + PrefixLen, Dev->Name16, NameLen * > sizeof(CHAR16)); > + } > + VarName[VarNameLen] =3D 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 =3D 0; > + > + NumDisks =3D GetDeviceCount(); > + > + for (Index =3D 0; Index < NumDisks; Index++) { > + OpalDisk =3D HiiGetOpalDiskCB(Index); > + > + if (OpalDisk !=3D NULL) { > + if (!OpalFeatureEnabled (&OpalDisk->SupportedAttributes, > &OpalDisk->LockingFeature)) { > + DEBUG ((DEBUG_INFO, "Ignoring disk %u because feature is disable= d > 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 =3D OpalDriverGetDeviceList(); > + CurrentDisk =3D 0; > + > + if (DiskIndex >=3D GetDeviceCount()) { > + return NULL; > + } > + > + while (Dev !=3D NULL) { > + if (CurrentDisk =3D=3D DiskIndex) { > + return Dev; > + } else { > + Dev =3D 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 =3D HiiGetDiskContextCB (DiskIndex); > + > + if (Ctx =3D=3D NULL) { > + return NULL; > + } > + > + Tmp =3D (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 =3D (OPAL_DRIVER_DEVICE*) HiiGetDiskContextCB (DiskIndex); > + > + if (Ctx !=3D NULL) { > + if (Ctx->NameZ =3D=3D 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. > +// > +// 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. > +// > +// **/ > + > +/=3D# > +///////////////////////////////// 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 sensiti= ve 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.
> +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BS= D > License > +which accompanies this distribution. The full text of the license may b= e 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_ITE= M > + * all bits together must be <=3D 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.
> +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BS= D > License > +which accompanies this distribution. The full text of the license may b= e 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) =3D MmioRead32 (MmioAddr); > + break; > + > + case 8: > + *((UINT64 *)MemBuffer) =3D MmioRead64 (MmioAddr); > + break; > + > + case 2: > + *((UINT16 *)MemBuffer) =3D MmioRead16 (MmioAddr); > + break; > + > + case 1: > + *((UINT8 *)MemBuffer) =3D MmioRead8 (MmioAddr); > + break; > + > + default: > + Ptr =3D (UINT8 *)MemBuffer; > + for (Offset =3D 0; Offset < Size; Offset +=3D 1) { > + Data =3D MmioRead8 (MmioAddr + Offset); > + Ptr[Offset] =3D 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 =3D (UINT8 *)MemBuffer; > + for (Offset =3D 0; Offset < Size; Offset +=3D 1) { > + Data =3D 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) =3D PciRead32 (MmioAddr); > + break; > + > + case 2: > + *((UINT16 *)MemBuffer) =3D PciRead16 (MmioAddr); > + break; > + > + case 1: > + *((UINT8 *)MemBuffer) =3D PciRead8 (MmioAddr); > + break; > + > + default: > + Ptr =3D (UINT8 *)MemBuffer; > + for (Offset =3D 0; Offset < Size; Offset +=3D 1) { > + Data =3D PciRead8 (MmioAddr + Offset); > + Ptr[Offset] =3D 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 =3D (UINT8 *)MemBuffer; > + for (Offset =3D 0; Offset < Size; Offset +=3D 1) { > + Data =3D 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] =3D 1; /* Controller Data */ > + PageSizeList[1] =3D 1; /* Identify Data */ > + PageSizeList[2] =3D 1; /* ASQ */ > + PageSizeList[3] =3D 1; /* ACQ */ > + PageSizeList[4] =3D 1; /* SQs */ > + PageSizeList[5] =3D 1; /* CQs */ > + PageSizeList[6] =3D NVME_PRP_SIZE * NVME_CSQ_DEPTH; /* PRPs */ > + PageSizeList[7] =3D 1; /* Security Commands */ > + > + if (BaseMemIndex > MAX_BASEMEM_COUNT) { > + ASSERT (FALSE); > + return 0; > + } > + > + Pages =3D 0; > + for (Index =3D 0; Index < BaseMemIndex; Index++) { > + Pages +=3D 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 stat= us. > + @return others - Fail to wait for specific controll= er > 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 t= o 500 * > Cap.To. > + // > + if (Nvme->Cap.To =3D=3D 0) { > + Timeout =3D 1; > + } else { > + Timeout =3D Nvme->Cap.To; > + } > + > + Status =3D EFI_SUCCESS; > + for(Index =3D (Timeout * 500); Index !=3D 0; --Index) { > + MicroSecondDelay (1000); > + > + // > + // Check if the controller is initialized > + // > + Status =3D NVME_GET_CSTS (Nvme, &Csts); > + if (EFI_ERROR(Status)) { > + DEBUG ((DEBUG_ERROR, "NVME_GET_CSTS fail, Status =3D %r\n", > Status)); > + return Status; > + } > + > + if ((BOOLEAN) Csts.Rdy =3D=3D WaitReady) { > + break; > + } > + } > + > + if (Index =3D=3D 0) { > + Status =3D 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 controlle= r. > + @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 =3D NVME_GET_CSTS (Nvme, &Csts); > + > + /// > + /// Read Controller Configuration Register. > + /// > + Status =3D NVME_GET_CC (Nvme, &Cc); > + if (EFI_ERROR(Status)) { > + DEBUG ((DEBUG_ERROR, "NVME_GET_CC fail, Status =3D %r\n", Status)); > + goto Done; > + } > + > + if (Cc.En =3D=3D 1) { > + Cc.En =3D 0; > + /// > + /// Disable the controller. > + /// > + Status =3D NVME_SET_CC (Nvme, &Cc); > + if (EFI_ERROR(Status)) { > + DEBUG ((DEBUG_ERROR, "NVME_SET_CC fail, Status =3D %r\n", Status))= ; > + goto Done; > + } > + } > + > + Status =3D NvmeWaitController (Nvme, FALSE); > + if (EFI_ERROR(Status)) { > + DEBUG ((DEBUG_ERROR, "NvmeWaitController fail, Status =3D %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 =3D 1; > + Cc.Iosqes =3D 6; > + Cc.Iocqes =3D 4; > + Status =3D NVME_SET_CC (Nvme, &Cc); > + if (EFI_ERROR(Status)) { > + DEBUG ((DEBUG_ERROR, "NVME_SET_CC fail, Status =3D %r\n", Status)); > + goto Done; > + } > + > + Status =3D NvmeWaitController (Nvme, TRUE); > + if (EFI_ERROR(Status)) { > + DEBUG ((DEBUG_ERROR, "NvmeWaitController fail, Status =3D %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 =3D NVME_GET_CC (Nvme, &Cc); > + if (EFI_ERROR(Status)) { > + DEBUG ((DEBUG_ERROR, "NVME_GET_CC fail, Status =3D %r\n", Status)); > + return Status; > + } > + > + Cc.Shn =3D 1; // Normal shutdown > + > + Status =3D NVME_SET_CC (Nvme, &Cc); > + if (EFI_ERROR(Status)) { > + DEBUG ((DEBUG_ERROR, "NVME_SET_CC fail, Status =3D %r\n", Status)); > + return Status; > + } > + > + Timeout =3D NVME_GENERIC_TIMEOUT/1000; // ms > + for(Index =3D (UINT32)(Timeout); Index !=3D 0; --Index) { > + MicroSecondDelay (1000); > + > + Status =3D NVME_GET_CSTS (Nvme, &Csts); > + if (EFI_ERROR(Status)) { > + DEBUG ((DEBUG_ERROR, "NVME_GET_CSTS fail, Status =3D %r\n", > Status)); > + return Status; > + } > + > + if (Csts.Shst =3D=3D 2) { // Shutdown processing complete > + break; > + } > + } > + > + if (Index =3D=3D 0) { > + Status =3D 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 =3D=3D 0x0 && Cq->Sc =3D=3D 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 th= em 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 =3D EFI_PAGE_SIZE / sizeof (UINT64); > + > + /// > + /// Calculate total PrpList number. > + /// > + *PrpListNo =3D (UINTN) DivU64x64Remainder ((UINT64)Pages, > (UINT64)PrpEntryNo, &Remainder); > + if (Remainder !=3D 0) { > + *PrpListNo +=3D 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 =3D (VOID *)(UINTN) NVME_PRP_BASE (Nvme, SqId); > + > + Bytes =3D EFI_PAGES_TO_SIZE (*PrpListNo); > + PrpListPhyAddr =3D (UINT64)(UINTN)(*PrpListHost); > + > + /// > + /// Fill all PRP lists except of last one. > + /// > + ZeroMem (*PrpListHost, Bytes); > + for (PrpListIndex =3D 0; PrpListIndex < *PrpListNo - 1; ++PrpListIndex= ) { > + PrpListBase =3D *(UINT64*)PrpListHost + PrpListIndex * EFI_PAGE_SIZE= ; > + > + for (PrpEntryIndex =3D 0; PrpEntryIndex < PrpEntryNo; ++PrpEntryInde= x) { > + PrpEntry =3D (UINT8 *)(UINTN) (PrpListBase + PrpEntryIndex * > sizeof(UINT64)); > + if (PrpEntryIndex !=3D PrpEntryNo - 1) { > + /// > + /// Fill all PRP entries except of last one. > + /// > + CopyMem (PrpEntry, (VOID *)(UINTN) (&PhysicalAddr), sizeof > (UINT64)); > + PhysicalAddr +=3D EFI_PAGE_SIZE; > + } else { > + /// > + /// Fill last PRP entries with next PRP List pointer. > + /// > + NewPhyAddr =3D (PrpListPhyAddr + (PrpListIndex + 1) * > EFI_PAGE_SIZE); > + CopyMem (PrpEntry, (VOID *)(UINTN) (&NewPhyAddr), sizeof > (UINT64)); > + } > + } > + } > + > + /// > + /// Fill last PRP list. > + /// > + PrpListBase =3D *(UINT64*)PrpListHost + PrpListIndex * EFI_PAGE_SIZE; > + for (PrpEntryIndex =3D 0; PrpEntryIndex < ((Remainder !=3D 0) ? Remain= der : > PrpEntryNo); ++PrpEntryIndex) { > + PrpEntry =3D (UINT8 *)(UINTN) (PrpListBase + PrpEntryIndex * > sizeof(UINT64)); > + CopyMem (PrpEntry, (VOID *)(UINTN) (&PhysicalAddr), sizeof (UINT64))= ; > + > + PhysicalAddr +=3D 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 =3D=3D NULL) || (Packet =3D=3D NULL)) { > + DEBUG ((DEBUG_ERROR, "NvmePassThru, invalid parameter: > Nvme(%x)/Packet(%x)\n", > + (UINTN)Nvme, (UINTN)Packet)); > + return EFI_INVALID_PARAMETER; > + } > + > + if ((Packet->NvmeCmd =3D=3D NULL) || (Packet->NvmeResponse =3D=3D 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 !=3D NVME_ADMIN_QUEUE && Packet->QueueId !=3D > NVME_IO_QUEUE) { > + DEBUG ((DEBUG_ERROR, "NvmePassThru, invalid parameter: > QueueId(%x)\n", > + Packet->QueueId)); > + return EFI_INVALID_PARAMETER; > + } > + > + PrpListHost =3D NULL; > + PrpListNo =3D 0; > + Status =3D EFI_SUCCESS; > + > + Qid =3D Packet->QueueId; > + Sq =3D Nvme->SqBuffer[Qid] + Nvme->SqTdbl[Qid].Sqt; > + Cq =3D Nvme->CqBuffer[Qid] + Nvme->CqHdbl[Qid].Cqh; > + if (Qid =3D=3D NVME_ADMIN_QUEUE) { > + SqSize =3D NVME_ASQ_SIZE + 1; > + CqSize =3D NVME_ACQ_SIZE + 1; > + } else { > + SqSize =3D NVME_CSQ_DEPTH; > + CqSize =3D NVME_CCQ_DEPTH; > + } > + > + if (Packet->NvmeCmd->Nsid !=3D 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 =3D Packet->NvmeCmd->Cdw0.Opcode; > + Sq->Fuse =3D Packet->NvmeCmd->Cdw0.FusedOperation; > + Sq->Cid =3D Packet->NvmeCmd->Cdw0.Cid; > + Sq->Nsid =3D Packet->NvmeCmd->Nsid; > + > + /// > + /// Currently we only support PRP for Data transfer, SGL is NOT suppor= ted. > + /// > + ASSERT (Sq->Psdt =3D=3D 0); > + if (Sq->Psdt !=3D 0) { > + DEBUG ((DEBUG_ERROR, "NvmePassThru: doesn't support SGL > mechanism\n")); > + return EFI_UNSUPPORTED; > + } > + > + Sq->Prp[0] =3D Packet->TransferBuffer; > + Sq->Prp[1] =3D 0; > + > + if(Packet->MetadataBuffer !=3D (UINT64)(UINTN)NULL) { > + Sq->Mptr =3D 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 =3D ((UINT32)Sq->Prp[0]) & (EFI_PAGE_SIZE - 1); > + Bytes =3D Packet->TransferLength; > + > + if ((Offset + Bytes) > (EFI_PAGE_SIZE * 2)) { > + /// > + /// Create PrpList for remaining Data Buffer. > + /// > + PhyAddr =3D (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1); > + Sq->Prp[1] =3D NvmeCreatePrpList (Nvme, Nvme->SqTdbl[Qid].Sqt, PhyAd= dr, > EFI_SIZE_TO_PAGES(Offset + Bytes) - 1, &PrpListHost, &PrpListNo); > + if (Sq->Prp[1] =3D=3D 0) { > + Status =3D 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] =3D (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1); > + } > + > + if(Packet->NvmeCmd->Flags & CDW10_VALID) { > + Sq->Payload.Raw.Cdw10 =3D Packet->NvmeCmd->Cdw10; > + } > + if(Packet->NvmeCmd->Flags & CDW11_VALID) { > + Sq->Payload.Raw.Cdw11 =3D Packet->NvmeCmd->Cdw11; > + } > + if(Packet->NvmeCmd->Flags & CDW12_VALID) { > + Sq->Payload.Raw.Cdw12 =3D Packet->NvmeCmd->Cdw12; > + } > + if(Packet->NvmeCmd->Flags & CDW13_VALID) { > + Sq->Payload.Raw.Cdw13 =3D Packet->NvmeCmd->Cdw13; > + } > + if(Packet->NvmeCmd->Flags & CDW14_VALID) { > + Sq->Payload.Raw.Cdw14 =3D Packet->NvmeCmd->Cdw14; > + } > + if(Packet->NvmeCmd->Flags & CDW15_VALID) { > + Sq->Payload.Raw.Cdw15 =3D Packet->NvmeCmd->Cdw15; > + } > + > + /// > + /// Ring the submission queue doorbell. > + /// > + Nvme->SqTdbl[Qid].Sqt++; > + if(Nvme->SqTdbl[Qid].Sqt =3D=3D SqSize) { > + Nvme->SqTdbl[Qid].Sqt =3D 0; > + } > + Status =3D 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 =3D EFI_TIMEOUT; > + Timer =3D 0; > + while (Timer < NVME_CMD_TIMEOUT) { > + //DEBUG ((DEBUG_VERBOSE, "Timer: %x, Cq:\n", Timer)); > + //DumpMem (Cq, sizeof (NVME_CQ)); > + if (Cq->Pt !=3D Nvme->Pt[Qid]) { > + Status =3D EFI_SUCCESS; > + break; > + } > + > + MicroSecondDelay (NVME_CMD_WAIT); > + Timer +=3D NVME_CMD_WAIT; > + } > + > + Nvme->CqHdbl[Qid].Cqh++; > + if (Nvme->CqHdbl[Qid].Cqh =3D=3D CqSize) { > + Nvme->CqHdbl[Qid].Cqh =3D 0; > + Nvme->Pt[Qid] ^=3D 1; > + } > + > + /// > + /// Copy the Respose Queue entry for this command to the callers respo= nse > Buffer > + /// > + CopyMem (Packet->NvmeResponse, Cq, sizeof(NVM_EXPRESS_RESPONSE)); > + > + if (!EFI_ERROR(Status)) { // We still need to check CQ status if no ti= meout > error occured > + Status =3D 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 ident= ify > controller Data. > + > + @return EFI_SUCCESS - Successfully get the identify > controller Data. > + @return others - Fail to get the identify controlle= r > 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 =3D NVME_ADMIN_IDENTIFY_OPC; > + Command.Cdw0.Cid =3D Nvme->Cid[NVME_ADMIN_QUEUE]++; > + // > + // According to Nvm Express 1.1 spec Figure 38, When not used, the fie= ld > shall be cleared to 0h. > + // For the Identify command, the Namespace Identifier is only used for= the > Namespace Data structure. > + // > + Command.Nsid =3D 0; > + > + CommandPacket.NvmeCmd =3D &Command; > + CommandPacket.NvmeResponse =3D &Response; > + CommandPacket.TransferBuffer =3D (UINT64)(UINTN)Buffer; > + CommandPacket.TransferLength =3D sizeof > (NVME_ADMIN_CONTROLLER_DATA); > + CommandPacket.CommandTimeout =3D NVME_GENERIC_TIMEOUT; > + CommandPacket.QueueId =3D NVME_ADMIN_QUEUE; > + // > + // Set bit 0 (Cns bit) to 1 to identify a controller > + // > + Command.Cdw10 =3D 1; > + Command.Flags =3D CDW10_VALID; > + > + Status =3D NvmePassThru ( > + Nvme, > + NVME_CONTROLLER_ID, > + 0, > + &CommandPacket > + ); > + if (!EFI_ERROR (Status)) { > + Status =3D 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 ident= ify > 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 =3D &Command; > + CommandPacket.NvmeResponse =3D &Response; > + > + Command.Cdw0.Opcode =3D NVME_ADMIN_IDENTIFY_OPC; > + Command.Cdw0.Cid =3D Nvme->Cid[NVME_ADMIN_QUEUE]++; > + Command.Nsid =3D NamespaceId; > + CommandPacket.TransferBuffer =3D (UINT64)(UINTN)Buffer; > + CommandPacket.TransferLength =3D sizeof > (NVME_ADMIN_NAMESPACE_DATA); > + CommandPacket.CommandTimeout =3D NVME_GENERIC_TIMEOUT; > + CommandPacket.QueueId =3D NVME_ADMIN_QUEUE; > + // > + // Set bit 0 (Cns bit) to 1 to identify a namespace > + // > + CommandPacket.NvmeCmd->Cdw10 =3D 0; > + CommandPacket.NvmeCmd->Flags =3D CDW10_VALID; > + > + Status =3D NvmePassThru ( > + Nvme, > + NamespaceId, > + 0, > + &CommandPacket > + ); > + if (!EFI_ERROR (Status)) { > + Status =3D 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 =3D Nvme->NamespaceData->Flbas; > + LbaFmtIdx =3D Flbas & 3; > + Lbads =3D Nvme->NamespaceData->LbaFormat[LbaFmtIdx].Lbads; > + > + BlockSize =3D (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 =3D 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 =3D &Command; > + CommandPacket.NvmeResponse =3D &Response; > + > + Command.Cdw0.Opcode =3D NVME_ADMIN_CRIOCQ_OPC; > + Command.Cdw0.Cid =3D Nvme->Cid[NVME_ADMIN_QUEUE]++; > + CommandPacket.TransferBuffer =3D > (UINT64)(UINTN)Nvme->CqBuffer[NVME_IO_QUEUE]; > + CommandPacket.TransferLength =3D EFI_PAGE_SIZE; > + CommandPacket.CommandTimeout =3D NVME_GENERIC_TIMEOUT; > + CommandPacket.QueueId =3D NVME_ADMIN_QUEUE; > + > + CrIoCq.Qid =3D NVME_IO_QUEUE; > + CrIoCq.Qsize =3D NVME_CCQ_SIZE; > + CrIoCq.Pc =3D 1; > + CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoCq, sizeof > (NVME_ADMIN_CRIOCQ)); > + CommandPacket.NvmeCmd->Flags =3D CDW10_VALID | CDW11_VALID; > + > + Status =3D NvmePassThru ( > + Nvme, > + NVME_CONTROLLER_ID, > + 0, > + &CommandPacket > + ); > + if (!EFI_ERROR (Status)) { > + Status =3D 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 =3D &Command; > + CommandPacket.NvmeResponse =3D &Response; > + > + Command.Cdw0.Opcode =3D NVME_ADMIN_CRIOSQ_OPC; > + Command.Cdw0.Cid =3D Nvme->Cid[NVME_ADMIN_QUEUE]++; > + CommandPacket.TransferBuffer =3D > (UINT64)(UINTN)Nvme->SqBuffer[NVME_IO_QUEUE]; > + CommandPacket.TransferLength =3D EFI_PAGE_SIZE; > + CommandPacket.CommandTimeout =3D NVME_GENERIC_TIMEOUT; > + CommandPacket.QueueId =3D NVME_ADMIN_QUEUE; > + > + CrIoSq.Qid =3D NVME_IO_QUEUE; > + CrIoSq.Qsize =3D NVME_CSQ_SIZE; > + CrIoSq.Pc =3D 1; > + CrIoSq.Cqid =3D NVME_IO_QUEUE; > + CrIoSq.Qprio =3D 0; > + CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoSq, sizeof > (NVME_ADMIN_CRIOSQ)); > + CommandPacket.NvmeCmd->Flags =3D CDW10_VALID | CDW11_VALID; > + > + Status =3D NvmePassThru ( > + Nvme, > + NVME_CONTROLLER_ID, > + 0, > + &CommandPacket > + ); > + if (!EFI_ERROR (Status)) { > + Status =3D 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 =3D (OACS *)&Nvme->ControllerData->Oacs; > + > + // > + // Verify security bit for Security Send/Receive commands > + // > + if (Oacs->Security =3D=3D 0) { > + DEBUG ((DEBUG_ERROR, "Security command doesn't support.\n")); > + return EFI_NOT_READY; > + } > + > + SecBuff =3D (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 =3D &Command; > + CommandPacket.NvmeResponse =3D &Response; > + > + Opcode =3D (UINT8)(SendCommand ? NVME_ADMIN_SECURITY_SEND_OPC : > NVME_ADMIN_SECURITY_RECV_OPC); > + Command.Cdw0.Opcode =3D Opcode; > + Command.Cdw0.Cid =3D Nvme->Cid[NVME_ADMIN_QUEUE]++; > + CommandPacket.TransferBuffer =3D (UINT64)(UINTN)SecBuff; > + CommandPacket.TransferLength =3D (UINT32)TransferLength; > + CommandPacket.CommandTimeout =3D NVME_GENERIC_TIMEOUT; > + CommandPacket.QueueId =3D NVME_ADMIN_QUEUE; > + > + SecSend.Spsp =3D SpSpecific; > + SecSend.Secp =3D SecurityProtocol; > + SecSend.Tl =3D (UINT32)TransferLength; > + > + CopyMem (&CommandPacket.NvmeCmd->Cdw10, &SecSend, sizeof > (NVME_ADMIN_SECSEND)); > + CommandPacket.NvmeCmd->Flags =3D CDW10_VALID | CDW11_VALID; > + > + Status =3D NvmePassThru ( > + Nvme, > + NVME_CONTROLLER_ID, > + 0, > + &CommandPacket > + ); > + if (!EFI_ERROR (Status)) { > + Status =3D 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 queu= e. > + > +**/ > +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 =3D &Command; > + CommandPacket.NvmeResponse =3D &Response; > + > + Command.Cdw0.Opcode =3D NVME_ADMIN_DELIOCQ_OPC; > + Command.Cdw0.Cid =3D Nvme->Cid[NVME_ADMIN_QUEUE]++; > + CommandPacket.TransferBuffer =3D > (UINT64)(UINTN)Nvme->CqBuffer[NVME_IO_QUEUE]; > + CommandPacket.TransferLength =3D EFI_PAGE_SIZE; > + CommandPacket.CommandTimeout =3D NVME_GENERIC_TIMEOUT; > + CommandPacket.QueueId =3D NVME_ADMIN_QUEUE; > + > + DelIoCq.Qid =3D NVME_IO_QUEUE; > + CopyMem (&CommandPacket.NvmeCmd->Cdw10, &DelIoCq, sizeof > (NVME_ADMIN_DEIOCQ)); > + CommandPacket.NvmeCmd->Flags =3D CDW10_VALID | CDW11_VALID; > + > + Status =3D NvmePassThru ( > + Nvme, > + NVME_CONTROLLER_ID, > + 0, > + &CommandPacket > + ); > + if (!EFI_ERROR (Status)) { > + Status =3D 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 queu= e. > + > +**/ > +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 =3D &Command; > + CommandPacket.NvmeResponse =3D &Response; > + > + Command.Cdw0.Opcode =3D NVME_ADMIN_DELIOSQ_OPC; > + Command.Cdw0.Cid =3D Nvme->Cid[NVME_ADMIN_QUEUE]++; > + CommandPacket.TransferBuffer =3D > (UINT64)(UINTN)Nvme->SqBuffer[NVME_IO_QUEUE]; > + CommandPacket.TransferLength =3D EFI_PAGE_SIZE; > + CommandPacket.CommandTimeout =3D NVME_GENERIC_TIMEOUT; > + CommandPacket.QueueId =3D NVME_ADMIN_QUEUE; > + > + DelIoSq.Qid =3D NVME_IO_QUEUE; > + CopyMem (&CommandPacket.NvmeCmd->Cdw10, &DelIoSq, sizeof > (NVME_ADMIN_DEIOSQ)); > + CommandPacket.NvmeCmd->Flags =3D CDW10_VALID | CDW11_VALID; > + > + Status =3D NvmePassThru ( > + Nvme, > + NVME_CONTROLLER_ID, > + 0, > + &CommandPacket > + ); > + if (!EFI_ERROR (Status)) { > + Status =3D 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 =3D IoMmuAllocateBuffer ( > + EFI_SIZE_TO_PAGES (NVME_MEM_MAX_SIZE), > + &Base, > + &DeviceAddress, > + &Mapping > + ); > + if (EFI_ERROR (Status)) { > + return EFI_OUT_OF_RESOURCES; > + } > + ASSERT (DeviceAddress =3D=3D ((EFI_PHYSICAL_ADDRESS) (UINTN) Base)); > + Nvme->BaseMemMapping =3D Mapping; > + Nvme->BaseMem =3D 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 !=3D NULL) { > + IoMmuFreeBuffer ( > + EFI_SIZE_TO_PAGES (NVME_MEM_MAX_SIZE), > + Nvme->BaseMem, > + Nvme->BaseMemMapping > + ); > + Nvme->BaseMem =3D 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 =3D Nvme->Nbar; > + MuBAR =3D 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 =3D=3D 0x0001) && (Ver.Mnr =3D=3D 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 =3D 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 !=3D 0x01) { > + DEBUG ((DEBUG_ERROR, "NvmeControllerInit fail: the controller doesn'= t > support NVMe command set\n")); > + Status =3D 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 =3D EFI_UNSUPPORTED; > + goto Done; > + } > + > + Nvme->Cid[0] =3D 0; > + Nvme->Cid[1] =3D 0; > + > + Nvme->Pt[0] =3D 0; > + Nvme->Pt[1] =3D 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 =3D 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 =3D NVME_ASQ_SIZE; > + Aqa.Rsvd1 =3D 0; > + Aqa.Acqs =3D NVME_ACQ_SIZE; > + Aqa.Rsvd2 =3D 0; > + > + /// > + /// Address of admin submission queue. > + /// > + Asq =3D (UINT64)(UINTN)(NVME_ASQ_BASE (Nvme) & ~0xFFF); > + > + /// > + /// Address of admin completion queue. > + /// > + Acq =3D (UINT64)(UINTN)(NVME_ACQ_BASE (Nvme) & ~0xFFF); > + > + /// > + /// Address of I/O submission & completion queue. > + /// > + Nvme->SqBuffer[0] =3D (NVME_SQ *)(UINTN)NVME_ASQ_BASE (Nvme); // > NVME_ADMIN_QUEUE > + Nvme->CqBuffer[0] =3D (NVME_CQ *)(UINTN)NVME_ACQ_BASE (Nvme); // > NVME_ADMIN_QUEUE > + Nvme->SqBuffer[1] =3D (NVME_SQ *)(UINTN)NVME_SQ_BASE (Nvme, 0); // > NVME_IO_QUEUE > + Nvme->CqBuffer[1] =3D (NVME_CQ *)(UINTN)NVME_CQ_BASE (Nvme, 0); // > NVME_IO_QUEUE > + > + DEBUG ((DEBUG_INFO, "Admin Submission Queue Size (Aqa.Asqs) =3D > [%08X]\n", Aqa.Asqs)); > + DEBUG ((DEBUG_INFO, "Admin Completion Queue Size (Aqa.Acqs) =3D > [%08X]\n", Aqa.Acqs)); > + DEBUG ((DEBUG_INFO, "Admin Submission Queue (SqBuffer[0]) =3D > [%08X]\n", Nvme->SqBuffer[0])); > + DEBUG ((DEBUG_INFO, "Admin Completion Queue (CqBuffer[0]) =3D > [%08X]\n", Nvme->CqBuffer[0])); > + DEBUG ((DEBUG_INFO, "I/O Submission Queue (SqBuffer[1]) =3D > [%08X]\n", Nvme->SqBuffer[1])); > + DEBUG ((DEBUG_INFO, "I/O Completion Queue (CqBuffer[1]) =3D > [%08X]\n", Nvme->CqBuffer[1])); > + > + /// > + /// Program admin queue attributes. > + /// > + Status =3D NVME_SET_AQA (Nvme, &Aqa); > + if (EFI_ERROR(Status)) { > + goto Done; > + } > + > + /// > + /// Program admin submission queue address. > + /// > + Status =3D NVME_SET_ASQ (Nvme, &Asq); > + if (EFI_ERROR(Status)) { > + goto Done; > + } > + > + /// > + /// Program admin completion queue address. > + /// > + Status =3D NVME_SET_ACQ (Nvme, &Acq); > + if (EFI_ERROR(Status)) { > + goto Done; > + } > + > + Status =3D NvmeEnableController (Nvme); > + if (EFI_ERROR(Status)) { > + goto Done; > + } > + > + /// > + /// Create one I/O completion queue. > + /// > + Status =3D NvmeCreateIoCompletionQueue (Nvme); > + if (EFI_ERROR(Status)) { > + goto Done; > + } > + > + /// > + /// Create one I/O Submission queue. > + /// > + Status =3D NvmeCreateIoSubmissionQueue (Nvme); > + if (EFI_ERROR(Status)) { > + goto Done; > + } > + > + /// > + /// Get current Identify Controller Data > + /// > + Nvme->ControllerData =3D (NVME_ADMIN_CONTROLLER_DATA *)(UINTN) > NVME_CONTROL_DATA_BASE (Nvme); > + Status =3D NvmeIdentifyController (Nvme, Nvme->ControllerData); > + if (EFI_ERROR(Status)) { > + goto Done; > + } > + > + /// > + /// Dump NvmExpress Identify Controller Data > + /// > + Nvme->ControllerData->Sn[19] =3D 0; > + Nvme->ControllerData->Mn[39] =3D 0; > + //NvmeDumpIdentifyController (Nvme->ControllerData); > + > + /// > + /// Get current Identify Namespace Data > + /// > + Nvme->NamespaceData =3D (NVME_ADMIN_NAMESPACE_DATA > *)NVME_NAMESPACE_DATA_BASE (Nvme); > + Status =3D NvmeIdentifyNamespace (Nvme, Nvme->Nsid, > Nvme->NamespaceData); > + if (EFI_ERROR(Status)) { > + DEBUG ((DEBUG_ERROR, "NvmeIdentifyNamespace fail, Status =3D %r\n", > Status)); > + goto Done; > + } > + > + /// > + /// Dump NvmExpress Identify Namespace Data > + /// > + if (Nvme->NamespaceData->Ncap =3D=3D 0) { > + DEBUG ((DEBUG_ERROR, "Invalid Namespace, Ncap: %lx\n", > Nvme->NamespaceData->Ncap)); > + Status =3D EFI_DEVICE_ERROR; > + goto Done; > + } > + > + Nvme->BlockSize =3D NvmeGetBlockSize (Nvme); > + Nvme->LastBlock =3D NvmeGetLastLba (Nvme); > + > + Nvme->State =3D 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 =3D EFI_SUCCESS; > + if (Nvme->State =3D=3D NvmeStatusInit || Nvme->State =3D=3D NvmeStatus= Max) { > + /// > + /// Destroy I/O Submission queue. > + /// > + Status =3D NvmeDestroyIoSubmissionQueue (Nvme); > + if (EFI_ERROR(Status)) { > + DEBUG ((DEBUG_ERROR, "NvmeDestroyIoSubmissionQueue fail, Status > =3D %r\n", Status)); > + return Status; > + } > + > + /// > + /// Destroy I/O completion queue. > + /// > + Status =3D NvmeDestroyIoCompletionQueue (Nvme); > + if (EFI_ERROR(Status)) { > + DEBUG ((DEBUG_ERROR, "NvmeDestroyIoCompletionQueue fail, Status > =3D %r\n", Status)); > + return Status; > + } > + > + Status =3D 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 =3D 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 =3D Nvme->BlockSize; > + Bytes =3D 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 =3D &Command; > + CommandPacket.NvmeResponse =3D &Response; > + > + CommandPacket.NvmeCmd->Cdw0.Opcode =3D NVME_IO_READ_OPC; > + CommandPacket.NvmeCmd->Cdw0.Cid =3D > Nvme->Cid[NVME_IO_QUEUE]++; > + CommandPacket.NvmeCmd->Nsid =3D Nvme->Nsid; > + CommandPacket.TransferBuffer =3D Buffer; > + > + CommandPacket.TransferLength =3D Bytes; > + CommandPacket.CommandTimeout =3D NVME_GENERIC_TIMEOUT; > + CommandPacket.QueueId =3D NVME_IO_QUEUE; > + > + CommandPacket.NvmeCmd->Cdw10 =3D (UINT32)Lba; > + CommandPacket.NvmeCmd->Cdw11 =3D (UINT32)(RShiftU64 (Lba, 32)); > + CommandPacket.NvmeCmd->Cdw12 =3D (Blocks - 1) & 0xFFFF; > + > + CommandPacket.NvmeCmd->Flags =3D CDW10_VALID | CDW11_VALID | > CDW12_VALID; > + > + Status =3D 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 =3D Nvme->BlockSize; > + Bytes =3D 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 =3D &Command; > + CommandPacket.NvmeResponse =3D &Response; > + > + CommandPacket.NvmeCmd->Cdw0.Opcode =3D NVME_IO_WRITE_OPC; > + CommandPacket.NvmeCmd->Cdw0.Cid =3D > Nvme->Cid[NVME_IO_QUEUE]++; > + CommandPacket.NvmeCmd->Nsid =3D Nvme->Nsid; > + CommandPacket.TransferBuffer =3D Buffer; > + > + CommandPacket.TransferLength =3D Bytes; > + CommandPacket.CommandTimeout =3D NVME_GENERIC_TIMEOUT; > + CommandPacket.QueueId =3D NVME_IO_QUEUE; > + > + CommandPacket.NvmeCmd->Cdw10 =3D (UINT32)Lba; > + CommandPacket.NvmeCmd->Cdw11 =3D (UINT32)(RShiftU64 (Lba, 32)); > + CommandPacket.NvmeCmd->Cdw12 =3D (Blocks - 1) & 0xFFFF; > + > + CommandPacket.MetadataBuffer =3D (UINT64)(UINTN)NULL; > + CommandPacket.MetadataLength =3D 0; > + > + CommandPacket.NvmeCmd->Flags =3D CDW10_VALID | CDW11_VALID | > CDW12_VALID; > + > + Status =3D 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 =3D &Command; > + CommandPacket.NvmeResponse =3D &Response; > + > + CommandPacket.NvmeCmd->Cdw0.Opcode =3D NVME_IO_FLUSH_OPC; > + CommandPacket.NvmeCmd->Cdw0.Cid =3D > Nvme->Cid[NVME_IO_QUEUE]++; > + CommandPacket.NvmeCmd->Nsid =3D Nvme->Nsid; > + CommandPacket.CommandTimeout =3D NVME_GENERIC_TIMEOUT; > + CommandPacket.QueueId =3D NVME_IO_QUEUE; > + > + Status =3D NvmePassThru ( > + Nvme, > + Nvme->Nsid, > + 0, > + &CommandPacket > + ); > + if (!EFI_ERROR (Status)) { > + Status =3D 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 <=3D NVME_MAX_SECTORS); > + Status =3D EFI_SUCCESS; > + BlockSize =3D Nvme->BlockSize; > + if (Nvme->ControllerData->Mdts !=3D 0) { > + MaxTransferBlocks =3D (1 << (Nvme->ControllerData->Mdts)) * (1 << > (Nvme->Cap.Mpsmin + 12)) / BlockSize; > + } else { > + MaxTransferBlocks =3D 1024; > + } > + > + while (Blocks > 0) { > + if (Blocks > MaxTransferBlocks) { > + Status =3D NvmeReadSectors (Nvme, Buffer, Lba, MaxTransferBlocks); > + > + Blocks -=3D MaxTransferBlocks; > + Buffer +=3D (MaxTransferBlocks * BlockSize); > + Lba +=3D MaxTransferBlocks; > + } else { > + Status =3D NvmeReadSectors (Nvme, Buffer, Lba, (UINT32) Blocks); > + Blocks =3D 0; > + } > + > + if (EFI_ERROR(Status)) { > + DEBUG ((DEBUG_ERROR, "NvmeRead fail, Status =3D %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 <=3D NVME_MAX_SECTORS); > + Status =3D EFI_SUCCESS; > + BlockSize =3D Nvme->BlockSize; > + > + if (Nvme->ControllerData->Mdts !=3D 0) { > + MaxTransferBlocks =3D (1 << (Nvme->ControllerData->Mdts)) * (1 << > (Nvme->Cap.Mpsmin + 12)) / BlockSize; > + } else { > + MaxTransferBlocks =3D 1024; > + } > + > + while (Blocks > 0) { > + if (Blocks > MaxTransferBlocks) { > + Status =3D NvmeWriteSectors (Nvme, Buffer, Lba, MaxTransferBlocks)= ; > + > + Blocks -=3D MaxTransferBlocks; > + Buffer +=3D (MaxTransferBlocks * BlockSize); > + Lba +=3D MaxTransferBlocks; > + } else { > + Status =3D NvmeWriteSectors (Nvme, Buffer, Lba, (UINT32) Blocks); > + Blocks =3D 0; > + } > + > + if (EFI_ERROR(Status)) { > + DEBUG ((DEBUG_ERROR, "NvmeWrite fail, Status =3D %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.
> +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BS= D > License > +which accompanies this distribution. The full text of the license may b= e 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.
> +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BS= D > License > +which accompanies this distribution. The full text of the license may b= e 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 capabilit= ies. > +// > +#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 - Submissi= on > 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 Referenc= e 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 Referenc= e 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 Setting= s > */ > + 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.
> +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BS= D > License > +which accompanies this distribution. The full text of the license may b= e 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.
> +# 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 =3D 0x00010007 > + BASE_NAME =3D OpalPasswordDxe > + FILE_GUID =3D > E3E4048D-6C0C-43E4-AE1C-FFB579D8EF41 > + MODULE_TYPE =3D DXE_DRIVER > + VERSION_STRING =3D 1.0 > + ENTRY_POINT =3D EfiDriverEntryPoint > + UNLOAD_IMAGE =3D OpalEfiDriverUnload > + > +# > +# The following information is for reference only and not required by th= e build > tools. > +# > +# VALID_ARCHITECTURES =3D 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.
> +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BS= D > License > +which accompanies this distribution. The full text of the license may b= e 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, 0x= 4, > 0xe } } > + > +formset > + guid =3D SETUP_FORMSET_GUID, > + title =3D STRING_TOKEN(STR_OPAL), > + help =3D STRING_TOKEN(STR_FORM_SET_HELP), > + classguid =3D 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 =3D OpalHiiConfig, // Define referenced name > in vfr > + guid =3D SETUP_VARIABLE_GUID; // GUID of this Buffer > storage > + > +form formid =3D FORMID_VALUE_MAIN_MENU, > + title =3D STRING_TOKEN(STR_OPAL); > + > + //CONFIG_VARIABLE(HII_KEY(HII_KEY_ID_VAR_SUPPORTED_DISKS), > SupportedDisks, 0x0, 0xFFFF); > + suppressif TRUE; > + numeric > + name =3D SupportedDisks, > + varid =3D OpalHiiConfig.SupportedDisks, > + prompt =3D STRING_TOKEN(STR_NULL), > + help =3D STRING_TOKEN(STR_NULL), > + flags =3D INTERACTIVE, > + key =3D 0x8002, > + minimum =3D 0x0, > + maximum =3D 0xFFFF, > + endnumeric; > + endif; > + > + subtitle text =3D STRING_TOKEN(STR_MAIN_OPAL_VERSION); > + > + subtitle text =3D STRING_TOKEN(STR_NULL); > + > + subtitle text =3D STRING_TOKEN(STR_MAIN_PHY_DISKS_LBL); > + > + //DISK( 0 ); > + suppressif ( questionref(SupportedDisks) & ( 0x1 ) ) =3D=3D 0; > + goto FORMID_VALUE_DISK_INFO_FORM_MAIN, > + prompt =3D STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_0 ), > + help =3D > STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP), > + flags =3D INTERACTIVE, > + key =3D 0x8001; > + endif; > + > + //DISK( 1 ); > + suppressif ( questionref(SupportedDisks) & ( 0x2 ) ) =3D=3D 0; > + goto FORMID_VALUE_DISK_INFO_FORM_MAIN, > + prompt =3D STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_1 ), > + help =3D > STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP), > + flags =3D INTERACTIVE, > + key =3D 0x8101; > + endif; > + > + //DISK( 2 ); > + suppressif ( questionref(SupportedDisks) & ( 0x4 ) ) =3D=3D 0; > + goto FORMID_VALUE_DISK_INFO_FORM_MAIN, > + prompt =3D STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_2 ), > + help =3D > STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP), > + flags =3D INTERACTIVE, > + key =3D 0x8201; > + endif; > + > + //DISK( 3 ); > + suppressif ( questionref(SupportedDisks) & ( 0x8 ) ) =3D=3D 0; > + goto FORMID_VALUE_DISK_INFO_FORM_MAIN, > + prompt =3D STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_3 ), > + help =3D > STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP), > + flags =3D INTERACTIVE, > + key =3D 0x8301; > + endif; > + > + //DISK( 4 ); > + suppressif ( questionref(SupportedDisks) & ( 0x10 ) ) =3D=3D 0; > + goto FORMID_VALUE_DISK_INFO_FORM_MAIN, > + prompt =3D STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_4 ), > + help =3D > STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP), > + flags =3D INTERACTIVE, > + key =3D 0x8401; > + endif; > + > + //DISK( 5 ); > + suppressif ( questionref(SupportedDisks) & ( 0x20 ) ) =3D=3D 0; > + goto FORMID_VALUE_DISK_INFO_FORM_MAIN, > + prompt =3D STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_5 ), > + help =3D > STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP), > + flags =3D INTERACTIVE, > + key =3D 0x8501; > + endif; > + > + //No disks on system > + suppressif ideqval OpalHiiConfig.NumDisks > 0; > + text > + help =3D STRING_TOKEN(STR_NULL), > + text =3D > STRING_TOKEN(STR_MAIN_NO_DISKS_PRESENT_LBL); > + endif; > + > + subtitle text =3D STRING_TOKEN(STR_NULL); > + > + grayoutif TRUE; > + text > + help =3D STRING_TOKEN(STR_BLOCKSID_STATUS_HELP), > + text =3D STRING_TOKEN(STR_BLOCKSID_STATUS); > + text > + help =3D STRING_TOKEN(STR_BLOCKSID_STATUS_HELP), > + text =3D STRING_TOKEN(STR_BLOCKSID_STATUS1); > + text > + help =3D STRING_TOKEN(STR_BLOCKSID_STATUS_HELP), > + text =3D STRING_TOKEN(STR_BLOCKSID_STATUS2); > + text > + help =3D STRING_TOKEN(STR_BLOCKSID_STATUS_HELP), > + text =3D STRING_TOKEN(STR_BLOCKSID_STATUS3); > + subtitle text =3D STRING_TOKEN(STR_NULL); > + endif; > + > + oneof varid =3D OpalHiiConfig.EnableBlockSid, > + questionid =3D 0x8004, > + prompt =3D STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID), > + help =3D > STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_HELP), > + flags =3D INTERACTIVE, > + option text =3D STRING_TOKEN(STR_NONE), value =3D 0, flags =3D DEF= AULT | > MANUFACTURING | RESET_REQUIRED; > + option text =3D STRING_TOKEN(STR_ENABLED), value =3D 1, flags =3D > RESET_REQUIRED; > + option text =3D STRING_TOKEN(STR_DISABLED), value =3D 2, flags =3D > RESET_REQUIRED; > + option text =3D > STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_TRUE), value =3D 3, flags =3D > RESET_REQUIRED; > + option text =3D > STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_FALSE), value =3D 4, flags =3D > RESET_REQUIRED; > + option text =3D > STRING_TOKEN(STR_DISK_INFO_DISABLE_BLOCKSID_TRUE), value =3D 5, flags =3D > RESET_REQUIRED; > + option text =3D > STRING_TOKEN(STR_DISK_INFO_DISABLE_BLOCKSID_FALSE), value =3D 6, flags = =3D > RESET_REQUIRED; > + endoneof; > + > + > + > +endform; // MAIN MENU FORM > + > +// > +///////////////// DISK INFO FORM ///////////////// > +// > +form formid =3D FORMID_VALUE_DISK_INFO_FORM_MAIN, > + title =3D STRING_TOKEN(STR_OPAL); > + > + suppressif TRUE; > + numeric > + name =3D SelectedDiskAvailableActions, > + varid =3D OpalHiiConfig.SelectedDiskAvailableActions, > + prompt =3D STRING_TOKEN(STR_NULL), > + help =3D STRING_TOKEN(STR_NULL), > + flags =3D INTERACTIVE, > + key =3D 0x8003, > + minimum =3D 0x0, > + maximum =3D 0xFFFF, > + endnumeric; > + endif; > + > + suppressif TRUE; > + checkbox varid =3D OpalHiiConfig.KeepUserDataForced, > + prompt =3D STRING_TOKEN(STR_NULL), > + help =3D STRING_TOKEN(STR_NULL), > + endcheckbox; > + endif; > + > + subtitle text =3D STRING_TOKEN(STR_MAIN_OPAL_VERSION); > + > + subtitle text =3D STRING_TOKEN(STR_NULL); > + > + text > + help =3D STRING_TOKEN(STR_NULL), > + text =3D STRING_TOKEN(STR_DISK_INFO_SELECTED_DISK_NAME); > + > + subtitle text =3D STRING_TOKEN(STR_NULL); > + > + subtitle text =3D STRING_TOKEN(STR_OPAL_REQUESTS_LBL); > + > + suppressif ( questionref(SelectedDiskAvailableActions) & > HII_ACTION_SET_ADMIN_PWD ) =3D=3D 0; > + grayoutif ideqval OpalHiiConfig.OpalRequest.Revert =3D=3D 1; > + grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert =3D=3D 1; > + checkbox varid =3D OpalHiiConfig.OpalRequest.SetAdminPwd, > + prompt =3D > STRING_TOKEN(STR_DISK_INFO_SET_ADMIN_PSWD), > + help =3D > STRING_TOKEN(STR_DISK_INFO_SET_ADMIN_PSWD_HELP), > + flags =3D INTERACTIVE | RESET_REQUIRED, > + key =3D 0x8005, > + endcheckbox; > + endif; > + endif; > + endif; > + > + suppressif ( questionref(SelectedDiskAvailableActions) & > HII_ACTION_SET_USER_PWD ) =3D=3D 0; > + grayoutif ideqval OpalHiiConfig.OpalRequest.DisableUser =3D=3D 1; > + grayoutif ideqval OpalHiiConfig.OpalRequest.Revert =3D=3D 1; > + grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert =3D=3D 1; > + checkbox varid =3D OpalHiiConfig.OpalRequest.SetUserPwd, > + prompt =3D STRING_TOKEN(STR_DISK_INFO_SET_USER_PSWD), > + help =3D > STRING_TOKEN(STR_DISK_INFO_SET_USER_PSWD_HELP), > + flags =3D INTERACTIVE | RESET_REQUIRED, > + key =3D 0x8006, > + endcheckbox; > + endif; > + endif; > + endif; > + endif; > + > + suppressif ( questionref(SelectedDiskAvailableActions) & > HII_ACTION_SECURE_ERASE ) =3D=3D 0; > + grayoutif ideqval OpalHiiConfig.OpalRequest.Revert =3D=3D 1; > + grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert =3D=3D 1; > + checkbox varid =3D OpalHiiConfig.OpalRequest.SecureErase, > + prompt =3D STRING_TOKEN(STR_DISK_INFO_SECURE_ERASE), > + help =3D > STRING_TOKEN(STR_DISK_INFO_SECURE_ERASE_HELP), > + flags =3D INTERACTIVE | RESET_REQUIRED, > + key =3D 0x8007, > + endcheckbox; > + endif; > + endif; > + endif; > + > + suppressif ( questionref(SelectedDiskAvailableActions) & > HII_ACTION_REVERT ) =3D=3D 0; > + grayoutif ideqval OpalHiiConfig.OpalRequest.SetAdminPwd =3D=3D 1; > + grayoutif ideqval OpalHiiConfig.OpalRequest.SetUserPwd =3D=3D 1; > + grayoutif ideqval OpalHiiConfig.OpalRequest.SecureErase =3D=3D 1; > + grayoutif ideqval OpalHiiConfig.OpalRequest.DisableUser =3D=3D 1; > + grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert =3D=3D 1; > + checkbox varid =3D OpalHiiConfig.OpalRequest.Revert, > + prompt =3D STRING_TOKEN(STR_DISK_INFO_REVERT), > + help =3D STRING_TOKEN(STR_DISK_INFO_REVERT_HELP), > + flags =3D INTERACTIVE | RESET_REQUIRED, > + key =3D 0x8008, > + endcheckbox; > + endif; > + endif; > + endif; > + endif; > + endif; > + endif; > + > + suppressif ideqval OpalHiiConfig.OpalRequest.Revert =3D=3D 0; > + grayoutif ideqval OpalHiiConfig.KeepUserDataForced =3D=3D 1; > + checkbox varid =3D OpalHiiConfig.OpalRequest.KeepUserData, > + prompt =3D > STRING_TOKEN(STR_KEEP_USER_DATA_PROMPT), > + help =3D STRING_TOKEN(STR_KEEP_USER_DATA_HELP), > + flags =3D INTERACTIVE | RESET_REQUIRED, > + key =3D 0x8009, > + endcheckbox; > + endif; > + endif; > + > + suppressif ( questionref(SelectedDiskAvailableActions) & > HII_ACTION_PSID_REVERT ) =3D=3D 0; > + grayoutif ideqval OpalHiiConfig.OpalRequest.SetAdminPwd =3D=3D 1; > + grayoutif ideqval OpalHiiConfig.OpalRequest.SetUserPwd =3D=3D 1; > + grayoutif ideqval OpalHiiConfig.OpalRequest.SecureErase =3D=3D 1; > + grayoutif ideqval OpalHiiConfig.OpalRequest.DisableUser =3D=3D 1; > + grayoutif ideqval OpalHiiConfig.OpalRequest.EnableFeature =3D=3D 1; > + grayoutif ideqval OpalHiiConfig.OpalRequest.Revert =3D=3D 1; > + checkbox varid =3D OpalHiiConfig.OpalRequest.PsidRevert, > + prompt =3D STRING_TOKEN(STR_DISK_INFO_PSID_REVERT), > + help =3D > STRING_TOKEN(STR_DISK_INFO_PSID_REVERT_HELP), > + flags =3D INTERACTIVE | RESET_REQUIRED, > + key =3D 0x800A, > + endcheckbox; > + endif; > + endif; > + endif; > + endif; > + endif; > + endif; > + endif; > + > + suppressif ( questionref(SelectedDiskAvailableActions) & > HII_ACTION_DISABLE_USER ) =3D=3D 0; > + grayoutif ideqval OpalHiiConfig.OpalRequest.SetUserPwd =3D=3D 1; > + grayoutif ideqval OpalHiiConfig.OpalRequest.Revert =3D=3D 1; > + grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert =3D=3D 1; > + checkbox varid =3D OpalHiiConfig.OpalRequest.DisableUser, > + prompt =3D STRING_TOKEN(STR_DISK_INFO_DISABLE_USER), > + help =3D > STRING_TOKEN(STR_DISK_INFO_DISABLE_USER_HELP), > + flags =3D INTERACTIVE | RESET_REQUIRED, > + key =3D 0x800B, > + endcheckbox; > + endif; > + endif; > + endif; > + endif; > + > + suppressif ( questionref(SelectedDiskAvailableActions) & > HII_ACTION_ENABLE_FEATURE ) =3D=3D 0; > + grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert =3D=3D 1; > + checkbox varid =3D OpalHiiConfig.OpalRequest.EnableFeature, > + prompt =3D STRING_TOKEN(STR_DISK_INFO_ENABLE_FEATURE), > + help =3D > STRING_TOKEN(STR_DISK_INFO_ENABLE_FEATURE_HELP), > + flags =3D INTERACTIVE | RESET_REQUIRED, > + key =3D 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.
> +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BS= D > License > +which accompanies this distribution. The full text of the license may b= e 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 =3D OPAL_DEVICE_ATA_GUID; > +EFI_GUID mOpalDeviceNvmeGuid =3D 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 =3D NULL; > + Status =3D PeiServicesLocatePpi ( > + &gEdkiiIoMmuPpiGuid, > + 0, > + NULL, > + (VOID **) &IoMmu > + ); > + if (!EFI_ERROR (Status) && (IoMmu !=3D NULL)) { > + return IoMmu; > + } > + > + return NULL; > +} > + > +/** > + Allocates pages that are suitable for an OperationBusMasterCommonBuffe= r > 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 lega= l > 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 =3D NULL; > + *DeviceAddress =3D 0; > + *Mapping =3D NULL; > + > + IoMmu =3D GetIoMmu (); > + > + if (IoMmu !=3D NULL) { > + Status =3D IoMmu->AllocateBuffer ( > + IoMmu, > + EfiBootServicesData, > + Pages, > + HostAddress, > + 0 > + ); > + if (EFI_ERROR (Status)) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + NumberOfBytes =3D EFI_PAGES_TO_SIZE (Pages); > + Status =3D IoMmu->Map ( > + IoMmu, > + EdkiiIoMmuOperationBusMasterCommonBuffer, > + *HostAddress, > + &NumberOfBytes, > + DeviceAddress, > + Mapping > + ); > + if (EFI_ERROR (Status)) { > + IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress); > + *HostAddress =3D NULL; > + return EFI_OUT_OF_RESOURCES; > + } > + Status =3D 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 =3D NULL; > + *HostAddress =3D NULL; > + return Status; > + } > + } else { > + Status =3D PeiServicesAllocatePages ( > + EfiBootServicesData, > + Pages, > + &HostPhyAddress > + ); > + if (EFI_ERROR (Status)) { > + return EFI_OUT_OF_RESOURCES; > + } > + *HostAddress =3D (VOID *) (UINTN) HostPhyAddress; > + *DeviceAddress =3D HostPhyAddress; > + *Mapping =3D 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 =3D GetIoMmu (); > + > + if (IoMmu !=3D 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 =3D EFI_DEVICE_ERROR; > + if (PeiDev->DeviceType =3D=3D OPAL_DEVICE_TYPE_ATA) { > + DevInfoAta =3D (OPAL_DEVICE_ATA *) PeiDev->Device; > + AhciContext =3D (AHCI_CONTEXT *) PeiDev->Context; > + > + BufferSizeBlocks =3D TransferLength / 512; > + > + ZeroMem( &AtaCommandBlock, sizeof( EFI_ATA_COMMAND_BLOCK ) ); > + AtaCommandBlock.AtaCommand =3D ( IoType =3D=3D OpalSend ) ? > ATA_COMMAND_TRUSTED_SEND : ATA_COMMAND_TRUSTED_RECEIVE; > + AtaCommandBlock.AtaSectorCount =3D ( UINT8 )BufferSizeBlocks; > + AtaCommandBlock.AtaSectorNumber =3D ( UINT8 )( BufferSizeBlocks >> 8= ); > + AtaCommandBlock.AtaFeatures =3D SecurityProtocol; > + AtaCommandBlock.AtaCylinderLow =3D ( UINT8 )( SpSpecific >> 8 ); > + AtaCommandBlock.AtaCylinderHigh =3D ( UINT8 )( SpSpecific ); > + AtaCommandBlock.AtaDeviceHead =3D ATA_DEVICE_LBA; > + > + > + ZeroMem( AhciContext->Buffer, HDD_PAYLOAD ); > + ASSERT( TransferLength <=3D HDD_PAYLOAD ); > + > + if (IoType =3D=3D OpalSend) { > + CopyMem( AhciContext->Buffer, Buffer, TransferLength ); > + } > + > + Status =3D AhciPioTransfer( > + AhciContext, > + (UINT8) DevInfoAta->Port, > + (UINT8) DevInfoAta->PortMultiplierPort, > + NULL, > + 0, > + ( IoType =3D=3D OpalSend ) ? FALSE : TRUE, // i/o dire= ction > + &AtaCommandBlock, > + NULL, > + AhciContext->Buffer, > + (UINT32)TransferLength, > + ATA_TIMEOUT > + ); > + > + if (IoType =3D=3D OpalRecv) { > + CopyMem( Buffer, AhciContext->Buffer, TransferLength ); > + } > + } else if (PeiDev->DeviceType =3D=3D OPAL_DEVICE_TYPE_NVME) { > + NvmeContext =3D (NVME_CONTEXT *) PeiDev->Context; > + Status =3D NvmeSecuritySendReceive ( > + NvmeContext, > + IoType =3D=3D 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 give= n > MediaId. > + The security protocol command sent is defined by SecurityProtocolId an= d > 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 sen= t 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 functi= on > returns > + EFI_NO_MEDIA. If the MediaId is not the ID for the current media in th= e > 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 funct= ion > 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 callin= g > 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 wai= t > indefinitely for the > + security protocol command to > execute. If Timeout is greater > + than zero, then this function wil= l > 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 Protoc= ol > 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 th= e > 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 =3D OPAL_PEI_DEVICE_FROM_THIS (This); > + if (PeiDev =3D=3D 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 speci= fic data > + SecurityProtocolSpecificData. If the underlying protocol command requi= res 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 c= ommand > is > + sent using the Trusted Non-Data command defined in ATA8-ACS. > + > + If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the functi= on 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 med= ia 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 funct= ion > 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 callin= g > 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 wai= t > indefinitely for the > + security protocol command to > execute. If Timeout is greater > + than zero, then this function wil= l > 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 Protoc= ol > 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 =3D OPAL_PEI_DEVICE_FROM_THIS (This); > + if (PeiDev =3D=3D 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 f= or > 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 =3D 0; > + Index =3D 0; > + RpBase =3D 0; > + > + while (sizeof (OPAL_DEVICE_NVME) + Length < DevInfoNvme->Length) { > + DevNode =3D (OPAL_PCI_DEVICE *)((UINT8*)DevInfoNvme->PciBridgeNode > + Length); > + RpBase =3D PCI_LIB_ADDRESS (DevNode->Bus, DevNode->Device, > DevNode->Function, 0x0); > + > + if (PcieConfBufferList !=3D NULL) { > + if (SaveAction) { > + StorePcieConfData =3D (UINT8 *) AllocateZeroPool > (OPAL_PCIE_ROOTPORT_SAVESIZE); > + ASSERT (StorePcieConfData !=3D NULL); > + OpalPciRead (StorePcieConfData, RpBase, > OPAL_PCIE_ROOTPORT_SAVESIZE); > + PcieConfBufferList[Index] =3D StorePcieConfData; > + } else { > + // Skip PCIe Command & Status registers > + StorePcieConfData =3D PcieConfBufferList[Index]; > + OpalPciWrite (RpBase, StorePcieConfData, 4); > + OpalPciWrite (RpBase + 8, StorePcieConfData + 8, > OPAL_PCIE_ROOTPORT_SAVESIZE - 8); > + > + FreePool (StorePcieConfData); > + } > + } > + > + Length +=3D sizeof (OPAL_PCI_DEVICE); > + Index ++; > + } > + > + return RpBase; > +} > + > +/** > + Configure RootPort for downstream PCIe NAND devices. > + > + @param[in] RpBase - PCIe configuration space address of th= is > 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 =3D=3D 0) { > + MemoryLimit =3D MemoryBase; > + } else { > + MemoryLimit =3D 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 de= scriptor > + > + @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 =3D &OpalDev->Sscp; > + Session.MediaId =3D 0; > + > + Ret =3D OpalGetSupportedAttributesInfo (&Session, &SupportedAttributes= , > &OpalBaseComId); > + if (Ret !=3D TcgResultSuccess) { > + return FALSE; > + } > + > + Session.OpalBaseComId =3D OpalBaseComId; > + *BlockSidSupported =3D SupportedAttributes.BlockSid =3D=3D 1 ? TRU= E : > FALSE; > + > + Ret =3D OpalGetLockingInfo(&Session, &LockingFeature); > + if (Ret !=3D 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 =3D FALSE; > + if (IsOpalDeviceLocked (OpalDev, &BlockSidSupport)) { > + ZeroMem(&Session, sizeof (Session)); > + Session.Sscp =3D &OpalDev->Sscp; > + Session.MediaId =3D 0; > + Session.OpalBaseComId =3D OpalDev->Device->OpalBaseComId; > + > + Result =3D OpalUtilUpdateGlobalLockingRange ( > + &Session, > + OpalDev->Device->Password, > + OpalDev->Device->PasswordLength, > + FALSE, > + FALSE > + ); > + DEBUG (( > + DEBUG_INFO, > + "%a() OpalUtilUpdateGlobalLockingRange() Result =3D 0x%x\n", > + __FUNCTION__, > + Result > + )); > + } > + > + PpStorageFlags =3D Tcg2PhysicalPresenceLibGetManagementFlags (); > + if ((PpStorageFlags & > TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID) !=3D 0) { > + BlockSIDEnabled =3D TRUE; > + } else { > + BlockSIDEnabled =3D FALSE; > + } > + if (BlockSIDEnabled && BlockSidSupport) { > + Result =3D OpalBlockSid (&Session, TRUE); > + DEBUG (( > + DEBUG_INFO, > + "%a() OpalBlockSid() Result =3D 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 =3D (UINT8 *) &TempDevInfoAta; > + DevInfoLengthAta =3D sizeof (OPAL_DEVICE_ATA); > + Status =3D RestoreLockBox (&mOpalDeviceAtaGuid, DevInfo, > &DevInfoLengthAta); > + if (Status =3D=3D EFI_BUFFER_TOO_SMALL) { > + DevInfo =3D AllocatePages (EFI_SIZE_TO_PAGES (DevInfoLengthAta)); > + if (DevInfo !=3D NULL) { > + Status =3D RestoreLockBox (&mOpalDeviceAtaGuid, DevInfo, > &DevInfoLengthAta); > + } > + } > + if (EFI_ERROR (Status) || (DevInfo =3D=3D NULL)) { > + return; > + } > + > + for (DevInfoAta =3D (OPAL_DEVICE_ATA *) DevInfo; > + (UINTN) DevInfoAta < ((UINTN) DevInfo + DevInfoLengthAta); > + DevInfoAta =3D (OPAL_DEVICE_ATA *) ((UINTN) DevInfoAta + > DevInfoAta->Length)) { > + Bus =3D DevInfoAta->Device.Bus; > + Device =3D DevInfoAta->Device.Device; > + Function =3D DevInfoAta->Device.Function; > + > + SataCmdSt =3D PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, > PCI_COMMAND_OFFSET)); > + PciWrite8 (PCI_LIB_ADDRESS (Bus, Device, Function, > PCI_COMMAND_OFFSET), 0x6); > + > + BaseClassCode =3D PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, > 0x0B)); > + SubClassCode =3D PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, > 0x0A)); > + if ((BaseClassCode !=3D PCI_CLASS_MASS_STORAGE) || > + ((SubClassCode !=3D PCI_CLASS_MASS_STORAGE_SATADPA) && > (SubClassCode !=3D PCI_CLASS_MASS_STORAGE_RAID))) { > + DEBUG ((DEBUG_ERROR, "%a() ClassCode/SubClassCode are not > supported\n", __FUNCTION__)); > + } else { > + AhciBar =3D PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x2= 4)); > + PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24), > DevInfoAta->BarAddr); > + > + ZeroMem (&AhciContext, sizeof (AHCI_CONTEXT)); > + AhciContext.AhciBar =3D DevInfoAta->BarAddr; > + AhciAllocateResource (&AhciContext); > + Status =3D AhciModeInitialize (&AhciContext, (UINT8)DevInfoAta->Po= rt); > + ASSERT_EFI_ERROR (Status); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "%a() AhciModeInitialize() error, > Status: %r\n", __FUNCTION__, Status)); > + } > + > + OpalDev.Signature =3D OPAL_PEI_DEVICE_SIGNATURE; > + OpalDev.Sscp.ReceiveData =3D SecurityReceiveData; > + OpalDev.Sscp.SendData =3D SecuritySendData; > + OpalDev.DeviceType =3D OPAL_DEVICE_TYPE_ATA; > + OpalDev.Device =3D (OPAL_DEVICE_COMMON *) DevInfoAta; > + OpalDev.Context =3D &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 !=3D (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 =3D (UINT8 *) &TempDevInfoNvme; > + DevInfoLengthNvme =3D sizeof (OPAL_DEVICE_NVME); > + Status =3D RestoreLockBox (&mOpalDeviceNvmeGuid, DevInfo, > &DevInfoLengthNvme); > + if (Status =3D=3D EFI_BUFFER_TOO_SMALL) { > + DevInfo =3D AllocatePages (EFI_SIZE_TO_PAGES (DevInfoLengthNvme)); > + if (DevInfo !=3D NULL) { > + Status =3D RestoreLockBox (&mOpalDeviceNvmeGuid, DevInfo, > &DevInfoLengthNvme); > + } > + } > + if (EFI_ERROR (Status) || (DevInfo =3D=3D NULL)) { > + return; > + } > + > + for (DevInfoNvme =3D (OPAL_DEVICE_NVME *) DevInfo; > + (UINTN) DevInfoNvme < ((UINTN) DevInfo + DevInfoLengthNvme); > + DevInfoNvme =3D (OPAL_DEVICE_NVME *) ((UINTN) DevInfoNvme + > DevInfoNvme->Length)) { > + Bus =3D DevInfoNvme->Device.Bus; > + Device =3D DevInfoNvme->Device.Device; > + Function =3D DevInfoNvme->Device.Function; > + > + RpBase =3D 0; > + NvmeCmdSt =3D 0; > + > + /// > + /// Save original RootPort configuration space to heap > + /// > + RpBase =3D SaveRestoreRootportConfSpace ( > + DevInfoNvme, > + TRUE, // save > + StorePcieConfDataList > + ); > + MemoryBase =3D DevInfoNvme->BarAddr; > + MemoryLength =3D 0; > + ConfigureRootPortForPcieNand (RpBase, Bus, (UINT32) MemoryBase, > (UINT32) MemoryLength); > + > + /// > + /// Enable PCIE decode for RootPort > + /// > + NvmeCmdSt =3D PciRead8 (RpBase + NVME_PCIE_PCICMD); > + PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0x6); > + > + BaseClassCode =3D PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, > 0x0B)); > + SubClassCode =3D PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, > 0x0A)); > + ProgInt =3D PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, > 0x09)); > + if ((BaseClassCode !=3D PCI_CLASS_MASS_STORAGE) || > + (SubClassCode !=3D PCI_CLASS_MASS_STORAGE_NVM) || > + (ProgInt !=3D PCI_IF_NVMHCI)) { > + DEBUG ((DEBUG_ERROR, "%a() ClassCode/SubClassCode/PI are not > supported\n", __FUNCTION__)); > + } else { > + ZeroMem (&NvmeContext, sizeof (NVME_CONTEXT)); > + NvmeContext.Nbar =3D DevInfoNvme->BarAddr; > + NvmeContext.PciBase =3D PCI_LIB_ADDRESS (Bus, Device, Function, 0x= 0); > + NvmeContext.NvmeInitWaitTime =3D 0; > + NvmeContext.Nsid =3D DevInfoNvme->NvmeNamespaceId; > + NvmeAllocateResource (&NvmeContext); > + Status =3D NvmeControllerInit (&NvmeContext); > + > + OpalDev.Signature =3D OPAL_PEI_DEVICE_SIGNATURE; > + OpalDev.Sscp.ReceiveData =3D SecurityReceiveData; > + OpalDev.Sscp.SendData =3D SecuritySendData; > + OpalDev.DeviceType =3D OPAL_DEVICE_TYPE_NVME; > + OpalDev.Device =3D (OPAL_DEVICE_COMMON *) DevInfoNvme; > + OpalDev.Context =3D &NvmeContext; > + > + UnlockOpalPassword (&OpalDev); > + > + Status =3D NvmeControllerExit (&NvmeContext); > + NvmeFreeResource (&NvmeContext); > + } > + > + ASSERT (RpBase !=3D 0); > + PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0); > + RpBase =3D SaveRestoreRootportConfSpace ( > + DevInfoNvme, > + FALSE, // restore > + StorePcieConfDataList > + ); > + PciWrite8 (RpBase + NVME_PCIE_PCICMD, NvmeCmdSt); > + } > + > + ZeroMem (DevInfo, DevInfoLengthNvme); > + if ((UINTN) DevInfo !=3D (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 PE= IM. > + 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 =3D PeiServicesGetBootMode (&BootMode); > + ASSERT_EFI_ERROR (Status); > + if (BootMode !=3D 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 =3D { > + (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 =3D 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.
> +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BS= D > License > +which accompanies this distribution. The full text of the license may b= e 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 > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +#include > + > +#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 OperationBusMasterCommonBuffe= r > 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 lega= l > 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.
> +# 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 =3D 0x00010005 > + BASE_NAME =3D OpalPasswordPei > + FILE_GUID =3D > DED60489-979C-4B5A-8EE4-4068B0CC38DC > + MODULE_TYPE =3D PEIM > + VERSION_STRING =3D 1.0 > + ENTRY_POINT =3D OpalPasswordPeiInit > + > +# > +# The following information is for reference only and not required by th= e build > tools. > +# > +# VALID_ARCHITECTURES =3D 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