#\r
SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordDxe.inf\r
SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.inf\r
+ SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordDxe.inf\r
+ SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.inf\r
\r
[Components.IPF]\r
SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.inf\r
--- /dev/null
+/** @file\r
+ UEFI Component Name(2) protocol implementation for Opal driver.\r
+\r
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "OpalDriver.h"\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gOpalComponentName = {\r
+ OpalEfiDriverComponentNameGetDriverName,\r
+ OpalEfiDriverComponentNameGetControllerName,\r
+ "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gOpalComponentName2 = {\r
+ OpalEfiDriverComponentName2GetDriverName,\r
+ OpalEfiDriverComponentName2GetControllerName,\r
+ "en"\r
+};\r
+\r
+\r
+/// The name of the driver in all the languages we support.\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mOpalDriverNameTable[] = {\r
+ { LANGUAGE_RFC_3066_ENGLISH, (CHAR16*)EFI_DRIVER_NAME_UNICODE },\r
+ { LANGUAGE_ISO_639_2_ENGLISH, (CHAR16*)EFI_DRIVER_NAME_UNICODE },\r
+ { 0, 0 }\r
+};\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param DriverName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverComponentNameGetDriverName(\r
+ EFI_COMPONENT_NAME_PROTOCOL* This,\r
+ CHAR8* Language,\r
+ CHAR16** DriverName\r
+ )\r
+{\r
+ return LookupUnicodeString2(\r
+ Language,\r
+ This->SupportedLanguages,\r
+ mOpalDriverNameTable,\r
+ DriverName,\r
+ TRUE\r
+ );\r
+}\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param DriverName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverComponentName2GetDriverName(\r
+ EFI_COMPONENT_NAME2_PROTOCOL* This,\r
+ CHAR8* Language,\r
+ CHAR16** DriverName\r
+ )\r
+{\r
+ return LookupUnicodeString2(\r
+ Language,\r
+ This->SupportedLanguages,\r
+ mOpalDriverNameTable,\r
+ DriverName,\r
+ FALSE\r
+ );\r
+}\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param ControllerHandle[in] The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param ChildHandle[in] The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param ControllerName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+GetControllerName(\r
+ EFI_HANDLE ControllerHandle,\r
+ EFI_HANDLE ChildHandle,\r
+ CHAR8* Language,\r
+ CHAR16** ControllerName\r
+ )\r
+{\r
+ if (Language == NULL || ControllerName == NULL || ControllerHandle == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ // don't support any controller or children names\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param ControllerHandle[in] The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param ChildHandle[in] The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param ControllerName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverComponentNameGetControllerName(\r
+ EFI_COMPONENT_NAME_PROTOCOL* This,\r
+ EFI_HANDLE ControllerHandle,\r
+ EFI_HANDLE ChildHandle,\r
+ CHAR8* Language,\r
+ CHAR16** ControllerName\r
+ )\r
+{\r
+ return (GetControllerName( ControllerHandle, ChildHandle, Language, ControllerName));\r
+}\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param ControllerHandle[in] The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param ChildHandle[in] The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param ControllerName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverComponentName2GetControllerName(\r
+ EFI_COMPONENT_NAME2_PROTOCOL* This,\r
+ EFI_HANDLE ControllerHandle,\r
+ EFI_HANDLE ChildHandle,\r
+ CHAR8* Language,\r
+ CHAR16** ControllerName\r
+ )\r
+{\r
+ return (GetControllerName(ControllerHandle, ChildHandle, Language, ControllerName));\r
+}\r
+\r
--- /dev/null
+/** @file\r
+ This driver is used for Opal Password Feature support at AHCI mode.\r
+\r
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#include "OpalPasswordPei.h"\r
+\r
+/**\r
+ Start command for give slot on specific port.\r
+\r
+ @param AhciBar AHCI bar address.\r
+ @param Port The number of port.\r
+ @param CommandSlot The number of CommandSlot.\r
+ @param Timeout The timeout Value of start.\r
+\r
+ @retval EFI_DEVICE_ERROR The command start unsuccessfully.\r
+ @retval EFI_TIMEOUT The operation is time out.\r
+ @retval EFI_SUCCESS The command start successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciStartCommand (\r
+ IN UINT32 AhciBar,\r
+ IN UINT8 Port,\r
+ IN UINT8 CommandSlot,\r
+ IN UINT64 Timeout\r
+ );\r
+\r
+/**\r
+ Stop command running for giving port\r
+\r
+ @param AhciBar AHCI bar address.\r
+ @param Port The number of port.\r
+ @param Timeout The timeout Value of stop.\r
+\r
+ @retval EFI_DEVICE_ERROR The command stop unsuccessfully.\r
+ @retval EFI_TIMEOUT The operation is time out.\r
+ @retval EFI_SUCCESS The command stop successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciStopCommand (\r
+ IN UINT32 AhciBar,\r
+ IN UINT8 Port,\r
+ IN UINT64 Timeout\r
+ );\r
+\r
+/**\r
+ Read AHCI Operation register.\r
+\r
+ @param AhciBar AHCI bar address.\r
+ @param Offset The operation register offset.\r
+\r
+ @return The register content read.\r
+\r
+**/\r
+UINT32\r
+EFIAPI\r
+AhciReadReg (\r
+ IN UINT32 AhciBar,\r
+ IN UINT32 Offset\r
+ )\r
+{\r
+ UINT32 Data;\r
+\r
+ Data = 0;\r
+\r
+ Data = MmioRead32 (AhciBar + Offset);\r
+\r
+ return Data;\r
+}\r
+\r
+/**\r
+ Write AHCI Operation register.\r
+\r
+ @param AhciBar AHCI bar address.\r
+ @param Offset The operation register offset.\r
+ @param Data The Data used to write down.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciWriteReg (\r
+ IN UINT32 AhciBar,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Data\r
+ )\r
+{\r
+ MmioWrite32 (AhciBar + Offset, Data);\r
+\r
+ return ;\r
+}\r
+\r
+/**\r
+ Do AND operation with the Value of AHCI Operation register.\r
+\r
+ @param AhciBar AHCI bar address.\r
+ @param Offset The operation register offset.\r
+ @param AndData The Data used to do AND operation.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciAndReg (\r
+ IN UINT32 AhciBar,\r
+ IN UINT32 Offset,\r
+ IN UINT32 AndData\r
+ )\r
+{\r
+ UINT32 Data;\r
+\r
+ Data = AhciReadReg (AhciBar, Offset);\r
+\r
+ Data &= AndData;\r
+\r
+ AhciWriteReg (AhciBar, Offset, Data);\r
+}\r
+\r
+/**\r
+ Do OR operation with the Value of AHCI Operation register.\r
+\r
+ @param AhciBar AHCI bar address.\r
+ @param Offset The operation register offset.\r
+ @param OrData The Data used to do OR operation.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciOrReg (\r
+ IN UINT32 AhciBar,\r
+ IN UINT32 Offset,\r
+ IN UINT32 OrData\r
+ )\r
+{\r
+ UINT32 Data;\r
+\r
+ Data = AhciReadReg (AhciBar, Offset);\r
+\r
+ Data |= OrData;\r
+\r
+ AhciWriteReg (AhciBar, Offset, Data);\r
+}\r
+\r
+/**\r
+ Wait for memory set to the test Value.\r
+\r
+ @param AhciBar AHCI bar address.\r
+ @param Offset The memory offset to test.\r
+ @param MaskValue The mask Value of memory.\r
+ @param TestValue The test Value of memory.\r
+ @param Timeout The time out Value for wait memory set.\r
+\r
+ @retval EFI_DEVICE_ERROR The memory is not set.\r
+ @retval EFI_TIMEOUT The memory setting is time out.\r
+ @retval EFI_SUCCESS The memory is correct set.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciWaitMmioSet (\r
+ IN UINT32 AhciBar,\r
+ IN UINT32 Offset,\r
+ IN UINT32 MaskValue,\r
+ IN UINT32 TestValue,\r
+ IN UINT64 Timeout\r
+ )\r
+{\r
+ UINT32 Value;\r
+ UINT32 Delay;\r
+\r
+ Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+\r
+ do {\r
+ Value = AhciReadReg (AhciBar, Offset) & MaskValue;\r
+\r
+ if (Value == TestValue) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Stall for 100 microseconds.\r
+ //\r
+ MicroSecondDelay (100);\r
+\r
+ Delay--;\r
+\r
+ } while (Delay > 0);\r
+\r
+ return EFI_TIMEOUT;\r
+}\r
+/**\r
+ Wait for the Value of the specified system memory set to the test Value.\r
+\r
+ @param Address The system memory address to test.\r
+ @param MaskValue The mask Value of memory.\r
+ @param TestValue The test Value of memory.\r
+ @param Timeout The time out Value for wait memory set, uses 100ns as a unit.\r
+\r
+ @retval EFI_TIMEOUT The system memory setting is time out.\r
+ @retval EFI_SUCCESS The system memory is correct set.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciWaitMemSet (\r
+ IN EFI_PHYSICAL_ADDRESS Address,\r
+ IN UINT32 MaskValue,\r
+ IN UINT32 TestValue,\r
+ IN UINT64 Timeout\r
+ )\r
+{\r
+ UINT32 Value;\r
+ UINT32 Delay;\r
+\r
+ Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);\r
+\r
+ do {\r
+ //\r
+ // Access sytem memory to see if the Value is the tested one.\r
+ //\r
+ // The system memory pointed by Address will be updated by the\r
+ // SATA Host Controller, "volatile" is introduced to prevent\r
+ // compiler from optimizing the access to the memory address\r
+ // to only read once.\r
+ //\r
+ Value = *(volatile UINT32 *) (UINTN) Address;\r
+ Value &= MaskValue;\r
+\r
+ if (Value == TestValue) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Stall for 100 microseconds.\r
+ //\r
+ MicroSecondDelay (100);\r
+\r
+ Delay--;\r
+\r
+ } while (Delay > 0);\r
+\r
+ return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+ Check the memory status to the test Value.\r
+\r
+ @param[in] Address The memory address to test.\r
+ @param[in] MaskValue The mask Value of memory.\r
+ @param[in] TestValue The test Value of memory.\r
+ @param[in, out] RetryTimes The retry times Value for waitting memory set. If 0, then just try once.\r
+\r
+ @retval EFI_NOTREADY The memory is not set.\r
+ @retval EFI_TIMEOUT The memory setting retry times out.\r
+ @retval EFI_SUCCESS The memory is correct set.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciCheckMemSet (\r
+ IN UINTN Address,\r
+ IN UINT32 MaskValue,\r
+ IN UINT32 TestValue,\r
+ IN OUT UINTN *RetryTimes OPTIONAL\r
+ )\r
+{\r
+ UINT32 Value;\r
+\r
+ if (RetryTimes != NULL) {\r
+ (*RetryTimes)--;\r
+ }\r
+\r
+ Value = *(volatile UINT32 *) Address;\r
+ Value &= MaskValue;\r
+\r
+ if (Value == TestValue) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if ((RetryTimes != NULL) && (*RetryTimes == 0)) {\r
+ return EFI_TIMEOUT;\r
+ } else {\r
+ return EFI_NOT_READY;\r
+ }\r
+}\r
+\r
+/**\r
+ Clear the port interrupt and error status. It will also clear\r
+ HBA interrupt status.\r
+\r
+ @param AhciBar AHCI bar address.\r
+ @param Port The number of port.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciClearPortStatus (\r
+ IN UINT32 AhciBar,\r
+ IN UINT8 Port\r
+ )\r
+{\r
+ UINT32 Offset;\r
+\r
+ //\r
+ // Clear any error status\r
+ //\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
+ AhciWriteReg (AhciBar, Offset, AhciReadReg (AhciBar, Offset));\r
+\r
+ //\r
+ // Clear any port interrupt status\r
+ //\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;\r
+ AhciWriteReg (AhciBar, Offset, AhciReadReg (AhciBar, Offset));\r
+\r
+ //\r
+ // Clear any HBA interrupt status\r
+ //\r
+ AhciWriteReg (AhciBar, EFI_AHCI_IS_OFFSET, AhciReadReg (AhciBar, EFI_AHCI_IS_OFFSET));\r
+}\r
+\r
+/**\r
+ Enable the FIS running for giving port.\r
+\r
+ @param AhciBar AHCI bar address.\r
+ @param Port The number of port.\r
+ @param Timeout The timeout Value of enabling FIS.\r
+\r
+ @retval EFI_DEVICE_ERROR The FIS enable setting fails.\r
+ @retval EFI_TIMEOUT The FIS enable setting is time out.\r
+ @retval EFI_SUCCESS The FIS enable successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciEnableFisReceive (\r
+ IN UINT32 AhciBar,\r
+ IN UINT8 Port,\r
+ IN UINT64 Timeout\r
+ )\r
+{\r
+ UINT32 Offset;\r
+\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+ AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_FRE);\r
+\r
+ return AhciWaitMmioSet (\r
+ AhciBar,\r
+ Offset,\r
+ EFI_AHCI_PORT_CMD_FR,\r
+ EFI_AHCI_PORT_CMD_FR,\r
+ Timeout\r
+ );\r
+}\r
+\r
+/**\r
+ Disable the FIS running for giving port.\r
+\r
+ @param AhciBar AHCI bar address.\r
+ @param Port The number of port.\r
+ @param Timeout The timeout Value of disabling FIS.\r
+\r
+ @retval EFI_DEVICE_ERROR The FIS disable setting fails.\r
+ @retval EFI_TIMEOUT The FIS disable setting is time out.\r
+ @retval EFI_UNSUPPORTED The port is in running state.\r
+ @retval EFI_SUCCESS The FIS disable successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciDisableFisReceive (\r
+ IN UINT32 AhciBar,\r
+ IN UINT8 Port,\r
+ IN UINT64 Timeout\r
+ )\r
+{\r
+ UINT32 Offset;\r
+ UINT32 Data;\r
+\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+ Data = AhciReadReg (AhciBar, Offset);\r
+\r
+ //\r
+ // Before disabling Fis receive, the DMA engine of the port should NOT be in running status.\r
+ //\r
+ if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) != 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Check if the Fis receive DMA engine for the port is running.\r
+ //\r
+ if ((Data & EFI_AHCI_PORT_CMD_FR) != EFI_AHCI_PORT_CMD_FR) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE));\r
+\r
+ return AhciWaitMmioSet (\r
+ AhciBar,\r
+ Offset,\r
+ EFI_AHCI_PORT_CMD_FR,\r
+ 0,\r
+ Timeout\r
+ );\r
+}\r
+\r
+/**\r
+ Build the command list, command table and prepare the fis receiver.\r
+\r
+ @param AhciContext The pointer to the AHCI_CONTEXT.\r
+ @param Port The number of port.\r
+ @param PortMultiplier The timeout Value of stop.\r
+ @param CommandFis The control fis will be used for the transfer.\r
+ @param CommandList The command list will be used for the transfer.\r
+ @param AtapiCommand The atapi command will be used for the transfer.\r
+ @param AtapiCommandLength The Length of the atapi command.\r
+ @param CommandSlotNumber The command slot will be used for the transfer.\r
+ @param DataPhysicalAddr The pointer to the Data Buffer pci bus master address.\r
+ @param DataLength The Data count to be transferred.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciBuildCommand (\r
+ IN AHCI_CONTEXT *AhciContext,\r
+ IN UINT8 Port,\r
+ IN UINT8 PortMultiplier,\r
+ IN EFI_AHCI_COMMAND_FIS *CommandFis,\r
+ IN EFI_AHCI_COMMAND_LIST *CommandList,\r
+ IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
+ IN UINT8 AtapiCommandLength,\r
+ IN UINT8 CommandSlotNumber,\r
+ IN OUT VOID *DataPhysicalAddr,\r
+ IN UINT64 DataLength\r
+ )\r
+{\r
+ EFI_AHCI_REGISTERS *AhciRegisters;\r
+ UINT32 AhciBar;\r
+ UINT64 BaseAddr;\r
+ UINT64 PrdtNumber;\r
+ UINTN RemainedData;\r
+ UINTN MemAddr;\r
+ DATA_64 Data64;\r
+ UINT32 Offset;\r
+\r
+ AhciRegisters = &AhciContext->AhciRegisters;\r
+ AhciBar = AhciContext->AhciBar;\r
+\r
+ //\r
+ // Filling the PRDT\r
+ //\r
+ PrdtNumber = DivU64x32 (DataLength + EFI_AHCI_MAX_DATA_PER_PRDT - 1, EFI_AHCI_MAX_DATA_PER_PRDT);\r
+\r
+ //\r
+ // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB Data block.\r
+ // It also limits that the maximum amount of the PRDT entry in the command table\r
+ // is 65535.\r
+ //\r
+ ASSERT (PrdtNumber <= 1);\r
+\r
+ Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis);\r
+\r
+ BaseAddr = Data64.Uint64;\r
+\r
+ ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));\r
+\r
+ ZeroMem (AhciRegisters->AhciCommandTable, sizeof (EFI_AHCI_COMMAND_TABLE));\r
+\r
+ CommandFis->AhciCFisPmNum = PortMultiplier;\r
+\r
+ CopyMem (&AhciRegisters->AhciCommandTable->CommandFis, CommandFis, sizeof (EFI_AHCI_COMMAND_FIS));\r
+\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+ if (AtapiCommand != NULL) {\r
+ CopyMem (\r
+ &AhciRegisters->AhciCommandTable->AtapiCmd,\r
+ AtapiCommand,\r
+ AtapiCommandLength\r
+ );\r
+\r
+ CommandList->AhciCmdA = 1;\r
+ CommandList->AhciCmdP = 1;\r
+\r
+ AhciOrReg (AhciBar, Offset, (EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));\r
+ } else {\r
+ AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));\r
+ }\r
+\r
+ RemainedData = (UINTN) DataLength;\r
+ MemAddr = (UINTN) DataPhysicalAddr;\r
+ CommandList->AhciCmdPrdtl = (UINT32)PrdtNumber;\r
+\r
+ AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDbc = (UINT32)RemainedData - 1;\r
+\r
+ Data64.Uint64 = (UINT64)MemAddr;\r
+ AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDba = Data64.Uint32.Lower32;\r
+ AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDbau = Data64.Uint32.Upper32;\r
+\r
+ //\r
+ // Set the last PRDT to Interrupt On Complete\r
+ //\r
+ AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtIoc = 1;\r
+\r
+ CopyMem (\r
+ (VOID *) ((UINTN) AhciRegisters->AhciCmdList + (UINTN) CommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST)),\r
+ CommandList,\r
+ sizeof (EFI_AHCI_COMMAND_LIST)\r
+ );\r
+\r
+ Data64.Uint64 = (UINT64)(UINTN) AhciRegisters->AhciCommandTable;\r
+ AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtba = Data64.Uint32.Lower32;\r
+ AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtbau = Data64.Uint32.Upper32;\r
+ AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdPmp = PortMultiplier;\r
+\r
+}\r
+\r
+/**\r
+ Buid a command FIS.\r
+\r
+ @param CmdFis A pointer to the EFI_AHCI_COMMAND_FIS Data structure.\r
+ @param AtaCommandBlock A pointer to the AhciBuildCommandFis Data structure.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciBuildCommandFis (\r
+ IN OUT EFI_AHCI_COMMAND_FIS *CmdFis,\r
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock\r
+ )\r
+{\r
+ ZeroMem (CmdFis, sizeof (EFI_AHCI_COMMAND_FIS));\r
+\r
+ CmdFis->AhciCFisType = EFI_AHCI_FIS_REGISTER_H2D;\r
+ //\r
+ // Indicator it's a command\r
+ //\r
+ CmdFis->AhciCFisCmdInd = 0x1;\r
+ CmdFis->AhciCFisCmd = AtaCommandBlock->AtaCommand;\r
+\r
+ CmdFis->AhciCFisFeature = AtaCommandBlock->AtaFeatures;\r
+ CmdFis->AhciCFisFeatureExp = AtaCommandBlock->AtaFeaturesExp;\r
+\r
+ CmdFis->AhciCFisSecNum = AtaCommandBlock->AtaSectorNumber;\r
+ CmdFis->AhciCFisSecNumExp = AtaCommandBlock->AtaSectorNumberExp;\r
+\r
+ CmdFis->AhciCFisClyLow = AtaCommandBlock->AtaCylinderLow;\r
+ CmdFis->AhciCFisClyLowExp = AtaCommandBlock->AtaCylinderLowExp;\r
+\r
+ CmdFis->AhciCFisClyHigh = AtaCommandBlock->AtaCylinderHigh;\r
+ CmdFis->AhciCFisClyHighExp = AtaCommandBlock->AtaCylinderHighExp;\r
+\r
+ CmdFis->AhciCFisSecCount = AtaCommandBlock->AtaSectorCount;\r
+ CmdFis->AhciCFisSecCountExp = AtaCommandBlock->AtaSectorCountExp;\r
+\r
+ CmdFis->AhciCFisDevHead = (UINT8) (AtaCommandBlock->AtaDeviceHead | 0xE0);\r
+}\r
+\r
+/**\r
+ Start a PIO Data transfer on specific port.\r
+\r
+ @param AhciContext The pointer to the AHCI_CONTEXT.\r
+ @param Port The number of port.\r
+ @param PortMultiplier The timeout Value of stop.\r
+ @param AtapiCommand The atapi command will be used for the transfer.\r
+ @param AtapiCommandLength The Length of the atapi command.\r
+ @param Read The transfer direction.\r
+ @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK Data.\r
+ @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK Data.\r
+ @param MemoryAddr The pointer to the Data Buffer.\r
+ @param DataCount The Data count to be transferred.\r
+ @param Timeout The timeout Value of non Data transfer.\r
+\r
+ @retval EFI_DEVICE_ERROR The PIO Data transfer abort with error occurs.\r
+ @retval EFI_TIMEOUT The operation is time out.\r
+ @retval EFI_UNSUPPORTED The device is not ready for transfer.\r
+ @retval EFI_SUCCESS The PIO Data transfer executes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciPioTransfer (\r
+ IN AHCI_CONTEXT *AhciContext,\r
+ IN UINT8 Port,\r
+ IN UINT8 PortMultiplier,\r
+ IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
+ IN UINT8 AtapiCommandLength,\r
+ IN BOOLEAN Read,\r
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
+ IN OUT VOID *MemoryAddr,\r
+ IN UINT32 DataCount,\r
+ IN UINT64 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_AHCI_REGISTERS *AhciRegisters;\r
+ UINT32 AhciBar;\r
+ UINT32 FisBaseAddr;\r
+ UINT32 Offset;\r
+ UINT32 Delay;\r
+ EFI_AHCI_COMMAND_FIS CFis;\r
+ EFI_AHCI_COMMAND_LIST CmdList;\r
+ UINT32 PortTfd;\r
+ UINT32 PrdCount;\r
+ UINT32 OldRfisLo;\r
+ UINT32 OldRfisHi;\r
+ UINT32 OldCmdListLo;\r
+ UINT32 OldCmdListHi;\r
+\r
+ AhciRegisters = &AhciContext->AhciRegisters;\r
+ AhciBar = AhciContext->AhciBar;\r
+\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
+ OldRfisLo = AhciReadReg (AhciBar, Offset);\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;\r
+ OldRfisHi = AhciReadReg (AhciBar, Offset);\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
+ AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciRFis);\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;\r
+ AhciWriteReg (AhciBar, Offset, 0);\r
+\r
+ //\r
+ // Single task envrionment, we only use one command table for all port\r
+ //\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
+ OldCmdListLo = AhciReadReg (AhciBar, Offset);\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;\r
+ OldCmdListHi = AhciReadReg (AhciBar, Offset);\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
+ AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciCmdList);\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;\r
+ AhciWriteReg (AhciBar, Offset, 0);\r
+\r
+ //\r
+ // Package read needed\r
+ //\r
+ AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
+\r
+ ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
+\r
+ CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
+ CmdList.AhciCmdW = Read ? 0 : 1;\r
+\r
+ AhciBuildCommand (\r
+ AhciContext,\r
+ Port,\r
+ PortMultiplier,\r
+ &CFis,\r
+ &CmdList,\r
+ AtapiCommand,\r
+ AtapiCommandLength,\r
+ 0,\r
+ MemoryAddr,\r
+ DataCount\r
+ );\r
+\r
+ Status = AhciStartCommand (\r
+ AhciBar,\r
+ Port,\r
+ 0,\r
+ Timeout\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Checking the status and wait the driver sending Data\r
+ //\r
+ FisBaseAddr = (UINT32)(UINTN)AhciRegisters->AhciRFis;\r
+ if (Read && (AtapiCommand == 0)) {\r
+ //\r
+ // Wait device sends the PIO setup fis before Data transfer\r
+ //\r
+ Status = EFI_TIMEOUT;\r
+ Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);\r
+ do {\r
+ Offset = FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET;\r
+\r
+ Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_PIO_SETUP, 0);\r
+ if (!EFI_ERROR (Status)) {\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
+ PortTfd = AhciReadReg (AhciBar, (UINT32) Offset);\r
+ //\r
+ // PxTFD will be updated if there is a D2H or SetupFIS received.\r
+ // For PIO IN transfer, D2H means a device error. Therefore we only need to check the TFD after receiving a SetupFIS.\r
+ //\r
+ if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ break;\r
+ }\r
+\r
+ PrdCount = *(volatile UINT32 *) (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));\r
+ if (PrdCount == DataCount) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
+ Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, 0);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Stall for 100 microseconds.\r
+ //\r
+ MicroSecondDelay(100);\r
+\r
+ Delay--;\r
+ } while (Delay > 0);\r
+ } else {\r
+ //\r
+ // Wait for D2H Fis is received\r
+ //\r
+ Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
+ Status = AhciWaitMemSet (\r
+ Offset,\r
+ EFI_AHCI_FIS_TYPE_MASK,\r
+ EFI_AHCI_FIS_REGISTER_D2H,\r
+ Timeout\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
+ PortTfd = AhciReadReg (AhciBar, (UINT32) Offset);\r
+ if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+\r
+Exit:\r
+ AhciStopCommand (\r
+ AhciBar,\r
+ Port,\r
+ Timeout\r
+ );\r
+\r
+ AhciDisableFisReceive (\r
+ AhciBar,\r
+ Port,\r
+ Timeout\r
+ );\r
+\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
+ AhciWriteReg (AhciBar, Offset, OldRfisLo);\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;\r
+ AhciWriteReg (AhciBar, Offset, OldRfisHi);\r
+\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
+ AhciWriteReg (AhciBar, Offset, OldCmdListLo);\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;\r
+ AhciWriteReg (AhciBar, Offset, OldCmdListHi);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Stop command running for giving port\r
+\r
+ @param AhciBar AHCI bar address.\r
+ @param Port The number of port.\r
+ @param Timeout The timeout Value of stop.\r
+\r
+ @retval EFI_DEVICE_ERROR The command stop unsuccessfully.\r
+ @retval EFI_TIMEOUT The operation is time out.\r
+ @retval EFI_SUCCESS The command stop successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciStopCommand (\r
+ IN UINT32 AhciBar,\r
+ IN UINT8 Port,\r
+ IN UINT64 Timeout\r
+ )\r
+{\r
+ UINT32 Offset;\r
+ UINT32 Data;\r
+\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+ Data = AhciReadReg (AhciBar, Offset);\r
+\r
+ if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if ((Data & EFI_AHCI_PORT_CMD_ST) != 0) {\r
+ AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_ST));\r
+ }\r
+\r
+ return AhciWaitMmioSet (\r
+ AhciBar,\r
+ Offset,\r
+ EFI_AHCI_PORT_CMD_CR,\r
+ 0,\r
+ Timeout\r
+ );\r
+}\r
+\r
+/**\r
+ Start command for give slot on specific port.\r
+\r
+ @param AhciBar AHCI bar address.\r
+ @param Port The number of port.\r
+ @param CommandSlot The number of CommandSlot.\r
+ @param Timeout The timeout Value of start.\r
+\r
+ @retval EFI_DEVICE_ERROR The command start unsuccessfully.\r
+ @retval EFI_TIMEOUT The operation is time out.\r
+ @retval EFI_SUCCESS The command start successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciStartCommand (\r
+ IN UINT32 AhciBar,\r
+ IN UINT8 Port,\r
+ IN UINT8 CommandSlot,\r
+ IN UINT64 Timeout\r
+ )\r
+{\r
+ UINT32 CmdSlotBit;\r
+ EFI_STATUS Status;\r
+ UINT32 PortStatus;\r
+ UINT32 StartCmd;\r
+ UINT32 PortTfd;\r
+ UINT32 Offset;\r
+ UINT32 Capability;\r
+\r
+ //\r
+ // Collect AHCI controller information\r
+ //\r
+ Capability = AhciReadReg(AhciBar, EFI_AHCI_CAPABILITY_OFFSET);\r
+\r
+ CmdSlotBit = (UINT32) (1 << CommandSlot);\r
+\r
+ AhciClearPortStatus (\r
+ AhciBar,\r
+ Port\r
+ );\r
+\r
+ Status = AhciEnableFisReceive (\r
+ AhciBar,\r
+ Port,\r
+ Timeout\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+ PortStatus = AhciReadReg (AhciBar, Offset);\r
+\r
+ StartCmd = 0;\r
+ if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) != 0) {\r
+ StartCmd = AhciReadReg (AhciBar, Offset);\r
+ StartCmd &= ~EFI_AHCI_PORT_CMD_ICC_MASK;\r
+ StartCmd |= EFI_AHCI_PORT_CMD_ACTIVE;\r
+ }\r
+\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
+ PortTfd = AhciReadReg (AhciBar, Offset);\r
+\r
+ if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) != 0) {\r
+ if ((Capability & BIT24) != 0) {\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+ AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_COL);\r
+\r
+ AhciWaitMmioSet (\r
+ AhciBar,\r
+ Offset,\r
+ EFI_AHCI_PORT_CMD_COL,\r
+ 0,\r
+ Timeout\r
+ );\r
+ }\r
+ }\r
+\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+ AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_ST | StartCmd);\r
+\r
+ //\r
+ // Setting the command\r
+ //\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SACT;\r
+ AhciAndReg (AhciBar, Offset, 0);\r
+ AhciOrReg (AhciBar, Offset, CmdSlotBit);\r
+\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
+ AhciAndReg (AhciBar, Offset, 0);\r
+ AhciOrReg (AhciBar, Offset, CmdSlotBit);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Do AHCI HBA reset.\r
+\r
+ @param[in] AhciBar AHCI bar address.\r
+ @param[in] Timeout The timeout Value of reset.\r
+\r
+ @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset.\r
+ @retval EFI_TIMEOUT The reset operation is time out.\r
+ @retval EFI_SUCCESS AHCI controller is reset successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciReset (\r
+ IN UINT32 AhciBar,\r
+ IN UINT64 Timeout\r
+ )\r
+{\r
+ UINT32 Delay;\r
+ UINT32 Value;\r
+ UINT32 Capability;\r
+\r
+ //\r
+ // Collect AHCI controller information\r
+ //\r
+ Capability = AhciReadReg (AhciBar, EFI_AHCI_CAPABILITY_OFFSET);\r
+\r
+ //\r
+ // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only is not set\r
+ //\r
+ if ((Capability & EFI_AHCI_CAP_SAM) == 0) {\r
+ AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
+ }\r
+\r
+ AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);\r
+\r
+ Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+\r
+ do {\r
+ Value = AhciReadReg(AhciBar, EFI_AHCI_GHC_OFFSET);\r
+ if ((Value & EFI_AHCI_GHC_RESET) == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Stall for 100 microseconds.\r
+ //\r
+ MicroSecondDelay(100);\r
+\r
+ Delay--;\r
+ } while (Delay > 0);\r
+\r
+ return EFI_TIMEOUT;\r
+\r
+\r
+}\r
+\r
+/**\r
+ Send Buffer cmd to specific device.\r
+\r
+ @param[in] AhciContext The pointer to the AHCI_CONTEXT.\r
+ @param[in] Port The port number of attached ATA device.\r
+ @param[in] PortMultiplier The port number of port multiplier of attached ATA device.\r
+ @param[in, out] Buffer The Data Buffer to store IDENTIFY PACKET Data.\r
+\r
+ @retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
+ @retval EFI_TIMEOUT The operation is time out.\r
+ @retval EFI_UNSUPPORTED The device is not ready for executing.\r
+ @retval EFI_SUCCESS The cmd executes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciIdentify (\r
+ IN AHCI_CONTEXT *AhciContext,\r
+ IN UINT8 Port,\r
+ IN UINT8 PortMultiplier,\r
+ IN OUT ATA_IDENTIFY_DATA *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
+\r
+ if (AhciContext == NULL || Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+\r
+ AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DRIVE;\r
+ AtaCommandBlock.AtaSectorCount = 1;\r
+\r
+ Status = AhciPioTransfer (\r
+ AhciContext,\r
+ Port,\r
+ PortMultiplier,\r
+ NULL,\r
+ 0,\r
+ TRUE,\r
+ &AtaCommandBlock,\r
+ NULL,\r
+ Buffer,\r
+ sizeof (ATA_IDENTIFY_DATA),\r
+ ATA_TIMEOUT\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Allocate transfer-related data struct which is used at AHCI mode.\r
+\r
+ @param[in, out] AhciContext The pointer to the AHCI_CONTEXT.\r
+\r
+ @retval EFI_OUT_OF_RESOURCE No enough resource.\r
+ @retval EFI_SUCCESS Successful to allocate resource.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciAllocateResource (\r
+ IN OUT AHCI_CONTEXT *AhciContext\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_AHCI_REGISTERS *AhciRegisters;\r
+ EFI_PHYSICAL_ADDRESS DeviceAddress;\r
+ VOID *Base;\r
+ VOID *Mapping;\r
+\r
+ AhciRegisters = &AhciContext->AhciRegisters;\r
+\r
+ //\r
+ // Allocate resources required by AHCI host controller.\r
+ //\r
+ Status = IoMmuAllocateBuffer (\r
+ EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),\r
+ &Base,\r
+ &DeviceAddress,\r
+ &Mapping\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));\r
+ AhciRegisters->AhciRFisMapping = Mapping;\r
+ AhciRegisters->AhciRFis = Base;\r
+ ZeroMem (AhciRegisters->AhciRFis, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)));\r
+\r
+ Status = IoMmuAllocateBuffer (\r
+ EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),\r
+ &Base,\r
+ &DeviceAddress,\r
+ &Mapping\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ IoMmuFreeBuffer (\r
+ EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),\r
+ AhciRegisters->AhciRFis,\r
+ AhciRegisters->AhciRFisMapping\r
+ );\r
+ AhciRegisters->AhciRFis = NULL;\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));\r
+ AhciRegisters->AhciCmdListMapping = Mapping;\r
+ AhciRegisters->AhciCmdList = Base;\r
+ ZeroMem (AhciRegisters->AhciCmdList, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)));\r
+\r
+ Status = IoMmuAllocateBuffer (\r
+ EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)),\r
+ &Base,\r
+ &DeviceAddress,\r
+ &Mapping\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ IoMmuFreeBuffer (\r
+ EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),\r
+ AhciRegisters->AhciCmdList,\r
+ AhciRegisters->AhciCmdListMapping\r
+ );\r
+ AhciRegisters->AhciCmdList = NULL;\r
+ IoMmuFreeBuffer (\r
+ EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),\r
+ AhciRegisters->AhciRFis,\r
+ AhciRegisters->AhciRFisMapping\r
+ );\r
+ AhciRegisters->AhciRFis = NULL;\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));\r
+ AhciRegisters->AhciCommandTableMapping = Mapping;\r
+ AhciRegisters->AhciCommandTable = Base;\r
+ ZeroMem (AhciRegisters->AhciCommandTable, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)));\r
+\r
+ //\r
+ // Allocate resources for data transfer.\r
+ //\r
+ Status = IoMmuAllocateBuffer (\r
+ EFI_SIZE_TO_PAGES (HDD_PAYLOAD),\r
+ &Base,\r
+ &DeviceAddress,\r
+ &Mapping\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ IoMmuFreeBuffer (\r
+ EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),\r
+ AhciRegisters->AhciCommandTable,\r
+ AhciRegisters->AhciCommandTableMapping\r
+ );\r
+ AhciRegisters->AhciCommandTable = NULL;\r
+ IoMmuFreeBuffer (\r
+ EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),\r
+ AhciRegisters->AhciCmdList,\r
+ AhciRegisters->AhciCmdListMapping\r
+ );\r
+ AhciRegisters->AhciCmdList = NULL;\r
+ IoMmuFreeBuffer (\r
+ EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),\r
+ AhciRegisters->AhciRFis,\r
+ AhciRegisters->AhciRFisMapping\r
+ );\r
+ AhciRegisters->AhciRFis = NULL;\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));\r
+ AhciContext->BufferMapping = Mapping;\r
+ AhciContext->Buffer = Base;\r
+ ZeroMem (AhciContext->Buffer, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (HDD_PAYLOAD));\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "%a() AhciContext 0x%x 0x%x 0x%x 0x%x\n",\r
+ __FUNCTION__,\r
+ AhciContext->Buffer,\r
+ AhciRegisters->AhciRFis,\r
+ AhciRegisters->AhciCmdList,\r
+ AhciRegisters->AhciCommandTable\r
+ ));\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Free allocated transfer-related data struct which is used at AHCI mode.\r
+\r
+ @param[in, out] AhciContext The pointer to the AHCI_CONTEXT.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciFreeResource (\r
+ IN OUT AHCI_CONTEXT *AhciContext\r
+ )\r
+{\r
+ EFI_AHCI_REGISTERS *AhciRegisters;\r
+\r
+ AhciRegisters = &AhciContext->AhciRegisters;\r
+\r
+ if (AhciContext->Buffer != NULL) {\r
+ IoMmuFreeBuffer (\r
+ EFI_SIZE_TO_PAGES (HDD_PAYLOAD),\r
+ AhciContext->Buffer,\r
+ AhciContext->BufferMapping\r
+ );\r
+ AhciContext->Buffer = NULL;\r
+ }\r
+\r
+ if (AhciRegisters->AhciCommandTable != NULL) {\r
+ IoMmuFreeBuffer (\r
+ EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)),\r
+ AhciRegisters->AhciCommandTable,\r
+ AhciRegisters->AhciCommandTableMapping\r
+ );\r
+ AhciRegisters->AhciCommandTable = NULL;\r
+ }\r
+\r
+ if (AhciRegisters->AhciCmdList != NULL) {\r
+ IoMmuFreeBuffer (\r
+ EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),\r
+ AhciRegisters->AhciCmdList,\r
+ AhciRegisters->AhciCmdListMapping\r
+ );\r
+ AhciRegisters->AhciCmdList = NULL;\r
+ }\r
+\r
+ if (AhciRegisters->AhciRFis != NULL) {\r
+ IoMmuFreeBuffer (\r
+ EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),\r
+ AhciRegisters->AhciRFis,\r
+ AhciRegisters->AhciRFisMapping\r
+ );\r
+ AhciRegisters->AhciRFis = NULL;\r
+ }\r
+}\r
+\r
+/**\r
+ Initialize ATA host controller at AHCI mode.\r
+\r
+ The function is designed to initialize ATA host controller.\r
+\r
+ @param[in] AhciContext The pointer to the AHCI_CONTEXT.\r
+ @param[in] Port The port number to do initialization.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciModeInitialize (\r
+ IN AHCI_CONTEXT *AhciContext,\r
+ IN UINT8 Port\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_AHCI_REGISTERS *AhciRegisters;\r
+ UINT32 AhciBar;\r
+ UINT32 Capability;\r
+ UINT32 Offset;\r
+ UINT32 Data;\r
+ UINT32 PhyDetectDelay;\r
+\r
+ AhciRegisters = &AhciContext->AhciRegisters;\r
+ AhciBar = AhciContext->AhciBar;\r
+\r
+ Status = AhciReset (AhciBar, ATA_TIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Collect AHCI controller information\r
+ //\r
+ Capability = AhciReadReg (AhciBar, EFI_AHCI_CAPABILITY_OFFSET);\r
+\r
+ //\r
+ // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only is not set\r
+ //\r
+ if ((Capability & EFI_AHCI_CAP_SAM) == 0) {\r
+ AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
+ }\r
+\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
+ AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciRFis);\r
+\r
+ //\r
+ // Single task envrionment, we only use one command table for all port\r
+ //\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
+ AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciCmdList);\r
+\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+ Data = AhciReadReg (AhciBar, Offset);\r
+ if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) {\r
+ AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_POD);\r
+ }\r
+\r
+ if ((Capability & BIT27) != 0) {\r
+ AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_SUD);\r
+ }\r
+\r
+ //\r
+ // Disable aggressive power management.\r
+ //\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
+ AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_SCTL_IPM_INIT);\r
+ //\r
+ // Disable the reporting of the corresponding interrupt to system software.\r
+ //\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;\r
+ AhciAndReg (AhciBar, Offset, 0);\r
+\r
+ Status = AhciEnableFisReceive (\r
+ AhciBar,\r
+ Port,\r
+ 5000000\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ\r
+ // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.\r
+ //\r
+ PhyDetectDelay = 16 * 1000;\r
+ do {\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
+ if (AhciReadReg(AhciBar, Offset) != 0) {\r
+ AhciWriteReg (AhciBar, Offset, AhciReadReg(AhciBar, Offset));\r
+ }\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
+\r
+ Data = AhciReadReg (AhciBar, Offset) & EFI_AHCI_PORT_TFD_MASK;\r
+ if (Data == 0) {\r
+ break;\r
+ }\r
+\r
+ MicroSecondDelay (1000);\r
+ PhyDetectDelay--;\r
+ } while (PhyDetectDelay > 0);\r
+\r
+ if (PhyDetectDelay == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;\r
+ Status = AhciWaitMmioSet (\r
+ AhciBar,\r
+ Offset,\r
+ 0x0000FFFF,\r
+ 0x00000101,\r
+ 160000000\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+ Header file for AHCI mode of ATA host controller.\r
+\r
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#ifndef __OPAL_PASSWORD_AHCI_MODE_H__\r
+#define __OPAL_PASSWORD_AHCI_MODE_H__\r
+\r
+//\r
+// OPAL LIBRARY CALLBACKS\r
+//\r
+#define ATA_COMMAND_TRUSTED_RECEIVE 0x5C\r
+#define ATA_COMMAND_TRUSTED_SEND 0x5E\r
+\r
+//\r
+// ATA TRUSTED commands express transfer Length in 512 byte multiple\r
+//\r
+#define ATA_TRUSTED_TRANSFER_LENGTH_MULTIPLE 512\r
+#define ATA_DEVICE_LBA 0x40 ///< Set for commands with LBA (rather than CHS) addresses\r
+\r
+\r
+#define EFI_AHCI_BAR_INDEX 0x05\r
+\r
+#define EFI_AHCI_CAPABILITY_OFFSET 0x0000\r
+#define EFI_AHCI_CAP_SAM BIT18\r
+#define EFI_AHCI_GHC_OFFSET 0x0004\r
+#define EFI_AHCI_GHC_RESET BIT0\r
+#define EFI_AHCI_GHC_IE BIT1\r
+#define EFI_AHCI_GHC_ENABLE BIT31\r
+#define EFI_AHCI_IS_OFFSET 0x0008\r
+#define EFI_AHCI_PI_OFFSET 0x000C\r
+\r
+typedef struct {\r
+ UINT32 Lower32;\r
+ UINT32 Upper32;\r
+} DATA_32;\r
+\r
+typedef union {\r
+ DATA_32 Uint32;\r
+ UINT64 Uint64;\r
+} DATA_64;\r
+\r
+//\r
+// Each PRDT entry can point to a memory block up to 4M byte\r
+//\r
+#define EFI_AHCI_MAX_DATA_PER_PRDT 0x400000\r
+\r
+#define EFI_AHCI_FIS_REGISTER_H2D 0x27 //Register FIS - Host to Device\r
+#define EFI_AHCI_FIS_REGISTER_H2D_LENGTH 20\r
+#define EFI_AHCI_FIS_REGISTER_D2H 0x34 //Register FIS - Device to Host\r
+#define EFI_AHCI_FIS_REGISTER_D2H_LENGTH 20\r
+#define EFI_AHCI_FIS_DMA_ACTIVATE 0x39 //DMA Activate FIS - Device to Host\r
+#define EFI_AHCI_FIS_DMA_ACTIVATE_LENGTH 4\r
+#define EFI_AHCI_FIS_DMA_SETUP 0x41 //DMA Setup FIS - Bi-directional\r
+#define EFI_AHCI_FIS_DMA_SETUP_LENGTH 28\r
+#define EFI_AHCI_FIS_DATA 0x46 //Data FIS - Bi-directional\r
+#define EFI_AHCI_FIS_BIST 0x58 //BIST Activate FIS - Bi-directional\r
+#define EFI_AHCI_FIS_BIST_LENGTH 12\r
+#define EFI_AHCI_FIS_PIO_SETUP 0x5F //PIO Setup FIS - Device to Host\r
+#define EFI_AHCI_FIS_PIO_SETUP_LENGTH 20\r
+#define EFI_AHCI_FIS_SET_DEVICE 0xA1 //Set Device Bits FIS - Device to Host\r
+#define EFI_AHCI_FIS_SET_DEVICE_LENGTH 8\r
+\r
+#define EFI_AHCI_D2H_FIS_OFFSET 0x40\r
+#define EFI_AHCI_DMA_FIS_OFFSET 0x00\r
+#define EFI_AHCI_PIO_FIS_OFFSET 0x20\r
+#define EFI_AHCI_SDB_FIS_OFFSET 0x58\r
+#define EFI_AHCI_FIS_TYPE_MASK 0xFF\r
+#define EFI_AHCI_U_FIS_OFFSET 0x60\r
+\r
+//\r
+// Port register\r
+//\r
+#define EFI_AHCI_PORT_START 0x0100\r
+#define EFI_AHCI_PORT_REG_WIDTH 0x0080\r
+#define EFI_AHCI_PORT_CLB 0x0000\r
+#define EFI_AHCI_PORT_CLBU 0x0004\r
+#define EFI_AHCI_PORT_FB 0x0008\r
+#define EFI_AHCI_PORT_FBU 0x000C\r
+#define EFI_AHCI_PORT_IS 0x0010\r
+#define EFI_AHCI_PORT_IS_DHRS BIT0\r
+#define EFI_AHCI_PORT_IS_PSS BIT1\r
+#define EFI_AHCI_PORT_IS_SSS BIT2\r
+#define EFI_AHCI_PORT_IS_SDBS BIT3\r
+#define EFI_AHCI_PORT_IS_UFS BIT4\r
+#define EFI_AHCI_PORT_IS_DPS BIT5\r
+#define EFI_AHCI_PORT_IS_PCS BIT6\r
+#define EFI_AHCI_PORT_IS_DIS BIT7\r
+#define EFI_AHCI_PORT_IS_PRCS BIT22\r
+#define EFI_AHCI_PORT_IS_IPMS BIT23\r
+#define EFI_AHCI_PORT_IS_OFS BIT24\r
+#define EFI_AHCI_PORT_IS_INFS BIT26\r
+#define EFI_AHCI_PORT_IS_IFS BIT27\r
+#define EFI_AHCI_PORT_IS_HBDS BIT28\r
+#define EFI_AHCI_PORT_IS_HBFS BIT29\r
+#define EFI_AHCI_PORT_IS_TFES BIT30\r
+#define EFI_AHCI_PORT_IS_CPDS BIT31\r
+#define EFI_AHCI_PORT_IS_CLEAR 0xFFFFFFFF\r
+#define EFI_AHCI_PORT_IS_FIS_CLEAR 0x0000000F\r
+\r
+#define EFI_AHCI_PORT_IE 0x0014\r
+#define EFI_AHCI_PORT_CMD 0x0018\r
+#define EFI_AHCI_PORT_CMD_ST_MASK 0xFFFFFFFE\r
+#define EFI_AHCI_PORT_CMD_ST BIT0\r
+#define EFI_AHCI_PORT_CMD_SUD BIT1\r
+#define EFI_AHCI_PORT_CMD_POD BIT2\r
+#define EFI_AHCI_PORT_CMD_COL BIT3\r
+#define EFI_AHCI_PORT_CMD_CR BIT15\r
+#define EFI_AHCI_PORT_CMD_FRE BIT4\r
+#define EFI_AHCI_PORT_CMD_FR BIT14\r
+#define EFI_AHCI_PORT_CMD_MASK ~(EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_FRE | EFI_AHCI_PORT_CMD_COL)\r
+#define EFI_AHCI_PORT_CMD_PMA BIT17\r
+#define EFI_AHCI_PORT_CMD_HPCP BIT18\r
+#define EFI_AHCI_PORT_CMD_MPSP BIT19\r
+#define EFI_AHCI_PORT_CMD_CPD BIT20\r
+#define EFI_AHCI_PORT_CMD_ESP BIT21\r
+#define EFI_AHCI_PORT_CMD_ATAPI BIT24\r
+#define EFI_AHCI_PORT_CMD_DLAE BIT25\r
+#define EFI_AHCI_PORT_CMD_ALPE BIT26\r
+#define EFI_AHCI_PORT_CMD_ASP BIT27\r
+#define EFI_AHCI_PORT_CMD_ICC_MASK (BIT28 | BIT29 | BIT30 | BIT31)\r
+#define EFI_AHCI_PORT_CMD_ACTIVE (1 << 28 )\r
+#define EFI_AHCI_PORT_TFD 0x0020\r
+#define EFI_AHCI_PORT_TFD_MASK (BIT7 | BIT3 | BIT0)\r
+#define EFI_AHCI_PORT_TFD_BSY BIT7\r
+#define EFI_AHCI_PORT_TFD_DRQ BIT3\r
+#define EFI_AHCI_PORT_TFD_ERR BIT0\r
+#define EFI_AHCI_PORT_TFD_ERR_MASK 0x00FF00\r
+#define EFI_AHCI_PORT_SIG 0x0024\r
+#define EFI_AHCI_PORT_SSTS 0x0028\r
+#define EFI_AHCI_PORT_SSTS_DET_MASK 0x000F\r
+#define EFI_AHCI_PORT_SSTS_DET 0x0001\r
+#define EFI_AHCI_PORT_SSTS_DET_PCE 0x0003\r
+#define EFI_AHCI_PORT_SSTS_SPD_MASK 0x00F0\r
+#define EFI_AHCI_PORT_SCTL 0x002C\r
+#define EFI_AHCI_PORT_SCTL_DET_MASK 0x000F\r
+#define EFI_AHCI_PORT_SCTL_MASK (~EFI_AHCI_PORT_SCTL_DET_MASK)\r
+#define EFI_AHCI_PORT_SCTL_DET_INIT 0x0001\r
+#define EFI_AHCI_PORT_SCTL_DET_PHYCOMM 0x0003\r
+#define EFI_AHCI_PORT_SCTL_SPD_MASK 0x00F0\r
+#define EFI_AHCI_PORT_SCTL_IPM_MASK 0x0F00\r
+#define EFI_AHCI_PORT_SCTL_IPM_INIT 0x0300\r
+#define EFI_AHCI_PORT_SCTL_IPM_PSD 0x0100\r
+#define EFI_AHCI_PORT_SCTL_IPM_SSD 0x0200\r
+#define EFI_AHCI_PORT_SERR 0x0030\r
+#define EFI_AHCI_PORT_SERR_RDIE BIT0\r
+#define EFI_AHCI_PORT_SERR_RCE BIT1\r
+#define EFI_AHCI_PORT_SERR_TDIE BIT8\r
+#define EFI_AHCI_PORT_SERR_PCDIE BIT9\r
+#define EFI_AHCI_PORT_SERR_PE BIT10\r
+#define EFI_AHCI_PORT_SERR_IE BIT11\r
+#define EFI_AHCI_PORT_SERR_PRC BIT16\r
+#define EFI_AHCI_PORT_SERR_PIE BIT17\r
+#define EFI_AHCI_PORT_SERR_CW BIT18\r
+#define EFI_AHCI_PORT_SERR_BDE BIT19\r
+#define EFI_AHCI_PORT_SERR_DE BIT20\r
+#define EFI_AHCI_PORT_SERR_CRCE BIT21\r
+#define EFI_AHCI_PORT_SERR_HE BIT22\r
+#define EFI_AHCI_PORT_SERR_LSE BIT23\r
+#define EFI_AHCI_PORT_SERR_TSTE BIT24\r
+#define EFI_AHCI_PORT_SERR_UFT BIT25\r
+#define EFI_AHCI_PORT_SERR_EX BIT26\r
+#define EFI_AHCI_PORT_ERR_CLEAR 0xFFFFFFFF\r
+#define EFI_AHCI_PORT_SACT 0x0034\r
+#define EFI_AHCI_PORT_CI 0x0038\r
+#define EFI_AHCI_PORT_SNTF 0x003C\r
+\r
+\r
+#pragma pack(1)\r
+//\r
+// Command List structure includes total 32 entries.\r
+// The entry Data structure is listed at the following.\r
+//\r
+typedef struct {\r
+ UINT32 AhciCmdCfl:5; //Command FIS Length\r
+ UINT32 AhciCmdA:1; //ATAPI\r
+ UINT32 AhciCmdW:1; //Write\r
+ UINT32 AhciCmdP:1; //Prefetchable\r
+ UINT32 AhciCmdR:1; //Reset\r
+ UINT32 AhciCmdB:1; //BIST\r
+ UINT32 AhciCmdC:1; //Clear Busy upon R_OK\r
+ UINT32 AhciCmdRsvd:1;\r
+ UINT32 AhciCmdPmp:4; //Port Multiplier Port\r
+ UINT32 AhciCmdPrdtl:16; //Physical Region Descriptor Table Length\r
+ UINT32 AhciCmdPrdbc; //Physical Region Descriptor Byte Count\r
+ UINT32 AhciCmdCtba; //Command Table Descriptor Base Address\r
+ UINT32 AhciCmdCtbau; //Command Table Descriptor Base Address Upper 32-BITs\r
+ UINT32 AhciCmdRsvd1[4];\r
+} EFI_AHCI_COMMAND_LIST;\r
+\r
+//\r
+// This is a software constructed FIS.\r
+// For Data transfer operations, this is the H2D Register FIS format as\r
+// specified in the Serial ATA Revision 2.6 specification.\r
+//\r
+typedef struct {\r
+ UINT8 AhciCFisType;\r
+ UINT8 AhciCFisPmNum:4;\r
+ UINT8 AhciCFisRsvd:1;\r
+ UINT8 AhciCFisRsvd1:1;\r
+ UINT8 AhciCFisRsvd2:1;\r
+ UINT8 AhciCFisCmdInd:1;\r
+ UINT8 AhciCFisCmd;\r
+ UINT8 AhciCFisFeature;\r
+ UINT8 AhciCFisSecNum;\r
+ UINT8 AhciCFisClyLow;\r
+ UINT8 AhciCFisClyHigh;\r
+ UINT8 AhciCFisDevHead;\r
+ UINT8 AhciCFisSecNumExp;\r
+ UINT8 AhciCFisClyLowExp;\r
+ UINT8 AhciCFisClyHighExp;\r
+ UINT8 AhciCFisFeatureExp;\r
+ UINT8 AhciCFisSecCount;\r
+ UINT8 AhciCFisSecCountExp;\r
+ UINT8 AhciCFisRsvd3;\r
+ UINT8 AhciCFisControl;\r
+ UINT8 AhciCFisRsvd4[4];\r
+ UINT8 AhciCFisRsvd5[44];\r
+} EFI_AHCI_COMMAND_FIS;\r
+\r
+//\r
+// ACMD: ATAPI command (12 or 16 bytes)\r
+//\r
+typedef struct {\r
+ UINT8 AtapiCmd[0x10];\r
+} EFI_AHCI_ATAPI_COMMAND;\r
+\r
+//\r
+// Physical Region Descriptor Table includes up to 65535 entries\r
+// The entry Data structure is listed at the following.\r
+// the actual entry number comes from the PRDTL field in the command\r
+// list entry for this command slot.\r
+//\r
+typedef struct {\r
+ UINT32 AhciPrdtDba; //Data Base Address\r
+ UINT32 AhciPrdtDbau; //Data Base Address Upper 32-BITs\r
+ UINT32 AhciPrdtRsvd;\r
+ UINT32 AhciPrdtDbc:22; //Data Byte Count\r
+ UINT32 AhciPrdtRsvd1:9;\r
+ UINT32 AhciPrdtIoc:1; //Interrupt on Completion\r
+} EFI_AHCI_COMMAND_PRDT;\r
+\r
+//\r
+// Command table Data strucute which is pointed to by the entry in the command list\r
+//\r
+typedef struct {\r
+ EFI_AHCI_COMMAND_FIS CommandFis; // A software constructed FIS.\r
+ EFI_AHCI_ATAPI_COMMAND AtapiCmd; // 12 or 16 bytes ATAPI cmd.\r
+ UINT8 Reserved[0x30];\r
+ EFI_AHCI_COMMAND_PRDT PrdtTable; // The scatter/gather list for Data transfer\r
+} EFI_AHCI_COMMAND_TABLE;\r
+\r
+//\r
+// Received FIS structure\r
+//\r
+typedef struct {\r
+ UINT8 AhciDmaSetupFis[0x1C]; // Dma Setup Fis: offset 0x00\r
+ UINT8 AhciDmaSetupFisRsvd[0x04];\r
+ UINT8 AhciPioSetupFis[0x14]; // Pio Setup Fis: offset 0x20\r
+ UINT8 AhciPioSetupFisRsvd[0x0C];\r
+ UINT8 AhciD2HRegisterFis[0x14]; // D2H Register Fis: offset 0x40\r
+ UINT8 AhciD2HRegisterFisRsvd[0x04];\r
+ UINT64 AhciSetDeviceBitsFis; // Set Device Bits Fix: offset 0x58\r
+ UINT8 AhciUnknownFis[0x40]; // Unkonwn Fis: offset 0x60\r
+ UINT8 AhciUnknownFisRsvd[0x60];\r
+} EFI_AHCI_RECEIVED_FIS;\r
+\r
+#pragma pack()\r
+\r
+typedef struct {\r
+ EFI_AHCI_RECEIVED_FIS *AhciRFis;\r
+ VOID *AhciRFisMapping;\r
+ EFI_AHCI_COMMAND_LIST *AhciCmdList;\r
+ VOID *AhciCmdListMapping;\r
+ EFI_AHCI_COMMAND_TABLE *AhciCommandTable;\r
+ VOID *AhciCommandTableMapping;\r
+} EFI_AHCI_REGISTERS;\r
+\r
+typedef struct {\r
+ VOID *Buffer;\r
+ VOID *BufferMapping;\r
+ EFI_AHCI_REGISTERS AhciRegisters;\r
+ UINT32 AhciBar;\r
+} AHCI_CONTEXT;\r
+\r
+/**\r
+ Send Buffer cmd to specific device.\r
+\r
+ @param AhciContext The pointer to the AHCI_CONTEXT.\r
+ @param Port The number of port.\r
+ @param PortMultiplier The timeout Value of stop.\r
+ @param Buffer The Data Buffer to store IDENTIFY PACKET Data.\r
+\r
+ @retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
+ @retval EFI_TIMEOUT The operation is time out.\r
+ @retval EFI_UNSUPPORTED The device is not ready for executing.\r
+ @retval EFI_SUCCESS The cmd executes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciIdentify (\r
+ IN AHCI_CONTEXT *AhciContext,\r
+ IN UINT8 Port,\r
+ IN UINT8 PortMultiplier,\r
+ IN OUT ATA_IDENTIFY_DATA *Buffer\r
+ );\r
+\r
+/**\r
+ Allocate transfer-related data struct which is used at AHCI mode.\r
+\r
+ @param[in, out] AhciContext The pointer to the AHCI_CONTEXT.\r
+\r
+ @retval EFI_OUT_OF_RESOURCE No enough resource.\r
+ @retval EFI_SUCCESS Successful to allocate resource.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciAllocateResource (\r
+ IN OUT AHCI_CONTEXT *AhciContext\r
+ );\r
+\r
+/**\r
+ Free allocated transfer-related data struct which is used at AHCI mode.\r
+\r
+ @param[in, out] AhciContext The pointer to the AHCI_CONTEXT.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciFreeResource (\r
+ IN OUT AHCI_CONTEXT *AhciContext\r
+ );\r
+\r
+/**\r
+ Initialize ATA host controller at AHCI mode.\r
+\r
+ The function is designed to initialize ATA host controller.\r
+\r
+ @param[in] AhciContext The pointer to the AHCI_CONTEXT.\r
+ @param[in] Port The port number to do initialization.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciModeInitialize (\r
+ IN AHCI_CONTEXT *AhciContext,\r
+ IN UINT8 Port\r
+ );\r
+\r
+typedef struct _EFI_ATA_COMMAND_BLOCK {\r
+ UINT8 Reserved1[2];\r
+ UINT8 AtaCommand;\r
+ UINT8 AtaFeatures;\r
+ UINT8 AtaSectorNumber;\r
+ UINT8 AtaCylinderLow;\r
+ UINT8 AtaCylinderHigh;\r
+ UINT8 AtaDeviceHead;\r
+ UINT8 AtaSectorNumberExp;\r
+ UINT8 AtaCylinderLowExp;\r
+ UINT8 AtaCylinderHighExp; \r
+ UINT8 AtaFeaturesExp;\r
+ UINT8 AtaSectorCount;\r
+ UINT8 AtaSectorCountExp;\r
+ UINT8 Reserved2[6];\r
+} EFI_ATA_COMMAND_BLOCK;\r
+\r
+typedef struct _EFI_ATA_STATUS_BLOCK {\r
+ UINT8 Reserved1[2];\r
+ UINT8 AtaStatus;\r
+ UINT8 AtaError;\r
+ UINT8 AtaSectorNumber;\r
+ UINT8 AtaCylinderLow;\r
+ UINT8 AtaCylinderHigh;\r
+ UINT8 AtaDeviceHead;\r
+ UINT8 AtaSectorNumberExp;\r
+ UINT8 AtaCylinderLowExp;\r
+ UINT8 AtaCylinderHighExp; \r
+ UINT8 Reserved2;\r
+ UINT8 AtaSectorCount;\r
+ UINT8 AtaSectorCountExp;\r
+ UINT8 Reserved3[6];\r
+} EFI_ATA_STATUS_BLOCK;\r
+\r
+/**\r
+ Start a PIO Data transfer on specific port.\r
+\r
+ @param AhciContext The pointer to the AHCI_CONTEXT.\r
+ @param Port The number of port.\r
+ @param PortMultiplier The timeout Value of stop.\r
+ @param AtapiCommand The atapi command will be used for the transfer.\r
+ @param AtapiCommandLength The Length of the atapi command.\r
+ @param Read The transfer direction.\r
+ @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK Data.\r
+ @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK Data.\r
+ @param MemoryAddr The pointer to the Data Buffer.\r
+ @param DataCount The Data count to be transferred.\r
+ @param Timeout The timeout Value of non Data transfer.\r
+\r
+ @retval EFI_DEVICE_ERROR The PIO Data transfer abort with error occurs.\r
+ @retval EFI_TIMEOUT The operation is time out.\r
+ @retval EFI_UNSUPPORTED The device is not ready for transfer.\r
+ @retval EFI_SUCCESS The PIO Data transfer executes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciPioTransfer (\r
+ IN AHCI_CONTEXT *AhciContext,\r
+ IN UINT8 Port,\r
+ IN UINT8 PortMultiplier,\r
+ IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
+ IN UINT8 AtapiCommandLength,\r
+ IN BOOLEAN Read,\r
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
+ IN OUT VOID *MemoryAddr,\r
+ IN UINT32 DataCount,\r
+ IN UINT64 Timeout\r
+ );\r
+\r
+\r
+#endif\r
+\r
--- /dev/null
+/** @file\r
+ Entrypoint of Opal UEFI Driver and contains all the logic to\r
+ register for new Opal device instances.\r
+\r
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+// This UEFI driver consumes EFI_STORAGE_SECURITY_PROTOCOL instances and installs an\r
+// HII GUI to manage Opal features if the device is Opal capable\r
+// If the Opal device is being managed by the UEFI Driver, it shall provide a popup\r
+// window during boot requesting a user password\r
+\r
+#include "OpalDriver.h"\r
+#include "OpalHii.h"\r
+\r
+EFI_GUID mOpalDeviceAtaGuid = OPAL_DEVICE_ATA_GUID;\r
+EFI_GUID mOpalDeviceNvmeGuid = OPAL_DEVICE_NVME_GUID;\r
+\r
+BOOLEAN mOpalEndOfDxe = FALSE;\r
+OPAL_REQUEST_VARIABLE *mOpalRequestVariable = NULL;\r
+UINTN mOpalRequestVariableSize = 0;\r
+CHAR16 mPopUpString[256];\r
+\r
+typedef struct {\r
+ UINT32 Address;\r
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;\r
+} OPAL_HC_PCI_REGISTER_SAVE;\r
+\r
+//\r
+// To unlock the Intel SATA controller at S3 Resume, restored the following registers.\r
+//\r
+const OPAL_HC_PCI_REGISTER_SAVE mSataHcRegisterSaveTemplate[] = {\r
+ {0x9, S3BootScriptWidthUint8},\r
+ {0x10, S3BootScriptWidthUint32},\r
+ {0x14, S3BootScriptWidthUint32},\r
+ {0x18, S3BootScriptWidthUint32},\r
+ {0x1C, S3BootScriptWidthUint32},\r
+ {0x20, S3BootScriptWidthUint32},\r
+ {0x24, S3BootScriptWidthUint32},\r
+ {0x3c, S3BootScriptWidthUint8},\r
+ {0x3d, S3BootScriptWidthUint8},\r
+ {0x40, S3BootScriptWidthUint16},\r
+ {0x42, S3BootScriptWidthUint16},\r
+ {0x92, S3BootScriptWidthUint16},\r
+ {0x94, S3BootScriptWidthUint32},\r
+ {0x9C, S3BootScriptWidthUint32},\r
+ {0x4, S3BootScriptWidthUint16},\r
+};\r
+\r
+OPAL_DRIVER mOpalDriver;\r
+\r
+//\r
+// Globals\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL gOpalDriverBinding = {\r
+ OpalEfiDriverBindingSupported,\r
+ OpalEfiDriverBindingStart,\r
+ OpalEfiDriverBindingStop,\r
+ 0x1b,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+/**\r
+\r
+ The function determines the available actions for the OPAL_DISK provided.\r
+\r
+ @param[in] SupportedAttributes The supported attributes for the device.\r
+ @param[in] LockingFeature The locking status for the device.\r
+ @param[in] OwnerShip The ownership for the device.\r
+ @param[out] AvalDiskActions Pointer to fill-out with appropriate disk actions.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportGetAvailableActions(\r
+ IN OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes,\r
+ IN TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature,\r
+ IN UINT16 OwnerShip,\r
+ OUT OPAL_DISK_ACTIONS *AvalDiskActions\r
+ )\r
+{\r
+ BOOLEAN ExistingPassword;\r
+\r
+ NULL_CHECK(AvalDiskActions);\r
+\r
+ AvalDiskActions->AdminPass = 1;\r
+ AvalDiskActions->UserPass = 0;\r
+ AvalDiskActions->DisableUser = 0;\r
+ AvalDiskActions->Unlock = 0;\r
+\r
+ //\r
+ // Revert is performed on locking sp, so only allow if locking sp is enabled\r
+ //\r
+ if (LockingFeature->LockingEnabled) {\r
+ AvalDiskActions->Revert = 1;\r
+ }\r
+\r
+ //\r
+ // Psid revert is available for any device with media encryption support\r
+ // Revert is allowed for any device with media encryption support, however it requires\r
+ //\r
+ if (SupportedAttributes->MediaEncryption) {\r
+\r
+ //\r
+ // Only allow psid revert if media encryption is enabled.\r
+ // Otherwise, someone who steals a disk can psid revert the disk and the user Data is still\r
+ // intact and accessible\r
+ //\r
+ AvalDiskActions->PsidRevert = 1;\r
+ AvalDiskActions->RevertKeepDataForced = 0;\r
+\r
+ //\r
+ // Secure erase is performed by generating a new encryption key\r
+ // this is only available if encryption is supported\r
+ //\r
+ AvalDiskActions->SecureErase = 1;\r
+ } else {\r
+ AvalDiskActions->PsidRevert = 0;\r
+ AvalDiskActions->SecureErase = 0;\r
+\r
+ //\r
+ // If no media encryption is supported, then a revert (using password) will not\r
+ // erase the Data (since you can't generate a new encryption key)\r
+ //\r
+ AvalDiskActions->RevertKeepDataForced = 1;\r
+ }\r
+\r
+ if (LockingFeature->Locked) {\r
+ AvalDiskActions->Unlock = 1;\r
+ } else {\r
+ AvalDiskActions->Unlock = 0;\r
+ }\r
+\r
+ //\r
+ // Only allow user to set password if an admin password exists\r
+ //\r
+ ExistingPassword = OpalUtilAdminPasswordExists(OwnerShip, LockingFeature);\r
+ AvalDiskActions->UserPass = ExistingPassword;\r
+\r
+ //\r
+ // This will still show up even if there isn't a user, which is fine\r
+ //\r
+ AvalDiskActions->DisableUser = ExistingPassword;\r
+\r
+ return TcgResultSuccess;\r
+}\r
+\r
+/**\r
+ Enable Opal Feature for the input device.\r
+\r
+ @param[in] Session The opal session for the opal device.\r
+ @param[in] Msid Msid\r
+ @param[in] MsidLength Msid Length\r
+ @param[in] Password Admin password\r
+ @param[in] PassLength Length of password in bytes\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportEnableOpalFeature (\r
+ IN OPAL_SESSION *Session,\r
+ IN VOID *Msid,\r
+ IN UINT32 MsidLength,\r
+ IN VOID *Password,\r
+ IN UINT32 PassLength\r
+ )\r
+{\r
+ TCG_RESULT Ret;\r
+\r
+ NULL_CHECK(Session);\r
+ NULL_CHECK(Msid);\r
+ NULL_CHECK(Password);\r
+\r
+ Ret = OpalUtilSetAdminPasswordAsSid(\r
+ Session,\r
+ Msid,\r
+ MsidLength,\r
+ Password,\r
+ PassLength\r
+ );\r
+ if (Ret == TcgResultSuccess) {\r
+ //\r
+ // Enable global locking range\r
+ //\r
+ Ret = OpalUtilSetOpalLockingRange(\r
+ Session,\r
+ Password,\r
+ PassLength,\r
+ OPAL_LOCKING_SP_LOCKING_GLOBALRANGE,\r
+ 0,\r
+ 0,\r
+ TRUE,\r
+ TRUE,\r
+ FALSE,\r
+ FALSE\r
+ );\r
+ }\r
+\r
+ return Ret;\r
+}\r
+\r
+/**\r
+ Update password for the Opal disk.\r
+\r
+ @param[in, out] OpalDisk The disk to update password.\r
+ @param[in] Password The input password.\r
+ @param[in] PasswordLength The input password length.\r
+\r
+**/\r
+VOID\r
+OpalSupportUpdatePassword (\r
+ IN OUT OPAL_DISK *OpalDisk,\r
+ IN VOID *Password,\r
+ IN UINT32 PasswordLength\r
+ )\r
+{\r
+ CopyMem (OpalDisk->Password, Password, PasswordLength);\r
+ OpalDisk->PasswordLength = (UINT8) PasswordLength;\r
+}\r
+\r
+/**\r
+ Extract device info from the device path.\r
+\r
+ @param[in] DevicePath Device path info for the device.\r
+ @param[out] DevInfoLength Device information length needed.\r
+ @param[out] DevInfo Device information extracted.\r
+\r
+ @return Device type.\r
+\r
+**/\r
+UINT8\r
+ExtractDeviceInfoFromDevicePath (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ OUT UINT16 *DevInfoLength,\r
+ OUT OPAL_DEVICE_COMMON *DevInfo OPTIONAL\r
+ )\r
+{\r
+ EFI_DEVICE_PATH_PROTOCOL *TmpDevPath;\r
+ EFI_DEVICE_PATH_PROTOCOL *TmpDevPath2;\r
+ PCI_DEVICE_PATH *PciDevPath;\r
+ UINT8 DeviceType;\r
+ UINT8 BusNum;\r
+ OPAL_PCI_DEVICE *PciDevice;\r
+ OPAL_DEVICE_ATA *DevInfoAta;\r
+ OPAL_DEVICE_NVME *DevInfoNvme;\r
+ SATA_DEVICE_PATH *SataDevPath;\r
+ NVME_NAMESPACE_DEVICE_PATH *NvmeDevPath;\r
+\r
+ ASSERT (DevicePath != NULL);\r
+ ASSERT (DevInfoLength != NULL);\r
+\r
+ DeviceType = OPAL_DEVICE_TYPE_UNKNOWN;\r
+ *DevInfoLength = 0;\r
+\r
+ TmpDevPath = DevicePath;\r
+\r
+ //\r
+ // Get device type.\r
+ //\r
+ while (!IsDevicePathEnd (TmpDevPath)) {\r
+ if (TmpDevPath->Type == MESSAGING_DEVICE_PATH && TmpDevPath->SubType == MSG_SATA_DP) {\r
+ //\r
+ // SATA\r
+ //\r
+ if (DevInfo != NULL) {\r
+ SataDevPath = (SATA_DEVICE_PATH *) TmpDevPath;\r
+ DevInfoAta = (OPAL_DEVICE_ATA *) DevInfo;\r
+ DevInfoAta->Port = SataDevPath->HBAPortNumber;\r
+ DevInfoAta->PortMultiplierPort = SataDevPath->PortMultiplierPortNumber;\r
+ }\r
+ DeviceType = OPAL_DEVICE_TYPE_ATA;\r
+ *DevInfoLength = sizeof (OPAL_DEVICE_ATA);\r
+ break;\r
+ } else if (TmpDevPath->Type == MESSAGING_DEVICE_PATH && TmpDevPath->SubType == MSG_NVME_NAMESPACE_DP) {\r
+ //\r
+ // NVMe\r
+ //\r
+ if (DevInfo != NULL) {\r
+ NvmeDevPath = (NVME_NAMESPACE_DEVICE_PATH *) TmpDevPath;\r
+ DevInfoNvme = (OPAL_DEVICE_NVME *) DevInfo;\r
+ DevInfoNvme->NvmeNamespaceId = NvmeDevPath->NamespaceId;\r
+ }\r
+ DeviceType = OPAL_DEVICE_TYPE_NVME;\r
+ *DevInfoLength = sizeof (OPAL_DEVICE_NVME);\r
+ break;\r
+ }\r
+ TmpDevPath = NextDevicePathNode (TmpDevPath);\r
+ }\r
+\r
+ //\r
+ // Get device info.\r
+ //\r
+ BusNum = 0;\r
+ TmpDevPath = DevicePath;\r
+ TmpDevPath2 = NextDevicePathNode (DevicePath);\r
+ while (!IsDevicePathEnd (TmpDevPath2)) {\r
+ if (TmpDevPath->Type == HARDWARE_DEVICE_PATH && TmpDevPath->SubType == HW_PCI_DP) {\r
+ PciDevPath = (PCI_DEVICE_PATH *) TmpDevPath;\r
+ if ((TmpDevPath2->Type == MESSAGING_DEVICE_PATH && TmpDevPath2->SubType == MSG_NVME_NAMESPACE_DP)||\r
+ (TmpDevPath2->Type == MESSAGING_DEVICE_PATH && TmpDevPath2->SubType == MSG_SATA_DP)) {\r
+ if (DevInfo != NULL) {\r
+ PciDevice = &DevInfo->Device;\r
+ PciDevice->Segment = 0;\r
+ PciDevice->Bus = BusNum;\r
+ PciDevice->Device = PciDevPath->Device;\r
+ PciDevice->Function = PciDevPath->Function;\r
+ }\r
+ } else {\r
+ if (DevInfo != NULL) {\r
+ PciDevice = (OPAL_PCI_DEVICE *) ((UINTN) DevInfo + *DevInfoLength);\r
+ PciDevice->Segment = 0;\r
+ PciDevice->Bus = BusNum;\r
+ PciDevice->Device = PciDevPath->Device;\r
+ PciDevice->Function = PciDevPath->Function;\r
+ }\r
+ *DevInfoLength += sizeof (OPAL_PCI_DEVICE);\r
+ if (TmpDevPath2->Type == HARDWARE_DEVICE_PATH && TmpDevPath2->SubType == HW_PCI_DP) {\r
+ BusNum = PciRead8 (PCI_LIB_ADDRESS (BusNum, PciDevPath->Device, PciDevPath->Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));\r
+ }\r
+ }\r
+ }\r
+\r
+ TmpDevPath = NextDevicePathNode (TmpDevPath);\r
+ TmpDevPath2 = NextDevicePathNode (TmpDevPath2);\r
+ }\r
+\r
+ ASSERT (DeviceType != OPAL_DEVICE_TYPE_UNKNOWN);\r
+ return DeviceType;\r
+}\r
+\r
+/**\r
+ Save boot script for ATA OPAL device.\r
+\r
+ @param[in] DevInfo Pointer to ATA Opal device information.\r
+\r
+ **/\r
+VOID\r
+OpalDeviceAtaSaveBootScript (\r
+ IN OPAL_DEVICE_ATA *DevInfo\r
+ )\r
+{\r
+ UINTN Bus;\r
+ UINTN Device;\r
+ UINTN Function;\r
+ UINTN Index;\r
+ EFI_STATUS Status;\r
+ UINTN Offset;\r
+ UINT64 Address;\r
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;\r
+ UINT32 Data;\r
+ OPAL_HC_PCI_REGISTER_SAVE *HcRegisterSaveListPtr;\r
+ UINTN Count;\r
+\r
+ Data = 0;\r
+\r
+ Bus = DevInfo->Device.Bus;\r
+ Device = DevInfo->Device.Device;\r
+ Function = DevInfo->Device.Function;\r
+\r
+ HcRegisterSaveListPtr = (OPAL_HC_PCI_REGISTER_SAVE *) mSataHcRegisterSaveTemplate;\r
+ Count = sizeof (mSataHcRegisterSaveTemplate) / sizeof (OPAL_HC_PCI_REGISTER_SAVE);\r
+\r
+ for (Index = 0; Index < Count; Index++) {\r
+ Offset = HcRegisterSaveListPtr[Index].Address;\r
+ Width = HcRegisterSaveListPtr[Index].Width;\r
+\r
+ switch (Width) {\r
+ case S3BootScriptWidthUint8:\r
+ Data = (UINT32)PciRead8 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));\r
+ break;\r
+ case S3BootScriptWidthUint16:\r
+ Data = (UINT32)PciRead16 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));\r
+ break;\r
+ case S3BootScriptWidthUint32:\r
+ Data = PciRead32 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ break;\r
+ }\r
+\r
+ Address = S3_BOOT_SCRIPT_LIB_PCI_ADDRESS (Bus, Device, Function, Offset);\r
+ Status = S3BootScriptSavePciCfgWrite (Width, Address, 1, &Data);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+}\r
+\r
+/**\r
+ Build ATA OPAL device info and save them to LockBox.\r
+\r
+ @param[in] BarAddr Bar address allocated.\r
+\r
+ **/\r
+VOID\r
+BuildOpalDeviceInfoAta (\r
+ IN UINT32 BarAddr\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 DeviceType;\r
+ OPAL_DEVICE_ATA *DevInfoAta;\r
+ OPAL_DEVICE_ATA *TempDevInfoAta;\r
+ UINTN DevInfoLengthAta;\r
+ UINT16 DevInfoLength;\r
+ OPAL_DRIVER_DEVICE *TmpDev;\r
+\r
+ //\r
+ // Build ATA OPAL device info and save them to LockBox.\r
+ //\r
+ DevInfoLengthAta = 0;\r
+ TmpDev = mOpalDriver.DeviceList;\r
+ while (TmpDev != NULL) {\r
+ DeviceType = ExtractDeviceInfoFromDevicePath (\r
+ TmpDev->OpalDisk.OpalDevicePath,\r
+ &DevInfoLength,\r
+ NULL\r
+ );\r
+ if (DeviceType == OPAL_DEVICE_TYPE_ATA) {\r
+ DevInfoLengthAta += DevInfoLength;\r
+ }\r
+\r
+ TmpDev = TmpDev->Next;\r
+ }\r
+\r
+ if (DevInfoLengthAta == 0) {\r
+ return;\r
+ }\r
+\r
+ DevInfoAta = AllocateZeroPool (DevInfoLengthAta);\r
+ ASSERT (DevInfoAta != NULL);\r
+\r
+ TempDevInfoAta = DevInfoAta;\r
+ TmpDev = mOpalDriver.DeviceList;\r
+ while (TmpDev != NULL) {\r
+ DeviceType = ExtractDeviceInfoFromDevicePath (\r
+ TmpDev->OpalDisk.OpalDevicePath,\r
+ &DevInfoLength,\r
+ NULL\r
+ );\r
+ if (DeviceType == OPAL_DEVICE_TYPE_ATA) {\r
+ ExtractDeviceInfoFromDevicePath (\r
+ TmpDev->OpalDisk.OpalDevicePath,\r
+ &DevInfoLength,\r
+ (OPAL_DEVICE_COMMON *) TempDevInfoAta\r
+ );\r
+ TempDevInfoAta->Length = DevInfoLength;\r
+ TempDevInfoAta->OpalBaseComId = TmpDev->OpalDisk.OpalBaseComId;\r
+ TempDevInfoAta->BarAddr = BarAddr;\r
+ CopyMem (\r
+ TempDevInfoAta->Password,\r
+ TmpDev->OpalDisk.Password,\r
+ TmpDev->OpalDisk.PasswordLength\r
+ );\r
+ TempDevInfoAta->PasswordLength = TmpDev->OpalDisk.PasswordLength;\r
+ OpalDeviceAtaSaveBootScript (TempDevInfoAta);\r
+ TempDevInfoAta = (OPAL_DEVICE_ATA *) ((UINTN) TempDevInfoAta + DevInfoLength);\r
+ }\r
+\r
+ TmpDev = TmpDev->Next;\r
+ }\r
+\r
+ Status = SaveLockBox (\r
+ &mOpalDeviceAtaGuid,\r
+ DevInfoAta,\r
+ DevInfoLengthAta\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = SetLockBoxAttributes (\r
+ &mOpalDeviceAtaGuid,\r
+ LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ ZeroMem (DevInfoAta, DevInfoLengthAta);\r
+ FreePool (DevInfoAta);\r
+}\r
+\r
+/**\r
+ Build NVMe OPAL device info and save them to LockBox.\r
+\r
+ @param[in] BarAddr Bar address allocated.\r
+\r
+ **/\r
+VOID\r
+BuildOpalDeviceInfoNvme (\r
+ IN UINT32 BarAddr\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 DeviceType;\r
+ OPAL_DEVICE_NVME *DevInfoNvme;\r
+ OPAL_DEVICE_NVME *TempDevInfoNvme;\r
+ UINTN DevInfoLengthNvme;\r
+ UINT16 DevInfoLength;\r
+ OPAL_DRIVER_DEVICE *TmpDev;\r
+\r
+ //\r
+ // Build NVMe OPAL device info and save them to LockBox.\r
+ //\r
+ DevInfoLengthNvme = 0;\r
+ TmpDev = mOpalDriver.DeviceList;\r
+ while (TmpDev != NULL) {\r
+ DeviceType = ExtractDeviceInfoFromDevicePath (\r
+ TmpDev->OpalDisk.OpalDevicePath,\r
+ &DevInfoLength,\r
+ NULL\r
+ );\r
+ if (DeviceType == OPAL_DEVICE_TYPE_NVME) {\r
+ DevInfoLengthNvme += DevInfoLength;\r
+ }\r
+\r
+ TmpDev = TmpDev->Next;\r
+ }\r
+\r
+ if (DevInfoLengthNvme == 0) {\r
+ return;\r
+ }\r
+\r
+ DevInfoNvme = AllocateZeroPool (DevInfoLengthNvme);\r
+ ASSERT (DevInfoNvme != NULL);\r
+\r
+ TempDevInfoNvme = DevInfoNvme;\r
+ TmpDev = mOpalDriver.DeviceList;\r
+ while (TmpDev != NULL) {\r
+ DeviceType = ExtractDeviceInfoFromDevicePath (\r
+ TmpDev->OpalDisk.OpalDevicePath,\r
+ &DevInfoLength,\r
+ NULL\r
+ );\r
+ if (DeviceType == OPAL_DEVICE_TYPE_NVME) {\r
+ ExtractDeviceInfoFromDevicePath (\r
+ TmpDev->OpalDisk.OpalDevicePath,\r
+ &DevInfoLength,\r
+ (OPAL_DEVICE_COMMON *) TempDevInfoNvme\r
+ );\r
+ TempDevInfoNvme->Length = DevInfoLength;\r
+ TempDevInfoNvme->OpalBaseComId = TmpDev->OpalDisk.OpalBaseComId;\r
+ TempDevInfoNvme->BarAddr = BarAddr;\r
+ CopyMem (\r
+ TempDevInfoNvme->Password,\r
+ TmpDev->OpalDisk.Password,\r
+ TmpDev->OpalDisk.PasswordLength\r
+ );\r
+ TempDevInfoNvme->PasswordLength = TmpDev->OpalDisk.PasswordLength;\r
+ TempDevInfoNvme = (OPAL_DEVICE_NVME *) ((UINTN) TempDevInfoNvme + DevInfoLength);\r
+ }\r
+\r
+ TmpDev = TmpDev->Next;\r
+ }\r
+\r
+ Status = SaveLockBox (\r
+ &mOpalDeviceNvmeGuid,\r
+ DevInfoNvme,\r
+ DevInfoLengthNvme\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = SetLockBoxAttributes (\r
+ &mOpalDeviceNvmeGuid,\r
+ LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ ZeroMem (DevInfoNvme, DevInfoLengthNvme);\r
+ FreePool (DevInfoNvme);\r
+}\r
+\r
+/**\r
+ Notification function of EFI_END_OF_DXE_EVENT_GROUP_GUID event group.\r
+\r
+ This is a notification function registered on EFI_END_OF_DXE_EVENT_GROUP_GUID event group.\r
+\r
+ @param Event Event whose notification function is being invoked.\r
+ @param Context Pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+OpalEndOfDxeEventNotify (\r
+ EFI_EVENT Event,\r
+ VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS Address;\r
+ UINT64 Length;\r
+ OPAL_DRIVER_DEVICE *TmpDev;\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
+\r
+ mOpalEndOfDxe = TRUE;\r
+\r
+ if (mOpalRequestVariable != NULL) {\r
+ //\r
+ // Free the OPAL request variable buffer here\r
+ // as the OPAL requests should have been processed.\r
+ //\r
+ FreePool (mOpalRequestVariable);\r
+ mOpalRequestVariable = NULL;\r
+ mOpalRequestVariableSize = 0;\r
+ }\r
+\r
+ //\r
+ // Assume 64K size and alignment are enough.\r
+ //\r
+ Length = 0x10000;\r
+ Address = 0xFFFFFFFF;\r
+ Status = gDS->AllocateMemorySpace (\r
+ EfiGcdAllocateMaxAddressSearchBottomUp,\r
+ EfiGcdMemoryTypeMemoryMappedIo,\r
+ 16, // 2^16: 64K Alignment\r
+ Length,\r
+ &Address,\r
+ gImageHandle,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ BuildOpalDeviceInfoAta ((UINT32) Address);\r
+ BuildOpalDeviceInfoNvme ((UINT32) Address);\r
+\r
+ //\r
+ // Zero passsword.\r
+ //\r
+ TmpDev = mOpalDriver.DeviceList;\r
+ while (TmpDev != NULL) {\r
+ ZeroMem (TmpDev->OpalDisk.Password, TmpDev->OpalDisk.PasswordLength);\r
+ TmpDev = TmpDev->Next;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
+\r
+ gBS->CloseEvent (Event);\r
+}\r
+\r
+/**\r
+ Get Psid input from the popup window.\r
+\r
+ @param[in] Dev The device which need Psid to process Psid Revert\r
+ OPAL request.\r
+ @param[in] PopUpString Pop up string.\r
+ @param[out] PressEsc Whether user escape function through Press ESC.\r
+\r
+ @retval Password string if success. NULL if failed.\r
+\r
+**/\r
+CHAR8 *\r
+OpalDriverPopUpPsidInput (\r
+ IN OPAL_DRIVER_DEVICE *Dev,\r
+ IN CHAR16 *PopUpString,\r
+ OUT BOOLEAN *PressEsc\r
+ )\r
+{\r
+ EFI_INPUT_KEY InputKey;\r
+ UINTN InputLength;\r
+ CHAR16 Mask[PSID_CHARACTER_LENGTH + 1];\r
+ CHAR16 Unicode[PSID_CHARACTER_LENGTH + 1];\r
+ CHAR8 *Ascii;\r
+\r
+ ZeroMem(Unicode, sizeof(Unicode));\r
+ ZeroMem(Mask, sizeof(Mask));\r
+\r
+ *PressEsc = FALSE;\r
+\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+\r
+ InputLength = 0;\r
+ while (TRUE) {\r
+ Mask[InputLength] = L'_';\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &InputKey,\r
+ PopUpString,\r
+ L"---------------------",\r
+ Mask,\r
+ NULL\r
+ );\r
+\r
+ //\r
+ // Check key.\r
+ //\r
+ if (InputKey.ScanCode == SCAN_NULL) {\r
+ //\r
+ // password finished\r
+ //\r
+ if (InputKey.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+ //\r
+ // Add the null terminator.\r
+ //\r
+ Unicode[InputLength] = 0;\r
+ Mask[InputLength] = 0;\r
+ break;\r
+ } else if ((InputKey.UnicodeChar == CHAR_NULL) ||\r
+ (InputKey.UnicodeChar == CHAR_TAB) ||\r
+ (InputKey.UnicodeChar == CHAR_LINEFEED)\r
+ ) {\r
+ continue;\r
+ } else {\r
+ //\r
+ // delete last key entered\r
+ //\r
+ if (InputKey.UnicodeChar == CHAR_BACKSPACE) {\r
+ if (InputLength > 0) {\r
+ Unicode[InputLength] = 0;\r
+ Mask[InputLength] = 0;\r
+ InputLength--;\r
+ }\r
+ } else {\r
+ //\r
+ // add Next key entry\r
+ //\r
+ Unicode[InputLength] = InputKey.UnicodeChar;\r
+ Mask[InputLength] = InputKey.UnicodeChar;\r
+ InputLength++;\r
+ if (InputLength == PSID_CHARACTER_LENGTH) {\r
+ //\r
+ // Add the null terminator.\r
+ //\r
+ Unicode[InputLength] = 0;\r
+ Mask[InputLength] = 0;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // exit on ESC\r
+ //\r
+ if (InputKey.ScanCode == SCAN_ESC) {\r
+ *PressEsc = TRUE;\r
+ break;\r
+ }\r
+ }\r
+\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+\r
+ if (InputLength == 0 || InputKey.ScanCode == SCAN_ESC) {\r
+ ZeroMem (Unicode, sizeof (Unicode));\r
+ ZeroMem (Mask, sizeof (Mask));\r
+ return NULL;\r
+ }\r
+\r
+ Ascii = AllocateZeroPool (PSID_CHARACTER_LENGTH + 1);\r
+ if (Ascii == NULL) {\r
+ ZeroMem (Unicode, sizeof (Unicode));\r
+ ZeroMem (Mask, sizeof (Mask));\r
+ return NULL;\r
+ }\r
+\r
+ UnicodeStrToAsciiStrS (Unicode, Ascii, PSID_CHARACTER_LENGTH + 1);\r
+ ZeroMem (Unicode, sizeof (Unicode));\r
+ ZeroMem (Mask, sizeof (Mask));\r
+\r
+ return Ascii;\r
+}\r
+\r
+\r
+/**\r
+ Get password input from the popup window.\r
+\r
+ @param[in] Dev The device which need password to unlock or\r
+ process OPAL request.\r
+ @param[in] PopUpString1 Pop up string 1.\r
+ @param[in] PopUpString2 Pop up string 2.\r
+ @param[out] PressEsc Whether user escape function through Press ESC.\r
+\r
+ @retval Password string if success. NULL if failed.\r
+\r
+**/\r
+CHAR8 *\r
+OpalDriverPopUpPasswordInput (\r
+ IN OPAL_DRIVER_DEVICE *Dev,\r
+ IN CHAR16 *PopUpString1,\r
+ IN CHAR16 *PopUpString2,\r
+ OUT BOOLEAN *PressEsc\r
+ )\r
+{\r
+ EFI_INPUT_KEY InputKey;\r
+ UINTN InputLength;\r
+ CHAR16 Mask[OPAL_MAX_PASSWORD_SIZE + 1];\r
+ CHAR16 Unicode[OPAL_MAX_PASSWORD_SIZE + 1];\r
+ CHAR8 *Ascii;\r
+\r
+ ZeroMem(Unicode, sizeof(Unicode));\r
+ ZeroMem(Mask, sizeof(Mask));\r
+\r
+ *PressEsc = FALSE;\r
+\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+\r
+ InputLength = 0;\r
+ while (TRUE) {\r
+ Mask[InputLength] = L'_';\r
+ if (PopUpString2 == NULL) {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &InputKey,\r
+ PopUpString1,\r
+ L"---------------------",\r
+ Mask,\r
+ NULL\r
+ );\r
+ } else {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &InputKey,\r
+ PopUpString1,\r
+ PopUpString2,\r
+ L"---------------------",\r
+ Mask,\r
+ NULL\r
+ );\r
+ }\r
+\r
+ //\r
+ // Check key.\r
+ //\r
+ if (InputKey.ScanCode == SCAN_NULL) {\r
+ //\r
+ // password finished\r
+ //\r
+ if (InputKey.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+ //\r
+ // Add the null terminator.\r
+ //\r
+ Unicode[InputLength] = 0;\r
+ Mask[InputLength] = 0;\r
+ break;\r
+ } else if ((InputKey.UnicodeChar == CHAR_NULL) ||\r
+ (InputKey.UnicodeChar == CHAR_TAB) ||\r
+ (InputKey.UnicodeChar == CHAR_LINEFEED)\r
+ ) {\r
+ continue;\r
+ } else {\r
+ //\r
+ // delete last key entered\r
+ //\r
+ if (InputKey.UnicodeChar == CHAR_BACKSPACE) {\r
+ if (InputLength > 0) {\r
+ Unicode[InputLength] = 0;\r
+ Mask[InputLength] = 0;\r
+ InputLength--;\r
+ }\r
+ } else {\r
+ //\r
+ // add Next key entry\r
+ //\r
+ Unicode[InputLength] = InputKey.UnicodeChar;\r
+ Mask[InputLength] = L'*';\r
+ InputLength++;\r
+ if (InputLength == OPAL_MAX_PASSWORD_SIZE) {\r
+ //\r
+ // Add the null terminator.\r
+ //\r
+ Unicode[InputLength] = 0;\r
+ Mask[InputLength] = 0;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // exit on ESC\r
+ //\r
+ if (InputKey.ScanCode == SCAN_ESC) {\r
+ *PressEsc = TRUE;\r
+ break;\r
+ }\r
+ }\r
+\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+\r
+ if (InputLength == 0 || InputKey.ScanCode == SCAN_ESC) {\r
+ ZeroMem (Unicode, sizeof (Unicode));\r
+ return NULL;\r
+ }\r
+\r
+ Ascii = AllocateZeroPool (OPAL_MAX_PASSWORD_SIZE + 1);\r
+ if (Ascii == NULL) {\r
+ ZeroMem (Unicode, sizeof (Unicode));\r
+ return NULL;\r
+ }\r
+\r
+ UnicodeStrToAsciiStrS (Unicode, Ascii, OPAL_MAX_PASSWORD_SIZE + 1);\r
+ ZeroMem (Unicode, sizeof (Unicode));\r
+\r
+ return Ascii;\r
+}\r
+\r
+/**\r
+ Check if disk is locked, show popup window and ask for password if it is.\r
+\r
+ @param[in] Dev The device which need to be unlocked.\r
+ @param[in] RequestString Request string.\r
+\r
+**/\r
+CHAR16 *\r
+OpalGetPopUpString (\r
+ IN OPAL_DRIVER_DEVICE *Dev,\r
+ IN CHAR16 *RequestString\r
+ )\r
+{\r
+ UINTN StrLength;\r
+\r
+ StrLength = StrLen (RequestString) + 1 + MAX (StrLen (Dev->Name16), StrLen (L"Disk"));\r
+ ASSERT (StrLength < sizeof (mPopUpString) / sizeof (CHAR16));\r
+\r
+ if (Dev->Name16 == NULL) {\r
+ UnicodeSPrint (mPopUpString, StrLength + 1, L"%s Disk", RequestString);\r
+ } else {\r
+ UnicodeSPrint (mPopUpString, StrLength + 1, L"%s %s", RequestString, Dev->Name16);\r
+ }\r
+\r
+ return mPopUpString;\r
+}\r
+\r
+/**\r
+ Check if disk is locked, show popup window and ask for password if it is.\r
+\r
+ @param[in] Dev The device which need to be unlocked.\r
+ @param[in] RequestString Request string.\r
+\r
+**/\r
+VOID\r
+OpalDriverRequestPassword (\r
+ IN OPAL_DRIVER_DEVICE *Dev,\r
+ IN CHAR16 *RequestString\r
+ )\r
+{\r
+ UINT8 Count;\r
+ BOOLEAN IsEnabled;\r
+ BOOLEAN IsLocked;\r
+ CHAR8 *Password;\r
+ UINT32 PasswordLen;\r
+ OPAL_SESSION Session;\r
+ BOOLEAN PressEsc;\r
+ EFI_INPUT_KEY Key;\r
+ TCG_RESULT Ret;\r
+ CHAR16 *PopUpString;\r
+\r
+ if (Dev == NULL) {\r
+ return;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
+\r
+ PopUpString = OpalGetPopUpString (Dev, RequestString);\r
+\r
+ Count = 0;\r
+\r
+ IsEnabled = OpalFeatureEnabled (&Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.LockingFeature);\r
+ if (IsEnabled) {\r
+ ZeroMem(&Session, sizeof(Session));\r
+ Session.Sscp = Dev->OpalDisk.Sscp;\r
+ Session.MediaId = Dev->OpalDisk.MediaId;\r
+ Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
+\r
+ IsLocked = OpalDeviceLocked (&Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.LockingFeature);\r
+\r
+ while (Count < MAX_PASSWORD_TRY_COUNT) {\r
+ Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, NULL, &PressEsc);\r
+ if (PressEsc) {\r
+ if (IsLocked) {\r
+ //\r
+ // Current device in the lock status and\r
+ // User not input password and press ESC,\r
+ // keep device in lock status and continue boot.\r
+ //\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Press ENTER to skip the request and continue boot,",\r
+ L"Press ESC to input password again",\r
+ NULL\r
+ );\r
+ } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
+\r
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+ //\r
+ // Keep lock and continue boot.\r
+ //\r
+ return;\r
+ } else {\r
+ //\r
+ // Let user input password again.\r
+ //\r
+ continue;\r
+ }\r
+ } else {\r
+ //\r
+ // Current device in the unlock status and\r
+ // User not input password and press ESC,\r
+ // Shutdown the device.\r
+ //\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Press ENTER to shutdown, Press ESC to input password again",\r
+ NULL\r
+ );\r
+ } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
+\r
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+ gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);\r
+ } else {\r
+ //\r
+ // Let user input password again.\r
+ //\r
+ continue;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (Password == NULL) {\r
+ Count ++;\r
+ continue;\r
+ }\r
+ PasswordLen = (UINT32) AsciiStrLen(Password);\r
+\r
+ if (IsLocked) {\r
+ Ret = OpalUtilUpdateGlobalLockingRange(&Session, Password, PasswordLen, FALSE, FALSE);\r
+ } else {\r
+ Ret = OpalUtilUpdateGlobalLockingRange(&Session, Password, PasswordLen, TRUE, TRUE);\r
+ if (Ret == TcgResultSuccess) {\r
+ Ret = OpalUtilUpdateGlobalLockingRange(&Session, Password, PasswordLen, FALSE, FALSE);\r
+ }\r
+ }\r
+\r
+ if (Ret == TcgResultSuccess) {\r
+ OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen);\r
+ DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
+ } else {\r
+ DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
+ }\r
+\r
+ if (Password != NULL) {\r
+ ZeroMem (Password, PasswordLen);\r
+ FreePool (Password);\r
+ }\r
+\r
+ if (Ret == TcgResultSuccess) {\r
+ break;\r
+ }\r
+\r
+ Count++;\r
+\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Invalid password.",\r
+ L"Press ENTER to retry",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ }\r
+\r
+ if (Count >= MAX_PASSWORD_TRY_COUNT) {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Opal password retry count exceeds the limit. Must shutdown!",\r
+ L"Press ENTER to shutdown",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+\r
+ gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Process Enable Feature OPAL request.\r
+\r
+ @param[in] Dev The device which has Enable Feature OPAL request.\r
+ @param[in] RequestString Request string.\r
+\r
+**/\r
+VOID\r
+ProcessOpalRequestEnableFeature (\r
+ IN OPAL_DRIVER_DEVICE *Dev,\r
+ IN CHAR16 *RequestString\r
+ )\r
+{\r
+ UINT8 Count;\r
+ CHAR8 *Password;\r
+ UINT32 PasswordLen;\r
+ CHAR8 *PasswordConfirm;\r
+ UINT32 PasswordLenConfirm;\r
+ OPAL_SESSION Session;\r
+ BOOLEAN PressEsc;\r
+ EFI_INPUT_KEY Key;\r
+ TCG_RESULT Ret;\r
+ CHAR16 *PopUpString;\r
+\r
+ if (Dev == NULL) {\r
+ return;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
+\r
+ PopUpString = OpalGetPopUpString (Dev, RequestString);\r
+\r
+ Count = 0;\r
+\r
+ ZeroMem(&Session, sizeof(Session));\r
+ Session.Sscp = Dev->OpalDisk.Sscp;\r
+ Session.MediaId = Dev->OpalDisk.MediaId;\r
+ Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
+\r
+ while (Count < MAX_PASSWORD_TRY_COUNT) {\r
+ Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your new password", &PressEsc);\r
+ if (PressEsc) {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Press ENTER to skip the request and continue boot,",\r
+ L"Press ESC to input password again",\r
+ NULL\r
+ );\r
+ } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
+\r
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+ return;\r
+ } else {\r
+ //\r
+ // Let user input password again.\r
+ //\r
+ continue;\r
+ }\r
+ }\r
+\r
+ if (Password == NULL) {\r
+ Count ++;\r
+ continue;\r
+ }\r
+ PasswordLen = (UINT32) AsciiStrLen(Password);\r
+\r
+ PasswordConfirm = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please confirm your new password", &PressEsc);\r
+ if (PasswordConfirm == NULL) {\r
+ ZeroMem (Password, PasswordLen);\r
+ FreePool (Password);\r
+ Count ++;\r
+ continue;\r
+ }\r
+ PasswordLenConfirm = (UINT32) AsciiStrLen(PasswordConfirm);\r
+ if ((PasswordLen != PasswordLenConfirm) ||\r
+ (CompareMem (Password, PasswordConfirm, PasswordLen) != 0)) {\r
+ ZeroMem (Password, PasswordLen);\r
+ FreePool (Password);\r
+ ZeroMem (PasswordConfirm, PasswordLenConfirm);\r
+ FreePool (PasswordConfirm);\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Passwords are not the same.",\r
+ L"Press ENTER to retry",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ Count ++;\r
+ continue;\r
+ }\r
+\r
+ if (PasswordConfirm != NULL) {\r
+ ZeroMem (PasswordConfirm, PasswordLenConfirm);\r
+ FreePool (PasswordConfirm);\r
+ }\r
+\r
+ Ret = OpalSupportEnableOpalFeature (&Session, Dev->OpalDisk.Msid, Dev->OpalDisk.MsidLength, Password, PasswordLen);\r
+ if (Ret == TcgResultSuccess) {\r
+ OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen);\r
+ DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
+ } else {\r
+ DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
+ }\r
+\r
+ if (Password != NULL) {\r
+ ZeroMem (Password, PasswordLen);\r
+ FreePool (Password);\r
+ }\r
+\r
+ if (Ret == TcgResultSuccess) {\r
+ break;\r
+ }\r
+\r
+ Count++;\r
+\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Request failed.",\r
+ L"Press ENTER to retry",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ }\r
+\r
+ if (Count >= MAX_PASSWORD_TRY_COUNT) {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Opal password retry count exceeds the limit.",\r
+ L"Press ENTER to skip the request and continue boot",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+ }\r
+}\r
+\r
+/**\r
+ Process Disable User OPAL request.\r
+\r
+ @param[in] Dev The device which has Disable User OPAL request.\r
+ @param[in] RequestString Request string.\r
+\r
+**/\r
+VOID\r
+ProcessOpalRequestDisableUser (\r
+ IN OPAL_DRIVER_DEVICE *Dev,\r
+ IN CHAR16 *RequestString\r
+ )\r
+{\r
+ UINT8 Count;\r
+ CHAR8 *Password;\r
+ UINT32 PasswordLen;\r
+ OPAL_SESSION Session;\r
+ BOOLEAN PressEsc;\r
+ EFI_INPUT_KEY Key;\r
+ TCG_RESULT Ret;\r
+ BOOLEAN PasswordFailed;\r
+ CHAR16 *PopUpString;\r
+\r
+ if (Dev == NULL) {\r
+ return;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
+\r
+ PopUpString = OpalGetPopUpString (Dev, RequestString);\r
+\r
+ Count = 0;\r
+\r
+ ZeroMem(&Session, sizeof(Session));\r
+ Session.Sscp = Dev->OpalDisk.Sscp;\r
+ Session.MediaId = Dev->OpalDisk.MediaId;\r
+ Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
+\r
+ while (Count < MAX_PASSWORD_TRY_COUNT) {\r
+ Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, NULL, &PressEsc);\r
+ if (PressEsc) {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Press ENTER to skip the request and continue boot,",\r
+ L"Press ESC to input password again",\r
+ NULL\r
+ );\r
+ } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
+\r
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+ return;\r
+ } else {\r
+ //\r
+ // Let user input password again.\r
+ //\r
+ continue;\r
+ }\r
+ }\r
+\r
+ if (Password == NULL) {\r
+ Count ++;\r
+ continue;\r
+ }\r
+ PasswordLen = (UINT32) AsciiStrLen(Password);\r
+\r
+ Ret = OpalUtilDisableUser(&Session, Password, PasswordLen, &PasswordFailed);\r
+ if (Ret == TcgResultSuccess) {\r
+ OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen);\r
+ DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
+ } else {\r
+ DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
+ }\r
+\r
+ if (Password != NULL) {\r
+ ZeroMem (Password, PasswordLen);\r
+ FreePool (Password);\r
+ }\r
+\r
+ if (Ret == TcgResultSuccess) {\r
+ break;\r
+ }\r
+\r
+ Count++;\r
+\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Invalid password, request failed.",\r
+ L"Press ENTER to retry",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ }\r
+\r
+ if (Count >= MAX_PASSWORD_TRY_COUNT) {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Opal password retry count exceeds the limit.",\r
+ L"Press ENTER to skip the request and continue boot",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+ }\r
+}\r
+\r
+/**\r
+ Process Psid Revert OPAL request.\r
+\r
+ @param[in] Dev The device which has Psid Revert OPAL request.\r
+ @param[in] RequestString Request string.\r
+\r
+**/\r
+VOID\r
+ProcessOpalRequestPsidRevert (\r
+ IN OPAL_DRIVER_DEVICE *Dev,\r
+ IN CHAR16 *RequestString\r
+ )\r
+{\r
+ UINT8 Count;\r
+ CHAR8 *Psid;\r
+ UINT32 PsidLen;\r
+ OPAL_SESSION Session;\r
+ BOOLEAN PressEsc;\r
+ EFI_INPUT_KEY Key;\r
+ TCG_RESULT Ret;\r
+ CHAR16 *PopUpString;\r
+\r
+ if (Dev == NULL) {\r
+ return;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
+\r
+ PopUpString = OpalGetPopUpString (Dev, RequestString);\r
+\r
+ Count = 0;\r
+\r
+ ZeroMem(&Session, sizeof(Session));\r
+ Session.Sscp = Dev->OpalDisk.Sscp;\r
+ Session.MediaId = Dev->OpalDisk.MediaId;\r
+ Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
+\r
+ while (Count < MAX_PSID_TRY_COUNT) {\r
+ Psid = OpalDriverPopUpPsidInput (Dev, PopUpString, &PressEsc);\r
+ if (PressEsc) {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Press ENTER to skip the request and continue boot,",\r
+ L"Press ESC to input Psid again",\r
+ NULL\r
+ );\r
+ } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
+\r
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+ return;\r
+ } else {\r
+ //\r
+ // Let user input Psid again.\r
+ //\r
+ continue;\r
+ }\r
+ }\r
+\r
+ if (Psid == NULL) {\r
+ Count ++;\r
+ continue;\r
+ }\r
+ PsidLen = (UINT32) AsciiStrLen(Psid);\r
+\r
+ Ret = OpalUtilPsidRevert(&Session, Psid, PsidLen);\r
+ if (Ret == TcgResultSuccess) {\r
+ DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
+ } else {\r
+ DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
+ }\r
+\r
+ if (Psid != NULL) {\r
+ ZeroMem (Psid, PsidLen);\r
+ FreePool (Psid);\r
+ }\r
+\r
+ if (Ret == TcgResultSuccess) {\r
+ break;\r
+ }\r
+\r
+ Count++;\r
+\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Invalid Psid, request failed.",\r
+ L"Press ENTER to retry",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ }\r
+\r
+ if (Count >= MAX_PSID_TRY_COUNT) {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Opal Psid retry count exceeds the limit.",\r
+ L"Press ENTER to skip the request and continue boot",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+ }\r
+}\r
+\r
+/**\r
+ Process Admin Revert OPAL request.\r
+\r
+ @param[in] Dev The device which has Revert OPAL request.\r
+ @param[in] KeepUserData Whether to keep user data or not.\r
+ @param[in] RequestString Request string.\r
+\r
+**/\r
+VOID\r
+ProcessOpalRequestRevert (\r
+ IN OPAL_DRIVER_DEVICE *Dev,\r
+ IN BOOLEAN KeepUserData,\r
+ IN CHAR16 *RequestString\r
+ )\r
+{\r
+ UINT8 Count;\r
+ CHAR8 *Password;\r
+ UINT32 PasswordLen;\r
+ OPAL_SESSION Session;\r
+ BOOLEAN PressEsc;\r
+ EFI_INPUT_KEY Key;\r
+ TCG_RESULT Ret;\r
+ BOOLEAN PasswordFailed;\r
+ CHAR16 *PopUpString;\r
+\r
+ if (Dev == NULL) {\r
+ return;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
+\r
+ PopUpString = OpalGetPopUpString (Dev, RequestString);\r
+\r
+ Count = 0;\r
+\r
+ ZeroMem(&Session, sizeof(Session));\r
+ Session.Sscp = Dev->OpalDisk.Sscp;\r
+ Session.MediaId = Dev->OpalDisk.MediaId;\r
+ Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
+\r
+ while (Count < MAX_PASSWORD_TRY_COUNT) {\r
+ Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, NULL, &PressEsc);\r
+ if (PressEsc) {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Press ENTER to skip the request and continue boot,",\r
+ L"Press ESC to input password again",\r
+ NULL\r
+ );\r
+ } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
+\r
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+ return;\r
+ } else {\r
+ //\r
+ // Let user input password again.\r
+ //\r
+ continue;\r
+ }\r
+ }\r
+\r
+ if (Password == NULL) {\r
+ Count ++;\r
+ continue;\r
+ }\r
+ PasswordLen = (UINT32) AsciiStrLen(Password);\r
+\r
+ if ((Dev->OpalDisk.SupportedAttributes.PyriteSsc == 1) &&\r
+ (Dev->OpalDisk.LockingFeature.MediaEncryption == 0)) {\r
+ //\r
+ // For pyrite type device which does not support media encryption,\r
+ // it does not accept "Keep User Data" parameter.\r
+ // So here hardcode a FALSE for this case.\r
+ //\r
+ Ret = OpalUtilRevert(\r
+ &Session,\r
+ FALSE,\r
+ Password,\r
+ PasswordLen,\r
+ &PasswordFailed,\r
+ Dev->OpalDisk.Msid,\r
+ Dev->OpalDisk.MsidLength\r
+ );\r
+ } else {\r
+ Ret = OpalUtilRevert(\r
+ &Session,\r
+ KeepUserData,\r
+ Password,\r
+ PasswordLen,\r
+ &PasswordFailed,\r
+ Dev->OpalDisk.Msid,\r
+ Dev->OpalDisk.MsidLength\r
+ );\r
+ }\r
+ if (Ret == TcgResultSuccess) {\r
+ OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen);\r
+ DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
+ } else {\r
+ DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
+ }\r
+\r
+ if (Password != NULL) {\r
+ ZeroMem (Password, PasswordLen);\r
+ FreePool (Password);\r
+ }\r
+\r
+ if (Ret == TcgResultSuccess) {\r
+ break;\r
+ }\r
+\r
+ Count++;\r
+\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Invalid password, request failed.",\r
+ L"Press ENTER to retry",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ }\r
+\r
+ if (Count >= MAX_PASSWORD_TRY_COUNT) {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Opal password retry count exceeds the limit.",\r
+ L"Press ENTER to skip the request and continue boot",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+ }\r
+}\r
+\r
+/**\r
+ Process Secure Erase OPAL request.\r
+\r
+ @param[in] Dev The device which has Secure Erase OPAL request.\r
+ @param[in] RequestString Request string.\r
+\r
+**/\r
+VOID\r
+ProcessOpalRequestSecureErase (\r
+ IN OPAL_DRIVER_DEVICE *Dev,\r
+ IN CHAR16 *RequestString\r
+ )\r
+{\r
+ UINT8 Count;\r
+ CHAR8 *Password;\r
+ UINT32 PasswordLen;\r
+ OPAL_SESSION Session;\r
+ BOOLEAN PressEsc;\r
+ EFI_INPUT_KEY Key;\r
+ TCG_RESULT Ret;\r
+ BOOLEAN PasswordFailed;\r
+ CHAR16 *PopUpString;\r
+\r
+ if (Dev == NULL) {\r
+ return;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
+\r
+ PopUpString = OpalGetPopUpString (Dev, RequestString);\r
+\r
+ Count = 0;\r
+\r
+ ZeroMem(&Session, sizeof(Session));\r
+ Session.Sscp = Dev->OpalDisk.Sscp;\r
+ Session.MediaId = Dev->OpalDisk.MediaId;\r
+ Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
+\r
+ while (Count < MAX_PASSWORD_TRY_COUNT) {\r
+ Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, NULL, &PressEsc);\r
+ if (PressEsc) {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Press ENTER to skip the request and continue boot,",\r
+ L"Press ESC to input password again",\r
+ NULL\r
+ );\r
+ } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
+\r
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+ return;\r
+ } else {\r
+ //\r
+ // Let user input password again.\r
+ //\r
+ continue;\r
+ }\r
+ }\r
+\r
+ if (Password == NULL) {\r
+ Count ++;\r
+ continue;\r
+ }\r
+ PasswordLen = (UINT32) AsciiStrLen(Password);\r
+\r
+ Ret = OpalUtilSecureErase(&Session, Password, PasswordLen, &PasswordFailed);\r
+ if (Ret == TcgResultSuccess) {\r
+ OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen);\r
+ DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
+ } else {\r
+ DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
+ }\r
+\r
+ if (Password != NULL) {\r
+ ZeroMem (Password, PasswordLen);\r
+ FreePool (Password);\r
+ }\r
+\r
+ if (Ret == TcgResultSuccess) {\r
+ break;\r
+ }\r
+\r
+ Count++;\r
+\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Invalid password, request failed.",\r
+ L"Press ENTER to retry",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ }\r
+\r
+ if (Count >= MAX_PASSWORD_TRY_COUNT) {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Opal password retry count exceeds the limit.",\r
+ L"Press ENTER to skip the request and continue boot",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+ }\r
+}\r
+\r
+/**\r
+ Process Set Admin Pwd OPAL request.\r
+\r
+ @param[in] Dev The device which has Set Admin Pwd Feature OPAL request.\r
+ @param[in] RequestString Request string.\r
+\r
+**/\r
+VOID\r
+ProcessOpalRequestSetUserPwd (\r
+ IN OPAL_DRIVER_DEVICE *Dev,\r
+ IN CHAR16 *RequestString\r
+ )\r
+{\r
+ UINT8 Count;\r
+ CHAR8 *OldPassword;\r
+ UINT32 OldPasswordLen;\r
+ CHAR8 *Password;\r
+ UINT32 PasswordLen;\r
+ CHAR8 *PasswordConfirm;\r
+ UINT32 PasswordLenConfirm;\r
+ OPAL_SESSION Session;\r
+ BOOLEAN PressEsc;\r
+ EFI_INPUT_KEY Key;\r
+ TCG_RESULT Ret;\r
+ CHAR16 *PopUpString;\r
+\r
+ if (Dev == NULL) {\r
+ return;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
+\r
+ PopUpString = OpalGetPopUpString (Dev, RequestString);\r
+\r
+ Count = 0;\r
+\r
+ while (Count < MAX_PASSWORD_TRY_COUNT) {\r
+ OldPassword = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your password", &PressEsc);\r
+ if (PressEsc) {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Press ENTER to skip the request and continue boot,",\r
+ L"Press ESC to input password again",\r
+ NULL\r
+ );\r
+ } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
+\r
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+ return;\r
+ } else {\r
+ //\r
+ // Let user input password again.\r
+ //\r
+ continue;\r
+ }\r
+ }\r
+\r
+ if (OldPassword == NULL) {\r
+ Count ++;\r
+ continue;\r
+ }\r
+ OldPasswordLen = (UINT32) AsciiStrLen(OldPassword);\r
+\r
+ ZeroMem(&Session, sizeof(Session));\r
+ Session.Sscp = Dev->OpalDisk.Sscp;\r
+ Session.MediaId = Dev->OpalDisk.MediaId;\r
+ Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
+ Ret = OpalUtilVerifyPassword (&Session, OldPassword, OldPasswordLen, OPAL_LOCKING_SP_USER1_AUTHORITY);\r
+ if (Ret == TcgResultSuccess) {\r
+ DEBUG ((DEBUG_INFO, "Verify with USER1 authority : Success\n"));\r
+ } else {\r
+ Ret = OpalUtilVerifyPassword (&Session, OldPassword, OldPasswordLen, OPAL_LOCKING_SP_ADMIN1_AUTHORITY);\r
+ if (Ret == TcgResultSuccess) {\r
+ DEBUG ((DEBUG_INFO, "Verify with ADMIN1 authority: Success\n"));\r
+ } else {\r
+ ZeroMem (OldPassword, OldPasswordLen);\r
+ FreePool (OldPassword);\r
+ DEBUG ((DEBUG_INFO, "Verify: Failure\n"));\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Incorrect password.",\r
+ L"Press ENTER to retry",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ Count ++;\r
+ continue;\r
+ }\r
+ }\r
+\r
+ Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your new password", &PressEsc);\r
+ if (Password == NULL) {\r
+ ZeroMem (OldPassword, OldPasswordLen);\r
+ FreePool (OldPassword);\r
+ Count ++;\r
+ continue;\r
+ }\r
+ PasswordLen = (UINT32) AsciiStrLen(Password);\r
+\r
+ PasswordConfirm = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please confirm your new password", &PressEsc);\r
+ if (PasswordConfirm == NULL) {\r
+ ZeroMem (OldPassword, OldPasswordLen);\r
+ FreePool (OldPassword);\r
+ ZeroMem (Password, PasswordLen);\r
+ FreePool (Password);\r
+ Count ++;\r
+ continue;\r
+ }\r
+ PasswordLenConfirm = (UINT32) AsciiStrLen(PasswordConfirm);\r
+ if ((PasswordLen != PasswordLenConfirm) ||\r
+ (CompareMem (Password, PasswordConfirm, PasswordLen) != 0)) {\r
+ ZeroMem (OldPassword, OldPasswordLen);\r
+ FreePool (OldPassword);\r
+ ZeroMem (Password, PasswordLen);\r
+ FreePool (Password);\r
+ ZeroMem (PasswordConfirm, PasswordLenConfirm);\r
+ FreePool (PasswordConfirm);\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Passwords are not the same.",\r
+ L"Press ENTER to retry",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ Count ++;\r
+ continue;\r
+ }\r
+\r
+ if (PasswordConfirm != NULL) {\r
+ ZeroMem (PasswordConfirm, PasswordLenConfirm);\r
+ FreePool (PasswordConfirm);\r
+ }\r
+\r
+ ZeroMem(&Session, sizeof(Session));\r
+ Session.Sscp = Dev->OpalDisk.Sscp;\r
+ Session.MediaId = Dev->OpalDisk.MediaId;\r
+ Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
+ Ret = OpalUtilSetUserPassword(\r
+ &Session,\r
+ OldPassword,\r
+ OldPasswordLen,\r
+ Password,\r
+ PasswordLen\r
+ );\r
+ if (Ret == TcgResultSuccess) {\r
+ OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen);\r
+ DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
+ } else {\r
+ DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
+ }\r
+\r
+ if (OldPassword != NULL) {\r
+ ZeroMem (OldPassword, OldPasswordLen);\r
+ FreePool (OldPassword);\r
+ }\r
+\r
+ if (Password != NULL) {\r
+ ZeroMem (Password, PasswordLen);\r
+ FreePool (Password);\r
+ }\r
+\r
+ if (Ret == TcgResultSuccess) {\r
+ break;\r
+ }\r
+\r
+ Count++;\r
+\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Request failed.",\r
+ L"Press ENTER to retry",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ }\r
+\r
+ if (Count >= MAX_PASSWORD_TRY_COUNT) {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Opal password retry count exceeds the limit.",\r
+ L"Press ENTER to skip the request and continue boot",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+ }\r
+}\r
+\r
+/**\r
+ Process Set Admin Pwd OPAL request.\r
+\r
+ @param[in] Dev The device which has Set Admin Pwd Feature OPAL request.\r
+ @param[in] RequestString Request string.\r
+\r
+**/\r
+VOID\r
+ProcessOpalRequestSetAdminPwd (\r
+ IN OPAL_DRIVER_DEVICE *Dev,\r
+ IN CHAR16 *RequestString\r
+ )\r
+{\r
+ UINT8 Count;\r
+ CHAR8 *OldPassword;\r
+ UINT32 OldPasswordLen;\r
+ CHAR8 *Password;\r
+ UINT32 PasswordLen;\r
+ CHAR8 *PasswordConfirm;\r
+ UINT32 PasswordLenConfirm;\r
+ OPAL_SESSION Session;\r
+ BOOLEAN PressEsc;\r
+ EFI_INPUT_KEY Key;\r
+ TCG_RESULT Ret;\r
+ CHAR16 *PopUpString;\r
+\r
+ if (Dev == NULL) {\r
+ return;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
+\r
+ PopUpString = OpalGetPopUpString (Dev, RequestString);\r
+\r
+ Count = 0;\r
+\r
+ while (Count < MAX_PASSWORD_TRY_COUNT) {\r
+ OldPassword = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your password", &PressEsc);\r
+ if (PressEsc) {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Press ENTER to skip the request and continue boot,",\r
+ L"Press ESC to input password again",\r
+ NULL\r
+ );\r
+ } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
+\r
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+ return;\r
+ } else {\r
+ //\r
+ // Let user input password again.\r
+ //\r
+ continue;\r
+ }\r
+ }\r
+\r
+ if (OldPassword == NULL) {\r
+ Count ++;\r
+ continue;\r
+ }\r
+ OldPasswordLen = (UINT32) AsciiStrLen(OldPassword);\r
+\r
+ ZeroMem(&Session, sizeof(Session));\r
+ Session.Sscp = Dev->OpalDisk.Sscp;\r
+ Session.MediaId = Dev->OpalDisk.MediaId;\r
+ Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
+ Ret = OpalUtilVerifyPassword (&Session, OldPassword, OldPasswordLen, OPAL_LOCKING_SP_ADMIN1_AUTHORITY);\r
+ if (Ret == TcgResultSuccess) {\r
+ DEBUG ((DEBUG_INFO, "Verify: Success\n"));\r
+ } else {\r
+ ZeroMem (OldPassword, OldPasswordLen);\r
+ FreePool (OldPassword);\r
+ DEBUG ((DEBUG_INFO, "Verify: Failure\n"));\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Incorrect password.",\r
+ L"Press ENTER to retry",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ Count ++;\r
+ continue;\r
+ }\r
+\r
+ Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your new password", &PressEsc);\r
+ if (Password == NULL) {\r
+ ZeroMem (OldPassword, OldPasswordLen);\r
+ FreePool (OldPassword);\r
+ Count ++;\r
+ continue;\r
+ }\r
+ PasswordLen = (UINT32) AsciiStrLen(Password);\r
+\r
+ PasswordConfirm = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please confirm your new password", &PressEsc);\r
+ if (PasswordConfirm == NULL) {\r
+ ZeroMem (OldPassword, OldPasswordLen);\r
+ FreePool (OldPassword);\r
+ ZeroMem (Password, PasswordLen);\r
+ FreePool (Password);\r
+ Count ++;\r
+ continue;\r
+ }\r
+ PasswordLenConfirm = (UINT32) AsciiStrLen(PasswordConfirm);\r
+ if ((PasswordLen != PasswordLenConfirm) ||\r
+ (CompareMem (Password, PasswordConfirm, PasswordLen) != 0)) {\r
+ ZeroMem (OldPassword, OldPasswordLen);\r
+ FreePool (OldPassword);\r
+ ZeroMem (Password, PasswordLen);\r
+ FreePool (Password);\r
+ ZeroMem (PasswordConfirm, PasswordLenConfirm);\r
+ FreePool (PasswordConfirm);\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Passwords are not the same.",\r
+ L"Press ENTER to retry",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ Count ++;\r
+ continue;\r
+ }\r
+\r
+ if (PasswordConfirm != NULL) {\r
+ ZeroMem (PasswordConfirm, PasswordLenConfirm);\r
+ FreePool (PasswordConfirm);\r
+ }\r
+\r
+\r
+ ZeroMem(&Session, sizeof(Session));\r
+ Session.Sscp = Dev->OpalDisk.Sscp;\r
+ Session.MediaId = Dev->OpalDisk.MediaId;\r
+ Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
+ Ret = OpalUtilSetAdminPassword(\r
+ &Session,\r
+ OldPassword,\r
+ OldPasswordLen,\r
+ Password,\r
+ PasswordLen\r
+ );\r
+ if (Ret == TcgResultSuccess) {\r
+ OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen);\r
+ DEBUG ((DEBUG_INFO, "%s Success\n", RequestString));\r
+ } else {\r
+ DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString));\r
+ }\r
+\r
+ if (OldPassword != NULL) {\r
+ ZeroMem (OldPassword, OldPasswordLen);\r
+ FreePool (OldPassword);\r
+ }\r
+\r
+ if (Password != NULL) {\r
+ ZeroMem (Password, PasswordLen);\r
+ FreePool (Password);\r
+ }\r
+\r
+ if (Ret == TcgResultSuccess) {\r
+ break;\r
+ }\r
+\r
+ Count++;\r
+\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Request failed.",\r
+ L"Press ENTER to retry",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ }\r
+\r
+ if (Count >= MAX_PASSWORD_TRY_COUNT) {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Opal password retry count exceeds the limit.",\r
+ L"Press ENTER to skip the request and continue boot",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+ }\r
+}\r
+\r
+/**\r
+ Process OPAL request.\r
+\r
+ @param[in] Dev The device which has OPAL request.\r
+\r
+**/\r
+VOID\r
+ProcessOpalRequest (\r
+ IN OPAL_DRIVER_DEVICE *Dev\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ OPAL_REQUEST_VARIABLE *TempVariable;\r
+ OPAL_REQUEST_VARIABLE *Variable;\r
+ UINTN VariableSize;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInVariable;\r
+ UINTN DevicePathSizeInVariable;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ UINTN DevicePathSize;\r
+ BOOLEAN KeepUserData;\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
+\r
+ if (mOpalRequestVariable == NULL) {\r
+ Status = GetVariable2 (\r
+ OPAL_REQUEST_VARIABLE_NAME,\r
+ &gHiiSetupVariableGuid,\r
+ (VOID **) &Variable,\r
+ &VariableSize\r
+ );\r
+ if (EFI_ERROR (Status) || (Variable == NULL)) {\r
+ return;\r
+ }\r
+ mOpalRequestVariable = Variable;\r
+ mOpalRequestVariableSize = VariableSize;\r
+\r
+ //\r
+ // Delete the OPAL request variable.\r
+ //\r
+ Status = gRT->SetVariable (\r
+ OPAL_REQUEST_VARIABLE_NAME,\r
+ (EFI_GUID *) &gHiiSetupVariableGuid,\r
+ 0,\r
+ 0,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ } else {\r
+ Variable = mOpalRequestVariable;\r
+ VariableSize = mOpalRequestVariableSize;\r
+ }\r
+\r
+ //\r
+ // Process the OPAL requests.\r
+ //\r
+ TempVariable = Variable;\r
+ while ((VariableSize > sizeof (OPAL_REQUEST_VARIABLE)) &&\r
+ (VariableSize >= TempVariable->Length) &&\r
+ (TempVariable->Length > sizeof (OPAL_REQUEST_VARIABLE))) {\r
+ DevicePathInVariable = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) TempVariable + sizeof (OPAL_REQUEST_VARIABLE));\r
+ DevicePathSizeInVariable = GetDevicePathSize (DevicePathInVariable);\r
+ DevicePath = Dev->OpalDisk.OpalDevicePath;\r
+ DevicePathSize = GetDevicePathSize (DevicePath);\r
+ if ((DevicePathSize == DevicePathSizeInVariable) &&\r
+ (CompareMem (DevicePath, DevicePathInVariable, DevicePathSize) == 0)) {\r
+ //\r
+ // Found the node for the OPAL device.\r
+ //\r
+ if (TempVariable->OpalRequest.SetAdminPwd != 0) {\r
+ ProcessOpalRequestSetAdminPwd (Dev, L"Update Admin Pwd:");\r
+ }\r
+ if (TempVariable->OpalRequest.SetUserPwd != 0) {\r
+ ProcessOpalRequestSetUserPwd (Dev, L"Set User Pwd:");\r
+ }\r
+ if (TempVariable->OpalRequest.SecureErase!= 0) {\r
+ ProcessOpalRequestSecureErase (Dev, L"Secure Erase:");\r
+ }\r
+ if (TempVariable->OpalRequest.Revert != 0) {\r
+ KeepUserData = (BOOLEAN) TempVariable->OpalRequest.KeepUserData;\r
+ ProcessOpalRequestRevert (\r
+ Dev,\r
+ KeepUserData,\r
+ KeepUserData ? L"Admin Revert(keep):" : L"Admin Revert:"\r
+ );\r
+ }\r
+ if (TempVariable->OpalRequest.PsidRevert != 0) {\r
+ ProcessOpalRequestPsidRevert (Dev, L"Psid Revert:");\r
+ }\r
+ if (TempVariable->OpalRequest.DisableUser != 0) {\r
+ ProcessOpalRequestDisableUser (Dev, L"Disable User:");\r
+ }\r
+ if (TempVariable->OpalRequest.EnableFeature != 0) {\r
+ ProcessOpalRequestEnableFeature (Dev, L"Enable Feature:");\r
+ }\r
+\r
+ break;\r
+ }\r
+\r
+ VariableSize -= TempVariable->Length;\r
+ TempVariable = (OPAL_REQUEST_VARIABLE *) ((UINTN) TempVariable + TempVariable->Length);\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
+}\r
+\r
+/**\r
+ Add new device to the global device list.\r
+\r
+ @param Dev New create device.\r
+\r
+**/\r
+VOID\r
+AddDeviceToTail(\r
+ IN OPAL_DRIVER_DEVICE *Dev\r
+ )\r
+{\r
+ OPAL_DRIVER_DEVICE *TmpDev;\r
+\r
+ if (mOpalDriver.DeviceList == NULL) {\r
+ mOpalDriver.DeviceList = Dev;\r
+ } else {\r
+ TmpDev = mOpalDriver.DeviceList;\r
+ while (TmpDev->Next != NULL) {\r
+ TmpDev = TmpDev->Next;\r
+ }\r
+\r
+ TmpDev->Next = Dev;\r
+ }\r
+}\r
+\r
+/**\r
+ Remove one device in the global device list.\r
+\r
+ @param Dev The device need to be removed.\r
+\r
+**/\r
+VOID\r
+RemoveDevice (\r
+ IN OPAL_DRIVER_DEVICE *Dev\r
+ )\r
+{\r
+ OPAL_DRIVER_DEVICE *TmpDev;\r
+\r
+ if (mOpalDriver.DeviceList == NULL) {\r
+ return;\r
+ }\r
+\r
+ if (mOpalDriver.DeviceList == Dev) {\r
+ mOpalDriver.DeviceList = NULL;\r
+ return;\r
+ }\r
+\r
+ TmpDev = mOpalDriver.DeviceList;\r
+ while (TmpDev->Next != NULL) {\r
+ if (TmpDev->Next == Dev) {\r
+ TmpDev->Next = Dev->Next;\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Get current device count.\r
+\r
+ @retval return the current created device count.\r
+\r
+**/\r
+UINT8\r
+GetDeviceCount (\r
+ VOID\r
+ )\r
+{\r
+ UINT8 Count;\r
+ OPAL_DRIVER_DEVICE *TmpDev;\r
+\r
+ Count = 0;\r
+ TmpDev = mOpalDriver.DeviceList;\r
+\r
+ while (TmpDev != NULL) {\r
+ Count++;\r
+ TmpDev = TmpDev->Next;\r
+ }\r
+\r
+ return Count;\r
+}\r
+\r
+/**\r
+ Get devcie list info.\r
+\r
+ @retval return the device list pointer.\r
+**/\r
+OPAL_DRIVER_DEVICE*\r
+OpalDriverGetDeviceList(\r
+ VOID\r
+ )\r
+{\r
+ return mOpalDriver.DeviceList;\r
+}\r
+\r
+/**\r
+ ReadyToBoot callback to send BlockSid command.\r
+\r
+ @param Event Pointer to this event\r
+ @param Context Event handler private Data\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+ReadyToBootCallback (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ OPAL_DRIVER_DEVICE *Itr;\r
+ TCG_RESULT Result;\r
+ OPAL_SESSION Session;\r
+ UINT32 PpStorageFlag;\r
+\r
+ gBS->CloseEvent (Event);\r
+\r
+ PpStorageFlag = Tcg2PhysicalPresenceLibGetManagementFlags ();\r
+ if ((PpStorageFlag & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID) != 0) {\r
+ //\r
+ // Send BlockSID command to each Opal disk\r
+ //\r
+ Itr = mOpalDriver.DeviceList;\r
+ while (Itr != NULL) {\r
+ if (Itr->OpalDisk.SupportedAttributes.BlockSid) {\r
+ ZeroMem(&Session, sizeof(Session));\r
+ Session.Sscp = Itr->OpalDisk.Sscp;\r
+ Session.MediaId = Itr->OpalDisk.MediaId;\r
+ Session.OpalBaseComId = Itr->OpalDisk.OpalBaseComId;\r
+\r
+ Result = OpalBlockSid (&Session, TRUE); // HardwareReset must always be TRUE\r
+ if (Result != TcgResultSuccess) {\r
+ DEBUG ((DEBUG_ERROR, "OpalBlockSid fail\n"));\r
+ break;\r
+ }\r
+ }\r
+\r
+ Itr = Itr->Next;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Stop this Controller.\r
+\r
+ @param Dev The device need to be stopped.\r
+\r
+**/\r
+VOID\r
+OpalDriverStopDevice (\r
+ OPAL_DRIVER_DEVICE *Dev\r
+ )\r
+{\r
+ //\r
+ // free each name\r
+ //\r
+ FreePool(Dev->Name16);\r
+\r
+ //\r
+ // remove OPAL_DRIVER_DEVICE from the list\r
+ // it updates the controllerList pointer\r
+ //\r
+ RemoveDevice(Dev);\r
+\r
+ //\r
+ // close protocols that were opened\r
+ //\r
+ gBS->CloseProtocol(\r
+ Dev->Handle,\r
+ &gEfiStorageSecurityCommandProtocolGuid,\r
+ gOpalDriverBinding.DriverBindingHandle,\r
+ Dev->Handle\r
+ );\r
+\r
+ gBS->CloseProtocol(\r
+ Dev->Handle,\r
+ &gEfiBlockIoProtocolGuid,\r
+ gOpalDriverBinding.DriverBindingHandle,\r
+ Dev->Handle\r
+ );\r
+\r
+ FreePool(Dev);\r
+}\r
+\r
+/**\r
+ Get devcie name through the component name protocol.\r
+\r
+ @param[in] AllHandlesBuffer The handle buffer for current system.\r
+ @param[in] NumAllHandles The number of handles for the handle buffer.\r
+ @param[in] Dev The device which need to get name.\r
+ @param[in] UseComp1 Whether use component name or name2 protocol.\r
+\r
+ @retval TRUE Find the name for this device.\r
+ @retval FALSE Not found the name for this device.\r
+**/\r
+BOOLEAN\r
+OpalDriverGetDeviceNameByProtocol(\r
+ EFI_HANDLE *AllHandlesBuffer,\r
+ UINTN NumAllHandles,\r
+ OPAL_DRIVER_DEVICE *Dev,\r
+ BOOLEAN UseComp1\r
+ )\r
+{\r
+ EFI_HANDLE* ProtocolHandlesBuffer;\r
+ UINTN NumProtocolHandles;\r
+ EFI_STATUS Status;\r
+ EFI_COMPONENT_NAME2_PROTOCOL* Cnp1_2; // efi component name and componentName2 have same layout\r
+ EFI_GUID Protocol;\r
+ UINTN StrLength;\r
+ EFI_DEVICE_PATH_PROTOCOL* TmpDevPath;\r
+ UINTN Index1;\r
+ UINTN Index2;\r
+ EFI_HANDLE TmpHandle;\r
+ CHAR16 *DevName;\r
+\r
+ if (Dev == NULL || AllHandlesBuffer == NULL || NumAllHandles == 0) {\r
+ return FALSE;\r
+ }\r
+\r
+ Protocol = UseComp1 ? gEfiComponentNameProtocolGuid : gEfiComponentName2ProtocolGuid;\r
+\r
+ //\r
+ // Find all EFI_HANDLES with protocol\r
+ //\r
+ Status = gBS->LocateHandleBuffer(\r
+ ByProtocol,\r
+ &Protocol,\r
+ NULL,\r
+ &NumProtocolHandles,\r
+ &ProtocolHandlesBuffer\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ return FALSE;\r
+ }\r
+\r
+\r
+ //\r
+ // Exit early if no supported devices\r
+ //\r
+ if (NumProtocolHandles == 0) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Get printable name by iterating through all protocols\r
+ // using the handle as the child, and iterate through all handles for the controller\r
+ // exit loop early once found, if not found, then delete device\r
+ // storage security protocol instances already exist, add them to internal list\r
+ //\r
+ Status = EFI_DEVICE_ERROR;\r
+ for (Index1 = 0; Index1 < NumProtocolHandles; Index1++) {\r
+ DevName = NULL;\r
+\r
+ if (Dev->Name16 != NULL) {\r
+ return TRUE;\r
+ }\r
+\r
+ TmpHandle = ProtocolHandlesBuffer[Index1];\r
+\r
+ Status = gBS->OpenProtocol(\r
+ TmpHandle,\r
+ &Protocol,\r
+ (VOID**)&Cnp1_2,\r
+ gImageHandle,\r
+ NULL,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR(Status) || Cnp1_2 == NULL) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Use all handles array as controller handle\r
+ //\r
+ for (Index2 = 0; Index2 < NumAllHandles; Index2++) {\r
+ Status = Cnp1_2->GetControllerName(\r
+ Cnp1_2,\r
+ AllHandlesBuffer[Index2],\r
+ Dev->Handle,\r
+ LANGUAGE_ISO_639_2_ENGLISH,\r
+ &DevName\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ Status = Cnp1_2->GetControllerName(\r
+ Cnp1_2,\r
+ AllHandlesBuffer[Index2],\r
+ Dev->Handle,\r
+ LANGUAGE_RFC_3066_ENGLISH,\r
+ &DevName\r
+ );\r
+ }\r
+ if (!EFI_ERROR(Status) && DevName != NULL) {\r
+ StrLength = StrLen(DevName) + 1; // Add one for NULL terminator\r
+ Dev->Name16 = AllocateZeroPool(StrLength * sizeof (CHAR16));\r
+ ASSERT (Dev->Name16 != NULL);\r
+ StrCpyS (Dev->Name16, StrLength, DevName);\r
+ Dev->NameZ = (CHAR8*)AllocateZeroPool(StrLength);\r
+ UnicodeStrToAsciiStrS (DevName, Dev->NameZ, StrLength);\r
+\r
+ //\r
+ // Retrieve bridge BDF info and port number or namespace depending on type\r
+ //\r
+ TmpDevPath = NULL;\r
+ Status = gBS->OpenProtocol(\r
+ Dev->Handle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID**)&TmpDevPath,\r
+ gImageHandle,\r
+ NULL,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (!EFI_ERROR(Status)) {\r
+ Dev->OpalDevicePath = DuplicateDevicePath (TmpDevPath);\r
+ return TRUE;\r
+ }\r
+\r
+ if (Dev->Name16 != NULL) {\r
+ FreePool(Dev->Name16);\r
+ Dev->Name16 = NULL;\r
+ }\r
+ if (Dev->NameZ != NULL) {\r
+ FreePool(Dev->NameZ);\r
+ Dev->NameZ = NULL;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Get devcie name through the component name protocol.\r
+\r
+ @param[in] Dev The device which need to get name.\r
+\r
+ @retval TRUE Find the name for this device.\r
+ @retval FALSE Not found the name for this device.\r
+**/\r
+BOOLEAN\r
+OpalDriverGetDriverDeviceName(\r
+ OPAL_DRIVER_DEVICE *Dev\r
+ )\r
+{\r
+ EFI_HANDLE* AllHandlesBuffer;\r
+ UINTN NumAllHandles;\r
+ EFI_STATUS Status;\r
+\r
+ if (Dev == NULL) {\r
+ DEBUG((DEBUG_ERROR | DEBUG_INIT, "OpalDriverGetDriverDeviceName Exiting, Dev=NULL\n"));\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Iterate through ComponentName2 handles to get name, if fails, try ComponentName\r
+ //\r
+ if (Dev->Name16 == NULL) {\r
+ DEBUG((DEBUG_ERROR | DEBUG_INIT, "Name is null, update it\n"));\r
+ //\r
+ // Find all EFI_HANDLES\r
+ //\r
+ Status = gBS->LocateHandleBuffer(\r
+ AllHandles,\r
+ NULL,\r
+ NULL,\r
+ &NumAllHandles,\r
+ &AllHandlesBuffer\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((DEBUG_INFO, "LocateHandleBuffer for AllHandles failed %r\n", Status ));\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Try component Name2\r
+ //\r
+ if (!OpalDriverGetDeviceNameByProtocol(AllHandlesBuffer, NumAllHandles, Dev, FALSE)) {\r
+ DEBUG((DEBUG_ERROR | DEBUG_INIT, "ComponentName2 failed to get device name, try ComponentName\n"));\r
+ if (!OpalDriverGetDeviceNameByProtocol(AllHandlesBuffer, NumAllHandles, Dev, TRUE)) {\r
+ DEBUG((DEBUG_ERROR | DEBUG_INIT, "ComponentName failed to get device name, skip device\n"));\r
+ return FALSE;\r
+ }\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Main entry for this driver.\r
+\r
+ @param ImageHandle Image Handle this driver.\r
+ @param SystemTable Pointer to SystemTable.\r
+\r
+ @retval EFI_SUCESS This function always complete successfully.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiDriverEntryPoint(\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE* SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_EVENT ReadyToBootEvent;\r
+ EFI_EVENT EndOfDxeEvent;\r
+\r
+ Status = EfiLibInstallDriverBindingComponentName2 (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gOpalDriverBinding,\r
+ ImageHandle,\r
+ &gOpalComponentName,\r
+ &gOpalComponentName2\r
+ );\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG((DEBUG_ERROR, "Install protocols to Opal driver Handle failed\n"));\r
+ return Status ;\r
+ }\r
+\r
+ //\r
+ // Initialize Driver object\r
+ //\r
+ ZeroMem(&mOpalDriver, sizeof(mOpalDriver));\r
+ mOpalDriver.Handle = ImageHandle;\r
+\r
+ Status = gBS->CreateEventEx (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ OpalEndOfDxeEventNotify,\r
+ NULL,\r
+ &gEfiEndOfDxeEventGroupGuid,\r
+ &EndOfDxeEvent\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // register a ReadyToBoot event callback for sending BlockSid command\r
+ //\r
+ Status = EfiCreateEventReadyToBootEx (\r
+ TPL_CALLBACK,\r
+ ReadyToBootCallback,\r
+ (VOID *) &ImageHandle,\r
+ &ReadyToBootEvent\r
+ );\r
+\r
+ //\r
+ // Install Hii packages.\r
+ //\r
+ HiiInstall();\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Tests to see if this driver supports a given controller.\r
+\r
+ This function checks to see if the controller contains an instance of the\r
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL and the EFI_BLOCK_IO_PROTOCL\r
+ and returns EFI_SUCCESS if it does.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle The Handle of the controller to test. This Handle\r
+ must support a protocol interface that supplies\r
+ an I/O abstraction to the driver.\r
+ @param[in] RemainingDevicePath This parameter is ignored.\r
+\r
+ @retval EFI_SUCCESS The device contains required protocols\r
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
+ RemainingDevicePath is already being managed by the driver\r
+ specified by This.\r
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
+ RemainingDevicePath is already being managed by a different\r
+ driver or an application that requires exclusive access.\r
+ Currently not implemented.\r
+ @retval EFI_UNSUPPORTED The device does not contain requires protocols\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverBindingSupported(\r
+ IN EFI_DRIVER_BINDING_PROTOCOL* This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL* RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL* SecurityCommand;\r
+ EFI_BLOCK_IO_PROTOCOL* BlkIo;\r
+\r
+ if (mOpalEndOfDxe) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Test EFI_STORAGE_SECURITY_COMMAND_PROTOCOL on controller Handle.\r
+ //\r
+ Status = gBS->OpenProtocol(\r
+ Controller,\r
+ &gEfiStorageSecurityCommandProtocolGuid,\r
+ ( VOID ** )&SecurityCommand,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+\r
+ if (Status == EFI_ALREADY_STARTED) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Close protocol and reopen in Start call\r
+ //\r
+ gBS->CloseProtocol(\r
+ Controller,\r
+ &gEfiStorageSecurityCommandProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ //\r
+ // Test EFI_BLOCK_IO_PROTOCOL on controller Handle, required by EFI_STORAGE_SECURITY_COMMAND_PROTOCOL\r
+ // function APIs\r
+ //\r
+ Status = gBS->OpenProtocol(\r
+ Controller,\r
+ &gEfiBlockIoProtocolGuid,\r
+ (VOID **)&BlkIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG((DEBUG_INFO, "No EFI_BLOCK_IO_PROTOCOL on controller\n"));\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Close protocol and reopen in Start call\r
+ //\r
+ gBS->CloseProtocol(\r
+ Controller,\r
+ &gEfiBlockIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Enables Opal Management on a supported device if available.\r
+\r
+ The start function is designed to be called after the Opal UEFI Driver has confirmed the\r
+ "controller", which is a child Handle, contains the EF_STORAGE_SECURITY_COMMAND protocols.\r
+ This function will complete the other necessary checks, such as verifying the device supports\r
+ the correct version of Opal. Upon verification, it will add the device to the\r
+ Opal HII list in order to expose Opal managmeent options.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle The Handle of the controller to start. This Handle\r
+ must support a protocol interface that supplies\r
+ an I/O abstraction to the driver.\r
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
+ parameter is ignored by device drivers, and is optional for bus\r
+ drivers. For a bus driver, if this parameter is NULL, then handles\r
+ for all the children of Controller are created by this driver.\r
+ If this parameter is not NULL and the first Device Path Node is\r
+ not the End of Device Path Node, then only the Handle for the\r
+ child device specified by the first Device Path Node of\r
+ RemainingDevicePath is created by this driver.\r
+ If the first Device Path Node of RemainingDevicePath is\r
+ the End of Device Path Node, no child Handle is created by this\r
+ driver.\r
+\r
+ @retval EFI_SUCCESS Opal management was enabled.\r
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+ @retval Others The driver failed to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverBindingStart(\r
+ IN EFI_DRIVER_BINDING_PROTOCOL* This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL* RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
+ OPAL_DRIVER_DEVICE *Dev;\r
+ OPAL_DRIVER_DEVICE *Itr;\r
+ BOOLEAN Result;\r
+\r
+ Itr = mOpalDriver.DeviceList;\r
+ while (Itr != NULL) {\r
+ if (Controller == Itr->Handle) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ Itr = Itr->Next;\r
+ }\r
+\r
+ //\r
+ // Create internal device for tracking. This allows all disks to be tracked\r
+ // by same HII form\r
+ //\r
+ Dev = (OPAL_DRIVER_DEVICE*)AllocateZeroPool(sizeof(OPAL_DRIVER_DEVICE));\r
+ if (Dev == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ Dev->Handle = Controller;\r
+\r
+ //\r
+ // Open EFI_STORAGE_SECURITY_COMMAND_PROTOCOL to perform Opal supported checks\r
+ //\r
+ Status = gBS->OpenProtocol(\r
+ Controller,\r
+ &gEfiStorageSecurityCommandProtocolGuid,\r
+ (VOID **)&Dev->Sscp,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ FreePool(Dev);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Open EFI_BLOCK_IO_PROTOCOL on controller Handle, required by EFI_STORAGE_SECURITY_COMMAND_PROTOCOL\r
+ // function APIs\r
+ //\r
+ Status = gBS->OpenProtocol(\r
+ Controller,\r
+ &gEfiBlockIoProtocolGuid,\r
+ (VOID **)&BlkIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ //\r
+ // Close storage security that was opened\r
+ //\r
+ gBS->CloseProtocol(\r
+ Controller,\r
+ &gEfiStorageSecurityCommandProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ FreePool(Dev);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Save mediaId\r
+ //\r
+ Dev->MediaId = BlkIo->Media->MediaId;\r
+\r
+ gBS->CloseProtocol(\r
+ Controller,\r
+ &gEfiBlockIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ //\r
+ // Acquire Ascii printable name of child, if not found, then ignore device\r
+ //\r
+ Result = OpalDriverGetDriverDeviceName (Dev);\r
+ if (!Result) {\r
+ goto Done;\r
+ }\r
+\r
+ Status = OpalDiskInitialize (Dev);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ AddDeviceToTail(Dev);\r
+\r
+ //\r
+ // Check if device is locked and prompt for password.\r
+ //\r
+ OpalDriverRequestPassword (Dev, L"Unlock:");\r
+\r
+ //\r
+ // Process OPAL request from last boot.\r
+ //\r
+ ProcessOpalRequest (Dev);\r
+\r
+ return EFI_SUCCESS;\r
+\r
+Done:\r
+ //\r
+ // free device, close protocols and exit\r
+ //\r
+ gBS->CloseProtocol(\r
+ Controller,\r
+ &gEfiStorageSecurityCommandProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ FreePool(Dev);\r
+\r
+ return EFI_DEVICE_ERROR;\r
+}\r
+\r
+/**\r
+ Stop this driver on Controller.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to stop driver on\r
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of\r
+ children is zero stop the entire bus driver.\r
+ @param ChildHandleBuffer List of Child Handles to Stop.\r
+\r
+ @retval EFI_SUCCESS This driver is removed Controller.\r
+ @retval other This driver could not be removed from this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverBindingStop(\r
+ EFI_DRIVER_BINDING_PROTOCOL* This,\r
+ EFI_HANDLE Controller,\r
+ UINTN NumberOfChildren,\r
+ EFI_HANDLE* ChildHandleBuffer\r
+ )\r
+{\r
+ OPAL_DRIVER_DEVICE* Itr;\r
+\r
+ Itr = mOpalDriver.DeviceList;\r
+\r
+ //\r
+ // does Controller match any of the devices we are managing for Opal\r
+ //\r
+ while (Itr != NULL) {\r
+ if (Itr->Handle == Controller) {\r
+ OpalDriverStopDevice (Itr);\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Itr = Itr->Next;\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+ Unloads UEFI Driver. Very useful for debugging and testing.\r
+\r
+ @param ImageHandle Image Handle this driver.\r
+\r
+ @retval EFI_SUCCESS This function always complete successfully.\r
+ @retval EFI_INVALID_PARAMETER The input ImageHandle is not valid.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverUnload (\r
+ IN EFI_HANDLE ImageHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ OPAL_DRIVER_DEVICE *Itr;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ if (ImageHandle != gImageHandle) {\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+\r
+ //\r
+ // Uninstall any interface added to each device by us\r
+ //\r
+ while (mOpalDriver.DeviceList) {\r
+ Itr = mOpalDriver.DeviceList;\r
+ //\r
+ // Remove OPAL_DRIVER_DEVICE from the list\r
+ // it updates the controllerList pointer\r
+ //\r
+ OpalDriverStopDevice(Itr);\r
+ }\r
+\r
+ //\r
+ // Uninstall the HII capability\r
+ //\r
+ Status = HiiUninstall();\r
+\r
+ return Status;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+ Values defined and used by the Opal UEFI Driver.\r
+\r
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _OPAL_DRIVER_H_\r
+#define _OPAL_DRIVER_H_\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <IndustryStandard/Pci.h>\r
+\r
+#include <Protocol/PciIo.h>\r
+#include <Protocol/SmmCommunication.h>\r
+#include <Protocol/BlockIo.h>\r
+#include <Protocol/LoadedImage.h>\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/DevicePathToText.h>\r
+#include <Protocol/StorageSecurityCommand.h>\r
+\r
+#include <Guid/EventGroup.h>\r
+\r
+#include <Library/UefiLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/HiiLib.h>\r
+#include <Library/UefiHiiServicesLib.h>\r
+#include <Library/PciLib.h>\r
+#include <Library/S3BootScriptLib.h>\r
+#include <Library/LockBoxLib.h>\r
+#include <Library/TcgStorageOpalLib.h>\r
+#include <Library/Tcg2PhysicalPresenceLib.h>\r
+\r
+#include "OpalPasswordCommon.h"\r
+#include "OpalHiiFormValues.h"\r
+\r
+#define EFI_DRIVER_NAME_UNICODE L"1.0 UEFI Opal Driver"\r
+\r
+// UEFI 2.1\r
+#define LANGUAGE_RFC_3066_ENGLISH ((CHAR8*)"en")\r
+\r
+// UEFI/EFI < 2.1\r
+#define LANGUAGE_ISO_639_2_ENGLISH ((CHAR8*)"eng")\r
+\r
+#define CONCAT_(x, y) x ## y\r
+#define CONCAT(x, y) CONCAT_(x, y)\r
+\r
+#define UNICODE_STR(x) CONCAT( L, x )\r
+\r
+extern EFI_DRIVER_BINDING_PROTOCOL gOpalDriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL gOpalComponentName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL gOpalComponentName2;\r
+\r
+#define OPAL_MSID_LENGHT 128\r
+\r
+#define MAX_PASSWORD_TRY_COUNT 5\r
+\r
+// PSID Length\r
+#define PSID_CHARACTER_LENGTH 0x20\r
+#define MAX_PSID_TRY_COUNT 5\r
+\r
+#pragma pack(1)\r
+\r
+//\r
+// Structure that is used to represent the available actions for an OpalDisk.\r
+// The data can then be utilized to expose/hide certain actions available to an end user\r
+// by the consumer of this library.\r
+//\r
+typedef struct {\r
+ //\r
+ // Indicates if the disk can support PSID Revert action. should verify disk supports PSID authority\r
+ //\r
+ UINT16 PsidRevert : 1;\r
+\r
+ //\r
+ // Indicates if the disk can support Revert action\r
+ //\r
+ UINT16 Revert : 1;\r
+\r
+ //\r
+ // Indicates if the user must keep data for revert action. It is true if no media encryption is supported.\r
+ //\r
+ UINT16 RevertKeepDataForced : 1;\r
+\r
+ //\r
+ // Indicates if the disk can support set Admin password\r
+ //\r
+ UINT16 AdminPass : 1;\r
+\r
+ //\r
+ // Indicates if the disk can support set User password. This action requires that a user\r
+ // password is first enabled.\r
+ //\r
+ UINT16 UserPass : 1;\r
+\r
+ //\r
+ // Indicates if unlock action is available. Requires disk to be currently locked.\r
+ //\r
+ UINT16 Unlock : 1;\r
+\r
+ //\r
+ // Indicates if Secure Erase action is available. Action requires admin credentials and media encryption support.\r
+ //\r
+ UINT16 SecureErase : 1;\r
+\r
+ //\r
+ // Indicates if Disable User action is available. Action requires admin credentials.\r
+ //\r
+ UINT16 DisableUser : 1;\r
+} OPAL_DISK_ACTIONS;\r
+\r
+//\r
+// Structure that is used to represent an OPAL_DISK.\r
+//\r
+typedef struct {\r
+ UINT32 MsidLength; // Byte length of MSID Pin for device\r
+ UINT8 Msid[OPAL_MSID_LENGHT]; // MSID Pin for device\r
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *Sscp;\r
+ UINT32 MediaId; // MediaId is used by Ssc Protocol.\r
+ EFI_DEVICE_PATH_PROTOCOL *OpalDevicePath;\r
+ UINT16 OpalBaseComId; // Opal SSC 1 base com id.\r
+ OPAL_OWNER_SHIP Owner;\r
+ OPAL_DISK_SUPPORT_ATTRIBUTE SupportedAttributes;\r
+ TCG_LOCKING_FEATURE_DESCRIPTOR LockingFeature; // Locking Feature Descriptor retrieved from performing a Level 0 Discovery\r
+ UINT8 PasswordLength;\r
+ UINT8 Password[OPAL_MAX_PASSWORD_SIZE];\r
+} OPAL_DISK;\r
+\r
+//\r
+// Device with block IO protocol\r
+//\r
+typedef struct _OPAL_DRIVER_DEVICE OPAL_DRIVER_DEVICE;\r
+\r
+struct _OPAL_DRIVER_DEVICE {\r
+ OPAL_DRIVER_DEVICE *Next; ///< Linked list pointer\r
+ EFI_HANDLE Handle; ///< Device handle\r
+ OPAL_DISK OpalDisk; ///< User context\r
+ CHAR16 *Name16; ///< Allocated/freed by UEFI Filter Driver at device creation/removal\r
+ CHAR8 *NameZ; ///< Allocated/freed by UEFI Filter Driver at device creation/removal\r
+ UINT32 MediaId; ///< Required parameter for EFI_STORAGE_SECURITY_COMMAND_PROTOCOL, from BLOCK_IO_MEDIA\r
+\r
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *Sscp; /// Device protocols consumed\r
+ EFI_DEVICE_PATH_PROTOCOL *OpalDevicePath;\r
+};\r
+\r
+//\r
+// Opal Driver UEFI Driver Model\r
+//\r
+typedef struct {\r
+ EFI_HANDLE Handle; ///< Driver image handle\r
+ OPAL_DRIVER_DEVICE *DeviceList; ///< Linked list of controllers owned by this Driver\r
+} OPAL_DRIVER;\r
+\r
+#pragma pack()\r
+\r
+//\r
+// Retrieves a OPAL_DRIVER_DEVICE based on the pointer to its StorageSecurity protocol.\r
+//\r
+#define DRIVER_DEVICE_FROM_OPALDISK(OpalDiskPointer) (OPAL_DRIVER_DEVICE*)(BASE_CR(OpalDiskPointer, OPAL_DRIVER_DEVICE, OpalDisk))\r
+\r
+/**\r
+ Get devcie list info.\r
+\r
+ @retval return the device list pointer.\r
+**/\r
+OPAL_DRIVER_DEVICE*\r
+OpalDriverGetDeviceList(\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Get devcie name through the component name protocol.\r
+\r
+ @param[in] Dev The device which need to get name.\r
+\r
+ @retval TRUE Find the name for this device.\r
+ @retval FALSE Not found the name for this device.\r
+**/\r
+BOOLEAN\r
+OpalDriverGetDriverDeviceName(\r
+ OPAL_DRIVER_DEVICE *Dev\r
+ );\r
+\r
+/**\r
+ Get current device count.\r
+\r
+ @retval return the current created device count.\r
+\r
+**/\r
+UINT8\r
+GetDeviceCount (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Update password for the Opal disk.\r
+\r
+ @param[in, out] OpalDisk The disk to update password.\r
+ @param[in] Password The input password.\r
+ @param[in] PasswordLength The input password length.\r
+\r
+**/\r
+VOID\r
+OpalSupportUpdatePassword (\r
+ IN OUT OPAL_DISK *OpalDisk,\r
+ IN VOID *Password,\r
+ IN UINT32 PasswordLength\r
+ );\r
+\r
+/**\r
+\r
+ The function performs determines the available actions for the OPAL_DISK provided.\r
+\r
+ @param[in] SupportedAttributes The support attribute for the device.\r
+ @param[in] LockingFeature The locking status for the device.\r
+ @param[in] OwnerShip The ownership for the device.\r
+ @param[out] AvalDiskActions Pointer to fill-out with appropriate disk actions.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportGetAvailableActions(\r
+ IN OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes,\r
+ IN TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature,\r
+ IN UINT16 OwnerShip,\r
+ OUT OPAL_DISK_ACTIONS *AvalDiskActions\r
+ );\r
+\r
+/**\r
+ Enable Opal Feature for the input device.\r
+\r
+ @param[in] Session The opal session for the opal device.\r
+ @param[in] Msid Msid\r
+ @param[in] MsidLength Msid Length\r
+ @param[in] Password Admin password\r
+ @param[in] PassLength Length of password in bytes \r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportEnableOpalFeature (\r
+ IN OPAL_SESSION *Session,\r
+ IN VOID *Msid,\r
+ IN UINT32 MsidLength,\r
+ IN VOID *Password,\r
+ IN UINT32 PassLength\r
+ );\r
+\r
+/**\r
+ Unloads UEFI Driver. Very useful for debugging and testing.\r
+\r
+ @param ImageHandle Image handle this driver.\r
+\r
+ @retval EFI_SUCCESS This function always complete successfully.\r
+ @retval EFI_INVALID_PARAMETER The input ImageHandle is not valid.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiDriverUnload(\r
+ EFI_HANDLE ImageHandle\r
+ );\r
+\r
+\r
+/**\r
+ Test to see if this driver supports Controller.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param ControllerHandle Handle of device to test\r
+ @param RemainingDevicePath Optional parameter use to pick a specific child\r
+ device to start.\r
+\r
+ @retval EFI_SUCCESS This driver supports this device.\r
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.\r
+ @retval other This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverBindingSupported(\r
+ EFI_DRIVER_BINDING_PROTOCOL* This,\r
+ EFI_HANDLE Controller,\r
+ EFI_DEVICE_PATH_PROTOCOL* RemainingDevicePath\r
+ );\r
+\r
+/**\r
+ Enables Opal Management on a supported device if available.\r
+\r
+ The start function is designed to be called after the Opal UEFI Driver has confirmed the\r
+ "controller", which is a child handle, contains the EF_STORAGE_SECURITY_COMMAND protocols.\r
+ This function will complete the other necessary checks, such as verifying the device supports\r
+ the correct version of Opal. Upon verification, it will add the device to the\r
+ Opal HII list in order to expose Opal managmeent options.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle The handle of the controller to start. This handle\r
+ must support a protocol interface that supplies\r
+ an I/O abstraction to the driver.\r
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
+ parameter is ignored by device drivers, and is optional for bus\r
+ drivers. For a bus driver, if this parameter is NULL, then handles\r
+ for all the children of Controller are created by this driver.\r
+ If this parameter is not NULL and the first Device Path Node is\r
+ not the End of Device Path Node, then only the handle for the\r
+ child device specified by the first Device Path Node of\r
+ RemainingDevicePath is created by this driver.\r
+ If the first Device Path Node of RemainingDevicePath is\r
+ the End of Device Path Node, no child handle is created by this\r
+ driver.\r
+\r
+ @retval EFI_SUCCESS Opal management was enabled.\r
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+ @retval Others The driver failed to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverBindingStart(\r
+ EFI_DRIVER_BINDING_PROTOCOL* This,\r
+ EFI_HANDLE Controller,\r
+ EFI_DEVICE_PATH_PROTOCOL* RemainingDevicePath\r
+ );\r
+\r
+/**\r
+ Stop this driver on Controller.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to stop driver on\r
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of\r
+ children is zero stop the entire bus driver.\r
+ @param ChildHandleBuffer List of Child Handles to Stop.\r
+\r
+ @retval EFI_SUCCESS This driver is removed Controller.\r
+ @retval other This driver could not be removed from this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverBindingStop(\r
+ EFI_DRIVER_BINDING_PROTOCOL* This,\r
+ EFI_HANDLE Controller,\r
+ UINTN NumberOfChildren,\r
+ EFI_HANDLE* ChildHandleBuffer\r
+ );\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param DriverName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverComponentNameGetDriverName(\r
+ EFI_COMPONENT_NAME_PROTOCOL* This,\r
+ CHAR8* Language,\r
+ CHAR16** DriverName\r
+ );\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param ControllerHandle[in] The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param ChildHandle[in] The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param ControllerName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverComponentNameGetControllerName(\r
+ EFI_COMPONENT_NAME_PROTOCOL* This,\r
+ EFI_HANDLE ControllerHandle,\r
+ EFI_HANDLE ChildHandle,\r
+ CHAR8* Language,\r
+ CHAR16** ControllerName\r
+ );\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param DriverName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverComponentName2GetDriverName(\r
+ EFI_COMPONENT_NAME2_PROTOCOL* This,\r
+ CHAR8* Language,\r
+ CHAR16** DriverName\r
+ );\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param ControllerHandle[in] The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param ChildHandle[in] The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param ControllerName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalEfiDriverComponentName2GetControllerName(\r
+ EFI_COMPONENT_NAME2_PROTOCOL* This,\r
+ EFI_HANDLE ControllerHandle,\r
+ EFI_HANDLE ChildHandle,\r
+ CHAR8* Language,\r
+ CHAR16** ControllerName\r
+ );\r
+\r
+#endif //_OPAL_DRIVER_H_\r
--- /dev/null
+/** @file\r
+ Implementation of the HII for the Opal UEFI Driver.\r
+\r
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "OpalHii.h"\r
+\r
+//\r
+// This is the generated IFR binary Data for each formset defined in VFR.\r
+// This Data array is ready to be used as input of HiiAddPackages() to\r
+// create a packagelist (which contains Form packages, String packages, etc).\r
+//\r
+extern UINT8 OpalPasswordFormBin[];\r
+\r
+//\r
+// This is the generated String package Data for all .UNI files.\r
+// This Data array is ready to be used as input of HiiAddPackages() to\r
+// create a packagelist (which contains Form packages, String packages, etc).\r
+//\r
+extern UINT8 OpalPasswordDxeStrings[];\r
+\r
+CHAR16 OpalPasswordStorageName[] = L"OpalHiiConfig";\r
+\r
+EFI_HII_CONFIG_ACCESS_PROTOCOL gHiiConfigAccessProtocol;\r
+\r
+//\r
+// Handle to the list of HII packages (forms and strings) for this driver\r
+//\r
+EFI_HII_HANDLE gHiiPackageListHandle = NULL;\r
+\r
+//\r
+// Package List GUID containing all form and string packages\r
+//\r
+const EFI_GUID gHiiPackageListGuid = PACKAGE_LIST_GUID;\r
+const EFI_GUID gHiiSetupVariableGuid = SETUP_VARIABLE_GUID;\r
+\r
+//\r
+// Structure that contains state of the HII\r
+// This structure is updated by Hii.cpp and its contents\r
+// is rendered in the HII.\r
+//\r
+OPAL_HII_CONFIGURATION gHiiConfiguration;\r
+\r
+//\r
+// The device path containing the VENDOR_DEVICE_PATH and EFI_DEVICE_PATH_PROTOCOL\r
+//\r
+HII_VENDOR_DEVICE_PATH gHiiVendorDevicePath = {\r
+ {\r
+ {\r
+ HARDWARE_DEVICE_PATH,\r
+ HW_VENDOR_DP,\r
+ {\r
+ (UINT8)(sizeof(VENDOR_DEVICE_PATH)),\r
+ (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8)\r
+ }\r
+ },\r
+ OPAL_PASSWORD_CONFIG_GUID\r
+ },\r
+ {\r
+ END_DEVICE_PATH_TYPE,\r
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+ {\r
+ (UINT8)(END_DEVICE_PATH_LENGTH),\r
+ (UINT8)((END_DEVICE_PATH_LENGTH) >> 8)\r
+ }\r
+ }\r
+};\r
+\r
+/**\r
+ Get saved OPAL request.\r
+\r
+ @param[in] OpalDisk The disk needs to get the saved OPAL request.\r
+ @param[out] OpalRequest OPAL request got.\r
+\r
+**/\r
+VOID\r
+GetSavedOpalRequest (\r
+ IN OPAL_DISK *OpalDisk,\r
+ OUT OPAL_REQUEST *OpalRequest\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ OPAL_REQUEST_VARIABLE *TempVariable;\r
+ OPAL_REQUEST_VARIABLE *Variable;\r
+ UINTN VariableSize;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInVariable;\r
+ UINTN DevicePathSizeInVariable;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ UINTN DevicePathSize;\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
+\r
+ Variable = NULL;\r
+ VariableSize = 0;\r
+\r
+ Status = GetVariable2 (\r
+ OPAL_REQUEST_VARIABLE_NAME,\r
+ &gHiiSetupVariableGuid,\r
+ (VOID **) &Variable,\r
+ &VariableSize\r
+ );\r
+ if (EFI_ERROR (Status) || (Variable == NULL)) {\r
+ return;\r
+ }\r
+\r
+ TempVariable = Variable;\r
+ while ((VariableSize > sizeof (OPAL_REQUEST_VARIABLE)) &&\r
+ (VariableSize >= TempVariable->Length) &&\r
+ (TempVariable->Length > sizeof (OPAL_REQUEST_VARIABLE))) {\r
+ DevicePathInVariable = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) TempVariable + sizeof (OPAL_REQUEST_VARIABLE));\r
+ DevicePathSizeInVariable = GetDevicePathSize (DevicePathInVariable);\r
+ DevicePath = OpalDisk->OpalDevicePath;\r
+ DevicePathSize = GetDevicePathSize (DevicePath);\r
+ if ((DevicePathSize == DevicePathSizeInVariable) &&\r
+ (CompareMem (DevicePath, DevicePathInVariable, DevicePathSize) == 0)) {\r
+ //\r
+ // Found the node for the OPAL device.\r
+ // Get the OPAL request.\r
+ //\r
+ CopyMem (OpalRequest, &TempVariable->OpalRequest, sizeof (OPAL_REQUEST));\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "OpalRequest got: 0x%x\n",\r
+ *OpalRequest\r
+ ));\r
+ break;\r
+ }\r
+ VariableSize -= TempVariable->Length;\r
+ TempVariable = (OPAL_REQUEST_VARIABLE *) ((UINTN) TempVariable + TempVariable->Length);\r
+ }\r
+\r
+ FreePool (Variable);\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
+}\r
+\r
+/**\r
+ Save OPAL request.\r
+\r
+ @param[in] OpalDisk The disk has OPAL request to save.\r
+ @param[in] OpalRequest OPAL request to save.\r
+\r
+**/\r
+VOID\r
+SaveOpalRequest (\r
+ IN OPAL_DISK *OpalDisk,\r
+ IN OPAL_REQUEST OpalRequest\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ OPAL_REQUEST_VARIABLE *TempVariable;\r
+ UINTN TempVariableSize;\r
+ OPAL_REQUEST_VARIABLE *Variable;\r
+ UINTN VariableSize;\r
+ OPAL_REQUEST_VARIABLE *NewVariable;\r
+ UINTN NewVariableSize;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInVariable;\r
+ UINTN DevicePathSizeInVariable;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ UINTN DevicePathSize;\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "OpalRequest to save: 0x%x\n",\r
+ OpalRequest\r
+ ));\r
+\r
+ Variable = NULL;\r
+ VariableSize = 0;\r
+ NewVariable = NULL;\r
+ NewVariableSize = 0;\r
+\r
+ Status = GetVariable2 (\r
+ OPAL_REQUEST_VARIABLE_NAME,\r
+ &gHiiSetupVariableGuid,\r
+ (VOID **) &Variable,\r
+ &VariableSize\r
+ );\r
+ if (!EFI_ERROR (Status) && (Variable != NULL)) {\r
+ TempVariable = Variable;\r
+ TempVariableSize = VariableSize;\r
+ while ((TempVariableSize > sizeof (OPAL_REQUEST_VARIABLE)) &&\r
+ (TempVariableSize >= TempVariable->Length) &&\r
+ (TempVariable->Length > sizeof (OPAL_REQUEST_VARIABLE))) {\r
+ DevicePathInVariable = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) TempVariable + sizeof (OPAL_REQUEST_VARIABLE));\r
+ DevicePathSizeInVariable = GetDevicePathSize (DevicePathInVariable);\r
+ DevicePath = OpalDisk->OpalDevicePath;\r
+ DevicePathSize = GetDevicePathSize (DevicePath);\r
+ if ((DevicePathSize == DevicePathSizeInVariable) &&\r
+ (CompareMem (DevicePath, DevicePathInVariable, DevicePathSize) == 0)) {\r
+ //\r
+ // Found the node for the OPAL device.\r
+ // Update the OPAL request.\r
+ //\r
+ CopyMem (&TempVariable->OpalRequest, &OpalRequest, sizeof (OPAL_REQUEST));\r
+ NewVariable = Variable;\r
+ NewVariableSize = VariableSize;\r
+ break;\r
+ }\r
+ TempVariableSize -= TempVariable->Length;\r
+ TempVariable = (OPAL_REQUEST_VARIABLE *) ((UINTN) TempVariable + TempVariable->Length);\r
+ }\r
+ if (NewVariable == NULL) {\r
+ //\r
+ // The node for the OPAL device is not found.\r
+ // Create node for the OPAL device.\r
+ //\r
+ DevicePath = OpalDisk->OpalDevicePath;\r
+ DevicePathSize = GetDevicePathSize (DevicePath);\r
+ NewVariableSize = VariableSize + sizeof (OPAL_REQUEST_VARIABLE) + DevicePathSize;\r
+ NewVariable = AllocatePool (NewVariableSize);\r
+ ASSERT (NewVariable != NULL);\r
+ CopyMem (NewVariable, Variable, VariableSize);\r
+ TempVariable = (OPAL_REQUEST_VARIABLE *) ((UINTN) NewVariable + VariableSize);\r
+ TempVariable->Length = (UINT32) (sizeof (OPAL_REQUEST_VARIABLE) + DevicePathSize);\r
+ CopyMem (&TempVariable->OpalRequest, &OpalRequest, sizeof (OPAL_REQUEST));\r
+ DevicePathInVariable = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) TempVariable + sizeof (OPAL_REQUEST_VARIABLE));\r
+ CopyMem (DevicePathInVariable, DevicePath, DevicePathSize);\r
+ }\r
+ } else {\r
+ DevicePath = OpalDisk->OpalDevicePath;\r
+ DevicePathSize = GetDevicePathSize (DevicePath);\r
+ NewVariableSize = sizeof (OPAL_REQUEST_VARIABLE) + DevicePathSize;\r
+ NewVariable = AllocatePool (NewVariableSize);\r
+ ASSERT (NewVariable != NULL);\r
+ NewVariable->Length = (UINT32) (sizeof (OPAL_REQUEST_VARIABLE) + DevicePathSize);\r
+ CopyMem (&NewVariable->OpalRequest, &OpalRequest, sizeof (OPAL_REQUEST));\r
+ DevicePathInVariable = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) NewVariable + sizeof (OPAL_REQUEST_VARIABLE));\r
+ CopyMem (DevicePathInVariable, DevicePath, DevicePathSize);\r
+ }\r
+ Status = gRT->SetVariable (\r
+ OPAL_REQUEST_VARIABLE_NAME,\r
+ (EFI_GUID *) &gHiiSetupVariableGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+ NewVariableSize,\r
+ NewVariable\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_INFO, "OpalRequest variable set failed (%r)\n", Status));\r
+ }\r
+ if (NewVariable != Variable) {\r
+ FreePool (NewVariable);\r
+ }\r
+ if (Variable != NULL) {\r
+ FreePool (Variable);\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
+}\r
+\r
+/**\r
+ Sets the current system state of global config variables.\r
+\r
+**/\r
+VOID\r
+HiiSetCurrentConfiguration(\r
+ VOID\r
+ )\r
+{\r
+ UINT32 PpStorageFlag;\r
+ EFI_STRING NewString;\r
+\r
+ gHiiConfiguration.NumDisks = GetDeviceCount();\r
+\r
+ //\r
+ // Update the BlockSID status string.\r
+ //\r
+ PpStorageFlag = Tcg2PhysicalPresenceLibGetManagementFlags ();\r
+\r
+ if ((PpStorageFlag & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID) != 0) {\r
+ NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_ENABLED), NULL);\r
+ if (NewString == NULL) {\r
+ DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( ) failed\n"));\r
+ return;\r
+ }\r
+ } else {\r
+ NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_DISABLED), NULL);\r
+ if (NewString == NULL) {\r
+ DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( ) failed\n"));\r
+ return;\r
+ }\r
+ }\r
+ HiiSetString(gHiiPackageListHandle, STRING_TOKEN(STR_BLOCKSID_STATUS1), NewString, NULL);\r
+ FreePool (NewString);\r
+\r
+ if ((PpStorageFlag & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_ENABLE_BLOCK_SID) != 0) {\r
+ NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_TRUE), NULL);\r
+ if (NewString == NULL) {\r
+ DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( ) failed\n"));\r
+ return;\r
+ }\r
+ } else {\r
+ NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_FALSE), NULL);\r
+ if (NewString == NULL) {\r
+ DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( ) failed\n"));\r
+ return;\r
+ }\r
+ }\r
+ HiiSetString(gHiiPackageListHandle, STRING_TOKEN(STR_BLOCKSID_STATUS2), NewString, NULL);\r
+ FreePool (NewString);\r
+\r
+ if ((PpStorageFlag & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_DISABLE_BLOCK_SID) != 0) {\r
+ NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_DISK_INFO_DISABLE_BLOCKSID_TRUE), NULL);\r
+ if (NewString == NULL) {\r
+ DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( ) failed\n"));\r
+ return;\r
+ }\r
+ } else {\r
+ NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_DISK_INFO_DISABLE_BLOCKSID_FALSE), NULL);\r
+ if (NewString == NULL) {\r
+ DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( ) failed\n"));\r
+ return;\r
+ }\r
+ }\r
+ HiiSetString(gHiiPackageListHandle, STRING_TOKEN(STR_BLOCKSID_STATUS3), NewString, NULL);\r
+ FreePool (NewString);\r
+}\r
+\r
+/**\r
+ Install the HII related resources.\r
+\r
+ @retval EFI_SUCCESS Install all the resources success.\r
+ @retval other Error occur when install the resources.\r
+**/\r
+EFI_STATUS\r
+HiiInstall(\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE DriverHandle;\r
+\r
+ //\r
+ // Clear the global configuration.\r
+ //\r
+ ZeroMem(&gHiiConfiguration, sizeof(gHiiConfiguration));\r
+\r
+ //\r
+ // Obtain the driver handle that the BIOS assigned us\r
+ //\r
+ DriverHandle = HiiGetDriverImageHandleCB();\r
+\r
+ //\r
+ // Populate the config access protocol with the three functions we are publishing\r
+ //\r
+ gHiiConfigAccessProtocol.ExtractConfig = ExtractConfig;\r
+ gHiiConfigAccessProtocol.RouteConfig = RouteConfig;\r
+ gHiiConfigAccessProtocol.Callback = DriverCallback;\r
+\r
+ //\r
+ // Associate the required protocols with our driver handle\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces(\r
+ &DriverHandle,\r
+ &gEfiHiiConfigAccessProtocolGuid,\r
+ &gHiiConfigAccessProtocol, // HII callback\r
+ &gEfiDevicePathProtocolGuid,\r
+ &gHiiVendorDevicePath, // required for HII callback allow all disks to be shown in same hii\r
+ NULL\r
+ );\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return OpalHiiAddPackages();\r
+}\r
+\r
+/**\r
+ Install the HII form and string packages.\r
+\r
+ @retval EFI_SUCCESS Install all the resources success.\r
+ @retval EFI_OUT_OF_RESOURCES Out of resource error.\r
+**/\r
+EFI_STATUS\r
+OpalHiiAddPackages(\r
+ VOID\r
+ )\r
+{\r
+ EFI_HANDLE DriverHandle;\r
+ CHAR16 *NewString;\r
+\r
+ DriverHandle = HiiGetDriverImageHandleCB();\r
+\r
+ //\r
+ // Publish the HII form and HII string packages\r
+ //\r
+ gHiiPackageListHandle = HiiAddPackages(\r
+ &gHiiPackageListGuid,\r
+ DriverHandle,\r
+ OpalPasswordDxeStrings,\r
+ OpalPasswordFormBin,\r
+ (VOID*)NULL\r
+ );\r
+\r
+ //\r
+ // Make sure the packages installed successfully\r
+ //\r
+ if (gHiiPackageListHandle == NULL) {\r
+ DEBUG ((DEBUG_INFO, "OpalHiiAddPackages failed\n"));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Update Version String in main window\r
+ //\r
+ NewString = HiiGetDriverNameCB ();\r
+ if (HiiSetString(gHiiPackageListHandle, STRING_TOKEN(STR_MAIN_OPAL_VERSION), NewString, NULL) == 0) {\r
+ DEBUG ((DEBUG_INFO, "OpalHiiAddPackages: HiiSetString( ) failed\n"));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Uninstall the HII capability.\r
+\r
+ @retval EFI_SUCCESS Uninstall all the resources success.\r
+ @retval others Other errors occur when unistall the hii resource.\r
+**/\r
+EFI_STATUS\r
+HiiUninstall(\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Remove the packages we've provided to the BIOS\r
+ //\r
+ HiiRemovePackages(gHiiPackageListHandle);\r
+\r
+ //\r
+ // Remove the protocols from our driver handle\r
+ //\r
+ Status = gBS->UninstallMultipleProtocolInterfaces(\r
+ HiiGetDriverImageHandleCB(),\r
+ &gEfiHiiConfigAccessProtocolGuid,\r
+ &gHiiConfigAccessProtocol, // HII callback\r
+ &gEfiDevicePathProtocolGuid,\r
+ &gHiiVendorDevicePath, // required for HII callback\r
+ NULL\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((DEBUG_INFO, "Cannot uninstall Hii Protocols: %r\n", Status));\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Updates the main menu form.\r
+\r
+ @retval EFI_SUCCESS update the main form success.\r
+**/\r
+EFI_STATUS\r
+HiiPopulateMainMenuForm (\r
+ VOID\r
+ )\r
+{\r
+ UINT8 Index;\r
+ CHAR8 *DiskName;\r
+ EFI_STRING_ID DiskNameId;\r
+ OPAL_DISK *OpalDisk;\r
+\r
+ HiiSetCurrentConfiguration();\r
+\r
+ gHiiConfiguration.SupportedDisks = 0;\r
+\r
+ for (Index = 0; Index < gHiiConfiguration.NumDisks; Index++) {\r
+ OpalDisk = HiiGetOpalDiskCB (Index);\r
+ if ((OpalDisk != NULL) && OpalFeatureSupported (&OpalDisk->SupportedAttributes)) {\r
+ gHiiConfiguration.SupportedDisks |= (1 << Index);\r
+ DiskNameId = GetDiskNameStringId (Index);\r
+ DiskName = HiiDiskGetNameCB (Index);\r
+ if ((DiskName == NULL) || (DiskNameId == 0)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ HiiSetFormString(DiskNameId, DiskName);\r
+ }\r
+ }\r
+\r
+ OpalHiiSetBrowserData ();\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Get disk name string id.\r
+\r
+ @param DiskIndex The input disk index info.\r
+\r
+ @retval The disk name string id.\r
+\r
+**/\r
+EFI_STRING_ID\r
+GetDiskNameStringId(\r
+ UINT8 DiskIndex\r
+ )\r
+{\r
+ switch (DiskIndex) {\r
+ case 0: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_0);\r
+ case 1: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_1);\r
+ case 2: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_2);\r
+ case 3: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_3);\r
+ case 4: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_4);\r
+ case 5: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_5);\r
+ }\r
+ return 0;\r
+}\r
+\r
+/**\r
+ This function processes the results of changes in configuration.\r
+\r
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+ @param Action Specifies the type of action taken by the browser.\r
+ @param QuestionId A unique value which is sent to the original\r
+ exporting driver so that it can identify the type\r
+ of data to expect.\r
+ @param Type The type of value for the question.\r
+ @param Value A pointer to the data being sent to the original\r
+ exporting driver.\r
+ @param ActionRequest On return, points to the action requested by the\r
+ callback function.\r
+\r
+ @retval EFI_SUCCESS The callback successfully handled the action.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the\r
+ variable and its data.\r
+ @retval EFI_DEVICE_ERROR The variable could not be saved.\r
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the\r
+ callback.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DriverCallback(\r
+ CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
+ EFI_BROWSER_ACTION Action,\r
+ EFI_QUESTION_ID QuestionId,\r
+ UINT8 Type,\r
+ EFI_IFR_TYPE_VALUE *Value,\r
+ EFI_BROWSER_ACTION_REQUEST *ActionRequest\r
+ )\r
+{\r
+ HII_KEY HiiKey;\r
+ UINT8 HiiKeyId;\r
+ UINT32 PpRequest;\r
+ OPAL_DISK *OpalDisk;\r
+\r
+ if (ActionRequest != NULL) {\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // If QuestionId is an auto-generated key (label, empty line, etc.), ignore it.\r
+ //\r
+ if ((QuestionId & HII_KEY_FLAG) == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ HiiKey.Raw = QuestionId;\r
+ HiiKeyId = (UINT8) HiiKey.KeyBits.Id;\r
+\r
+ if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {\r
+ switch (HiiKeyId) {\r
+ case HII_KEY_ID_VAR_SUPPORTED_DISKS:\r
+ DEBUG ((DEBUG_INFO, "HII_KEY_ID_VAR_SUPPORTED_DISKS\n"));\r
+ return HiiPopulateMainMenuForm ();\r
+\r
+ case HII_KEY_ID_VAR_SELECTED_DISK_AVAILABLE_ACTIONS:\r
+ DEBUG ((DEBUG_INFO, "HII_KEY_ID_VAR_SELECTED_DISK_AVAILABLE_ACTIONS\n"));\r
+ return HiiPopulateDiskInfoForm();\r
+ }\r
+ } else if (Action == EFI_BROWSER_ACTION_CHANGING) {\r
+ switch (HiiKeyId) {\r
+ case HII_KEY_ID_GOTO_DISK_INFO:\r
+ return HiiSelectDisk((UINT8)HiiKey.KeyBits.Index);\r
+ }\r
+ } else if (Action == EFI_BROWSER_ACTION_CHANGED) {\r
+ switch (HiiKeyId) {\r
+ case HII_KEY_ID_BLOCKSID:\r
+ switch (Value->u8) {\r
+ case 0:\r
+ PpRequest = TCG2_PHYSICAL_PRESENCE_NO_ACTION;\r
+ break;\r
+\r
+ case 1:\r
+ PpRequest = TCG2_PHYSICAL_PRESENCE_ENABLE_BLOCK_SID;\r
+ break;\r
+\r
+ case 2:\r
+ PpRequest = TCG2_PHYSICAL_PRESENCE_DISABLE_BLOCK_SID;\r
+ break;\r
+\r
+ case 3:\r
+ PpRequest = TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_TRUE;\r
+ break;\r
+\r
+ case 4:\r
+ PpRequest = TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_FALSE;\r
+ break;\r
+\r
+ case 5:\r
+ PpRequest = TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_TRUE;\r
+ break;\r
+\r
+ case 6:\r
+ PpRequest = TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_FALSE;\r
+ break;\r
+\r
+ default:\r
+ PpRequest = TCG2_PHYSICAL_PRESENCE_NO_ACTION;\r
+ DEBUG ((DEBUG_ERROR, "Invalid value input!\n"));\r
+ break;\r
+ }\r
+ HiiSetBlockSidAction(PpRequest);\r
+\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
+ return EFI_SUCCESS;\r
+\r
+ case HII_KEY_ID_SET_ADMIN_PWD:\r
+ DEBUG ((DEBUG_INFO, "HII_KEY_ID_SET_ADMIN_PWD\n"));\r
+ gHiiConfiguration.OpalRequest.SetAdminPwd = Value->b;\r
+ OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);\r
+ if (OpalDisk != NULL) {\r
+ SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);\r
+ }\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
+ return EFI_SUCCESS;\r
+\r
+ case HII_KEY_ID_SET_USER_PWD:\r
+ DEBUG ((DEBUG_INFO, "HII_KEY_ID_SET_USER_PWD\n"));\r
+ gHiiConfiguration.OpalRequest.SetUserPwd = Value->b;\r
+ OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);\r
+ if (OpalDisk != NULL) {\r
+ SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);\r
+ }\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
+ return EFI_SUCCESS;\r
+\r
+ case HII_KEY_ID_SECURE_ERASE:\r
+ DEBUG ((DEBUG_INFO, "HII_KEY_ID_SECURE_ERASE\n"));\r
+ gHiiConfiguration.OpalRequest.SecureErase = Value->b;\r
+ OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);\r
+ if (OpalDisk != NULL) {\r
+ SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);\r
+ }\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
+ return EFI_SUCCESS;\r
+ \r
+ case HII_KEY_ID_REVERT:\r
+ DEBUG ((DEBUG_INFO, "HII_KEY_ID_REVERT\n"));\r
+ gHiiConfiguration.OpalRequest.Revert = Value->b;\r
+ OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);\r
+ if (OpalDisk != NULL) {\r
+ SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);\r
+ }\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
+ return EFI_SUCCESS;\r
+ case HII_KEY_ID_KEEP_USER_DATA:\r
+ DEBUG ((DEBUG_INFO, "HII_KEY_ID_KEEP_USER_DATA\n"));\r
+ gHiiConfiguration.OpalRequest.KeepUserData = Value->b;\r
+ OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);\r
+ if (OpalDisk != NULL) {\r
+ SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);\r
+ }\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
+ return EFI_SUCCESS;\r
+\r
+ case HII_KEY_ID_PSID_REVERT:\r
+ DEBUG ((DEBUG_INFO, "HII_KEY_ID_PSID_REVERT\n"));\r
+ gHiiConfiguration.OpalRequest.PsidRevert = Value->b;\r
+ OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);\r
+ if (OpalDisk != NULL) {\r
+ SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);\r
+ }\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
+ return EFI_SUCCESS;\r
+\r
+ case HII_KEY_ID_DISABLE_USER:\r
+ DEBUG ((DEBUG_INFO, "HII_KEY_ID_DISABLE_USER\n"));\r
+ gHiiConfiguration.OpalRequest.DisableUser = Value->b;\r
+ OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);\r
+ if (OpalDisk != NULL) {\r
+ SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);\r
+ }\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
+ return EFI_SUCCESS;\r
+\r
+ case HII_KEY_ID_ENABLE_FEATURE:\r
+ DEBUG ((DEBUG_INFO, "HII_KEY_ID_ENABLE_FEATURE\n"));\r
+ gHiiConfiguration.OpalRequest.EnableFeature = Value->b;\r
+ OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);\r
+ if (OpalDisk != NULL) {\r
+ SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest);\r
+ }\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
+ return EFI_SUCCESS;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ Update the global Disk index info.\r
+\r
+ @param Index The input disk index info.\r
+\r
+ @retval EFI_SUCCESS Update the disk index info success.\r
+\r
+**/\r
+EFI_STATUS\r
+HiiSelectDisk(\r
+ UINT8 Index\r
+ )\r
+{\r
+ OpalHiiGetBrowserData();\r
+ gHiiConfiguration.SelectedDiskIndex = Index;\r
+ OpalHiiSetBrowserData ();\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Draws the disk info form.\r
+\r
+ @retval EFI_SUCCESS Draw the disk info success.\r
+\r
+**/\r
+EFI_STATUS\r
+HiiPopulateDiskInfoForm(\r
+ VOID\r
+ )\r
+{\r
+ OPAL_DISK* OpalDisk;\r
+ OPAL_DISK_ACTIONS AvailActions;\r
+ TCG_RESULT Ret;\r
+ CHAR8 *DiskName;\r
+\r
+ OpalHiiGetBrowserData();\r
+\r
+ DiskName = HiiDiskGetNameCB (gHiiConfiguration.SelectedDiskIndex);\r
+ if (DiskName == NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ HiiSetFormString(STRING_TOKEN(STR_DISK_INFO_SELECTED_DISK_NAME), DiskName);\r
+\r
+ gHiiConfiguration.SelectedDiskAvailableActions = HII_ACTION_NONE;\r
+ ZeroMem (&gHiiConfiguration.OpalRequest, sizeof (OPAL_REQUEST));\r
+ gHiiConfiguration.KeepUserDataForced = FALSE;\r
+\r
+ OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);\r
+\r
+ if (OpalDisk != NULL) {\r
+ OpalDiskUpdateStatus (OpalDisk);\r
+ Ret = OpalSupportGetAvailableActions(&OpalDisk->SupportedAttributes, &OpalDisk->LockingFeature, OpalDisk->Owner, &AvailActions);\r
+ if (Ret == TcgResultSuccess) {\r
+ //\r
+ // Update actions, always allow PSID Revert\r
+ //\r
+ gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.PsidRevert == 1) ? HII_ACTION_PSID_REVERT : HII_ACTION_NONE;\r
+\r
+ //\r
+ // Always allow unlock to handle device migration\r
+ //\r
+ gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.Unlock == 1) ? HII_ACTION_UNLOCK : HII_ACTION_NONE;\r
+\r
+ if (!OpalFeatureEnabled (&OpalDisk->SupportedAttributes, &OpalDisk->LockingFeature)) {\r
+ if (OpalDisk->Owner == OpalOwnershipNobody) {\r
+ gHiiConfiguration.SelectedDiskAvailableActions |= HII_ACTION_ENABLE_FEATURE;\r
+\r
+ //\r
+ // Update strings\r
+ //\r
+ HiiSetFormString( STRING_TOKEN(STR_DISK_INFO_PSID_REVERT), "PSID Revert to factory default");\r
+ } else {\r
+ DEBUG ((DEBUG_INFO, "Feature disabled but ownership != nobody\n"));\r
+ }\r
+ } else {\r
+ gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.Revert == 1) ? HII_ACTION_REVERT : HII_ACTION_NONE;\r
+ gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.AdminPass == 1) ? HII_ACTION_SET_ADMIN_PWD : HII_ACTION_NONE;\r
+ gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.UserPass == 1) ? HII_ACTION_SET_USER_PWD : HII_ACTION_NONE;\r
+ gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.SecureErase == 1) ? HII_ACTION_SECURE_ERASE : HII_ACTION_NONE;\r
+ gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.DisableUser == 1) ? HII_ACTION_DISABLE_USER : HII_ACTION_NONE;\r
+\r
+ HiiSetFormString (STRING_TOKEN(STR_DISK_INFO_PSID_REVERT), "PSID Revert to factory default and Disable");\r
+\r
+ //\r
+ // Determine revert options for disk\r
+ // Default initialize keep user Data to be true\r
+ //\r
+ gHiiConfiguration.OpalRequest.KeepUserData = 1;\r
+ if (AvailActions.RevertKeepDataForced) {\r
+ gHiiConfiguration.KeepUserDataForced = TRUE;\r
+ }\r
+ }\r
+ }\r
+\r
+ GetSavedOpalRequest (OpalDisk, &gHiiConfiguration.OpalRequest);\r
+ }\r
+\r
+ //\r
+ // Pass the current configuration to the BIOS\r
+ //\r
+ OpalHiiSetBrowserData ();\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Send BlockSid request through TPM physical presence module.\r
+\r
+ @param PpRequest TPM physical presence operation request.\r
+\r
+ @retval EFI_SUCCESS Do the required action success.\r
+ @retval Others Other error occur.\r
+\r
+**/\r
+EFI_STATUS\r
+HiiSetBlockSidAction (\r
+ IN UINT32 PpRequest\r
+ )\r
+{\r
+ UINT32 ReturnCode;\r
+ EFI_STATUS Status;\r
+\r
+ ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (PpRequest, 0);\r
+ if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS) {\r
+ Status = EFI_SUCCESS;\r
+ } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED) {\r
+ Status = EFI_UNSUPPORTED;\r
+ } else {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ This function processes the results of changes in configuration.\r
+\r
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+ @param Configuration A null-terminated Unicode string in <ConfigResp>\r
+ format.\r
+ @param Progress A pointer to a string filled in with the offset of\r
+ the most recent '&' before the first failing\r
+ name/value pair (or the beginning of the string if\r
+ the failure is in the first name/value pair) or\r
+ the terminating NULL if all was successful.\r
+\r
+ @retval EFI_SUCCESS The Results is processed successfully.\r
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.\r
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this\r
+ driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RouteConfig(\r
+ CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
+ CONST EFI_STRING Configuration,\r
+ EFI_STRING *Progress\r
+ )\r
+{\r
+ if (Configuration == NULL || Progress == NULL) {\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+\r
+ *Progress = Configuration;\r
+ if (!HiiIsConfigHdrMatch (Configuration, &gHiiSetupVariableGuid, OpalPasswordStorageName)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ *Progress = Configuration + StrLen (Configuration);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function allows a caller to extract the current configuration for one\r
+ or more named elements from the target driver.\r
+\r
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+ @param Request A null-terminated Unicode string in\r
+ <ConfigRequest> format.\r
+ @param Progress On return, points to a character in the Request\r
+ string. Points to the string's null terminator if\r
+ request was successful. Points to the most recent\r
+ '&' before the first failing name/value pair (or\r
+ the beginning of the string if the failure is in\r
+ the first name/value pair) if the request was not\r
+ successful.\r
+ @param Results A null-terminated Unicode string in\r
+ <ConfigAltResp> format which has all values filled\r
+ in for the names in the Request string. String to\r
+ be allocated by the called function.\r
+\r
+ @retval EFI_SUCCESS The Results is filled with the requested values.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.\r
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.\r
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this\r
+ driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ExtractConfig(\r
+ CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
+ CONST EFI_STRING Request,\r
+ EFI_STRING *Progress,\r
+ EFI_STRING *Results\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_STRING ConfigRequest;\r
+ EFI_STRING ConfigRequestHdr;\r
+ UINTN BufferSize;\r
+ UINTN Size;\r
+ BOOLEAN AllocatedRequest;\r
+ EFI_HANDLE DriverHandle;\r
+\r
+ //\r
+ // Check for valid parameters\r
+ //\r
+ if (Progress == NULL || Results == NULL) {\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+\r
+ *Progress = Request;\r
+ if ((Request != NULL) &&\r
+ !HiiIsConfigHdrMatch (Request, &gHiiSetupVariableGuid, OpalPasswordStorageName)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ AllocatedRequest = FALSE;\r
+ BufferSize = sizeof (OPAL_HII_CONFIGURATION);\r
+ ConfigRequest = Request;\r
+ if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {\r
+ //\r
+ // Request has no request element, construct full request string.\r
+ // Allocate and fill a buffer large enough to hold the <ConfigHdr> template\r
+ // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator\r
+ //\r
+ DriverHandle = HiiGetDriverImageHandleCB();\r
+ ConfigRequestHdr = HiiConstructConfigHdr (&gHiiSetupVariableGuid, OpalPasswordStorageName, DriverHandle);\r
+ Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);\r
+ ConfigRequest = AllocateZeroPool (Size);\r
+ if (ConfigRequest == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ AllocatedRequest = TRUE;\r
+ UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);\r
+ FreePool (ConfigRequestHdr);\r
+ }\r
+\r
+ //\r
+ // Convert Buffer Data to <ConfigResp> by helper function BlockToConfig( )\r
+ //\r
+ Status = gHiiConfigRouting->BlockToConfig(\r
+ gHiiConfigRouting,\r
+ ConfigRequest,\r
+ (UINT8*)&gHiiConfiguration,\r
+ sizeof(OPAL_HII_CONFIGURATION),\r
+ Results,\r
+ Progress\r
+ );\r
+\r
+ //\r
+ // Free the allocated config request string.\r
+ //\r
+ if (AllocatedRequest) {\r
+ FreePool (ConfigRequest);\r
+ ConfigRequest = NULL;\r
+ }\r
+\r
+ //\r
+ // Set Progress string to the original request string.\r
+ //\r
+ if (Request == NULL) {\r
+ *Progress = NULL;\r
+ } else if (StrStr (Request, L"OFFSET") == NULL) {\r
+ *Progress = Request + StrLen (Request);\r
+ }\r
+\r
+ return (Status);\r
+}\r
+\r
+\r
+/**\r
+\r
+ Pass the current system state to the bios via the hii_G_Configuration.\r
+\r
+**/\r
+VOID\r
+OpalHiiSetBrowserData (\r
+ VOID\r
+ )\r
+{\r
+ HiiSetBrowserData(\r
+ &gHiiSetupVariableGuid,\r
+ (CHAR16*)L"OpalHiiConfig",\r
+ sizeof(gHiiConfiguration),\r
+ (UINT8*)&gHiiConfiguration,\r
+ NULL\r
+ );\r
+}\r
+\r
+\r
+/**\r
+\r
+ Populate the hii_g_Configuraton with the browser Data.\r
+\r
+**/\r
+VOID\r
+OpalHiiGetBrowserData (\r
+ VOID\r
+ )\r
+{\r
+ HiiGetBrowserData(\r
+ &gHiiSetupVariableGuid,\r
+ (CHAR16*)L"OpalHiiConfig",\r
+ sizeof(gHiiConfiguration),\r
+ (UINT8*)&gHiiConfiguration\r
+ );\r
+}\r
+\r
+/**\r
+ Set a string Value in a form.\r
+\r
+ @param DestStringId The stringid which need to update.\r
+ @param SrcAsciiStr The string nned to update.\r
+\r
+ @retval EFI_SUCCESS Do the required action success.\r
+ @retval Others Other error occur.\r
+\r
+**/\r
+EFI_STATUS\r
+HiiSetFormString(\r
+ EFI_STRING_ID DestStringId,\r
+ CHAR8 *SrcAsciiStr\r
+ )\r
+{\r
+ UINT32 Len;\r
+ UINT32 UniSize;\r
+ CHAR16* UniStr;\r
+\r
+ //\r
+ // Determine the Length of the sting\r
+ //\r
+ Len = ( UINT32 )AsciiStrLen( SrcAsciiStr );\r
+\r
+ //\r
+ // Allocate space for the unicode string, including terminator\r
+ //\r
+ UniSize = (Len + 1) * sizeof(CHAR16);\r
+ UniStr = (CHAR16*)AllocateZeroPool(UniSize);\r
+\r
+ //\r
+ // Copy into unicode string, then copy into string id\r
+ //\r
+ AsciiStrToUnicodeStrS ( SrcAsciiStr, UniStr, Len + 1);\r
+\r
+ //\r
+ // Update the string in the form\r
+ //\r
+ if (HiiSetString(gHiiPackageListHandle, DestStringId, UniStr, NULL) == 0) {\r
+ DEBUG ((DEBUG_INFO, "HiiSetFormString( ) failed\n"));\r
+ FreePool(UniStr);\r
+ return (EFI_OUT_OF_RESOURCES);\r
+ }\r
+\r
+ //\r
+ // Free the memory\r
+ //\r
+ FreePool(UniStr);\r
+\r
+ return (EFI_SUCCESS);\r
+}\r
+\r
+/**\r
+ Initialize the Opal disk base on the hardware info get from device.\r
+\r
+ @param Dev The Opal device.\r
+\r
+ @retval EFI_SUCESS Initialize the device success.\r
+ @retval EFI_DEVICE_ERROR Get info from device failed.\r
+\r
+**/\r
+EFI_STATUS\r
+OpalDiskInitialize (\r
+ IN OPAL_DRIVER_DEVICE *Dev\r
+ )\r
+{\r
+ TCG_RESULT TcgResult;\r
+ OPAL_SESSION Session;\r
+\r
+ ZeroMem(&Dev->OpalDisk, sizeof(OPAL_DISK));\r
+ Dev->OpalDisk.Sscp = Dev->Sscp;\r
+ Dev->OpalDisk.MediaId = Dev->MediaId;\r
+ Dev->OpalDisk.OpalDevicePath = Dev->OpalDevicePath;\r
+\r
+ ZeroMem(&Session, sizeof(Session));\r
+ Session.Sscp = Dev->Sscp;\r
+ Session.MediaId = Dev->MediaId;\r
+\r
+ TcgResult = OpalGetSupportedAttributesInfo (&Session, &Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.OpalBaseComId);\r
+ if (TcgResult != TcgResultSuccess) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;\r
+\r
+ TcgResult = OpalUtilGetMsid (&Session, Dev->OpalDisk.Msid, OPAL_MSID_LENGHT, &Dev->OpalDisk.MsidLength);\r
+ if (TcgResult != TcgResultSuccess) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return OpalDiskUpdateStatus (&Dev->OpalDisk);\r
+}\r
+\r
+/**\r
+ Update the device info.\r
+\r
+ @param OpalDisk The Opal device.\r
+\r
+ @retval EFI_SUCESS Initialize the device success.\r
+ @retval EFI_DEVICE_ERROR Get info from device failed.\r
+ @retval EFI_INVALID_PARAMETER Not get Msid info before get ownership info.\r
+\r
+**/\r
+EFI_STATUS\r
+OpalDiskUpdateStatus (\r
+ OPAL_DISK *OpalDisk\r
+ )\r
+{\r
+ TCG_RESULT TcgResult;\r
+ OPAL_SESSION Session;\r
+\r
+ ZeroMem(&Session, sizeof(Session));\r
+ Session.Sscp = OpalDisk->Sscp;\r
+ Session.MediaId = OpalDisk->MediaId;\r
+ Session.OpalBaseComId = OpalDisk->OpalBaseComId;\r
+\r
+ TcgResult = OpalGetLockingInfo(&Session, &OpalDisk->LockingFeature);\r
+ if (TcgResult != TcgResultSuccess) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (OpalDisk->MsidLength == 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ } else {\r
+ //\r
+ // Base on the Msid info to get the ownership, so Msid info must get first.\r
+ //\r
+ OpalDisk->Owner = OpalUtilDetermineOwnership(&Session, OpalDisk->Msid, OpalDisk->MsidLength);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+ Public Header file of HII library used by Opal UEFI Driver.\r
+ Defines required callbacks of Opal HII library.\r
+\r
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _OPAL_HII_H_\r
+#define _OPAL_HII_H_\r
+\r
+#include <Protocol/HiiConfigAccess.h>\r
+\r
+#include "OpalDriver.h"\r
+#include "OpalHiiFormValues.h"\r
+\r
+#define OPAL_PASSWORD_CONFIG_GUID \\r
+ { \\r
+ 0x0d510a4f, 0xa81b, 0x473f, { 0x87, 0x07, 0xb7, 0xfd, 0xfb, 0xc0, 0x45, 0xba } \\r
+ }\r
+\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+ UINT16 Id: HII_KEY_ID_BITS;\r
+ UINT16 Index: HII_KEY_INDEX_BITS;\r
+ UINT16 Flag: HII_KEY_FLAG_BITS;\r
+} KEY_BITS;\r
+\r
+typedef union {\r
+ UINT16 Raw;\r
+ KEY_BITS KeyBits;\r
+} HII_KEY;\r
+\r
+typedef struct {\r
+ VENDOR_DEVICE_PATH VendorDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL End;\r
+} HII_VENDOR_DEVICE_PATH;\r
+\r
+#pragma pack()\r
+\r
+extern const EFI_GUID gHiiSetupVariableGuid;\r
+\r
+/**\r
+ This function processes the results of changes in configuration.\r
+\r
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+ @param Configuration A null-terminated Unicode string in <ConfigResp>\r
+ format.\r
+ @param Progress A pointer to a string filled in with the offset of\r
+ the most recent '&' before the first failing\r
+ name/value pair (or the beginning of the string if\r
+ the failure is in the first name/value pair) or\r
+ the terminating NULL if all was successful.\r
+\r
+ @retval EFI_SUCCESS The Results is processed successfully.\r
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.\r
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this\r
+ driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RouteConfig(\r
+ CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
+ CONST EFI_STRING Configuration,\r
+ EFI_STRING *Progress\r
+ );\r
+\r
+/**\r
+ This function allows a caller to extract the current configuration for one\r
+ or more named elements from the target driver.\r
+\r
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+ @param Request A null-terminated Unicode string in\r
+ <ConfigRequest> format.\r
+ @param Progress On return, points to a character in the Request\r
+ string. Points to the string's null terminator if\r
+ request was successful. Points to the most recent\r
+ '&' before the first failing name/value pair (or\r
+ the beginning of the string if the failure is in\r
+ the first name/value pair) if the request was not\r
+ successful.\r
+ @param Results A null-terminated Unicode string in\r
+ <ConfigAltResp> format which has all values filled\r
+ in for the names in the Request string. String to\r
+ be allocated by the called function.\r
+\r
+ @retval EFI_SUCCESS The Results is filled with the requested values.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.\r
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.\r
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this\r
+ driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ExtractConfig(\r
+ CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
+ CONST EFI_STRING Request,\r
+ EFI_STRING *Progress,\r
+ EFI_STRING *Results\r
+ );\r
+\r
+/**\r
+ This function processes the results of changes in configuration.\r
+\r
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+ @param Action Specifies the type of action taken by the browser.\r
+ @param QuestionId A unique value which is sent to the original\r
+ exporting driver so that it can identify the type\r
+ of data to expect.\r
+ @param Type The type of value for the question.\r
+ @param Value A pointer to the data being sent to the original\r
+ exporting driver.\r
+ @param ActionRequest On return, points to the action requested by the\r
+ callback function.\r
+\r
+ @retval EFI_SUCCESS The callback successfully handled the action.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the\r
+ variable and its data.\r
+ @retval EFI_DEVICE_ERROR The variable could not be saved.\r
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the\r
+ callback.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DriverCallback(\r
+ CONST EFI_HII_CONFIG_ACCESS_PROTOCOL* This,\r
+ EFI_BROWSER_ACTION Action,\r
+ EFI_QUESTION_ID QuestionId,\r
+ UINT8 Type,\r
+ EFI_IFR_TYPE_VALUE* Value,\r
+ EFI_BROWSER_ACTION_REQUEST* ActionRequest\r
+ );\r
+\r
+/**\r
+\r
+ Pass the current system state to the bios via the hii_G_Configuration.\r
+\r
+**/\r
+VOID\r
+OpalHiiSetBrowserData (\r
+ VOID\r
+ );\r
+\r
+/**\r
+\r
+ Populate the hii_g_Configuraton with the browser Data.\r
+\r
+**/\r
+VOID\r
+OpalHiiGetBrowserData (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Draws the disk info form.\r
+\r
+ @retval EFI_SUCCESS Draw the disk info success.\r
+\r
+**/\r
+EFI_STATUS\r
+HiiPopulateDiskInfoForm(\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Update the global Disk index info.\r
+\r
+ @param Index The input disk index info.\r
+\r
+ @retval EFI_SUCCESS Update the disk index info success.\r
+\r
+**/\r
+EFI_STATUS\r
+HiiSelectDisk(\r
+ UINT8 Index\r
+ );\r
+\r
+/**\r
+ Use the input password to do the specified action.\r
+\r
+ @param Str The input password saved in.\r
+\r
+ @retval EFI_SUCCESS Do the required action success.\r
+ @retval Others Other error occur.\r
+\r
+**/\r
+EFI_STATUS\r
+HiiPasswordEntered(\r
+ EFI_STRING_ID Str\r
+ );\r
+\r
+/**\r
+ Update block sid info.\r
+\r
+ @param PpRequest Input the Pp Request.\r
+\r
+ @retval EFI_SUCCESS Do the required action success.\r
+ @retval Others Other error occur.\r
+\r
+**/\r
+EFI_STATUS\r
+HiiSetBlockSidAction (\r
+ UINT32 PpRequest\r
+ );\r
+\r
+/**\r
+ Reverts the Opal disk to factory default.\r
+\r
+ @param PsidStringId The string id for the PSID info.\r
+\r
+ @retval EFI_SUCCESS Do the required action success.\r
+\r
+**/\r
+EFI_STATUS\r
+HiiPsidRevert(\r
+ EFI_STRING_ID PsidStringId\r
+ );\r
+\r
+/**\r
+ Get disk name string id.\r
+\r
+ @param DiskIndex The input disk index info.\r
+\r
+ @retval The disk name string id.\r
+\r
+**/\r
+EFI_STRING_ID\r
+GetDiskNameStringId(\r
+ UINT8 DiskIndex\r
+ );\r
+\r
+/**\r
+ Update the device info.\r
+\r
+ @param OpalDisk The Opal device.\r
+\r
+ @retval EFI_SUCESS Initialize the device success.\r
+ @retval EFI_DEVICE_ERROR Get info from device failed.\r
+ @retval EFI_INVALID_PARAMETER Not get Msid info before get ownership info.\r
+\r
+**/\r
+EFI_STATUS\r
+OpalDiskUpdateStatus (\r
+ OPAL_DISK *OpalDisk\r
+ );\r
+\r
+/**\r
+ Get the driver image handle.\r
+\r
+ @retval the driver image handle.\r
+\r
+**/\r
+EFI_HANDLE\r
+HiiGetDriverImageHandleCB(\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Install the HII form and string packages.\r
+\r
+ @retval EFI_SUCCESS Install all the resources success.\r
+ @retval EFI_OUT_OF_RESOURCES Out of resource error.\r
+**/\r
+EFI_STATUS\r
+OpalHiiAddPackages(\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Check whether enable feature or not.\r
+\r
+ @retval Return the disk number.\r
+\r
+**/\r
+UINT8\r
+HiiGetNumConfigRequiredOpalDisksCB(\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Returns the driver name.\r
+\r
+ @retval Returns the driver name.\r
+\r
+**/\r
+CHAR16*\r
+HiiGetDriverNameCB(\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Returns the opaque pointer to a physical disk context.\r
+\r
+ @param DiskIndex Input the disk index.\r
+\r
+ @retval The device pointer.\r
+\r
+**/\r
+OPAL_DISK*\r
+HiiGetOpalDiskCB(\r
+ UINT8 DiskIndex\r
+ );\r
+\r
+/**\r
+ Returns the disk name.\r
+\r
+ @param DiskIndex Input the disk index.\r
+\r
+ @retval Returns the disk name.\r
+\r
+**/\r
+CHAR8*\r
+HiiDiskGetNameCB(\r
+ UINT8 DiskIndex\r
+ );\r
+\r
+/**\r
+ Set a string Value in a form.\r
+\r
+ @param DestStringId The stringid which need to update.\r
+ @param SrcAsciiStr The string nned to update.\r
+\r
+ @retval EFI_SUCCESS Do the required action success.\r
+ @retval Others Other error occur.\r
+\r
+**/\r
+EFI_STATUS\r
+HiiSetFormString(\r
+ EFI_STRING_ID DestStringId,\r
+ CHAR8 *SrcAsciiStr\r
+ );\r
+\r
+/**\r
+ Install the HII related resources.\r
+\r
+ @retval EFI_SUCCESS Install all the resources success.\r
+ @retval other Error occur when install the resources.\r
+**/\r
+EFI_STATUS\r
+HiiInstall(\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Uninstall the HII capability.\r
+\r
+ @retval EFI_SUCCESS Uninstall all the resources success.\r
+ @retval others Other errors occur when unistall the hii resource.\r
+**/\r
+EFI_STATUS\r
+HiiUninstall(\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Initialize the Opal disk base on the hardware info get from device.\r
+\r
+ @param Dev The Opal device.\r
+\r
+ @retval EFI_SUCESS Initialize the device success.\r
+ @retval EFI_DEVICE_ERROR Get info from device failed.\r
+\r
+**/\r
+EFI_STATUS\r
+OpalDiskInitialize (\r
+ IN OPAL_DRIVER_DEVICE *Dev\r
+ );\r
+\r
+#endif // _HII_H_\r
--- /dev/null
+/** @file\r
+ Callbacks required by the HII of the Opal UEFI Driver to help display\r
+ Opal device information.\r
+\r
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "OpalHii.h"\r
+\r
+/**\r
+ Get Opal var name.\r
+ The return Value must be freed by caller if not NULL\r
+\r
+ @param OpalDisk The disk.\r
+ @param Prefix The prefix string.\r
+\r
+ @retval The var name string.\r
+\r
+**/\r
+CHAR16*\r
+OpalDriverGetOpalVarName(\r
+ OPAL_DISK *OpalDisk,\r
+ const CHAR16 *Prefix\r
+ )\r
+{\r
+ OPAL_DRIVER_DEVICE* Dev;\r
+ UINTN PrefixLen;\r
+ UINTN NameLen;\r
+ UINTN VarNameLen;\r
+ CHAR16* VarName;\r
+\r
+ Dev = DRIVER_DEVICE_FROM_OPALDISK(OpalDisk);\r
+ if (Dev == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ PrefixLen = StrLen(Prefix);\r
+\r
+ NameLen = 0;\r
+ if (Dev->Name16 != NULL) {\r
+ NameLen = StrLen(Dev->Name16);\r
+ }\r
+\r
+ VarNameLen = PrefixLen + NameLen;\r
+\r
+ VarName = (CHAR16*)AllocateZeroPool((VarNameLen + 1) * sizeof(CHAR16));\r
+ if (VarName == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ CopyMem(VarName, Prefix, PrefixLen * sizeof(CHAR16));\r
+ if (Dev->Name16 != NULL) {\r
+ CopyMem(VarName + PrefixLen, Dev->Name16, NameLen * sizeof(CHAR16));\r
+ }\r
+ VarName[VarNameLen] = 0;\r
+\r
+ return VarName;\r
+}\r
+\r
+/**\r
+ Get the driver image handle.\r
+\r
+ @retval the driver image handle.\r
+\r
+**/\r
+EFI_HANDLE\r
+HiiGetDriverImageHandleCB(\r
+ VOID\r
+ )\r
+{\r
+ return gImageHandle;\r
+}\r
+\r
+/**\r
+ Check whether enable feature or not.\r
+\r
+ @retval Return the disk number.\r
+\r
+**/\r
+UINT8\r
+HiiGetNumConfigRequiredOpalDisksCB(\r
+ VOID\r
+ )\r
+{\r
+ UINT8 NumDisks;\r
+ UINT8 NumLockedOpalDisks;\r
+ OPAL_DISK *OpalDisk;\r
+ UINT8 Index;\r
+\r
+ NumLockedOpalDisks = 0;\r
+\r
+ NumDisks = GetDeviceCount();\r
+\r
+ for (Index = 0; Index < NumDisks; Index++) {\r
+ OpalDisk = HiiGetOpalDiskCB(Index);\r
+\r
+ if (OpalDisk != NULL) {\r
+ if (!OpalFeatureEnabled (&OpalDisk->SupportedAttributes, &OpalDisk->LockingFeature)) {\r
+ DEBUG ((DEBUG_INFO, "Ignoring disk %u because feature is disabled or health has already been inspected\n", Index));\r
+ } else if (OpalDeviceLocked (&OpalDisk->SupportedAttributes, &OpalDisk->LockingFeature)) {\r
+ NumLockedOpalDisks++;\r
+ }\r
+ }\r
+ }\r
+\r
+ return NumLockedOpalDisks;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Returns the opaque pointer to a physical disk context.\r
+\r
+ @param DiskIndex Input the disk index.\r
+\r
+ @retval The device pointer.\r
+\r
+**/\r
+VOID *\r
+HiiGetDiskContextCB(\r
+ UINT8 DiskIndex\r
+ )\r
+{\r
+ OPAL_DRIVER_DEVICE* Dev;\r
+ UINT8 CurrentDisk;\r
+\r
+ Dev = OpalDriverGetDeviceList();\r
+ CurrentDisk = 0;\r
+\r
+ if (DiskIndex >= GetDeviceCount()) {\r
+ return NULL;\r
+ }\r
+\r
+ while (Dev != NULL) {\r
+ if (CurrentDisk == DiskIndex) {\r
+ return Dev;\r
+ } else {\r
+ Dev = Dev->Next;\r
+ CurrentDisk++;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Returns the opaque pointer to a physical disk context.\r
+\r
+ @param DiskIndex Input the disk index.\r
+\r
+ @retval The device pointer.\r
+\r
+**/\r
+OPAL_DISK*\r
+HiiGetOpalDiskCB(\r
+ UINT8 DiskIndex\r
+ )\r
+{\r
+ VOID *Ctx;\r
+ OPAL_DRIVER_DEVICE *Tmp;\r
+\r
+ Ctx = HiiGetDiskContextCB (DiskIndex);\r
+\r
+ if (Ctx == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ Tmp = (OPAL_DRIVER_DEVICE*) Ctx;\r
+\r
+ return &Tmp->OpalDisk;\r
+}\r
+\r
+/**\r
+ Returns the disk name.\r
+\r
+ @param DiskIndex Input the disk index.\r
+\r
+ @retval Returns the disk name.\r
+\r
+**/\r
+CHAR8*\r
+HiiDiskGetNameCB(\r
+ UINT8 DiskIndex\r
+ )\r
+{\r
+ OPAL_DRIVER_DEVICE* Ctx;\r
+\r
+ Ctx = (OPAL_DRIVER_DEVICE*) HiiGetDiskContextCB (DiskIndex);\r
+\r
+ if (Ctx != NULL) {\r
+ if (Ctx->NameZ == NULL) {\r
+ OpalDriverGetDriverDeviceName (Ctx);\r
+ }\r
+ return Ctx->NameZ;\r
+ }\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Returns the driver name.\r
+\r
+ @retval Returns the driver name.\r
+\r
+**/\r
+CHAR16*\r
+HiiGetDriverNameCB(\r
+ VOID\r
+ )\r
+{\r
+ return (CHAR16*)EFI_DRIVER_NAME_UNICODE;\r
+}\r
--- /dev/null
+// /** @file\r
+//\r
+// String definitions for Setup formset.\r
+//\r
+// Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions of the BSD License\r
+// which accompanies this distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+/=#\r
+///////////////////////////////// GENERIC DEFINITIONS /////////////////////////////////\r
+#langdef en-US "English"\r
+#string STR_NULL #language en-US " "\r
+\r
+///////////////////////////////// FORM SET /////////////////////////////////\r
+#string STR_FORM_SET_HELP #language en-US "Manage Opal disks"\r
+\r
+///////////////////////////////// MULTIPLE FORMS /////////////////////////////////\r
+#string STR_OPAL #language en-US "Opal"\r
+#string STR_MAIN_OPAL_VERSION #language en-US "Version 00.0.0.0000"\r
+\r
+///////////////////////////////// MAIN MENU FORM /////////////////////////////////\r
+#string STR_MAIN_PHY_DISKS_LBL #language en-US "Physical Disks:"\r
+\r
+#string STR_MAIN_GOTO_DISK_INFO_0 #language en-US " "\r
+#string STR_MAIN_GOTO_DISK_INFO_1 #language en-US " "\r
+#string STR_MAIN_GOTO_DISK_INFO_2 #language en-US " "\r
+#string STR_MAIN_GOTO_DISK_INFO_3 #language en-US " "\r
+#string STR_MAIN_GOTO_DISK_INFO_4 #language en-US " "\r
+#string STR_MAIN_GOTO_DISK_INFO_5 #language en-US " "\r
+\r
+#string STR_MAIN_GOTO_DISK_INFO_HELP #language en-US "Select to see Opal disk actions"\r
+\r
+#string STR_MAIN_NO_DISKS_PRESENT_LBL #language en-US "No disks connected to system"\r
+#string STR_MAIN_NO_DISKS_PRESENT_LBL_HELP #language en-US "The storage needs to be connected before EndOfDxe"\r
+\r
+///////////////////////////////// DISK INFO MENU FORM /////////////////////////////////\r
+#string STR_DISK_INFO_SELECTED_DISK_NAME #language en-US " "\r
+\r
+#string STR_DISK_INFO_LOCK #language en-US "Lock"\r
+#string STR_DISK_INFO_UNLOCK #language en-US "Unlock"\r
+#string STR_DISK_INFO_SET_ADMIN_PSWD #language en-US "Update Drive Admin Password"\r
+#string STR_DISK_INFO_SET_USER_PSWD #language en-US "Set Drive User Password"\r
+#string STR_DISK_INFO_SECURE_ERASE #language en-US "Secure Erase User Data"\r
+#string STR_DISK_INFO_PSID_REVERT #language en-US "PSID Revert to factory default"\r
+#string STR_DISK_INFO_REVERT #language en-US "Admin Revert to factory default and Disable"\r
+#string STR_DISK_INFO_DISABLE_USER #language en-US "Disable User"\r
+#string STR_DISK_INFO_ENABLE_FEATURE #language en-US "Enable Feature"\r
+#string STR_DISK_INFO_ENABLE_BLOCKSID #language en-US "TCG Storage Action"\r
+#string STR_ENABLED #language en-US "Enable BlockSID"\r
+#string STR_DISABLED #language en-US "Disable BlockSID"\r
+\r
+#string STR_NONE #language en-US "None"\r
+#string STR_DISK_INFO_ENABLE_BLOCKSID_TRUE #language en-US "Require physical presence when remote enable BlockSID"\r
+#string STR_DISK_INFO_ENABLE_BLOCKSID_FALSE #language en-US "Not require physical presence when remote enable BlockSID"\r
+#string STR_DISK_INFO_DISABLE_BLOCKSID_TRUE #language en-US "Require physical presence when remote disable BlockSID"\r
+#string STR_DISK_INFO_DISABLE_BLOCKSID_FALSE #language en-US "Not require physical presence when remote disable BlockSID"\r
+\r
+#string STR_BLOCKSID_STATUS_HELP #language en-US "BlockSID action change status"\r
+#string STR_BLOCKSID_STATUS #language en-US "Current BlockSID Status:"\r
+#string STR_BLOCKSID_STATUS1 #language en-US ""\r
+#string STR_BLOCKSID_STATUS2 #language en-US ""\r
+#string STR_BLOCKSID_STATUS3 #language en-US ""\r
+\r
+#string STR_OPAL_REQUESTS_LBL #language en-US "Opal Password Requests:"\r
+#string STR_DISK_INFO_LOCK_HELP #language en-US "Lock the disk"\r
+#string STR_DISK_INFO_UNLOCK_HELP #language en-US "Unlock the disk"\r
+#string STR_DISK_INFO_SET_ADMIN_PSWD_HELP #language en-US "Set password for the administrator, reset is required for the request to be processed in next boot"\r
+#string STR_DISK_INFO_SET_USER_PSWD_HELP #language en-US "Set password for User 1, reset is required for the request to be processed in next boot"\r
+#string STR_DISK_INFO_SECURE_ERASE_HELP #language en-US "Securely erase the disk, reset is required for the request to be processed in next boot"\r
+#string STR_DISK_INFO_REVERT_HELP #language en-US "Revert the disk to factory defaults, reset is required for the request to be processed in next boot"\r
+#string STR_DISK_INFO_PSID_REVERT_HELP #language en-US "Revert the disk to factory defaults, PSID is a 32 character case sensitive value, reset is required for the request to be processed in next boot"\r
+#string STR_DISK_INFO_DISABLE_USER_HELP #language en-US "Disable User, reset is required for the request to be processed in next boot"\r
+#string STR_DISK_INFO_ENABLE_FEATURE_HELP #language en-US "Enable Feature, reset is required for the request to be processed in next boot"\r
+#string STR_KEEP_USER_DATA_PROMPT #language en-US " Keep User Data"\r
+#string STR_KEEP_USER_DATA_HELP #language en-US "Check to keep user data, otherwise data will be lost"\r
+\r
+#string STR_DISK_INFO_ENABLE_BLOCKSID_HELP #language en-US "Change BlockSID actions, includes enable or disable BlockSID, Require or not require physical presence when remote enable or disable BlockSID"\r
--- /dev/null
+/** @file\r
+ Defines Opal HII form ids, structures and values.\r
+\r
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#ifndef _OPAL_HII_FORM_VALUES_H_\r
+#define _OPAL_HII_FORM_VALUES_H_\r
+\r
+// ID's for various forms that will be used by HII\r
+#define FORMID_VALUE_MAIN_MENU 0x01\r
+#define FORMID_VALUE_DISK_INFO_FORM_MAIN 0x02\r
+\r
+#define OPAL_REQUEST_VARIABLE_NAME L"OpalRequest"\r
+\r
+#pragma pack(1)\r
+typedef struct {\r
+ UINT16 Lock:1;\r
+ UINT16 Unlock:1;\r
+ UINT16 SetAdminPwd:1;\r
+ UINT16 SetUserPwd:1;\r
+ UINT16 SecureErase:1;\r
+ UINT16 Revert:1;\r
+ UINT16 PsidRevert:1;\r
+ UINT16 DisableUser:1;\r
+ UINT16 DisableFeature:1;\r
+ UINT16 EnableFeature:1;\r
+ UINT16 Reserved:5;\r
+ UINT16 KeepUserData:1;\r
+} OPAL_REQUEST;\r
+\r
+typedef struct {\r
+ UINT8 NumDisks;\r
+ UINT8 SelectedDiskIndex;\r
+ UINT16 SelectedDiskAvailableActions;\r
+ UINT16 SupportedDisks;\r
+ BOOLEAN KeepUserDataForced;\r
+ OPAL_REQUEST OpalRequest;\r
+ UINT8 EnableBlockSid;\r
+} OPAL_HII_CONFIGURATION;\r
+\r
+typedef struct {\r
+ UINT32 Length;\r
+ OPAL_REQUEST OpalRequest;\r
+ //EFI_DEVICE_PATH_PROTOCOL OpalDevicePath;\r
+} OPAL_REQUEST_VARIABLE;\r
+\r
+#pragma pack()\r
+\r
+/* Action Flags */\r
+#define HII_ACTION_NONE 0x0000\r
+#define HII_ACTION_LOCK 0x0001\r
+#define HII_ACTION_UNLOCK 0x0002\r
+#define HII_ACTION_SET_ADMIN_PWD 0x0004\r
+#define HII_ACTION_SET_USER_PWD 0x0008\r
+#define HII_ACTION_SECURE_ERASE 0x0010\r
+#define HII_ACTION_REVERT 0x0020\r
+#define HII_ACTION_PSID_REVERT 0x0040\r
+#define HII_ACTION_DISABLE_USER 0x0080\r
+#define HII_ACTION_DISABLE_FEATURE 0x0100\r
+#define HII_ACTION_ENABLE_FEATURE 0x0200\r
+\r
+/* Number of bits allocated for each part of a unique key for an HII_ITEM\r
+ * all bits together must be <= 16 (EFI_QUESTION_ID is UINT16)\r
+ * 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\r
+ * | |-----------------------| |---------------------------|\r
+ * FLG INDEX ID\r
+ */\r
+#define HII_KEY_ID_BITS 8\r
+#define HII_KEY_INDEX_BITS 7\r
+#define HII_KEY_FLAG_BITS 1\r
+\r
+#define HII_KEY_FLAG 0x8000 // bit 15 (zero based)\r
+\r
+/***********/\r
+/* Key IDs */\r
+/***********/\r
+\r
+#define HII_KEY_ID_GOTO_DISK_INFO 1\r
+\r
+#define HII_KEY_ID_VAR_SUPPORTED_DISKS 2\r
+#define HII_KEY_ID_VAR_SELECTED_DISK_AVAILABLE_ACTIONS 3\r
+\r
+#define HII_KEY_ID_BLOCKSID 4\r
+#define HII_KEY_ID_SET_ADMIN_PWD 5\r
+#define HII_KEY_ID_SET_USER_PWD 6\r
+#define HII_KEY_ID_SECURE_ERASE 7\r
+#define HII_KEY_ID_REVERT 8\r
+#define HII_KEY_ID_KEEP_USER_DATA 9\r
+#define HII_KEY_ID_PSID_REVERT 0xA\r
+#define HII_KEY_ID_DISABLE_USER 0xB\r
+#define HII_KEY_ID_ENABLE_FEATURE 0xC\r
+\r
+#define HII_KEY_ID_MAX 0xC // !!Update each time a new ID is added!!\r
+\r
+#define HII_KEY_WITH_INDEX(id, index) \\r
+ ( \\r
+ HII_KEY_FLAG | \\r
+ (id) | \\r
+ ((index) << HII_KEY_ID_BITS) \\r
+ )\r
+\r
+#define HII_KEY(id) HII_KEY_WITH_INDEX(id, 0)\r
+\r
+#define PACKAGE_LIST_GUID { 0xf0308176, 0x9058, 0x4153, { 0x93, 0x3d, 0xda, 0x2f, 0xdc, 0xc8, 0x3e, 0x44 } }\r
+\r
+/* {410483CF-F4F9-4ece-848A-1958FD31CEB7} */\r
+#define SETUP_FORMSET_GUID { 0x410483cf, 0xf4f9, 0x4ece, { 0x84, 0x8a, 0x19, 0x58, 0xfd, 0x31, 0xce, 0xb7 } }\r
+\r
+// {BBF1ACD2-28D8-44ea-A291-58A237FEDF1A}\r
+#define SETUP_VARIABLE_GUID { 0xbbf1acd2, 0x28d8, 0x44ea, { 0xa2, 0x91, 0x58, 0xa2, 0x37, 0xfe, 0xdf, 0x1a } }\r
+\r
+#endif //_HII_FORM_VALUES_H_\r
+\r
--- /dev/null
+/** @file\r
+ Provide functions to initialize NVME controller and perform NVME commands\r
+\r
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "OpalPasswordPei.h"\r
+\r
+\r
+#define ALIGN(v, a) (UINTN)((((v) - 1) | ((a) - 1)) + 1)\r
+\r
+///\r
+/// NVME Host controller registers operation\r
+///\r
+#define NVME_GET_CAP(Nvme, Cap) NvmeMmioRead (Cap, Nvme->Nbar + NVME_CAP_OFFSET, sizeof (NVME_CAP))\r
+#define NVME_GET_CC(Nvme, Cc) NvmeMmioRead (Cc, Nvme->Nbar + NVME_CC_OFFSET, sizeof (NVME_CC))\r
+#define NVME_SET_CC(Nvme, Cc) NvmeMmioWrite (Nvme->Nbar + NVME_CC_OFFSET, Cc, sizeof (NVME_CC))\r
+#define NVME_GET_CSTS(Nvme, Csts) NvmeMmioRead (Csts, Nvme->Nbar + NVME_CSTS_OFFSET, sizeof (NVME_CSTS))\r
+#define NVME_GET_AQA(Nvme, Aqa) NvmeMmioRead (Aqa, Nvme->Nbar + NVME_AQA_OFFSET, sizeof (NVME_AQA))\r
+#define NVME_SET_AQA(Nvme, Aqa) NvmeMmioWrite (Nvme->Nbar + NVME_AQA_OFFSET, Aqa, sizeof (NVME_AQA))\r
+#define NVME_GET_ASQ(Nvme, Asq) NvmeMmioRead (Asq, Nvme->Nbar + NVME_ASQ_OFFSET, sizeof (NVME_ASQ))\r
+#define NVME_SET_ASQ(Nvme, Asq) NvmeMmioWrite (Nvme->Nbar + NVME_ASQ_OFFSET, Asq, sizeof (NVME_ASQ))\r
+#define NVME_GET_ACQ(Nvme, Acq) NvmeMmioRead (Acq, Nvme->Nbar + NVME_ACQ_OFFSET, sizeof (NVME_ACQ))\r
+#define NVME_SET_ACQ(Nvme, Acq) NvmeMmioWrite (Nvme->Nbar + NVME_ACQ_OFFSET, Acq, sizeof (NVME_ACQ))\r
+#define NVME_GET_VER(Nvme, Ver) NvmeMmioRead (Ver, Nvme->Nbar + NVME_VER_OFFSET, sizeof (NVME_VER))\r
+#define NVME_SET_SQTDBL(Nvme, Qid, Sqtdbl) NvmeMmioWrite (Nvme->Nbar + NVME_SQTDBL_OFFSET(Qid, Nvme->Cap.Dstrd), Sqtdbl, sizeof (NVME_SQTDBL))\r
+#define NVME_SET_CQHDBL(Nvme, Qid, Cqhdbl) NvmeMmioWrite (Nvme->Nbar + NVME_CQHDBL_OFFSET(Qid, Nvme->Cap.Dstrd), Cqhdbl, sizeof (NVME_CQHDBL))\r
+\r
+///\r
+/// Base memory address\r
+///\r
+enum {\r
+ BASEMEM_CONTROLLER_DATA,\r
+ BASEMEM_IDENTIFY_DATA,\r
+ BASEMEM_ASQ,\r
+ BASEMEM_ACQ,\r
+ BASEMEM_SQ,\r
+ BASEMEM_CQ,\r
+ BASEMEM_PRP,\r
+ BASEMEM_SECURITY,\r
+ MAX_BASEMEM_COUNT\r
+};\r
+\r
+///\r
+/// All of base memories are 4K(0x1000) alignment\r
+///\r
+#define NVME_MEM_BASE(Nvme) ((UINTN)(Nvme->BaseMem))\r
+#define NVME_CONTROL_DATA_BASE(Nvme) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_CONTROLLER_DATA)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))\r
+#define NVME_NAMESPACE_DATA_BASE(Nvme) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_IDENTIFY_DATA)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))\r
+#define NVME_ASQ_BASE(Nvme) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_ASQ)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))\r
+#define NVME_ACQ_BASE(Nvme) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_ACQ)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))\r
+#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))\r
+#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))\r
+#define NVME_PRP_BASE(Nvme, index) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_PRP) + ((index)*NVME_PRP_SIZE)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))\r
+#define NVME_SEC_BASE(Nvme) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_SECURITY)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))\r
+\r
+/**\r
+ Transfer MMIO Data to memory.\r
+\r
+ @param[in,out] MemBuffer - Destination: Memory address\r
+ @param[in] MmioAddr - Source: MMIO address\r
+ @param[in] Size - Size for read\r
+\r
+ @retval EFI_SUCCESS - MMIO read sucessfully\r
+**/\r
+EFI_STATUS\r
+NvmeMmioRead (\r
+ IN OUT VOID *MemBuffer,\r
+ IN UINTN MmioAddr,\r
+ IN UINTN Size\r
+ )\r
+{\r
+ UINTN Offset;\r
+ UINT8 Data;\r
+ UINT8 *Ptr;\r
+\r
+ // priority has adjusted\r
+ switch (Size) {\r
+ case 4:\r
+ *((UINT32 *)MemBuffer) = MmioRead32 (MmioAddr);\r
+ break;\r
+\r
+ case 8:\r
+ *((UINT64 *)MemBuffer) = MmioRead64 (MmioAddr);\r
+ break;\r
+\r
+ case 2:\r
+ *((UINT16 *)MemBuffer) = MmioRead16 (MmioAddr);\r
+ break;\r
+\r
+ case 1:\r
+ *((UINT8 *)MemBuffer) = MmioRead8 (MmioAddr);\r
+ break;\r
+\r
+ default:\r
+ Ptr = (UINT8 *)MemBuffer;\r
+ for (Offset = 0; Offset < Size; Offset += 1) {\r
+ Data = MmioRead8 (MmioAddr + Offset);\r
+ Ptr[Offset] = Data;\r
+ }\r
+ break;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Transfer memory data to MMIO.\r
+\r
+ @param[in,out] MmioAddr - Destination: MMIO address\r
+ @param[in] MemBuffer - Source: Memory address\r
+ @param[in] Size - Size for write\r
+\r
+ @retval EFI_SUCCESS - MMIO write sucessfully\r
+**/\r
+EFI_STATUS\r
+NvmeMmioWrite (\r
+ IN OUT UINTN MmioAddr,\r
+ IN VOID *MemBuffer,\r
+ IN UINTN Size\r
+ )\r
+{\r
+ UINTN Offset;\r
+ UINT8 Data;\r
+ UINT8 *Ptr;\r
+\r
+ // priority has adjusted\r
+ switch (Size) {\r
+ case 4:\r
+ MmioWrite32 (MmioAddr, *((UINT32 *)MemBuffer));\r
+ break;\r
+\r
+ case 8:\r
+ MmioWrite64 (MmioAddr, *((UINT64 *)MemBuffer));\r
+ break;\r
+\r
+ case 2:\r
+ MmioWrite16 (MmioAddr, *((UINT16 *)MemBuffer));\r
+ break;\r
+\r
+ case 1:\r
+ MmioWrite8 (MmioAddr, *((UINT8 *)MemBuffer));\r
+ break;\r
+\r
+ default:\r
+ Ptr = (UINT8 *)MemBuffer;\r
+ for (Offset = 0; Offset < Size; Offset += 1) {\r
+ Data = Ptr[Offset];\r
+ MmioWrite8 (MmioAddr + Offset, Data);\r
+ }\r
+ break;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Transfer MMIO data to memory.\r
+\r
+ @param[in,out] MemBuffer - Destination: Memory address\r
+ @param[in] MmioAddr - Source: MMIO address\r
+ @param[in] Size - Size for read\r
+\r
+ @retval EFI_SUCCESS - MMIO read sucessfully\r
+**/\r
+EFI_STATUS\r
+OpalPciRead (\r
+ IN OUT VOID *MemBuffer,\r
+ IN UINTN MmioAddr,\r
+ IN UINTN Size\r
+ )\r
+{\r
+ UINTN Offset;\r
+ UINT8 Data;\r
+ UINT8 *Ptr;\r
+\r
+ // priority has adjusted\r
+ switch (Size) {\r
+ case 4:\r
+ *((UINT32 *)MemBuffer) = PciRead32 (MmioAddr);\r
+ break;\r
+\r
+ case 2:\r
+ *((UINT16 *)MemBuffer) = PciRead16 (MmioAddr);\r
+ break;\r
+\r
+ case 1:\r
+ *((UINT8 *)MemBuffer) = PciRead8 (MmioAddr);\r
+ break;\r
+\r
+ default:\r
+ Ptr = (UINT8 *)MemBuffer;\r
+ for (Offset = 0; Offset < Size; Offset += 1) {\r
+ Data = PciRead8 (MmioAddr + Offset);\r
+ Ptr[Offset] = Data;\r
+ }\r
+ break;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Transfer memory data to MMIO.\r
+\r
+ @param[in,out] MmioAddr - Destination: MMIO address\r
+ @param[in] MemBuffer - Source: Memory address\r
+ @param[in] Size - Size for write\r
+\r
+ @retval EFI_SUCCESS - MMIO write sucessfully\r
+**/\r
+EFI_STATUS\r
+OpalPciWrite (\r
+ IN OUT UINTN MmioAddr,\r
+ IN VOID *MemBuffer,\r
+ IN UINTN Size\r
+ )\r
+{\r
+ UINTN Offset;\r
+ UINT8 Data;\r
+ UINT8 *Ptr;\r
+\r
+ // priority has adjusted\r
+ switch (Size) {\r
+ case 4:\r
+ PciWrite32 (MmioAddr, *((UINT32 *)MemBuffer));\r
+ break;\r
+\r
+ case 2:\r
+ PciWrite16 (MmioAddr, *((UINT16 *)MemBuffer));\r
+ break;\r
+\r
+ case 1:\r
+ PciWrite8 (MmioAddr, *((UINT8 *)MemBuffer));\r
+ break;\r
+\r
+ default:\r
+ Ptr = (UINT8 *)MemBuffer;\r
+ for (Offset = 0; Offset < Size; Offset += 1) {\r
+ Data = Ptr[Offset];\r
+ PciWrite8 (MmioAddr + Offset, Data);\r
+ }\r
+ break;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Get total pages for specific NVME based memory.\r
+\r
+ @param[in] BaseMemIndex - The Index of BaseMem (0-based).\r
+\r
+ @retval - The page count for specific BaseMem Index\r
+\r
+**/\r
+UINT32\r
+NvmeGetBaseMemPages (\r
+ IN UINTN BaseMemIndex\r
+ )\r
+{\r
+ UINT32 Pages;\r
+ UINTN Index;\r
+ UINT32 PageSizeList[8];\r
+\r
+ PageSizeList[0] = 1; /* Controller Data */\r
+ PageSizeList[1] = 1; /* Identify Data */\r
+ PageSizeList[2] = 1; /* ASQ */\r
+ PageSizeList[3] = 1; /* ACQ */\r
+ PageSizeList[4] = 1; /* SQs */\r
+ PageSizeList[5] = 1; /* CQs */\r
+ PageSizeList[6] = NVME_PRP_SIZE * NVME_CSQ_DEPTH; /* PRPs */\r
+ PageSizeList[7] = 1; /* Security Commands */\r
+\r
+ if (BaseMemIndex > MAX_BASEMEM_COUNT) {\r
+ ASSERT (FALSE);\r
+ return 0;\r
+ }\r
+\r
+ Pages = 0;\r
+ for (Index = 0; Index < BaseMemIndex; Index++) {\r
+ Pages += PageSizeList[Index];\r
+ }\r
+\r
+ return Pages;\r
+}\r
+\r
+/**\r
+ Wait for NVME controller status to be ready or not.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+ @param[in] WaitReady - Flag for waitting status ready or not\r
+\r
+ @return EFI_SUCCESS - Successfully to wait specific status.\r
+ @return others - Fail to wait for specific controller status.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+NvmeWaitController (\r
+ IN NVME_CONTEXT *Nvme,\r
+ IN BOOLEAN WaitReady\r
+ )\r
+{\r
+ NVME_CSTS Csts;\r
+ EFI_STATUS Status;\r
+ UINT32 Index;\r
+ UINT8 Timeout;\r
+\r
+ //\r
+ // Cap.To specifies max delay time in 500ms increments for Csts.Rdy to set after\r
+ // Cc.Enable. Loop produces a 1 millisecond delay per itteration, up to 500 * Cap.To.\r
+ //\r
+ if (Nvme->Cap.To == 0) {\r
+ Timeout = 1;\r
+ } else {\r
+ Timeout = Nvme->Cap.To;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+ for(Index = (Timeout * 500); Index != 0; --Index) {\r
+ MicroSecondDelay (1000);\r
+\r
+ //\r
+ // Check if the controller is initialized\r
+ //\r
+ Status = NVME_GET_CSTS (Nvme, &Csts);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((DEBUG_ERROR, "NVME_GET_CSTS fail, Status = %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ if ((BOOLEAN) Csts.Rdy == WaitReady) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Index == 0) {\r
+ Status = EFI_TIMEOUT;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Disable the Nvm Express controller.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+\r
+ @return EFI_SUCCESS - Successfully disable the controller.\r
+ @return others - Fail to disable the controller.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+NvmeDisableController (\r
+ IN NVME_CONTEXT *Nvme\r
+ )\r
+{\r
+ NVME_CC Cc;\r
+ NVME_CSTS Csts;\r
+ EFI_STATUS Status;\r
+\r
+ Status = NVME_GET_CSTS (Nvme, &Csts);\r
+\r
+ ///\r
+ /// Read Controller Configuration Register.\r
+ ///\r
+ Status = NVME_GET_CC (Nvme, &Cc);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((DEBUG_ERROR, "NVME_GET_CC fail, Status = %r\n", Status));\r
+ goto Done;\r
+ }\r
+\r
+ if (Cc.En == 1) {\r
+ Cc.En = 0;\r
+ ///\r
+ /// Disable the controller.\r
+ ///\r
+ Status = NVME_SET_CC (Nvme, &Cc);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((DEBUG_ERROR, "NVME_SET_CC fail, Status = %r\n", Status));\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ Status = NvmeWaitController (Nvme, FALSE);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((DEBUG_ERROR, "NvmeWaitController fail, Status = %r\n", Status));\r
+ goto Done;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+Done:\r
+ DEBUG ((DEBUG_INFO, "NvmeDisableController fail, Status: %r\n", Status));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Enable the Nvm Express controller.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+\r
+ @return EFI_SUCCESS - Successfully enable the controller.\r
+ @return EFI_DEVICE_ERROR - Fail to enable the controller.\r
+ @return EFI_TIMEOUT - Fail to enable the controller in given time slot.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+NvmeEnableController (\r
+ IN NVME_CONTEXT *Nvme\r
+ )\r
+{\r
+ NVME_CC Cc;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Enable the controller\r
+ //\r
+ ZeroMem (&Cc, sizeof (NVME_CC));\r
+ Cc.En = 1;\r
+ Cc.Iosqes = 6;\r
+ Cc.Iocqes = 4;\r
+ Status = NVME_SET_CC (Nvme, &Cc);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((DEBUG_ERROR, "NVME_SET_CC fail, Status = %r\n", Status));\r
+ goto Done;\r
+ }\r
+\r
+ Status = NvmeWaitController (Nvme, TRUE);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((DEBUG_ERROR, "NvmeWaitController fail, Status = %r\n", Status));\r
+ goto Done;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+Done:\r
+ DEBUG ((DEBUG_INFO, "NvmeEnableController fail, Status: %r\n", Status));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Shutdown the Nvm Express controller.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+\r
+ @return EFI_SUCCESS - Successfully shutdown the controller.\r
+ @return EFI_DEVICE_ERROR - Fail to shutdown the controller.\r
+ @return EFI_TIMEOUT - Fail to shutdown the controller in given time slot.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+NvmeShutdownController (\r
+ IN NVME_CONTEXT *Nvme\r
+ )\r
+{\r
+ NVME_CC Cc;\r
+ NVME_CSTS Csts;\r
+ EFI_STATUS Status;\r
+ UINT32 Index;\r
+ UINTN Timeout;\r
+\r
+ Status = NVME_GET_CC (Nvme, &Cc);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((DEBUG_ERROR, "NVME_GET_CC fail, Status = %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ Cc.Shn = 1; // Normal shutdown\r
+\r
+ Status = NVME_SET_CC (Nvme, &Cc);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((DEBUG_ERROR, "NVME_SET_CC fail, Status = %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ Timeout = NVME_GENERIC_TIMEOUT/1000; // ms\r
+ for(Index = (UINT32)(Timeout); Index != 0; --Index) {\r
+ MicroSecondDelay (1000);\r
+\r
+ Status = NVME_GET_CSTS (Nvme, &Csts);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((DEBUG_ERROR, "NVME_GET_CSTS fail, Status = %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ if (Csts.Shst == 2) { // Shutdown processing complete\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Index == 0) {\r
+ Status = EFI_TIMEOUT;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Check the execution status from a given completion queue entry.\r
+\r
+ @param[in] Cq - A pointer to the NVME_CQ item.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeCheckCqStatus (\r
+ IN NVME_CQ *Cq\r
+ )\r
+{\r
+ if (Cq->Sct == 0x0 && Cq->Sc == 0x0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "Dump NVMe Completion Entry Status from [0x%x]:\n", (UINTN)Cq));\r
+ DEBUG ((DEBUG_INFO, " SQ Identifier : [0x%x], Phase Tag : [%d], Cmd Identifier : [0x%x]\n", Cq->Sqid, Cq->Pt, Cq->Cid));\r
+ DEBUG ((DEBUG_INFO, " NVMe Cmd Execution Result - "));\r
+\r
+ switch (Cq->Sct) {\r
+ case 0x0:\r
+ switch (Cq->Sc) {\r
+ case 0x0:\r
+ DEBUG ((DEBUG_INFO, "Successful Completion\n"));\r
+ return EFI_SUCCESS;\r
+ case 0x1:\r
+ DEBUG ((DEBUG_INFO, "Invalid Command Opcode\n"));\r
+ break;\r
+ case 0x2:\r
+ DEBUG ((DEBUG_INFO, "Invalid Field in Command\n"));\r
+ break;\r
+ case 0x3:\r
+ DEBUG ((DEBUG_INFO, "Command ID Conflict\n"));\r
+ break;\r
+ case 0x4:\r
+ DEBUG ((DEBUG_INFO, "Data Transfer Error\n"));\r
+ break;\r
+ case 0x5:\r
+ DEBUG ((DEBUG_INFO, "Commands Aborted due to Power Loss Notification\n"));\r
+ break;\r
+ case 0x6:\r
+ DEBUG ((DEBUG_INFO, "Internal Device Error\n"));\r
+ break;\r
+ case 0x7:\r
+ DEBUG ((DEBUG_INFO, "Command Abort Requested\n"));\r
+ break;\r
+ case 0x8:\r
+ DEBUG ((DEBUG_INFO, "Command Aborted due to SQ Deletion\n"));\r
+ break;\r
+ case 0x9:\r
+ DEBUG ((DEBUG_INFO, "Command Aborted due to Failed Fused Command\n"));\r
+ break;\r
+ case 0xA:\r
+ DEBUG ((DEBUG_INFO, "Command Aborted due to Missing Fused Command\n"));\r
+ break;\r
+ case 0xB:\r
+ DEBUG ((DEBUG_INFO, "Invalid Namespace or Format\n"));\r
+ break;\r
+ case 0xC:\r
+ DEBUG ((DEBUG_INFO, "Command Sequence Error\n"));\r
+ break;\r
+ case 0xD:\r
+ DEBUG ((DEBUG_INFO, "Invalid SGL Last Segment Descriptor\n"));\r
+ break;\r
+ case 0xE:\r
+ DEBUG ((DEBUG_INFO, "Invalid Number of SGL Descriptors\n"));\r
+ break;\r
+ case 0xF:\r
+ DEBUG ((DEBUG_INFO, "Data SGL Length Invalid\n"));\r
+ break;\r
+ case 0x10:\r
+ DEBUG ((DEBUG_INFO, "Metadata SGL Length Invalid\n"));\r
+ break;\r
+ case 0x11:\r
+ DEBUG ((DEBUG_INFO, "SGL Descriptor Type Invalid\n"));\r
+ break;\r
+ case 0x80:\r
+ DEBUG ((DEBUG_INFO, "LBA Out of Range\n"));\r
+ break;\r
+ case 0x81:\r
+ DEBUG ((DEBUG_INFO, "Capacity Exceeded\n"));\r
+ break;\r
+ case 0x82:\r
+ DEBUG ((DEBUG_INFO, "Namespace Not Ready\n"));\r
+ break;\r
+ case 0x83:\r
+ DEBUG ((DEBUG_INFO, "Reservation Conflict\n"));\r
+ break;\r
+ }\r
+ break;\r
+\r
+ case 0x1:\r
+ switch (Cq->Sc) {\r
+ case 0x0:\r
+ DEBUG ((DEBUG_INFO, "Completion Queue Invalid\n"));\r
+ break;\r
+ case 0x1:\r
+ DEBUG ((DEBUG_INFO, "Invalid Queue Identifier\n"));\r
+ break;\r
+ case 0x2:\r
+ DEBUG ((DEBUG_INFO, "Maximum Queue Size Exceeded\n"));\r
+ break;\r
+ case 0x3:\r
+ DEBUG ((DEBUG_INFO, "Abort Command Limit Exceeded\n"));\r
+ break;\r
+ case 0x5:\r
+ DEBUG ((DEBUG_INFO, "Asynchronous Event Request Limit Exceeded\n"));\r
+ break;\r
+ case 0x6:\r
+ DEBUG ((DEBUG_INFO, "Invalid Firmware Slot\n"));\r
+ break;\r
+ case 0x7:\r
+ DEBUG ((DEBUG_INFO, "Invalid Firmware Image\n"));\r
+ break;\r
+ case 0x8:\r
+ DEBUG ((DEBUG_INFO, "Invalid Interrupt Vector\n"));\r
+ break;\r
+ case 0x9:\r
+ DEBUG ((DEBUG_INFO, "Invalid Log Page\n"));\r
+ break;\r
+ case 0xA:\r
+ DEBUG ((DEBUG_INFO, "Invalid Format\n"));\r
+ break;\r
+ case 0xB:\r
+ DEBUG ((DEBUG_INFO, "Firmware Application Requires Conventional Reset\n"));\r
+ break;\r
+ case 0xC:\r
+ DEBUG ((DEBUG_INFO, "Invalid Queue Deletion\n"));\r
+ break;\r
+ case 0xD:\r
+ DEBUG ((DEBUG_INFO, "Feature Identifier Not Saveable\n"));\r
+ break;\r
+ case 0xE:\r
+ DEBUG ((DEBUG_INFO, "Feature Not Changeable\n"));\r
+ break;\r
+ case 0xF:\r
+ DEBUG ((DEBUG_INFO, "Feature Not Namespace Specific\n"));\r
+ break;\r
+ case 0x10:\r
+ DEBUG ((DEBUG_INFO, "Firmware Application Requires NVM Subsystem Reset\n"));\r
+ break;\r
+ case 0x80:\r
+ DEBUG ((DEBUG_INFO, "Conflicting Attributes\n"));\r
+ break;\r
+ case 0x81:\r
+ DEBUG ((DEBUG_INFO, "Invalid Protection Information\n"));\r
+ break;\r
+ case 0x82:\r
+ DEBUG ((DEBUG_INFO, "Attempted Write to Read Only Range\n"));\r
+ break;\r
+ }\r
+ break;\r
+\r
+ case 0x2:\r
+ switch (Cq->Sc) {\r
+ case 0x80:\r
+ DEBUG ((DEBUG_INFO, "Write Fault\n"));\r
+ break;\r
+ case 0x81:\r
+ DEBUG ((DEBUG_INFO, "Unrecovered Read Error\n"));\r
+ break;\r
+ case 0x82:\r
+ DEBUG ((DEBUG_INFO, "End-to-end Guard Check Error\n"));\r
+ break;\r
+ case 0x83:\r
+ DEBUG ((DEBUG_INFO, "End-to-end Application Tag Check Error\n"));\r
+ break;\r
+ case 0x84:\r
+ DEBUG ((DEBUG_INFO, "End-to-end Reference Tag Check Error\n"));\r
+ break;\r
+ case 0x85:\r
+ DEBUG ((DEBUG_INFO, "Compare Failure\n"));\r
+ break;\r
+ case 0x86:\r
+ DEBUG ((DEBUG_INFO, "Access Denied\n"));\r
+ break;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ DEBUG ((DEBUG_INFO, "Unknown error\n"));\r
+ break;\r
+ }\r
+\r
+ return EFI_DEVICE_ERROR;\r
+}\r
+\r
+/**\r
+ Create PRP lists for Data transfer which is larger than 2 memory pages.\r
+ Note here we calcuate the number of required PRP lists and allocate them at one time.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+ @param[in] SqId - The SQ index for this PRP\r
+ @param[in] PhysicalAddr - The physical base address of Data Buffer.\r
+ @param[in] Pages - The number of pages to be transfered.\r
+ @param[out] PrpListHost - The host base address of PRP lists.\r
+ @param[in,out] PrpListNo - The number of PRP List.\r
+\r
+ @retval The pointer Value to the first PRP List of the PRP lists.\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+NvmeCreatePrpList (\r
+ IN NVME_CONTEXT *Nvme,\r
+ IN UINT16 SqId,\r
+ IN EFI_PHYSICAL_ADDRESS PhysicalAddr,\r
+ IN UINTN Pages,\r
+ OUT VOID **PrpListHost,\r
+ IN OUT UINTN *PrpListNo\r
+ )\r
+{\r
+ UINTN PrpEntryNo;\r
+ UINT64 PrpListBase;\r
+ UINTN PrpListIndex;\r
+ UINTN PrpEntryIndex;\r
+ UINT64 Remainder;\r
+ EFI_PHYSICAL_ADDRESS PrpListPhyAddr;\r
+ UINTN Bytes;\r
+ UINT8 *PrpEntry;\r
+ EFI_PHYSICAL_ADDRESS NewPhyAddr;\r
+\r
+ ///\r
+ /// The number of Prp Entry in a memory page.\r
+ ///\r
+ PrpEntryNo = EFI_PAGE_SIZE / sizeof (UINT64);\r
+\r
+ ///\r
+ /// Calculate total PrpList number.\r
+ ///\r
+ *PrpListNo = (UINTN) DivU64x64Remainder ((UINT64)Pages, (UINT64)PrpEntryNo, &Remainder);\r
+ if (Remainder != 0) {\r
+ *PrpListNo += 1;\r
+ }\r
+\r
+ if (*PrpListNo > NVME_PRP_SIZE) {\r
+ DEBUG ((DEBUG_INFO, "NvmeCreatePrpList (PhysicalAddr: %lx, Pages: %x) PrpEntryNo: %x\n",\r
+ PhysicalAddr, Pages, PrpEntryNo));\r
+ DEBUG ((DEBUG_INFO, "*PrpListNo: %x, Remainder: %lx", *PrpListNo, Remainder));\r
+ ASSERT (FALSE);\r
+ }\r
+ *PrpListHost = (VOID *)(UINTN) NVME_PRP_BASE (Nvme, SqId);\r
+\r
+ Bytes = EFI_PAGES_TO_SIZE (*PrpListNo);\r
+ PrpListPhyAddr = (UINT64)(UINTN)(*PrpListHost);\r
+\r
+ ///\r
+ /// Fill all PRP lists except of last one.\r
+ ///\r
+ ZeroMem (*PrpListHost, Bytes);\r
+ for (PrpListIndex = 0; PrpListIndex < *PrpListNo - 1; ++PrpListIndex) {\r
+ PrpListBase = *(UINT64*)PrpListHost + PrpListIndex * EFI_PAGE_SIZE;\r
+\r
+ for (PrpEntryIndex = 0; PrpEntryIndex < PrpEntryNo; ++PrpEntryIndex) {\r
+ PrpEntry = (UINT8 *)(UINTN) (PrpListBase + PrpEntryIndex * sizeof(UINT64));\r
+ if (PrpEntryIndex != PrpEntryNo - 1) {\r
+ ///\r
+ /// Fill all PRP entries except of last one.\r
+ ///\r
+ CopyMem (PrpEntry, (VOID *)(UINTN) (&PhysicalAddr), sizeof (UINT64));\r
+ PhysicalAddr += EFI_PAGE_SIZE;\r
+ } else {\r
+ ///\r
+ /// Fill last PRP entries with next PRP List pointer.\r
+ ///\r
+ NewPhyAddr = (PrpListPhyAddr + (PrpListIndex + 1) * EFI_PAGE_SIZE);\r
+ CopyMem (PrpEntry, (VOID *)(UINTN) (&NewPhyAddr), sizeof (UINT64));\r
+ }\r
+ }\r
+ }\r
+\r
+ ///\r
+ /// Fill last PRP list.\r
+ ///\r
+ PrpListBase = *(UINT64*)PrpListHost + PrpListIndex * EFI_PAGE_SIZE;\r
+ for (PrpEntryIndex = 0; PrpEntryIndex < ((Remainder != 0) ? Remainder : PrpEntryNo); ++PrpEntryIndex) {\r
+ PrpEntry = (UINT8 *)(UINTN) (PrpListBase + PrpEntryIndex * sizeof(UINT64));\r
+ CopyMem (PrpEntry, (VOID *)(UINTN) (&PhysicalAddr), sizeof (UINT64));\r
+\r
+ PhysicalAddr += EFI_PAGE_SIZE;\r
+ }\r
+\r
+ return PrpListPhyAddr;\r
+}\r
+\r
+/**\r
+ Check whether there are available command slots.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+ @param[in] Qid - Queue index\r
+\r
+ @retval EFI_SUCCESS - Available command slot is found\r
+ @retval EFI_NOT_READY - No available command slot is found\r
+ @retval EFI_DEVICE_ERROR - Error occurred on device side.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeHasFreeCmdSlot (\r
+ IN NVME_CONTEXT *Nvme,\r
+ IN UINT8 Qid\r
+ )\r
+{\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Check whether all command slots are clean.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+ @param[in] Qid - Queue index\r
+\r
+ @retval EFI_SUCCESS - All command slots are clean\r
+ @retval EFI_NOT_READY - Not all command slots are clean\r
+ @retval EFI_DEVICE_ERROR - Error occurred on device side.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeIsAllCmdSlotClean (\r
+ IN NVME_CONTEXT *Nvme,\r
+ IN UINT8 Qid\r
+ )\r
+{\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Waits until all NVME commands completed.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+ @param[in] Qid - Queue index\r
+\r
+ @retval EFI_SUCCESS - All NVME commands have completed\r
+ @retval EFI_TIMEOUT - Timeout occured\r
+ @retval EFI_NOT_READY - Not all NVME commands have completed\r
+ @retval others - Error occurred on device side.\r
+**/\r
+EFI_STATUS\r
+NvmeWaitAllComplete (\r
+ IN NVME_CONTEXT *Nvme,\r
+ IN UINT8 Qid\r
+ )\r
+{\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function supports\r
+ both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the nonblocking\r
+ I/O functionality is optional.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+ @param[in] NamespaceId - Is a 32 bit Namespace ID to which the Express HCI command packet will be sent.\r
+ A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in the namespace\r
+ ID specifies that the command packet should be sent to all valid namespaces.\r
+ @param[in] NamespaceUuid - Is a 64 bit Namespace UUID to which the Express HCI command packet will be sent.\r
+ A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in the namespace\r
+ UUID specifies that the command packet should be sent to all valid namespaces.\r
+ @param[in,out] Packet - A pointer to the NVM Express HCI Command Packet to send to the NVMe namespace specified\r
+ by NamespaceId.\r
+\r
+ @retval EFI_SUCCESS - The NVM Express Command Packet was sent by the host. TransferLength bytes were transferred\r
+ to, or from DataBuffer.\r
+ @retval EFI_NOT_READY - The NVM Express Command Packet could not be sent because the controller is not ready. The caller\r
+ may retry again later.\r
+ @retval EFI_DEVICE_ERROR - A device error occurred while attempting to send the NVM Express Command Packet.\r
+ @retval EFI_INVALID_PARAMETER - Namespace, or the contents of NVM_EXPRESS_PASS_THRU_COMMAND_PACKET are invalid. The NVM\r
+ Express Command Packet was not sent, so no additional status information is available.\r
+ @retval EFI_UNSUPPORTED - The command described by the NVM Express Command Packet is not supported by the host adapter.\r
+ The NVM Express Command Packet was not sent, so no additional status information is available.\r
+ @retval EFI_TIMEOUT - A timeout occurred while waiting for the NVM Express Command Packet to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmePassThru (\r
+ IN NVME_CONTEXT *Nvme,\r
+ IN UINT32 NamespaceId,\r
+ IN UINT64 NamespaceUuid,\r
+ IN OUT NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ NVME_SQ *Sq;\r
+ NVME_CQ *Cq;\r
+ UINT8 Qid;\r
+ UINT32 Bytes;\r
+ UINT32 Offset;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+ VOID *PrpListHost;\r
+ UINTN PrpListNo;\r
+ UINT32 Timer;\r
+ UINTN SqSize;\r
+ UINTN CqSize;\r
+\r
+ ///\r
+ /// check the Data fields in Packet parameter.\r
+ ///\r
+ if ((Nvme == NULL) || (Packet == NULL)) {\r
+ DEBUG ((DEBUG_ERROR, "NvmePassThru, invalid parameter: Nvme(%x)/Packet(%x)\n",\r
+ (UINTN)Nvme, (UINTN)Packet));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Packet->NvmeCmd == NULL) || (Packet->NvmeResponse == NULL)) {\r
+ DEBUG ((DEBUG_ERROR, "NvmePassThru, invalid parameter: NvmeCmd(%x)/NvmeResponse(%x)\n",\r
+ (UINTN)Packet->NvmeCmd, (UINTN)Packet->NvmeResponse));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Packet->QueueId != NVME_ADMIN_QUEUE && Packet->QueueId != NVME_IO_QUEUE) {\r
+ DEBUG ((DEBUG_ERROR, "NvmePassThru, invalid parameter: QueueId(%x)\n",\r
+ Packet->QueueId));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ PrpListHost = NULL;\r
+ PrpListNo = 0;\r
+ Status = EFI_SUCCESS;\r
+\r
+ Qid = Packet->QueueId;\r
+ Sq = Nvme->SqBuffer[Qid] + Nvme->SqTdbl[Qid].Sqt;\r
+ Cq = Nvme->CqBuffer[Qid] + Nvme->CqHdbl[Qid].Cqh;\r
+ if (Qid == NVME_ADMIN_QUEUE) {\r
+ SqSize = NVME_ASQ_SIZE + 1;\r
+ CqSize = NVME_ACQ_SIZE + 1;\r
+ } else {\r
+ SqSize = NVME_CSQ_DEPTH;\r
+ CqSize = NVME_CCQ_DEPTH;\r
+ }\r
+\r
+ if (Packet->NvmeCmd->Nsid != NamespaceId) {\r
+ DEBUG ((DEBUG_ERROR, "NvmePassThru: Nsid mismatch (%x, %x)\n",\r
+ Packet->NvmeCmd->Nsid, NamespaceId));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ZeroMem (Sq, sizeof (NVME_SQ));\r
+ Sq->Opc = Packet->NvmeCmd->Cdw0.Opcode;\r
+ Sq->Fuse = Packet->NvmeCmd->Cdw0.FusedOperation;\r
+ Sq->Cid = Packet->NvmeCmd->Cdw0.Cid;\r
+ Sq->Nsid = Packet->NvmeCmd->Nsid;\r
+\r
+ ///\r
+ /// Currently we only support PRP for Data transfer, SGL is NOT supported.\r
+ ///\r
+ ASSERT (Sq->Psdt == 0);\r
+ if (Sq->Psdt != 0) {\r
+ DEBUG ((DEBUG_ERROR, "NvmePassThru: doesn't support SGL mechanism\n"));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Sq->Prp[0] = Packet->TransferBuffer;\r
+ Sq->Prp[1] = 0;\r
+\r
+ if(Packet->MetadataBuffer != (UINT64)(UINTN)NULL) {\r
+ Sq->Mptr = Packet->MetadataBuffer;\r
+ }\r
+\r
+ ///\r
+ /// If the Buffer Size spans more than two memory pages (page Size as defined in CC.Mps),\r
+ /// then build a PRP list in the second PRP submission queue entry.\r
+ ///\r
+ Offset = ((UINT32)Sq->Prp[0]) & (EFI_PAGE_SIZE - 1);\r
+ Bytes = Packet->TransferLength;\r
+\r
+ if ((Offset + Bytes) > (EFI_PAGE_SIZE * 2)) {\r
+ ///\r
+ /// Create PrpList for remaining Data Buffer.\r
+ ///\r
+ PhyAddr = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1);\r
+ Sq->Prp[1] = NvmeCreatePrpList (Nvme, Nvme->SqTdbl[Qid].Sqt, PhyAddr, EFI_SIZE_TO_PAGES(Offset + Bytes) - 1, &PrpListHost, &PrpListNo);\r
+ if (Sq->Prp[1] == 0) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ DEBUG ((DEBUG_ERROR, "NvmeCreatePrpList fail, Status: %r\n", Status));\r
+ goto EXIT;\r
+ }\r
+\r
+ } else if ((Offset + Bytes) > EFI_PAGE_SIZE) {\r
+ Sq->Prp[1] = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1);\r
+ }\r
+\r
+ if(Packet->NvmeCmd->Flags & CDW10_VALID) {\r
+ Sq->Payload.Raw.Cdw10 = Packet->NvmeCmd->Cdw10;\r
+ }\r
+ if(Packet->NvmeCmd->Flags & CDW11_VALID) {\r
+ Sq->Payload.Raw.Cdw11 = Packet->NvmeCmd->Cdw11;\r
+ }\r
+ if(Packet->NvmeCmd->Flags & CDW12_VALID) {\r
+ Sq->Payload.Raw.Cdw12 = Packet->NvmeCmd->Cdw12;\r
+ }\r
+ if(Packet->NvmeCmd->Flags & CDW13_VALID) {\r
+ Sq->Payload.Raw.Cdw13 = Packet->NvmeCmd->Cdw13;\r
+ }\r
+ if(Packet->NvmeCmd->Flags & CDW14_VALID) {\r
+ Sq->Payload.Raw.Cdw14 = Packet->NvmeCmd->Cdw14;\r
+ }\r
+ if(Packet->NvmeCmd->Flags & CDW15_VALID) {\r
+ Sq->Payload.Raw.Cdw15 = Packet->NvmeCmd->Cdw15;\r
+ }\r
+\r
+ ///\r
+ /// Ring the submission queue doorbell.\r
+ ///\r
+ Nvme->SqTdbl[Qid].Sqt++;\r
+ if(Nvme->SqTdbl[Qid].Sqt == SqSize) {\r
+ Nvme->SqTdbl[Qid].Sqt = 0;\r
+ }\r
+ Status = NVME_SET_SQTDBL (Nvme, Qid, &Nvme->SqTdbl[Qid]);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((DEBUG_ERROR, "NVME_SET_SQTDBL fail, Status: %r\n", Status));\r
+ goto EXIT;\r
+ }\r
+\r
+ ///\r
+ /// Wait for completion queue to get filled in.\r
+ ///\r
+ Status = EFI_TIMEOUT;\r
+ Timer = 0;\r
+ while (Timer < NVME_CMD_TIMEOUT) {\r
+ //DEBUG ((DEBUG_VERBOSE, "Timer: %x, Cq:\n", Timer));\r
+ //DumpMem (Cq, sizeof (NVME_CQ));\r
+ if (Cq->Pt != Nvme->Pt[Qid]) {\r
+ Status = EFI_SUCCESS;\r
+ break;\r
+ }\r
+\r
+ MicroSecondDelay (NVME_CMD_WAIT);\r
+ Timer += NVME_CMD_WAIT;\r
+ }\r
+\r
+ Nvme->CqHdbl[Qid].Cqh++;\r
+ if (Nvme->CqHdbl[Qid].Cqh == CqSize) {\r
+ Nvme->CqHdbl[Qid].Cqh = 0;\r
+ Nvme->Pt[Qid] ^= 1;\r
+ }\r
+\r
+ ///\r
+ /// Copy the Respose Queue entry for this command to the callers response Buffer\r
+ ///\r
+ CopyMem (Packet->NvmeResponse, Cq, sizeof(NVM_EXPRESS_RESPONSE));\r
+\r
+ if (!EFI_ERROR(Status)) { // We still need to check CQ status if no timeout error occured\r
+ Status = NvmeCheckCqStatus (Cq);\r
+ }\r
+ NVME_SET_CQHDBL (Nvme, Qid, &Nvme->CqHdbl[Qid]);\r
+\r
+EXIT:\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Get identify controller Data.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+ @param[in] Buffer - The Buffer used to store the identify controller Data.\r
+\r
+ @return EFI_SUCCESS - Successfully get the identify controller Data.\r
+ @return others - Fail to get the identify controller Data.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+NvmeIdentifyController (\r
+ IN NVME_CONTEXT *Nvme,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
+ NVM_EXPRESS_COMMAND Command;\r
+ NVM_EXPRESS_RESPONSE Response;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r
+\r
+ Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_OPC;\r
+ Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++;\r
+ //\r
+ // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.\r
+ // For the Identify command, the Namespace Identifier is only used for the Namespace Data structure.\r
+ //\r
+ Command.Nsid = 0;\r
+\r
+ CommandPacket.NvmeCmd = &Command;\r
+ CommandPacket.NvmeResponse = &Response;\r
+ CommandPacket.TransferBuffer = (UINT64)(UINTN)Buffer;\r
+ CommandPacket.TransferLength = sizeof (NVME_ADMIN_CONTROLLER_DATA);\r
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
+ CommandPacket.QueueId = NVME_ADMIN_QUEUE;\r
+ //\r
+ // Set bit 0 (Cns bit) to 1 to identify a controller\r
+ //\r
+ Command.Cdw10 = 1;\r
+ Command.Flags = CDW10_VALID;\r
+\r
+ Status = NvmePassThru (\r
+ Nvme,\r
+ NVME_CONTROLLER_ID,\r
+ 0,\r
+ &CommandPacket\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Get specified identify namespace Data.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+ @param[in] NamespaceId - The specified namespace identifier.\r
+ @param[in] Buffer - The Buffer used to store the identify namespace Data.\r
+\r
+ @return EFI_SUCCESS - Successfully get the identify namespace Data.\r
+ @return others - Fail to get the identify namespace Data.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+NvmeIdentifyNamespace (\r
+ IN NVME_CONTEXT *Nvme,\r
+ IN UINT32 NamespaceId,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
+ NVM_EXPRESS_COMMAND Command;\r
+ NVM_EXPRESS_RESPONSE Response;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r
+\r
+ CommandPacket.NvmeCmd = &Command;\r
+ CommandPacket.NvmeResponse = &Response;\r
+\r
+ Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_OPC;\r
+ Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++;\r
+ Command.Nsid = NamespaceId;\r
+ CommandPacket.TransferBuffer = (UINT64)(UINTN)Buffer;\r
+ CommandPacket.TransferLength = sizeof (NVME_ADMIN_NAMESPACE_DATA);\r
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
+ CommandPacket.QueueId = NVME_ADMIN_QUEUE;\r
+ //\r
+ // Set bit 0 (Cns bit) to 1 to identify a namespace\r
+ //\r
+ CommandPacket.NvmeCmd->Cdw10 = 0;\r
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID;\r
+\r
+ Status = NvmePassThru (\r
+ Nvme,\r
+ NamespaceId,\r
+ 0,\r
+ &CommandPacket\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Get Block Size for specific namespace of NVME.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+\r
+ @return - Block Size in bytes\r
+\r
+**/\r
+STATIC\r
+UINT32\r
+NvmeGetBlockSize (\r
+ IN NVME_CONTEXT *Nvme\r
+ )\r
+{\r
+ UINT32 BlockSize;\r
+ UINT32 Lbads;\r
+ UINT32 Flbas;\r
+ UINT32 LbaFmtIdx;\r
+\r
+ Flbas = Nvme->NamespaceData->Flbas;\r
+ LbaFmtIdx = Flbas & 3;\r
+ Lbads = Nvme->NamespaceData->LbaFormat[LbaFmtIdx].Lbads;\r
+\r
+ BlockSize = (UINT32)1 << Lbads;\r
+ return BlockSize;\r
+}\r
+\r
+/**\r
+ Get last LBA for specific namespace of NVME.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+\r
+ @return - Last LBA address\r
+\r
+**/\r
+STATIC\r
+EFI_LBA\r
+NvmeGetLastLba (\r
+ IN NVME_CONTEXT *Nvme\r
+ )\r
+{\r
+ EFI_LBA LastBlock;\r
+ LastBlock = Nvme->NamespaceData->Nsze - 1;\r
+ return LastBlock;\r
+}\r
+\r
+/**\r
+ Create io completion queue.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+\r
+ @return EFI_SUCCESS - Successfully create io completion queue.\r
+ @return others - Fail to create io completion queue.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+NvmeCreateIoCompletionQueue (\r
+ IN NVME_CONTEXT *Nvme\r
+ )\r
+{\r
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
+ NVM_EXPRESS_COMMAND Command;\r
+ NVM_EXPRESS_RESPONSE Response;\r
+ EFI_STATUS Status;\r
+ NVME_ADMIN_CRIOCQ CrIoCq;\r
+\r
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r
+ ZeroMem (&CrIoCq, sizeof(NVME_ADMIN_CRIOCQ));\r
+\r
+ CommandPacket.NvmeCmd = &Command;\r
+ CommandPacket.NvmeResponse = &Response;\r
+\r
+ Command.Cdw0.Opcode = NVME_ADMIN_CRIOCQ_OPC;\r
+ Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++;\r
+ CommandPacket.TransferBuffer = (UINT64)(UINTN)Nvme->CqBuffer[NVME_IO_QUEUE];\r
+ CommandPacket.TransferLength = EFI_PAGE_SIZE;\r
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
+ CommandPacket.QueueId = NVME_ADMIN_QUEUE;\r
+\r
+ CrIoCq.Qid = NVME_IO_QUEUE;\r
+ CrIoCq.Qsize = NVME_CCQ_SIZE;\r
+ CrIoCq.Pc = 1;\r
+ CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoCq, sizeof (NVME_ADMIN_CRIOCQ));\r
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;\r
+\r
+ Status = NvmePassThru (\r
+ Nvme,\r
+ NVME_CONTROLLER_ID,\r
+ 0,\r
+ &CommandPacket\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Create io submission queue.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+\r
+ @return EFI_SUCCESS - Successfully create io submission queue.\r
+ @return others - Fail to create io submission queue.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+NvmeCreateIoSubmissionQueue (\r
+ IN NVME_CONTEXT *Nvme\r
+ )\r
+{\r
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
+ NVM_EXPRESS_COMMAND Command;\r
+ NVM_EXPRESS_RESPONSE Response;\r
+ EFI_STATUS Status;\r
+ NVME_ADMIN_CRIOSQ CrIoSq;\r
+\r
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r
+ ZeroMem (&CrIoSq, sizeof(NVME_ADMIN_CRIOSQ));\r
+\r
+ CommandPacket.NvmeCmd = &Command;\r
+ CommandPacket.NvmeResponse = &Response;\r
+\r
+ Command.Cdw0.Opcode = NVME_ADMIN_CRIOSQ_OPC;\r
+ Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++;\r
+ CommandPacket.TransferBuffer = (UINT64)(UINTN)Nvme->SqBuffer[NVME_IO_QUEUE];\r
+ CommandPacket.TransferLength = EFI_PAGE_SIZE;\r
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
+ CommandPacket.QueueId = NVME_ADMIN_QUEUE;\r
+\r
+ CrIoSq.Qid = NVME_IO_QUEUE;\r
+ CrIoSq.Qsize = NVME_CSQ_SIZE;\r
+ CrIoSq.Pc = 1;\r
+ CrIoSq.Cqid = NVME_IO_QUEUE;\r
+ CrIoSq.Qprio = 0;\r
+ CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoSq, sizeof (NVME_ADMIN_CRIOSQ));\r
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;\r
+\r
+ Status = NvmePassThru (\r
+ Nvme,\r
+ NVME_CONTROLLER_ID,\r
+ 0,\r
+ &CommandPacket\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Security send and receive commands.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+ @param[in] SendCommand - The flag to indicate the command type, TRUE for Send command and FALSE for receive command\r
+ @param[in] SecurityProtocol - Security Protocol\r
+ @param[in] SpSpecific - Security Protocol Specific\r
+ @param[in] TransferLength - Transfer Length of Buffer (in bytes) - always a multiple of 512\r
+ @param[in,out] TransferBuffer - Address of Data to transfer\r
+\r
+ @return EFI_SUCCESS - Successfully create io submission queue.\r
+ @return others - Fail to send/receive commands.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeSecuritySendReceive (\r
+ IN NVME_CONTEXT *Nvme,\r
+ IN BOOLEAN SendCommand,\r
+ IN UINT8 SecurityProtocol,\r
+ IN UINT16 SpSpecific,\r
+ IN UINTN TransferLength,\r
+ IN OUT VOID *TransferBuffer\r
+ )\r
+{\r
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
+ NVM_EXPRESS_COMMAND Command;\r
+ NVM_EXPRESS_RESPONSE Response;\r
+ EFI_STATUS Status;\r
+ NVME_ADMIN_SECSEND SecSend;\r
+ OACS *Oacs;\r
+ UINT8 Opcode;\r
+ VOID* *SecBuff;\r
+\r
+ Oacs = (OACS *)&Nvme->ControllerData->Oacs;\r
+\r
+ //\r
+ // Verify security bit for Security Send/Receive commands\r
+ //\r
+ if (Oacs->Security == 0) {\r
+ DEBUG ((DEBUG_ERROR, "Security command doesn't support.\n"));\r
+ return EFI_NOT_READY;\r
+ }\r
+\r
+ SecBuff = (VOID *)(UINTN) NVME_SEC_BASE (Nvme);\r
+\r
+ //\r
+ // Actions for sending security command\r
+ //\r
+ if (SendCommand) {\r
+ CopyMem (SecBuff, TransferBuffer, TransferLength);\r
+ }\r
+\r
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r
+ ZeroMem (&SecSend, sizeof(NVME_ADMIN_SECSEND));\r
+\r
+ CommandPacket.NvmeCmd = &Command;\r
+ CommandPacket.NvmeResponse = &Response;\r
+\r
+ Opcode = (UINT8)(SendCommand ? NVME_ADMIN_SECURITY_SEND_OPC : NVME_ADMIN_SECURITY_RECV_OPC);\r
+ Command.Cdw0.Opcode = Opcode;\r
+ Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++;\r
+ CommandPacket.TransferBuffer = (UINT64)(UINTN)SecBuff;\r
+ CommandPacket.TransferLength = (UINT32)TransferLength;\r
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
+ CommandPacket.QueueId = NVME_ADMIN_QUEUE;\r
+\r
+ SecSend.Spsp = SpSpecific;\r
+ SecSend.Secp = SecurityProtocol;\r
+ SecSend.Tl = (UINT32)TransferLength;\r
+\r
+ CopyMem (&CommandPacket.NvmeCmd->Cdw10, &SecSend, sizeof (NVME_ADMIN_SECSEND));\r
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;\r
+\r
+ Status = NvmePassThru (\r
+ Nvme,\r
+ NVME_CONTROLLER_ID,\r
+ 0,\r
+ &CommandPacket\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);\r
+ }\r
+\r
+ //\r
+ // Actions for receiving security command\r
+ //\r
+ if (!SendCommand) {\r
+ CopyMem (TransferBuffer, SecBuff, TransferLength);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Destroy io completion queue.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+\r
+ @return EFI_SUCCESS - Successfully destroy io completion queue.\r
+ @return others - Fail to destroy io completion queue.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+NvmeDestroyIoCompletionQueue (\r
+ IN NVME_CONTEXT *Nvme\r
+ )\r
+{\r
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
+ NVM_EXPRESS_COMMAND Command;\r
+ NVM_EXPRESS_RESPONSE Response;\r
+ EFI_STATUS Status;\r
+ NVME_ADMIN_DEIOCQ DelIoCq;\r
+\r
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r
+ ZeroMem (&DelIoCq, sizeof(NVME_ADMIN_DEIOCQ));\r
+\r
+ CommandPacket.NvmeCmd = &Command;\r
+ CommandPacket.NvmeResponse = &Response;\r
+\r
+ Command.Cdw0.Opcode = NVME_ADMIN_DELIOCQ_OPC;\r
+ Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++;\r
+ CommandPacket.TransferBuffer = (UINT64)(UINTN)Nvme->CqBuffer[NVME_IO_QUEUE];\r
+ CommandPacket.TransferLength = EFI_PAGE_SIZE;\r
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
+ CommandPacket.QueueId = NVME_ADMIN_QUEUE;\r
+\r
+ DelIoCq.Qid = NVME_IO_QUEUE;\r
+ CopyMem (&CommandPacket.NvmeCmd->Cdw10, &DelIoCq, sizeof (NVME_ADMIN_DEIOCQ));\r
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;\r
+\r
+ Status = NvmePassThru (\r
+ Nvme,\r
+ NVME_CONTROLLER_ID,\r
+ 0,\r
+ &CommandPacket\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Destroy io submission queue.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+\r
+ @return EFI_SUCCESS - Successfully destroy io submission queue.\r
+ @return others - Fail to destroy io submission queue.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+NvmeDestroyIoSubmissionQueue (\r
+ IN NVME_CONTEXT *Nvme\r
+ )\r
+{\r
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
+ NVM_EXPRESS_COMMAND Command;\r
+ NVM_EXPRESS_RESPONSE Response;\r
+ EFI_STATUS Status;\r
+ NVME_ADMIN_DEIOSQ DelIoSq;\r
+\r
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r
+ ZeroMem (&DelIoSq, sizeof(NVME_ADMIN_DEIOSQ));\r
+\r
+ CommandPacket.NvmeCmd = &Command;\r
+ CommandPacket.NvmeResponse = &Response;\r
+\r
+ Command.Cdw0.Opcode = NVME_ADMIN_DELIOSQ_OPC;\r
+ Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++;\r
+ CommandPacket.TransferBuffer = (UINT64)(UINTN)Nvme->SqBuffer[NVME_IO_QUEUE];\r
+ CommandPacket.TransferLength = EFI_PAGE_SIZE;\r
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
+ CommandPacket.QueueId = NVME_ADMIN_QUEUE;\r
+\r
+ DelIoSq.Qid = NVME_IO_QUEUE;\r
+ CopyMem (&CommandPacket.NvmeCmd->Cdw10, &DelIoSq, sizeof (NVME_ADMIN_DEIOSQ));\r
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;\r
+\r
+ Status = NvmePassThru (\r
+ Nvme,\r
+ NVME_CONTROLLER_ID,\r
+ 0,\r
+ &CommandPacket\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Allocate transfer-related Data struct which is used at Nvme.\r
+\r
+ @param[in, out] Nvme The pointer to the NVME_CONTEXT Data structure.\r
+\r
+ @retval EFI_OUT_OF_RESOURCE No enough resource.\r
+ @retval EFI_SUCCESS Successful to allocate resource.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmeAllocateResource (\r
+ IN OUT NVME_CONTEXT *Nvme\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS DeviceAddress;\r
+ VOID *Base;\r
+ VOID *Mapping;\r
+\r
+ //\r
+ // Allocate resources for DMA.\r
+ //\r
+ Status = IoMmuAllocateBuffer (\r
+ EFI_SIZE_TO_PAGES (NVME_MEM_MAX_SIZE),\r
+ &Base,\r
+ &DeviceAddress,\r
+ &Mapping\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));\r
+ Nvme->BaseMemMapping = Mapping;\r
+ Nvme->BaseMem = Base;\r
+ ZeroMem (Nvme->BaseMem, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (NVME_MEM_MAX_SIZE));\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "%a() NvmeContext 0x%x\n",\r
+ __FUNCTION__,\r
+ Nvme->BaseMem\r
+ ));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Free allocated transfer-related Data struct which is used at NVMe.\r
+\r
+ @param[in, out] Nvme The pointer to the NVME_CONTEXT Data structure.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+NvmeFreeResource (\r
+ IN OUT NVME_CONTEXT *Nvme\r
+ )\r
+{\r
+ if (Nvme->BaseMem != NULL) {\r
+ IoMmuFreeBuffer (\r
+ EFI_SIZE_TO_PAGES (NVME_MEM_MAX_SIZE),\r
+ Nvme->BaseMem,\r
+ Nvme->BaseMemMapping\r
+ );\r
+ Nvme->BaseMem = NULL;\r
+ }\r
+}\r
+\r
+/**\r
+ Initialize the Nvm Express controller.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+\r
+ @retval EFI_SUCCESS - The NVM Express Controller is initialized successfully.\r
+ @retval Others - A device error occurred while initializing the controller.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeControllerInit (\r
+ IN NVME_CONTEXT *Nvme\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ NVME_AQA Aqa;\r
+ NVME_ASQ Asq;\r
+ NVME_ACQ Acq;\r
+ NVME_VER Ver;\r
+\r
+ UINT32 MlBAR;\r
+ UINT32 MuBAR;\r
+\r
+ ///\r
+ /// Update PCIE BAR0/1 for NVME device\r
+ ///\r
+ MlBAR = Nvme->Nbar;\r
+ MuBAR = 0;\r
+ PciWrite32 (Nvme->PciBase + 0x10, MlBAR); // MLBAR (BAR0)\r
+ PciWrite32 (Nvme->PciBase + 0x14, MuBAR); // MUBAR (BAR1)\r
+\r
+ ///\r
+ /// Enable PCIE decode\r
+ ///\r
+ PciWrite8 (Nvme->PciBase + NVME_PCIE_PCICMD, 0x6);\r
+\r
+ // Version\r
+ NVME_GET_VER (Nvme, &Ver);\r
+ if (!(Ver.Mjr == 0x0001) && (Ver.Mnr == 0x0000)) {\r
+ DEBUG ((DEBUG_INFO, "\n!!!\n!!! NVME Version mismatch for the implementation !!!\n!!!\n"));\r
+ }\r
+\r
+ ///\r
+ /// Read the Controller Capabilities register and verify that the NVM command set is supported\r
+ ///\r
+ Status = NVME_GET_CAP (Nvme, &Nvme->Cap);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "NVME_GET_CAP fail, Status: %r\n", Status));\r
+ goto Done;\r
+ }\r
+\r
+ if (Nvme->Cap.Css != 0x01) {\r
+ DEBUG ((DEBUG_ERROR, "NvmeControllerInit fail: the controller doesn't support NVMe command set\n"));\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Done;\r
+ }\r
+\r
+ ///\r
+ /// Currently the driver only supports 4k page Size.\r
+ ///\r
+ if ((Nvme->Cap.Mpsmin + 12) > EFI_PAGE_SHIFT) {\r
+ DEBUG ((DEBUG_ERROR, "NvmeControllerInit fail: only supports 4k page Size\n"));\r
+ ASSERT (FALSE);\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Done;\r
+ }\r
+\r
+ Nvme->Cid[0] = 0;\r
+ Nvme->Cid[1] = 0;\r
+\r
+ Nvme->Pt[0] = 0;\r
+ Nvme->Pt[1] = 0;\r
+\r
+ ZeroMem ((VOID *)(UINTN)(&(Nvme->SqTdbl[0])), sizeof (NVME_SQTDBL) * NVME_MAX_IO_QUEUES);\r
+ ZeroMem ((VOID *)(UINTN)(&(Nvme->CqHdbl[0])), sizeof (NVME_CQHDBL) * NVME_MAX_IO_QUEUES);\r
+\r
+ ZeroMem (Nvme->BaseMem, NVME_MEM_MAX_SIZE);\r
+\r
+ Status = NvmeDisableController (Nvme);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((DEBUG_ERROR, "NvmeDisableController fail, Status: %r\n", Status));\r
+ goto Done;\r
+ }\r
+\r
+ ///\r
+ /// set number of entries admin submission & completion queues.\r
+ ///\r
+ Aqa.Asqs = NVME_ASQ_SIZE;\r
+ Aqa.Rsvd1 = 0;\r
+ Aqa.Acqs = NVME_ACQ_SIZE;\r
+ Aqa.Rsvd2 = 0;\r
+\r
+ ///\r
+ /// Address of admin submission queue.\r
+ ///\r
+ Asq = (UINT64)(UINTN)(NVME_ASQ_BASE (Nvme) & ~0xFFF);\r
+\r
+ ///\r
+ /// Address of admin completion queue.\r
+ ///\r
+ Acq = (UINT64)(UINTN)(NVME_ACQ_BASE (Nvme) & ~0xFFF);\r
+\r
+ ///\r
+ /// Address of I/O submission & completion queue.\r
+ ///\r
+ Nvme->SqBuffer[0] = (NVME_SQ *)(UINTN)NVME_ASQ_BASE (Nvme); // NVME_ADMIN_QUEUE\r
+ Nvme->CqBuffer[0] = (NVME_CQ *)(UINTN)NVME_ACQ_BASE (Nvme); // NVME_ADMIN_QUEUE\r
+ Nvme->SqBuffer[1] = (NVME_SQ *)(UINTN)NVME_SQ_BASE (Nvme, 0); // NVME_IO_QUEUE\r
+ Nvme->CqBuffer[1] = (NVME_CQ *)(UINTN)NVME_CQ_BASE (Nvme, 0); // NVME_IO_QUEUE\r
+\r
+ DEBUG ((DEBUG_INFO, "Admin Submission Queue Size (Aqa.Asqs) = [%08X]\n", Aqa.Asqs));\r
+ DEBUG ((DEBUG_INFO, "Admin Completion Queue Size (Aqa.Acqs) = [%08X]\n", Aqa.Acqs));\r
+ DEBUG ((DEBUG_INFO, "Admin Submission Queue (SqBuffer[0]) = [%08X]\n", Nvme->SqBuffer[0]));\r
+ DEBUG ((DEBUG_INFO, "Admin Completion Queue (CqBuffer[0]) = [%08X]\n", Nvme->CqBuffer[0]));\r
+ DEBUG ((DEBUG_INFO, "I/O Submission Queue (SqBuffer[1]) = [%08X]\n", Nvme->SqBuffer[1]));\r
+ DEBUG ((DEBUG_INFO, "I/O Completion Queue (CqBuffer[1]) = [%08X]\n", Nvme->CqBuffer[1]));\r
+\r
+ ///\r
+ /// Program admin queue attributes.\r
+ ///\r
+ Status = NVME_SET_AQA (Nvme, &Aqa);\r
+ if (EFI_ERROR(Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ ///\r
+ /// Program admin submission queue address.\r
+ ///\r
+ Status = NVME_SET_ASQ (Nvme, &Asq);\r
+ if (EFI_ERROR(Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ ///\r
+ /// Program admin completion queue address.\r
+ ///\r
+ Status = NVME_SET_ACQ (Nvme, &Acq);\r
+ if (EFI_ERROR(Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ Status = NvmeEnableController (Nvme);\r
+ if (EFI_ERROR(Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ ///\r
+ /// Create one I/O completion queue.\r
+ ///\r
+ Status = NvmeCreateIoCompletionQueue (Nvme);\r
+ if (EFI_ERROR(Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ ///\r
+ /// Create one I/O Submission queue.\r
+ ///\r
+ Status = NvmeCreateIoSubmissionQueue (Nvme);\r
+ if (EFI_ERROR(Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ ///\r
+ /// Get current Identify Controller Data\r
+ ///\r
+ Nvme->ControllerData = (NVME_ADMIN_CONTROLLER_DATA *)(UINTN) NVME_CONTROL_DATA_BASE (Nvme);\r
+ Status = NvmeIdentifyController (Nvme, Nvme->ControllerData);\r
+ if (EFI_ERROR(Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ ///\r
+ /// Dump NvmExpress Identify Controller Data\r
+ ///\r
+ Nvme->ControllerData->Sn[19] = 0;\r
+ Nvme->ControllerData->Mn[39] = 0;\r
+ //NvmeDumpIdentifyController (Nvme->ControllerData);\r
+\r
+ ///\r
+ /// Get current Identify Namespace Data\r
+ ///\r
+ Nvme->NamespaceData = (NVME_ADMIN_NAMESPACE_DATA *)NVME_NAMESPACE_DATA_BASE (Nvme);\r
+ Status = NvmeIdentifyNamespace (Nvme, Nvme->Nsid, Nvme->NamespaceData);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((DEBUG_ERROR, "NvmeIdentifyNamespace fail, Status = %r\n", Status));\r
+ goto Done;\r
+ }\r
+\r
+ ///\r
+ /// Dump NvmExpress Identify Namespace Data\r
+ ///\r
+ if (Nvme->NamespaceData->Ncap == 0) {\r
+ DEBUG ((DEBUG_ERROR, "Invalid Namespace, Ncap: %lx\n", Nvme->NamespaceData->Ncap));\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Done;\r
+ }\r
+\r
+ Nvme->BlockSize = NvmeGetBlockSize (Nvme);\r
+ Nvme->LastBlock = NvmeGetLastLba (Nvme);\r
+\r
+ Nvme->State = NvmeStatusInit;\r
+\r
+ return EFI_SUCCESS;\r
+\r
+Done:\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Un-initialize the Nvm Express controller.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+\r
+ @retval EFI_SUCCESS - The NVM Express Controller is un-initialized successfully.\r
+ @retval Others - A device error occurred while un-initializing the controller.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeControllerExit (\r
+ IN NVME_CONTEXT *Nvme\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = EFI_SUCCESS;\r
+ if (Nvme->State == NvmeStatusInit || Nvme->State == NvmeStatusMax) {\r
+ ///\r
+ /// Destroy I/O Submission queue.\r
+ ///\r
+ Status = NvmeDestroyIoSubmissionQueue (Nvme);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((DEBUG_ERROR, "NvmeDestroyIoSubmissionQueue fail, Status = %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ ///\r
+ /// Destroy I/O completion queue.\r
+ ///\r
+ Status = NvmeDestroyIoCompletionQueue (Nvme);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((DEBUG_ERROR, "NvmeDestroyIoCompletionQueue fail, Status = %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ Status = NvmeShutdownController (Nvme);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((DEBUG_ERROR, "NvmeShutdownController fail, Status: %r\n", Status));\r
+ }\r
+ }\r
+\r
+ ///\r
+ /// Disable PCIE decode\r
+ ///\r
+ PciWrite8 (Nvme->PciBase + NVME_PCIE_PCICMD, 0x0);\r
+ PciWrite32 (Nvme->PciBase + 0x10, 0); // MLBAR (BAR0)\r
+ PciWrite32 (Nvme->PciBase + 0x14, 0); // MUBAR (BAR1)\r
+\r
+ Nvme->State = NvmeStatusUnknown;\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Read sector Data from the NVMe device.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+ @param[in,out] Buffer - The Buffer used to store the Data read from the device.\r
+ @param[in] Lba - The start block number.\r
+ @param[in] Blocks - Total block number to be read.\r
+\r
+ @retval EFI_SUCCESS - Datum are read from the device.\r
+ @retval Others - Fail to read all the datum.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeReadSectors (\r
+ IN NVME_CONTEXT *Nvme,\r
+ IN OUT UINT64 Buffer,\r
+ IN UINT64 Lba,\r
+ IN UINT32 Blocks\r
+ )\r
+{\r
+ UINT32 Bytes;\r
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
+ NVM_EXPRESS_COMMAND Command;\r
+ NVM_EXPRESS_RESPONSE Response;\r
+ EFI_STATUS Status;\r
+ UINT32 BlockSize;\r
+\r
+ BlockSize = Nvme->BlockSize;\r
+ Bytes = Blocks * BlockSize;\r
+\r
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r
+\r
+ CommandPacket.NvmeCmd = &Command;\r
+ CommandPacket.NvmeResponse = &Response;\r
+\r
+ CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_READ_OPC;\r
+ CommandPacket.NvmeCmd->Cdw0.Cid = Nvme->Cid[NVME_IO_QUEUE]++;\r
+ CommandPacket.NvmeCmd->Nsid = Nvme->Nsid;\r
+ CommandPacket.TransferBuffer = Buffer;\r
+\r
+ CommandPacket.TransferLength = Bytes;\r
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
+ CommandPacket.QueueId = NVME_IO_QUEUE;\r
+\r
+ CommandPacket.NvmeCmd->Cdw10 = (UINT32)Lba;\r
+ CommandPacket.NvmeCmd->Cdw11 = (UINT32)(RShiftU64 (Lba, 32));\r
+ CommandPacket.NvmeCmd->Cdw12 = (Blocks - 1) & 0xFFFF;\r
+\r
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;\r
+\r
+ Status = NvmePassThru (\r
+ Nvme,\r
+ Nvme->Nsid,\r
+ 0,\r
+ &CommandPacket\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Write sector Data to the NVMe device.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+ @param[in] Buffer - The Buffer to be written into the device.\r
+ @param[in] Lba - The start block number.\r
+ @param[in] Blocks - Total block number to be written.\r
+\r
+ @retval EFI_SUCCESS - Datum are written into the Buffer.\r
+ @retval Others - Fail to write all the datum.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeWriteSectors (\r
+ IN NVME_CONTEXT *Nvme,\r
+ IN UINT64 Buffer,\r
+ IN UINT64 Lba,\r
+ IN UINT32 Blocks\r
+ )\r
+{\r
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
+ NVM_EXPRESS_COMMAND Command;\r
+ NVM_EXPRESS_RESPONSE Response;\r
+ EFI_STATUS Status;\r
+ UINT32 Bytes;\r
+ UINT32 BlockSize;\r
+\r
+ BlockSize = Nvme->BlockSize;\r
+ Bytes = Blocks * BlockSize;\r
+\r
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r
+\r
+ CommandPacket.NvmeCmd = &Command;\r
+ CommandPacket.NvmeResponse = &Response;\r
+\r
+ CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_WRITE_OPC;\r
+ CommandPacket.NvmeCmd->Cdw0.Cid = Nvme->Cid[NVME_IO_QUEUE]++;\r
+ CommandPacket.NvmeCmd->Nsid = Nvme->Nsid;\r
+ CommandPacket.TransferBuffer = Buffer;\r
+\r
+ CommandPacket.TransferLength = Bytes;\r
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
+ CommandPacket.QueueId = NVME_IO_QUEUE;\r
+\r
+ CommandPacket.NvmeCmd->Cdw10 = (UINT32)Lba;\r
+ CommandPacket.NvmeCmd->Cdw11 = (UINT32)(RShiftU64 (Lba, 32));\r
+ CommandPacket.NvmeCmd->Cdw12 = (Blocks - 1) & 0xFFFF;\r
+\r
+ CommandPacket.MetadataBuffer = (UINT64)(UINTN)NULL;\r
+ CommandPacket.MetadataLength = 0;\r
+\r
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;\r
+\r
+ Status = NvmePassThru (\r
+ Nvme,\r
+ Nvme->Nsid,\r
+ 0,\r
+ &CommandPacket\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Flushes all modified Data to the device.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+\r
+ @retval EFI_SUCCESS - Datum are written into the Buffer.\r
+ @retval Others - Fail to write all the datum.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeFlush (\r
+ IN NVME_CONTEXT *Nvme\r
+ )\r
+{\r
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
+ NVM_EXPRESS_COMMAND Command;\r
+ NVM_EXPRESS_RESPONSE Response;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r
+\r
+ CommandPacket.NvmeCmd = &Command;\r
+ CommandPacket.NvmeResponse = &Response;\r
+\r
+ CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_FLUSH_OPC;\r
+ CommandPacket.NvmeCmd->Cdw0.Cid = Nvme->Cid[NVME_IO_QUEUE]++;\r
+ CommandPacket.NvmeCmd->Nsid = Nvme->Nsid;\r
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
+ CommandPacket.QueueId = NVME_IO_QUEUE;\r
+\r
+ Status = NvmePassThru (\r
+ Nvme,\r
+ Nvme->Nsid,\r
+ 0,\r
+ &CommandPacket\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Read some blocks from the device.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+ @param[out] Buffer - The Buffer used to store the Data read from the device.\r
+ @param[in] Lba - The start block number.\r
+ @param[in] Blocks - Total block number to be read.\r
+\r
+ @retval EFI_SUCCESS - Datum are read from the device.\r
+ @retval Others - Fail to read all the datum.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeRead (\r
+ IN NVME_CONTEXT *Nvme,\r
+ OUT UINT64 Buffer,\r
+ IN UINT64 Lba,\r
+ IN UINTN Blocks\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 BlockSize;\r
+ UINT32 MaxTransferBlocks;\r
+\r
+ ASSERT (Blocks <= NVME_MAX_SECTORS);\r
+ Status = EFI_SUCCESS;\r
+ BlockSize = Nvme->BlockSize;\r
+ if (Nvme->ControllerData->Mdts != 0) {\r
+ MaxTransferBlocks = (1 << (Nvme->ControllerData->Mdts)) * (1 << (Nvme->Cap.Mpsmin + 12)) / BlockSize;\r
+ } else {\r
+ MaxTransferBlocks = 1024;\r
+ }\r
+\r
+ while (Blocks > 0) {\r
+ if (Blocks > MaxTransferBlocks) {\r
+ Status = NvmeReadSectors (Nvme, Buffer, Lba, MaxTransferBlocks);\r
+\r
+ Blocks -= MaxTransferBlocks;\r
+ Buffer += (MaxTransferBlocks * BlockSize);\r
+ Lba += MaxTransferBlocks;\r
+ } else {\r
+ Status = NvmeReadSectors (Nvme, Buffer, Lba, (UINT32) Blocks);\r
+ Blocks = 0;\r
+ }\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((DEBUG_ERROR, "NvmeRead fail, Status = %r\n", Status));\r
+ break;\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Write some blocks to the device.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+ @param[in] Buffer - The Buffer to be written into the device.\r
+ @param[in] Lba - The start block number.\r
+ @param[in] Blocks - Total block number to be written.\r
+\r
+ @retval EFI_SUCCESS - Datum are written into the Buffer.\r
+ @retval Others - Fail to write all the datum.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeWrite (\r
+ IN NVME_CONTEXT *Nvme,\r
+ IN UINT64 Buffer,\r
+ IN UINT64 Lba,\r
+ IN UINTN Blocks\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 BlockSize;\r
+ UINT32 MaxTransferBlocks;\r
+\r
+ ASSERT (Blocks <= NVME_MAX_SECTORS);\r
+ Status = EFI_SUCCESS;\r
+ BlockSize = Nvme->BlockSize;\r
+\r
+ if (Nvme->ControllerData->Mdts != 0) {\r
+ MaxTransferBlocks = (1 << (Nvme->ControllerData->Mdts)) * (1 << (Nvme->Cap.Mpsmin + 12)) / BlockSize;\r
+ } else {\r
+ MaxTransferBlocks = 1024;\r
+ }\r
+\r
+ while (Blocks > 0) {\r
+ if (Blocks > MaxTransferBlocks) {\r
+ Status = NvmeWriteSectors (Nvme, Buffer, Lba, MaxTransferBlocks);\r
+\r
+ Blocks -= MaxTransferBlocks;\r
+ Buffer += (MaxTransferBlocks * BlockSize);\r
+ Lba += MaxTransferBlocks;\r
+ } else {\r
+ Status = NvmeWriteSectors (Nvme, Buffer, Lba, (UINT32) Blocks);\r
+ Blocks = 0;\r
+ }\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((DEBUG_ERROR, "NvmeWrite fail, Status = %r\n", Status));\r
+ break;\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+ Header file for NVMe function definitions\r
+\r
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __OPAL_PASSWORD_NVME_MODE_H__\r
+#define __OPAL_PASSWORD_NVME_MODE_H__\r
+\r
+\r
+#include "OpalNvmeReg.h"\r
+\r
+#define NVME_MAX_SECTORS 0x10000\r
+//\r
+// QueueId\r
+//\r
+#define NVME_ADMIN_QUEUE 0x00\r
+#define NVME_IO_QUEUE 0x01\r
+\r
+typedef struct {\r
+ UINT8 Opcode;\r
+ UINT8 FusedOperation;\r
+ #define NORMAL_CMD 0x00\r
+ #define FUSED_FIRST_CMD 0x01\r
+ #define FUSED_SECOND_CMD 0x02\r
+ UINT16 Cid;\r
+} NVME_CDW0;\r
+\r
+typedef struct {\r
+ NVME_CDW0 Cdw0;\r
+ UINT8 Flags;\r
+ #define CDW10_VALID 0x01\r
+ #define CDW11_VALID 0x02\r
+ #define CDW12_VALID 0x04\r
+ #define CDW13_VALID 0x08\r
+ #define CDW14_VALID 0x10\r
+ #define CDW15_VALID 0x20\r
+ UINT32 Nsid;\r
+ UINT32 Cdw10;\r
+ UINT32 Cdw11;\r
+ UINT32 Cdw12;\r
+ UINT32 Cdw13;\r
+ UINT32 Cdw14;\r
+ UINT32 Cdw15;\r
+} NVM_EXPRESS_COMMAND;\r
+\r
+typedef struct {\r
+ UINT32 Cdw0;\r
+ UINT32 Cdw1;\r
+ UINT32 Cdw2;\r
+ UINT32 Cdw3;\r
+} NVM_EXPRESS_RESPONSE;\r
+\r
+typedef struct {\r
+ UINT64 CommandTimeout;\r
+ UINT64 TransferBuffer;\r
+ UINT32 TransferLength;\r
+ UINT64 MetadataBuffer;\r
+ UINT32 MetadataLength;\r
+ UINT8 QueueId;\r
+ NVM_EXPRESS_COMMAND *NvmeCmd;\r
+ NVM_EXPRESS_RESPONSE *NvmeResponse;\r
+} NVM_EXPRESS_PASS_THRU_COMMAND_PACKET;\r
+\r
+\r
+#pragma pack(1)\r
+\r
+// Internal fields\r
+typedef enum {\r
+ NvmeStatusUnknown,\r
+ NvmeStatusInit,\r
+ NvmeStatusInuse,\r
+ NvmeStatusMax,\r
+} NVME_STATUS;\r
+\r
+typedef struct {\r
+ UINT32 Nbar;\r
+ VOID *BaseMem;\r
+ VOID *BaseMemMapping;\r
+ BOOLEAN PollCancellation;\r
+ UINT16 NvmeInitWaitTime;\r
+\r
+ NVME_STATUS State;\r
+ UINT8 BusID;\r
+ UINT8 DeviceID;\r
+ UINT8 FuncID;\r
+ UINTN PciBase;\r
+\r
+ UINT32 Nsid;\r
+ UINT64 Nsuuid;\r
+ UINT32 BlockSize;\r
+ EFI_LBA LastBlock;\r
+\r
+ //\r
+ // Pointers to 4kB aligned submission & completion queues.\r
+ //\r
+ NVME_SQ *SqBuffer[NVME_MAX_IO_QUEUES];\r
+ NVME_CQ *CqBuffer[NVME_MAX_IO_QUEUES];\r
+ UINT16 Cid[NVME_MAX_IO_QUEUES];\r
+\r
+ //\r
+ // Submission and completion queue indices.\r
+ //\r
+ NVME_SQTDBL SqTdbl[NVME_MAX_IO_QUEUES];\r
+ NVME_CQHDBL CqHdbl[NVME_MAX_IO_QUEUES];\r
+ UINT8 Pt[NVME_MAX_IO_QUEUES];\r
+\r
+ UINTN SqeCount[NVME_MAX_IO_QUEUES];\r
+\r
+ //\r
+ // Nvme controller capabilities\r
+ //\r
+ NVME_CAP Cap;\r
+\r
+ //\r
+ // pointer to identify controller Data\r
+ //\r
+ NVME_ADMIN_CONTROLLER_DATA *ControllerData;\r
+ NVME_ADMIN_NAMESPACE_DATA *NamespaceData;\r
+} NVME_CONTEXT;\r
+\r
+#pragma pack()\r
+\r
+/**\r
+ Transfer MMIO Data to memory.\r
+\r
+ @param[in,out] MemBuffer - Destination: Memory address\r
+ @param[in] MmioAddr - Source: MMIO address\r
+ @param[in] Size - Size for read\r
+\r
+ @retval EFI_SUCCESS - MMIO read sucessfully\r
+**/\r
+EFI_STATUS\r
+NvmeMmioRead (\r
+ IN OUT VOID *MemBuffer,\r
+ IN UINTN MmioAddr,\r
+ IN UINTN Size\r
+ );\r
+\r
+/**\r
+ Transfer memory Data to MMIO.\r
+\r
+ @param[in,out] MmioAddr - Destination: MMIO address\r
+ @param[in] MemBuffer - Source: Memory address\r
+ @param[in] Size - Size for write\r
+\r
+ @retval EFI_SUCCESS - MMIO write sucessfully\r
+**/\r
+EFI_STATUS\r
+NvmeMmioWrite (\r
+ IN OUT UINTN MmioAddr,\r
+ IN VOID *MemBuffer,\r
+ IN UINTN Size\r
+ );\r
+\r
+/**\r
+ Transfer memory data to MMIO.\r
+\r
+ @param[in,out] MmioAddr - Destination: MMIO address\r
+ @param[in] MemBuffer - Source: Memory address\r
+ @param[in] Size - Size for write\r
+\r
+ @retval EFI_SUCCESS - MMIO write sucessfully\r
+**/\r
+EFI_STATUS\r
+OpalPciWrite (\r
+ IN OUT UINTN MmioAddr,\r
+ IN VOID *MemBuffer,\r
+ IN UINTN Size\r
+ );\r
+\r
+/**\r
+ Transfer MMIO data to memory.\r
+\r
+ @param[in,out] MemBuffer - Destination: Memory address\r
+ @param[in] MmioAddr - Source: MMIO address\r
+ @param[in] Size - Size for read\r
+\r
+ @retval EFI_SUCCESS - MMIO read sucessfully\r
+**/\r
+EFI_STATUS\r
+OpalPciRead (\r
+ IN OUT VOID *MemBuffer,\r
+ IN UINTN MmioAddr,\r
+ IN UINTN Size\r
+ );\r
+\r
+/**\r
+ Allocate transfer-related Data struct which is used at Nvme.\r
+\r
+ @param[in, out] Nvme The pointer to the NVME_CONTEXT Data structure.\r
+\r
+ @retval EFI_OUT_OF_RESOURCE No enough resource.\r
+ @retval EFI_SUCCESS Successful to allocate resource.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmeAllocateResource (\r
+ IN OUT NVME_CONTEXT *Nvme\r
+ );\r
+\r
+/**\r
+ Free allocated transfer-related Data struct which is used at NVMe.\r
+\r
+ @param[in, out] Nvme The pointer to the NVME_CONTEXT Data structure.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+NvmeFreeResource (\r
+ IN OUT NVME_CONTEXT *Nvme\r
+ );\r
+\r
+/**\r
+ Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function supports\r
+ both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the nonblocking\r
+ I/O functionality is optional.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+ @param[in] NamespaceId - Is a 32 bit Namespace ID to which the Express HCI command packet will be sent.\r
+ A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in the namespace\r
+ ID specifies that the command packet should be sent to all valid namespaces.\r
+ @param[in] NamespaceUuid - Is a 64 bit Namespace UUID to which the Express HCI command packet will be sent.\r
+ A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in the namespace\r
+ UUID specifies that the command packet should be sent to all valid namespaces.\r
+ @param[in,out] Packet - A pointer to the NVM Express HCI Command Packet to send to the NVMe namespace specified\r
+ by NamespaceId.\r
+\r
+ @retval EFI_SUCCESS - The NVM Express Command Packet was sent by the host. TransferLength bytes were transferred\r
+ to, or from DataBuffer.\r
+ @retval EFI_NOT_READY - The NVM Express Command Packet could not be sent because the controller is not ready. The caller\r
+ may retry again later.\r
+ @retval EFI_DEVICE_ERROR - A device error occurred while attempting to send the NVM Express Command Packet.\r
+ @retval EFI_INVALID_PARAMETER - Namespace, or the contents of NVM_EXPRESS_PASS_THRU_COMMAND_PACKET are invalid. The NVM\r
+ Express Command Packet was not sent, so no additional status information is available.\r
+ @retval EFI_UNSUPPORTED - The command described by the NVM Express Command Packet is not supported by the host adapter.\r
+ The NVM Express Command Packet was not sent, so no additional status information is available.\r
+ @retval EFI_TIMEOUT - A timeout occurred while waiting for the NVM Express Command Packet to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmePassThru (\r
+ IN NVME_CONTEXT *Nvme,\r
+ IN UINT32 NamespaceId,\r
+ IN UINT64 NamespaceUuid,\r
+ IN OUT NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet\r
+ );\r
+\r
+/**\r
+ Waits until all NVME commands completed.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+ @param[in] Qid - Queue index\r
+\r
+ @retval EFI_SUCCESS - All NVME commands have completed\r
+ @retval EFI_TIMEOUT - Timeout occured\r
+ @retval EFI_NOT_READY - Not all NVME commands have completed\r
+ @retval others - Error occurred on device side.\r
+**/\r
+EFI_STATUS\r
+NvmeWaitAllComplete (\r
+ IN NVME_CONTEXT *Nvme,\r
+ IN UINT8 Qid\r
+ );\r
+\r
+/**\r
+ Initialize the Nvm Express controller.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+\r
+ @retval EFI_SUCCESS - The NVM Express Controller is initialized successfully.\r
+ @retval Others - A device error occurred while initializing the controller.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeControllerInit (\r
+ IN NVME_CONTEXT *Nvme\r
+ );\r
+\r
+/**\r
+ Un-initialize the Nvm Express controller.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+\r
+ @retval EFI_SUCCESS - The NVM Express Controller is un-initialized successfully.\r
+ @retval Others - A device error occurred while un-initializing the controller.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeControllerExit (\r
+ IN NVME_CONTEXT *Nvme\r
+ );\r
+\r
+/**\r
+ Check whether there are available command slots.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+ @param[in] Qid - Queue index\r
+\r
+ @retval EFI_SUCCESS - Available command slot is found\r
+ @retval EFI_NOT_READY - No available command slot is found\r
+ @retval EFI_DEVICE_ERROR - Error occurred on device side.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeHasFreeCmdSlot (\r
+ IN NVME_CONTEXT *Nvme,\r
+ IN UINT8 Qid\r
+ );\r
+\r
+/**\r
+ Check whether all command slots are clean.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+ @param[in] Qid - Queue index\r
+\r
+ @retval EFI_SUCCESS - All command slots are clean\r
+ @retval EFI_NOT_READY - Not all command slots are clean\r
+ @retval EFI_DEVICE_ERROR - Error occurred on device side.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeIsAllCmdSlotClean (\r
+ IN NVME_CONTEXT *Nvme,\r
+ IN UINT8 Qid\r
+ );\r
+\r
+/**\r
+ Read sector Data from the NVMe device.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+ @param[in,out] Buffer - The Buffer used to store the Data read from the device.\r
+ @param[in] Lba - The start block number.\r
+ @param[in] Blocks - Total block number to be read.\r
+\r
+ @retval EFI_SUCCESS - Datum are read from the device.\r
+ @retval Others - Fail to read all the datum.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeReadSectors (\r
+ IN NVME_CONTEXT *Nvme,\r
+ IN OUT UINT64 Buffer,\r
+ IN UINT64 Lba,\r
+ IN UINT32 Blocks\r
+ );\r
+\r
+/**\r
+ Write sector Data to the NVMe device.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+ @param[in] Buffer - The Buffer to be written into the device.\r
+ @param[in] Lba - The start block number.\r
+ @param[in] Blocks - Total block number to be written.\r
+\r
+ @retval EFI_SUCCESS - Datum are written into the Buffer.\r
+ @retval Others - Fail to write all the datum.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeWriteSectors (\r
+ IN NVME_CONTEXT *Nvme,\r
+ IN UINT64 Buffer,\r
+ IN UINT64 Lba,\r
+ IN UINT32 Blocks\r
+ );\r
+\r
+/**\r
+ Flushes all modified Data to the device.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+\r
+ @retval EFI_SUCCESS - Datum are written into the Buffer.\r
+ @retval Others - Fail to write all the datum.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeFlush (\r
+ IN NVME_CONTEXT *Nvme\r
+ );\r
+\r
+/**\r
+ Read some blocks from the device.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+ @param[out] Buffer - The Buffer used to store the Data read from the device.\r
+ @param[in] Lba - The start block number.\r
+ @param[in] Blocks - Total block number to be read.\r
+\r
+ @retval EFI_SUCCESS - Datum are read from the device.\r
+ @retval Others - Fail to read all the datum.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeRead (\r
+ IN NVME_CONTEXT *Nvme,\r
+ OUT UINT64 Buffer,\r
+ IN UINT64 Lba,\r
+ IN UINTN Blocks\r
+ );\r
+\r
+/**\r
+ Write some blocks to the device.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+ @param[in] Buffer - The Buffer to be written into the device.\r
+ @param[in] Lba - The start block number.\r
+ @param[in] Blocks - Total block number to be written.\r
+\r
+ @retval EFI_SUCCESS - Datum are written into the Buffer.\r
+ @retval Others - Fail to write all the datum.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeWrite (\r
+ IN NVME_CONTEXT *Nvme,\r
+ IN UINT64 Buffer,\r
+ IN UINT64 Lba,\r
+ IN UINTN Blocks\r
+ );\r
+\r
+/**\r
+ Security send and receive commands.\r
+\r
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.\r
+ @param[in] SendCommand - The flag to indicate the command type, TRUE for Send command and FALSE for receive command\r
+ @param[in] SecurityProtocol - Security Protocol\r
+ @param[in] SpSpecific - Security Protocol Specific\r
+ @param[in] TransferLength - Transfer Length of Buffer (in bytes) - always a multiple of 512\r
+ @param[in,out] TransferBuffer - Address of Data to transfer\r
+\r
+ @return EFI_SUCCESS - Successfully create io submission queue.\r
+ @return others - Fail to send/receive commands.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeSecuritySendReceive (\r
+ IN NVME_CONTEXT *Nvme,\r
+ IN BOOLEAN SendCommand,\r
+ IN UINT8 SecurityProtocol,\r
+ IN UINT16 SpSpecific,\r
+ IN UINTN TransferLength,\r
+ IN OUT VOID *TransferBuffer\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ Header file for Registers and Structure definitions\r
+\r
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#ifndef __OPAL_PASSWORD_NVME_REG_H__\r
+#define __OPAL_PASSWORD_NVME_REG_H__\r
+\r
+//\r
+// PCI Header for PCIe root port configuration\r
+//\r
+#define NVME_PCIE_PCICMD 0x04\r
+#define NVME_PCIE_BNUM 0x18\r
+#define NVME_PCIE_SEC_BNUM 0x19\r
+#define NVME_PCIE_IOBL 0x1C\r
+#define NVME_PCIE_MBL 0x20\r
+#define NVME_PCIE_PMBL 0x24\r
+#define NVME_PCIE_PMBU32 0x28\r
+#define NVME_PCIE_PMLU32 0x2C\r
+#define NVME_PCIE_INTR 0x3C\r
+\r
+//\r
+// NVMe related definitions\r
+//\r
+#define PCI_CLASS_MASS_STORAGE_NVM 0x08 // mass storage sub-class non-volatile memory.\r
+#define PCI_IF_NVMHCI 0x02 // mass storage programming interface NVMHCI.\r
+\r
+#define NVME_ASQ_SIZE 1 // Number of admin submission queue entries, which is 0-based\r
+#define NVME_ACQ_SIZE 1 // Number of admin completion queue entries, which is 0-based\r
+\r
+#define NVME_CSQ_SIZE 63 // Number of I/O submission queue entries, which is 0-based\r
+#define NVME_CCQ_SIZE 63 // Number of I/O completion queue entries, which is 0-based\r
+\r
+#define NVME_MAX_IO_QUEUES 2 // Number of I/O queues supported by the driver, 1 for AQ, 1 for CQ\r
+\r
+#define NVME_CSQ_DEPTH (NVME_CSQ_SIZE+1)\r
+#define NVME_CCQ_DEPTH (NVME_CCQ_SIZE+1)\r
+#define NVME_PRP_SIZE (4) // Pages of PRP list\r
+\r
+#define NVME_CONTROLLER_ID 0\r
+\r
+//\r
+// Time out Value for Nvme transaction execution\r
+//\r
+#define NVME_GENERIC_TIMEOUT 5000000 ///< us\r
+#define NVME_CMD_WAIT 100 ///< us\r
+#define NVME_CMD_TIMEOUT 20000000 ///< us\r
+\r
+\r
+\r
+#define NVME_MEM_MAX_SIZE \\r
+ (( \\r
+ 1 /* Controller Data */ + \\r
+ 1 /* Identify Data */ + \\r
+ 1 /* ASQ */ + \\r
+ 1 /* ACQ */ + \\r
+ 1 /* SQs */ + \\r
+ 1 /* CQs */ + \\r
+ NVME_PRP_SIZE * NVME_CSQ_DEPTH /* PRPs */ + \\r
+ 1 /* SECURITY */ \\r
+ ) * EFI_PAGE_SIZE)\r
+\r
+\r
+//\r
+// controller register offsets\r
+//\r
+#define NVME_CAP_OFFSET 0x0000 // Controller Capabilities\r
+#define NVME_VER_OFFSET 0x0008 // Version\r
+#define NVME_INTMS_OFFSET 0x000c // Interrupt Mask Set\r
+#define NVME_INTMC_OFFSET 0x0010 // Interrupt Mask Clear\r
+#define NVME_CC_OFFSET 0x0014 // Controller Configuration\r
+#define NVME_CSTS_OFFSET 0x001c // Controller Status\r
+#define NVME_AQA_OFFSET 0x0024 // Admin Queue Attributes\r
+#define NVME_ASQ_OFFSET 0x0028 // Admin Submission Queue Base Address\r
+#define NVME_ACQ_OFFSET 0x0030 // Admin Completion Queue Base Address\r
+#define NVME_SQ0_OFFSET 0x1000 // Submission Queue 0 (admin) Tail Doorbell\r
+#define NVME_CQ0_OFFSET 0x1004 // Completion Queue 0 (admin) Head Doorbell\r
+\r
+//\r
+// These register offsets are defined as 0x1000 + (N * (4 << CAP.DSTRD))\r
+// Get the doorbell stride bit shift Value from the controller capabilities.\r
+//\r
+#define NVME_SQTDBL_OFFSET(QID, DSTRD) 0x1000 + ((2 * (QID)) * (4 << (DSTRD))) // Submission Queue y (NVM) Tail Doorbell\r
+#define NVME_CQHDBL_OFFSET(QID, DSTRD) 0x1000 + (((2 * (QID)) + 1) * (4 << (DSTRD))) // Completion Queue y (NVM) Head Doorbell\r
+\r
+\r
+#pragma pack(1)\r
+\r
+//\r
+// 3.1.1 Offset 00h: CAP - Controller Capabilities\r
+//\r
+typedef struct {\r
+ UINT16 Mqes; // Maximum Queue Entries Supported\r
+ UINT8 Cqr:1; // Contiguous Queues Required\r
+ UINT8 Ams:2; // Arbitration Mechanism Supported\r
+ UINT8 Rsvd1:5;\r
+ UINT8 To; // Timeout\r
+ UINT16 Dstrd:4;\r
+ UINT16 Rsvd2:1;\r
+ UINT16 Css:4; // Command Sets Supported\r
+ UINT16 Rsvd3:7;\r
+ UINT8 Mpsmin:4;\r
+ UINT8 Mpsmax:4;\r
+ UINT8 Rsvd4;\r
+} NVME_CAP;\r
+\r
+//\r
+// 3.1.2 Offset 08h: VS - Version\r
+//\r
+typedef struct {\r
+ UINT16 Mnr; // Minor version number\r
+ UINT16 Mjr; // Major version number\r
+} NVME_VER;\r
+\r
+//\r
+// 3.1.5 Offset 14h: CC - Controller Configuration\r
+//\r
+typedef struct {\r
+ UINT16 En:1; // Enable\r
+ UINT16 Rsvd1:3;\r
+ UINT16 Css:3; // Command Set Selected\r
+ UINT16 Mps:4; // Memory Page Size\r
+ UINT16 Ams:3; // Arbitration Mechanism Selected\r
+ UINT16 Shn:2; // Shutdown Notification\r
+ UINT8 Iosqes:4; // I/O Submission Queue Entry Size\r
+ UINT8 Iocqes:4; // I/O Completion Queue Entry Size\r
+ UINT8 Rsvd2;\r
+} NVME_CC;\r
+\r
+//\r
+// 3.1.6 Offset 1Ch: CSTS - Controller Status\r
+//\r
+typedef struct {\r
+ UINT32 Rdy:1; // Ready\r
+ UINT32 Cfs:1; // Controller Fatal Status\r
+ UINT32 Shst:2; // Shutdown Status\r
+ UINT32 Nssro:1; // NVM Subsystem Reset Occurred\r
+ UINT32 Rsvd1:27;\r
+} NVME_CSTS;\r
+\r
+//\r
+// 3.1.8 Offset 24h: AQA - Admin Queue Attributes\r
+//\r
+typedef struct {\r
+ UINT16 Asqs:12; // Submission Queue Size\r
+ UINT16 Rsvd1:4;\r
+ UINT16 Acqs:12; // Completion Queue Size\r
+ UINT16 Rsvd2:4;\r
+} NVME_AQA;\r
+\r
+//\r
+// 3.1.9 Offset 28h: ASQ - Admin Submission Queue Base Address\r
+//\r
+#define NVME_ASQ UINT64\r
+\r
+//\r
+// 3.1.10 Offset 30h: ACQ - Admin Completion Queue Base Address\r
+//\r
+#define NVME_ACQ UINT64\r
+\r
+//\r
+// 3.1.11 Offset (1000h + ((2y) * (4 << CAP.DSTRD))): SQyTDBL - Submission Queue y Tail Doorbell\r
+//\r
+typedef struct {\r
+ UINT16 Sqt;\r
+ UINT16 Rsvd1;\r
+} NVME_SQTDBL;\r
+\r
+//\r
+// 3.1.12 Offset (1000h + ((2y + 1) * (4 << CAP.DSTRD))): CQyHDBL - Completion Queue y Head Doorbell\r
+//\r
+typedef struct {\r
+ UINT16 Cqh;\r
+ UINT16 Rsvd1;\r
+} NVME_CQHDBL;\r
+\r
+//\r
+// NVM command set structures\r
+//\r
+// Read Command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10, 11\r
+ //\r
+ UINT64 Slba; /* Starting Sector Address */\r
+ //\r
+ // CDW 12\r
+ //\r
+ UINT16 Nlb; /* Number of Sectors */\r
+ UINT16 Rsvd1:10;\r
+ UINT16 Prinfo:4; /* Protection Info Check */\r
+ UINT16 Fua:1; /* Force Unit Access */\r
+ UINT16 Lr:1; /* Limited Retry */\r
+ //\r
+ // CDW 13\r
+ //\r
+ UINT32 Af:4; /* Access Frequency */\r
+ UINT32 Al:2; /* Access Latency */\r
+ UINT32 Sr:1; /* Sequential Request */\r
+ UINT32 In:1; /* Incompressible */\r
+ UINT32 Rsvd2:24;\r
+ //\r
+ // CDW 14\r
+ //\r
+ UINT32 Eilbrt; /* Expected Initial Logical Block Reference Tag */\r
+ //\r
+ // CDW 15\r
+ //\r
+ UINT16 Elbat; /* Expected Logical Block Application Tag */\r
+ UINT16 Elbatm; /* Expected Logical Block Application Tag Mask */\r
+} NVME_READ;\r
+\r
+//\r
+// Write Command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10, 11\r
+ //\r
+ UINT64 Slba; /* Starting Sector Address */\r
+ //\r
+ // CDW 12\r
+ //\r
+ UINT16 Nlb; /* Number of Sectors */\r
+ UINT16 Rsvd1:10;\r
+ UINT16 Prinfo:4; /* Protection Info Check */\r
+ UINT16 Fua:1; /* Force Unit Access */\r
+ UINT16 Lr:1; /* Limited Retry */\r
+ //\r
+ // CDW 13\r
+ //\r
+ UINT32 Af:4; /* Access Frequency */\r
+ UINT32 Al:2; /* Access Latency */\r
+ UINT32 Sr:1; /* Sequential Request */\r
+ UINT32 In:1; /* Incompressible */\r
+ UINT32 Rsvd2:24;\r
+ //\r
+ // CDW 14\r
+ //\r
+ UINT32 Ilbrt; /* Initial Logical Block Reference Tag */\r
+ //\r
+ // CDW 15\r
+ //\r
+ UINT16 Lbat; /* Logical Block Application Tag */\r
+ UINT16 Lbatm; /* Logical Block Application Tag Mask */\r
+} NVME_WRITE;\r
+\r
+//\r
+// Flush\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Flush; /* Flush */\r
+} NVME_FLUSH;\r
+\r
+//\r
+// Write Uncorrectable command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10, 11\r
+ //\r
+ UINT64 Slba; /* Starting LBA */\r
+ //\r
+ // CDW 12\r
+ //\r
+ UINT32 Nlb:16; /* Number of Logical Blocks */\r
+ UINT32 Rsvd1:16;\r
+} NVME_WRITE_UNCORRECTABLE;\r
+\r
+//\r
+// Write Zeroes command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10, 11\r
+ //\r
+ UINT64 Slba; /* Starting LBA */\r
+ //\r
+ // CDW 12\r
+ //\r
+ UINT16 Nlb; /* Number of Logical Blocks */\r
+ UINT16 Rsvd1:10;\r
+ UINT16 Prinfo:4; /* Protection Info Check */\r
+ UINT16 Fua:1; /* Force Unit Access */\r
+ UINT16 Lr:1; /* Limited Retry */\r
+ //\r
+ // CDW 13\r
+ //\r
+ UINT32 Rsvd2;\r
+ //\r
+ // CDW 14\r
+ //\r
+ UINT32 Ilbrt; /* Initial Logical Block Reference Tag */\r
+ //\r
+ // CDW 15\r
+ //\r
+ UINT16 Lbat; /* Logical Block Application Tag */\r
+ UINT16 Lbatm; /* Logical Block Application Tag Mask */\r
+} NVME_WRITE_ZEROES;\r
+\r
+//\r
+// Compare command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10, 11\r
+ //\r
+ UINT64 Slba; /* Starting LBA */\r
+ //\r
+ // CDW 12\r
+ //\r
+ UINT16 Nlb; /* Number of Logical Blocks */\r
+ UINT16 Rsvd1:10;\r
+ UINT16 Prinfo:4; /* Protection Info Check */\r
+ UINT16 Fua:1; /* Force Unit Access */\r
+ UINT16 Lr:1; /* Limited Retry */\r
+ //\r
+ // CDW 13\r
+ //\r
+ UINT32 Rsvd2;\r
+ //\r
+ // CDW 14\r
+ //\r
+ UINT32 Eilbrt; /* Expected Initial Logical Block Reference Tag */\r
+ //\r
+ // CDW 15\r
+ //\r
+ UINT16 Elbat; /* Expected Logical Block Application Tag */\r
+ UINT16 Elbatm; /* Expected Logical Block Application Tag Mask */\r
+} NVME_COMPARE;\r
+\r
+typedef union {\r
+ NVME_READ Read;\r
+ NVME_WRITE Write;\r
+ NVME_FLUSH Flush;\r
+ NVME_WRITE_UNCORRECTABLE WriteUncorrectable;\r
+ NVME_WRITE_ZEROES WriteZeros;\r
+ NVME_COMPARE Compare;\r
+} NVME_CMD;\r
+\r
+typedef struct {\r
+ UINT16 Mp; /* Maximum Power */\r
+ UINT8 Rsvd1; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT8 Mps:1; /* Max Power Scale */\r
+ UINT8 Nops:1; /* Non-Operational State */\r
+ UINT8 Rsvd2:6; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT32 Enlat; /* Entry Latency */\r
+ UINT32 Exlat; /* Exit Latency */\r
+ UINT8 Rrt:5; /* Relative Read Throughput */\r
+ UINT8 Rsvd3:3; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT8 Rrl:5; /* Relative Read Leatency */\r
+ UINT8 Rsvd4:3; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT8 Rwt:5; /* Relative Write Throughput */\r
+ UINT8 Rsvd5:3; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT8 Rwl:5; /* Relative Write Leatency */\r
+ UINT8 Rsvd6:3; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT8 Rsvd7[16]; /* Reserved as of Nvm Express 1.1 Spec */\r
+} NVME_PSDESCRIPTOR;\r
+\r
+//\r
+// Identify Controller Data\r
+//\r
+typedef struct {\r
+ //\r
+ // Controller Capabilities and Features 0-255\r
+ //\r
+ UINT16 Vid; /* PCI Vendor ID */\r
+ UINT16 Ssvid; /* PCI sub-system vendor ID */\r
+ UINT8 Sn[20]; /* Produce serial number */\r
+\r
+ UINT8 Mn[40]; /* Proeduct model number */\r
+ UINT8 Fr[8]; /* Firmware Revision */\r
+ UINT8 Rab; /* Recommended Arbitration Burst */\r
+ UINT8 Ieee_oiu[3]; /* Organization Unique Identifier */\r
+ UINT8 Cmic; /* Multi-interface Capabilities */\r
+ UINT8 Mdts; /* Maximum Data Transfer Size */\r
+ UINT8 Cntlid[2]; /* Controller ID */\r
+ UINT8 Rsvd1[176]; /* Reserved as of Nvm Express 1.1 Spec */\r
+ //\r
+ // Admin Command Set Attributes\r
+ //\r
+ UINT16 Oacs; /* Optional Admin Command Support */\r
+ UINT8 Acl; /* Abort Command Limit */\r
+ UINT8 Aerl; /* Async Event Request Limit */\r
+ UINT8 Frmw; /* Firmware updates */\r
+ UINT8 Lpa; /* Log Page Attributes */\r
+ UINT8 Elpe; /* Error Log Page Entries */\r
+ UINT8 Npss; /* Number of Power States Support */\r
+ UINT8 Avscc; /* Admin Vendor Specific Command Configuration */\r
+ UINT8 Apsta; /* Autonomous Power State Transition Attributes */\r
+ UINT8 Rsvd2[246]; /* Reserved as of Nvm Express 1.1 Spec */\r
+ //\r
+ // NVM Command Set Attributes\r
+ //\r
+ UINT8 Sqes; /* Submission Queue Entry Size */\r
+ UINT8 Cqes; /* Completion Queue Entry Size */\r
+ UINT16 Rsvd3; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT32 Nn; /* Number of Namespaces */\r
+ UINT16 Oncs; /* Optional NVM Command Support */\r
+ UINT16 Fuses; /* Fused Operation Support */\r
+ UINT8 Fna; /* Format NVM Attributes */\r
+ UINT8 Vwc; /* Volatile Write Cache */\r
+ UINT16 Awun; /* Atomic Write Unit Normal */\r
+ UINT16 Awupf; /* Atomic Write Unit Power Fail */\r
+ UINT8 Nvscc; /* NVM Vendor Specific Command Configuration */\r
+ UINT8 Rsvd4; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT16 Acwu; /* Atomic Compare & Write Unit */\r
+ UINT16 Rsvd5; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT32 Sgls; /* SGL Support */\r
+ UINT8 Rsvd6[164]; /* Reserved as of Nvm Express 1.1 Spec */\r
+ //\r
+ // I/O Command set Attributes\r
+ //\r
+ UINT8 Rsvd7[1344]; /* Reserved as of Nvm Express 1.1 Spec */\r
+ //\r
+ // Power State Descriptors\r
+ //\r
+ NVME_PSDESCRIPTOR PsDescriptor[32];\r
+\r
+ UINT8 VendorData[1024]; /* Vendor specific Data */\r
+} NVME_ADMIN_CONTROLLER_DATA;\r
+\r
+typedef struct {\r
+ UINT16 Security : 1; /* supports security send/receive commands */\r
+ UINT16 Format : 1; /* supports format nvm command */\r
+ UINT16 Firmware : 1; /* supports firmware activate/download commands */\r
+ UINT16 Oacs_rsvd : 13;\r
+ } OACS; // optional admin command support: NVME_ADMIN_CONTROLLER_DATA.Oacs\r
+\r
+typedef struct {\r
+ UINT16 Ms; /* Metadata Size */\r
+ UINT8 Lbads; /* LBA Data Size */\r
+ UINT8 Rp:2; /* Relative Performance */\r
+ #define LBAF_RP_BEST 00b\r
+ #define LBAF_RP_BETTER 01b\r
+ #define LBAF_RP_GOOD 10b\r
+ #define LBAF_RP_DEGRADED 11b\r
+ UINT8 Rsvd1:6; /* Reserved as of Nvm Express 1.1 Spec */\r
+} NVME_LBAFORMAT;\r
+\r
+//\r
+// Identify Namespace Data\r
+//\r
+typedef struct {\r
+ //\r
+ // NVM Command Set Specific\r
+ //\r
+ UINT64 Nsze; /* Namespace Size (total number of blocks in formatted namespace) */\r
+ UINT64 Ncap; /* Namespace Capacity (max number of logical blocks) */\r
+ UINT64 Nuse; /* Namespace Utilization */\r
+ UINT8 Nsfeat; /* Namespace Features */\r
+ UINT8 Nlbaf; /* Number of LBA Formats */\r
+ UINT8 Flbas; /* Formatted LBA Size */\r
+ UINT8 Mc; /* Metadata Capabilities */\r
+ UINT8 Dpc; /* End-to-end Data Protection capabilities */\r
+ UINT8 Dps; /* End-to-end Data Protection Type Settings */\r
+ UINT8 Nmic; /* Namespace Multi-path I/O and Namespace Sharing Capabilities */\r
+ UINT8 Rescap; /* Reservation Capabilities */\r
+ UINT8 Rsvd1[88]; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT64 Eui64; /* IEEE Extended Unique Identifier */\r
+ //\r
+ // LBA Format\r
+ //\r
+ NVME_LBAFORMAT LbaFormat[16];\r
+\r
+ UINT8 Rsvd2[192]; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT8 VendorData[3712]; /* Vendor specific Data */\r
+} NVME_ADMIN_NAMESPACE_DATA;\r
+\r
+//\r
+// NvmExpress Admin Identify Cmd\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Cns:2;\r
+ UINT32 Rsvd1:30;\r
+} NVME_ADMIN_IDENTIFY;\r
+\r
+//\r
+// NvmExpress Admin Create I/O Completion Queue\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Qid:16; /* Queue Identifier */\r
+ UINT32 Qsize:16; /* Queue Size */\r
+\r
+ //\r
+ // CDW 11\r
+ //\r
+ UINT32 Pc:1; /* Physically Contiguous */\r
+ UINT32 Ien:1; /* Interrupts Enabled */\r
+ UINT32 Rsvd1:14; /* reserved as of Nvm Express 1.1 Spec */\r
+ UINT32 Iv:16; /* Interrupt Vector */\r
+} NVME_ADMIN_CRIOCQ;\r
+\r
+//\r
+// NvmExpress Admin Create I/O Submission Queue\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Qid:16; /* Queue Identifier */\r
+ UINT32 Qsize:16; /* Queue Size */\r
+\r
+ //\r
+ // CDW 11\r
+ //\r
+ UINT32 Pc:1; /* Physically Contiguous */\r
+ UINT32 Qprio:2; /* Queue Priority */\r
+ UINT32 Rsvd1:13; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT32 Cqid:16; /* Completion Queue ID */\r
+} NVME_ADMIN_CRIOSQ;\r
+\r
+//\r
+// NvmExpress Admin Delete I/O Completion Queue\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT16 Qid;\r
+ UINT16 Rsvd1;\r
+} NVME_ADMIN_DEIOCQ;\r
+\r
+//\r
+// NvmExpress Admin Delete I/O Submission Queue\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT16 Qid;\r
+ UINT16 Rsvd1;\r
+} NVME_ADMIN_DEIOSQ;\r
+\r
+//\r
+// NvmExpress Admin Security Send\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Resv:8; /* Reserve */\r
+ UINT32 Spsp:16; /* SP Specific */\r
+ UINT32 Secp:8; /* Security Protocol */\r
+\r
+ //\r
+ // CDW 11\r
+ //\r
+ UINT32 Tl; /* Transfer Length */\r
+} NVME_ADMIN_SECSEND;\r
+\r
+//\r
+// NvmExpress Admin Abort Command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Sqid:16; /* Submission Queue identifier */\r
+ UINT32 Cid:16; /* Command Identifier */\r
+} NVME_ADMIN_ABORT;\r
+\r
+//\r
+// NvmExpress Admin Firmware Activate Command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Fs:3; /* Submission Queue identifier */\r
+ UINT32 Aa:2; /* Command Identifier */\r
+ UINT32 Rsvd1:27;\r
+} NVME_ADMIN_FIRMWARE_ACTIVATE;\r
+\r
+//\r
+// NvmExpress Admin Firmware Image Download Command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Numd; /* Number of Dwords */\r
+ //\r
+ // CDW 11\r
+ //\r
+ UINT32 Ofst; /* Offset */\r
+} NVME_ADMIN_FIRMWARE_IMAGE_DOWNLOAD;\r
+\r
+//\r
+// NvmExpress Admin Get Features Command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Fid:8; /* Feature Identifier */\r
+ UINT32 Sel:3; /* Select */\r
+ UINT32 Rsvd1:21;\r
+} NVME_ADMIN_GET_FEATURES;\r
+\r
+//\r
+// NvmExpress Admin Get Log Page Command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Lid:8; /* Log Page Identifier */\r
+ #define LID_ERROR_INFO\r
+ #define LID_SMART_INFO\r
+ #define LID_FW_SLOT_INFO\r
+ UINT32 Rsvd1:8;\r
+ UINT32 Numd:12; /* Number of Dwords */\r
+ UINT32 Rsvd2:4; /* Reserved as of Nvm Express 1.1 Spec */\r
+} NVME_ADMIN_GET_LOG_PAGE;\r
+\r
+//\r
+// NvmExpress Admin Set Features Command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Fid:8; /* Feature Identifier */\r
+ UINT32 Rsvd1:23;\r
+ UINT32 Sv:1; /* Save */\r
+} NVME_ADMIN_SET_FEATURES;\r
+\r
+//\r
+// NvmExpress Admin Format NVM Command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Lbaf:4; /* LBA Format */\r
+ UINT32 Ms:1; /* Metadata Settings */\r
+ UINT32 Pi:3; /* Protection Information */\r
+ UINT32 Pil:1; /* Protection Information Location */\r
+ UINT32 Ses:3; /* Secure Erase Settings */\r
+ UINT32 Rsvd1:20;\r
+} NVME_ADMIN_FORMAT_NVM;\r
+\r
+//\r
+// NvmExpress Admin Security Receive Command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Rsvd1:8;\r
+ UINT32 Spsp:16; /* SP Specific */\r
+ UINT32 Secp:8; /* Security Protocol */\r
+ //\r
+ // CDW 11\r
+ //\r
+ UINT32 Al; /* Allocation Length */\r
+} NVME_ADMIN_SECURITY_RECEIVE;\r
+\r
+//\r
+// NvmExpress Admin Security Send Command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Rsvd1:8;\r
+ UINT32 Spsp:16; /* SP Specific */\r
+ UINT32 Secp:8; /* Security Protocol */\r
+ //\r
+ // CDW 11\r
+ //\r
+ UINT32 Tl; /* Transfer Length */\r
+} NVME_ADMIN_SECURITY_SEND;\r
+\r
+typedef union {\r
+ NVME_ADMIN_IDENTIFY Identify;\r
+ NVME_ADMIN_CRIOCQ CrIoCq;\r
+ NVME_ADMIN_CRIOSQ CrIoSq;\r
+ NVME_ADMIN_DEIOCQ DeIoCq;\r
+ NVME_ADMIN_DEIOSQ DeIoSq;\r
+ NVME_ADMIN_ABORT Abort;\r
+ NVME_ADMIN_FIRMWARE_ACTIVATE Activate;\r
+ NVME_ADMIN_FIRMWARE_IMAGE_DOWNLOAD FirmwareImageDownload;\r
+ NVME_ADMIN_GET_FEATURES GetFeatures;\r
+ NVME_ADMIN_GET_LOG_PAGE GetLogPage;\r
+ NVME_ADMIN_SET_FEATURES SetFeatures;\r
+ NVME_ADMIN_FORMAT_NVM FormatNvm;\r
+ NVME_ADMIN_SECURITY_RECEIVE SecurityReceive;\r
+ NVME_ADMIN_SECURITY_SEND SecuritySend;\r
+} NVME_ADMIN_CMD;\r
+\r
+typedef struct {\r
+ UINT32 Cdw10;\r
+ UINT32 Cdw11;\r
+ UINT32 Cdw12;\r
+ UINT32 Cdw13;\r
+ UINT32 Cdw14;\r
+ UINT32 Cdw15;\r
+} NVME_RAW;\r
+\r
+typedef union {\r
+ NVME_ADMIN_CMD Admin; // Union of Admin commands\r
+ NVME_CMD Nvm; // Union of Nvm commands\r
+ NVME_RAW Raw;\r
+} NVME_PAYLOAD;\r
+\r
+//\r
+// Submission Queue\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 0, Common to all comnmands\r
+ //\r
+ UINT8 Opc; // Opcode\r
+ UINT8 Fuse:2; // Fused Operation\r
+ UINT8 Rsvd1:5;\r
+ UINT8 Psdt:1; // PRP or SGL for Data Transfer\r
+ UINT16 Cid; // Command Identifier\r
+\r
+ //\r
+ // CDW 1\r
+ //\r
+ UINT32 Nsid; // Namespace Identifier\r
+\r
+ //\r
+ // CDW 2,3\r
+ //\r
+ UINT64 Rsvd2;\r
+\r
+ //\r
+ // CDW 4,5\r
+ //\r
+ UINT64 Mptr; // Metadata Pointer\r
+\r
+ //\r
+ // CDW 6-9\r
+ //\r
+ UINT64 Prp[2]; // First and second PRP entries\r
+\r
+ NVME_PAYLOAD Payload;\r
+\r
+} NVME_SQ;\r
+\r
+//\r
+// Completion Queue\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 0\r
+ //\r
+ UINT32 Dword0;\r
+ //\r
+ // CDW 1\r
+ //\r
+ UINT32 Rsvd1;\r
+ //\r
+ // CDW 2\r
+ //\r
+ UINT16 Sqhd; // Submission Queue Head Pointer\r
+ UINT16 Sqid; // Submission Queue Identifier\r
+ //\r
+ // CDW 3\r
+ //\r
+ UINT16 Cid; // Command Identifier\r
+ UINT16 Pt:1; // Phase Tag\r
+ UINT16 Sc:8; // Status Code\r
+ UINT16 Sct:3; // Status Code Type\r
+ UINT16 Rsvd2:2;\r
+ UINT16 Mo:1; // More\r
+ UINT16 Dnr:1; // Retry\r
+} NVME_CQ;\r
+\r
+//\r
+// Nvm Express Admin cmd opcodes\r
+//\r
+#define NVME_ADMIN_DELIOSQ_OPC 0\r
+#define NVME_ADMIN_CRIOSQ_OPC 1\r
+#define NVME_ADMIN_DELIOCQ_OPC 4\r
+#define NVME_ADMIN_CRIOCQ_OPC 5\r
+#define NVME_ADMIN_IDENTIFY_OPC 6\r
+#define NVME_ADMIN_SECURITY_SEND_OPC 0x81\r
+#define NVME_ADMIN_SECURITY_RECV_OPC 0x82\r
+\r
+#define NVME_IO_FLUSH_OPC 0\r
+#define NVME_IO_WRITE_OPC 1\r
+#define NVME_IO_READ_OPC 2\r
+\r
+//\r
+// Offset from the beginning of private Data queue Buffer\r
+//\r
+#define NVME_ASQ_BUF_OFFSET EFI_PAGE_SIZE\r
+\r
+#pragma pack()\r
+\r
+#endif\r
+\r
--- /dev/null
+/** @file\r
+ Opal Password common header file.\r
+\r
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _OPAL_PASSWORD_COMMON_H_\r
+#define _OPAL_PASSWORD_COMMON_H_\r
+\r
+#define OPAL_MAX_PASSWORD_SIZE 32\r
+\r
+#define OPAL_DEVICE_TYPE_UNKNOWN 0x0\r
+#define OPAL_DEVICE_TYPE_ATA 0x1\r
+#define OPAL_DEVICE_TYPE_NVME 0x2\r
+\r
+typedef struct {\r
+ UINT16 Segment;\r
+ UINT8 Bus;\r
+ UINT8 Device;\r
+ UINT8 Function;\r
+ UINT8 Reserved;\r
+} OPAL_PCI_DEVICE;\r
+\r
+typedef struct {\r
+ UINT16 Length;\r
+ OPAL_PCI_DEVICE Device;\r
+ UINT8 PasswordLength;\r
+ UINT8 Password[OPAL_MAX_PASSWORD_SIZE];\r
+ UINT16 OpalBaseComId;\r
+ UINT32 BarAddr;\r
+} OPAL_DEVICE_COMMON;\r
+\r
+#define OPAL_DEVICE_ATA_GUID { 0xcb934fe1, 0xb8cd, 0x46b1, { 0xa0, 0x58, 0xdd, 0xcb, 0x7, 0xb7, 0xb4, 0x17 } }\r
+\r
+typedef struct {\r
+ UINT16 Length;\r
+ OPAL_PCI_DEVICE Device;\r
+ UINT8 PasswordLength;\r
+ UINT8 Password[OPAL_MAX_PASSWORD_SIZE];\r
+ UINT16 OpalBaseComId;\r
+ UINT32 BarAddr;\r
+ UINT16 Port;\r
+ UINT16 PortMultiplierPort;\r
+} OPAL_DEVICE_ATA;\r
+\r
+#define OPAL_DEVICE_NVME_GUID { 0xde116925, 0xaf7f, 0x42d9, { 0x83, 0xc0, 0x7e, 0xd6, 0x26, 0x59, 0x0, 0xfb } }\r
+\r
+typedef struct {\r
+ UINT16 Length;\r
+ OPAL_PCI_DEVICE Device;\r
+ UINT8 PasswordLength;\r
+ UINT8 Password[OPAL_MAX_PASSWORD_SIZE];\r
+ UINT16 OpalBaseComId;\r
+ UINT32 BarAddr;\r
+ UINT32 NvmeNamespaceId;\r
+ OPAL_PCI_DEVICE PciBridgeNode[0];\r
+} OPAL_DEVICE_NVME;\r
+\r
+#endif // _OPAL_PASSWORD_COMMON_H_\r
--- /dev/null
+## @file\r
+# This is a OpalPasswordDxe driver.\r
+#\r
+# This module is used to Management the Opal feature\r
+# for Opal supported devices.\r
+#\r
+# Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+[Defines]\r
+ INF_VERSION = 0x00010007\r
+ BASE_NAME = OpalPasswordDxe\r
+ FILE_GUID = E3E4048D-6C0C-43E4-AE1C-FFB579D8EF41\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ ENTRY_POINT = EfiDriverEntryPoint\r
+ UNLOAD_IMAGE = OpalEfiDriverUnload\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ OpalDriver.c\r
+ OpalDriver.h\r
+ OpalPasswordCommon.h\r
+ OpalHii.c\r
+ OpalHii.h\r
+ OpalHiiCallbacks.c\r
+ OpalHiiFormValues.h\r
+ OpalHiiFormStrings.uni\r
+ OpalPasswordForm.vfr\r
+ ComponentName.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+ SecurityPkg/SecurityPkg.dec\r
+\r
+[LibraryClasses]\r
+ BaseLib\r
+ MemoryAllocationLib\r
+ UefiBootServicesTableLib\r
+ UefiDriverEntryPoint\r
+ UefiRuntimeServicesTableLib\r
+ DxeServicesTableLib\r
+ UefiHiiServicesLib\r
+ BaseMemoryLib\r
+ DebugLib\r
+ HiiLib\r
+ PrintLib\r
+ DevicePathLib\r
+ UefiLib\r
+ TcgStorageOpalLib\r
+ Tcg2PhysicalPresenceLib\r
+ PciLib\r
+ S3BootScriptLib\r
+ LockBoxLib\r
+\r
+[Protocols]\r
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES\r
+ gEfiStorageSecurityCommandProtocolGuid ## CONSUMES\r
+ gEfiComponentNameProtocolGuid ## PRODUCES\r
+ gEfiComponentName2ProtocolGuid ## PRODUCES\r
+ gEfiBlockIoProtocolGuid ## CONSUMES\r
+ gEfiPciIoProtocolGuid ## CONSUMES\r
+ gEfiDevicePathToTextProtocolGuid ## CONSUMES\r
+\r
+[Guids]\r
+ gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event\r
+\r
+[Depex]\r
+ gEfiHiiStringProtocolGuid AND gEfiHiiDatabaseProtocolGuid\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#include "OpalHiiFormValues.h"\r
+\r
+\r
+#define EFI_HII_PLATFORM_SETUP_FORMSET_GUID \\r
+ { 0x93039971, 0x8545, 0x4b04, { 0xb4, 0x5e, 0x32, 0xeb, 0x83, 0x26, 0x4, 0xe } }\r
+\r
+formset\r
+ guid = SETUP_FORMSET_GUID,\r
+ title = STRING_TOKEN(STR_OPAL),\r
+ help = STRING_TOKEN(STR_FORM_SET_HELP),\r
+ classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,\r
+\r
+ // Define a Buffer Storage (EFI_IFR_VARSTORE) that will be filled\r
+ // out initially through extractConfig call\r
+ varstore OPAL_HII_CONFIGURATION, // This is the Data structure type\r
+ name = OpalHiiConfig, // Define referenced name in vfr\r
+ guid = SETUP_VARIABLE_GUID; // GUID of this Buffer storage\r
+\r
+form formid = FORMID_VALUE_MAIN_MENU,\r
+ title = STRING_TOKEN(STR_OPAL);\r
+\r
+ //CONFIG_VARIABLE(HII_KEY(HII_KEY_ID_VAR_SUPPORTED_DISKS), SupportedDisks, 0x0, 0xFFFF);\r
+ suppressif TRUE;\r
+ numeric\r
+ name = SupportedDisks,\r
+ varid = OpalHiiConfig.SupportedDisks,\r
+ prompt = STRING_TOKEN(STR_NULL),\r
+ help = STRING_TOKEN(STR_NULL),\r
+ flags = INTERACTIVE,\r
+ key = 0x8002,\r
+ minimum = 0x0,\r
+ maximum = 0xFFFF,\r
+ endnumeric;\r
+ endif;\r
+\r
+ subtitle text = STRING_TOKEN(STR_MAIN_OPAL_VERSION);\r
+\r
+ subtitle text = STRING_TOKEN(STR_NULL);\r
+\r
+ subtitle text = STRING_TOKEN(STR_MAIN_PHY_DISKS_LBL);\r
+\r
+ //DISK( 0 );\r
+ suppressif ( questionref(SupportedDisks) & ( 0x1 ) ) == 0;\r
+ goto FORMID_VALUE_DISK_INFO_FORM_MAIN,\r
+ prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_0 ),\r
+ help = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP),\r
+ flags = INTERACTIVE,\r
+ key = 0x8001;\r
+ endif;\r
+\r
+ //DISK( 1 );\r
+ suppressif ( questionref(SupportedDisks) & ( 0x2 ) ) == 0;\r
+ goto FORMID_VALUE_DISK_INFO_FORM_MAIN,\r
+ prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_1 ),\r
+ help = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP),\r
+ flags = INTERACTIVE,\r
+ key = 0x8101;\r
+ endif;\r
+\r
+ //DISK( 2 );\r
+ suppressif ( questionref(SupportedDisks) & ( 0x4 ) ) == 0;\r
+ goto FORMID_VALUE_DISK_INFO_FORM_MAIN,\r
+ prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_2 ),\r
+ help = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP),\r
+ flags = INTERACTIVE,\r
+ key = 0x8201;\r
+ endif;\r
+\r
+ //DISK( 3 );\r
+ suppressif ( questionref(SupportedDisks) & ( 0x8 ) ) == 0;\r
+ goto FORMID_VALUE_DISK_INFO_FORM_MAIN,\r
+ prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_3 ),\r
+ help = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP),\r
+ flags = INTERACTIVE,\r
+ key = 0x8301;\r
+ endif;\r
+\r
+ //DISK( 4 );\r
+ suppressif ( questionref(SupportedDisks) & ( 0x10 ) ) == 0;\r
+ goto FORMID_VALUE_DISK_INFO_FORM_MAIN,\r
+ prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_4 ),\r
+ help = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP),\r
+ flags = INTERACTIVE,\r
+ key = 0x8401;\r
+ endif;\r
+\r
+ //DISK( 5 );\r
+ suppressif ( questionref(SupportedDisks) & ( 0x20 ) ) == 0;\r
+ goto FORMID_VALUE_DISK_INFO_FORM_MAIN,\r
+ prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_5 ),\r
+ help = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP),\r
+ flags = INTERACTIVE,\r
+ key = 0x8501;\r
+ endif;\r
+\r
+ //No disks on system\r
+ suppressif ideqval OpalHiiConfig.NumDisks > 0;\r
+ text\r
+ help = STRING_TOKEN(STR_MAIN_NO_DISKS_PRESENT_LBL_HELP),\r
+ text = STRING_TOKEN(STR_MAIN_NO_DISKS_PRESENT_LBL);\r
+ endif;\r
+\r
+ subtitle text = STRING_TOKEN(STR_NULL);\r
+\r
+ grayoutif TRUE;\r
+ text\r
+ help = STRING_TOKEN(STR_BLOCKSID_STATUS_HELP),\r
+ text = STRING_TOKEN(STR_BLOCKSID_STATUS);\r
+ text\r
+ help = STRING_TOKEN(STR_BLOCKSID_STATUS_HELP),\r
+ text = STRING_TOKEN(STR_BLOCKSID_STATUS1);\r
+ text\r
+ help = STRING_TOKEN(STR_BLOCKSID_STATUS_HELP),\r
+ text = STRING_TOKEN(STR_BLOCKSID_STATUS2);\r
+ text\r
+ help = STRING_TOKEN(STR_BLOCKSID_STATUS_HELP),\r
+ text = STRING_TOKEN(STR_BLOCKSID_STATUS3);\r
+ subtitle text = STRING_TOKEN(STR_NULL);\r
+ endif;\r
+\r
+ oneof varid = OpalHiiConfig.EnableBlockSid,\r
+ questionid = 0x8004,\r
+ prompt = STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID),\r
+ help = STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_HELP),\r
+ flags = INTERACTIVE,\r
+ option text = STRING_TOKEN(STR_NONE), value = 0, flags = DEFAULT | MANUFACTURING | RESET_REQUIRED;\r
+ option text = STRING_TOKEN(STR_ENABLED), value = 1, flags = RESET_REQUIRED;\r
+ option text = STRING_TOKEN(STR_DISABLED), value = 2, flags = RESET_REQUIRED;\r
+ option text = STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_TRUE), value = 3, flags = RESET_REQUIRED;\r
+ option text = STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_FALSE), value = 4, flags = RESET_REQUIRED;\r
+ option text = STRING_TOKEN(STR_DISK_INFO_DISABLE_BLOCKSID_TRUE), value = 5, flags = RESET_REQUIRED;\r
+ option text = STRING_TOKEN(STR_DISK_INFO_DISABLE_BLOCKSID_FALSE), value = 6, flags = RESET_REQUIRED;\r
+ endoneof;\r
+\r
+\r
+\r
+endform; // MAIN MENU FORM\r
+\r
+//\r
+///////////////// DISK INFO FORM /////////////////\r
+//\r
+form formid = FORMID_VALUE_DISK_INFO_FORM_MAIN,\r
+ title = STRING_TOKEN(STR_OPAL);\r
+\r
+ suppressif TRUE;\r
+ numeric\r
+ name = SelectedDiskAvailableActions,\r
+ varid = OpalHiiConfig.SelectedDiskAvailableActions,\r
+ prompt = STRING_TOKEN(STR_NULL),\r
+ help = STRING_TOKEN(STR_NULL),\r
+ flags = INTERACTIVE,\r
+ key = 0x8003,\r
+ minimum = 0x0,\r
+ maximum = 0xFFFF,\r
+ endnumeric;\r
+ endif;\r
+\r
+ suppressif TRUE;\r
+ checkbox varid = OpalHiiConfig.KeepUserDataForced,\r
+ prompt = STRING_TOKEN(STR_NULL),\r
+ help = STRING_TOKEN(STR_NULL),\r
+ endcheckbox;\r
+ endif;\r
+\r
+ subtitle text = STRING_TOKEN(STR_MAIN_OPAL_VERSION);\r
+\r
+ subtitle text = STRING_TOKEN(STR_NULL);\r
+\r
+ text\r
+ help = STRING_TOKEN(STR_NULL),\r
+ text = STRING_TOKEN(STR_DISK_INFO_SELECTED_DISK_NAME);\r
+\r
+ subtitle text = STRING_TOKEN(STR_NULL);\r
+\r
+ subtitle text = STRING_TOKEN(STR_OPAL_REQUESTS_LBL);\r
+\r
+ suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_SET_ADMIN_PWD ) == 0;\r
+ grayoutif ideqval OpalHiiConfig.OpalRequest.Revert == 1;\r
+ grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert == 1;\r
+ checkbox varid = OpalHiiConfig.OpalRequest.SetAdminPwd,\r
+ prompt = STRING_TOKEN(STR_DISK_INFO_SET_ADMIN_PSWD),\r
+ help = STRING_TOKEN(STR_DISK_INFO_SET_ADMIN_PSWD_HELP),\r
+ flags = INTERACTIVE | RESET_REQUIRED,\r
+ key = 0x8005,\r
+ endcheckbox;\r
+ endif;\r
+ endif;\r
+ endif;\r
+\r
+ suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_SET_USER_PWD ) == 0;\r
+ grayoutif ideqval OpalHiiConfig.OpalRequest.DisableUser == 1;\r
+ grayoutif ideqval OpalHiiConfig.OpalRequest.Revert == 1;\r
+ grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert == 1;\r
+ checkbox varid = OpalHiiConfig.OpalRequest.SetUserPwd,\r
+ prompt = STRING_TOKEN(STR_DISK_INFO_SET_USER_PSWD),\r
+ help = STRING_TOKEN(STR_DISK_INFO_SET_USER_PSWD_HELP),\r
+ flags = INTERACTIVE | RESET_REQUIRED,\r
+ key = 0x8006,\r
+ endcheckbox;\r
+ endif;\r
+ endif;\r
+ endif;\r
+ endif;\r
+\r
+ suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_SECURE_ERASE ) == 0;\r
+ grayoutif ideqval OpalHiiConfig.OpalRequest.Revert == 1;\r
+ grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert == 1;\r
+ checkbox varid = OpalHiiConfig.OpalRequest.SecureErase,\r
+ prompt = STRING_TOKEN(STR_DISK_INFO_SECURE_ERASE),\r
+ help = STRING_TOKEN(STR_DISK_INFO_SECURE_ERASE_HELP),\r
+ flags = INTERACTIVE | RESET_REQUIRED,\r
+ key = 0x8007,\r
+ endcheckbox;\r
+ endif;\r
+ endif;\r
+ endif;\r
+\r
+ suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_REVERT ) == 0;\r
+ grayoutif ideqval OpalHiiConfig.OpalRequest.SetAdminPwd == 1;\r
+ grayoutif ideqval OpalHiiConfig.OpalRequest.SetUserPwd == 1;\r
+ grayoutif ideqval OpalHiiConfig.OpalRequest.SecureErase == 1;\r
+ grayoutif ideqval OpalHiiConfig.OpalRequest.DisableUser == 1;\r
+ grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert == 1;\r
+ checkbox varid = OpalHiiConfig.OpalRequest.Revert,\r
+ prompt = STRING_TOKEN(STR_DISK_INFO_REVERT),\r
+ help = STRING_TOKEN(STR_DISK_INFO_REVERT_HELP),\r
+ flags = INTERACTIVE | RESET_REQUIRED,\r
+ key = 0x8008,\r
+ endcheckbox;\r
+ endif;\r
+ endif;\r
+ endif;\r
+ endif;\r
+ endif;\r
+ endif;\r
+\r
+ suppressif ideqval OpalHiiConfig.OpalRequest.Revert == 0;\r
+ grayoutif ideqval OpalHiiConfig.KeepUserDataForced == 1;\r
+ checkbox varid = OpalHiiConfig.OpalRequest.KeepUserData,\r
+ prompt = STRING_TOKEN(STR_KEEP_USER_DATA_PROMPT),\r
+ help = STRING_TOKEN(STR_KEEP_USER_DATA_HELP),\r
+ flags = INTERACTIVE | RESET_REQUIRED,\r
+ key = 0x8009,\r
+ endcheckbox;\r
+ endif;\r
+ endif;\r
+\r
+ suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_PSID_REVERT ) == 0;\r
+ grayoutif ideqval OpalHiiConfig.OpalRequest.SetAdminPwd == 1;\r
+ grayoutif ideqval OpalHiiConfig.OpalRequest.SetUserPwd == 1;\r
+ grayoutif ideqval OpalHiiConfig.OpalRequest.SecureErase == 1;\r
+ grayoutif ideqval OpalHiiConfig.OpalRequest.DisableUser == 1;\r
+ grayoutif ideqval OpalHiiConfig.OpalRequest.EnableFeature == 1;\r
+ grayoutif ideqval OpalHiiConfig.OpalRequest.Revert == 1;\r
+ checkbox varid = OpalHiiConfig.OpalRequest.PsidRevert,\r
+ prompt = STRING_TOKEN(STR_DISK_INFO_PSID_REVERT),\r
+ help = STRING_TOKEN(STR_DISK_INFO_PSID_REVERT_HELP),\r
+ flags = INTERACTIVE | RESET_REQUIRED,\r
+ key = 0x800A,\r
+ endcheckbox;\r
+ endif;\r
+ endif;\r
+ endif;\r
+ endif;\r
+ endif;\r
+ endif;\r
+ endif;\r
+\r
+ suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_DISABLE_USER ) == 0;\r
+ grayoutif ideqval OpalHiiConfig.OpalRequest.SetUserPwd == 1;\r
+ grayoutif ideqval OpalHiiConfig.OpalRequest.Revert == 1;\r
+ grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert == 1;\r
+ checkbox varid = OpalHiiConfig.OpalRequest.DisableUser,\r
+ prompt = STRING_TOKEN(STR_DISK_INFO_DISABLE_USER),\r
+ help = STRING_TOKEN(STR_DISK_INFO_DISABLE_USER_HELP),\r
+ flags = INTERACTIVE | RESET_REQUIRED,\r
+ key = 0x800B,\r
+ endcheckbox;\r
+ endif;\r
+ endif;\r
+ endif;\r
+ endif;\r
+\r
+ suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_ENABLE_FEATURE ) == 0;\r
+ grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert == 1;\r
+ checkbox varid = OpalHiiConfig.OpalRequest.EnableFeature,\r
+ prompt = STRING_TOKEN(STR_DISK_INFO_ENABLE_FEATURE),\r
+ help = STRING_TOKEN(STR_DISK_INFO_ENABLE_FEATURE_HELP),\r
+ flags = INTERACTIVE | RESET_REQUIRED,\r
+ key = 0x800C,\r
+ endcheckbox;\r
+ endif;\r
+ endif;\r
+\r
+endform; // DISK INFO FORM\r
+\r
+endformset;\r
--- /dev/null
+/** @file\r
+ Opal Password PEI driver which is used to unlock Opal Password for S3.\r
+\r
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "OpalPasswordPei.h"\r
+\r
+EFI_GUID mOpalDeviceAtaGuid = OPAL_DEVICE_ATA_GUID;\r
+EFI_GUID mOpalDeviceNvmeGuid = OPAL_DEVICE_NVME_GUID;\r
+\r
+#define OPAL_PCIE_ROOTPORT_SAVESIZE (0x40)\r
+#define STORE_INVALID_ROOTPORT_INDEX ((UINT8) -1)\r
+\r
+/**\r
+ Get IOMMU PPI.\r
+\r
+ @return Pointer to IOMMU PPI.\r
+\r
+**/\r
+EDKII_IOMMU_PPI *\r
+GetIoMmu (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EDKII_IOMMU_PPI *IoMmu;\r
+\r
+ IoMmu = NULL;\r
+ Status = PeiServicesLocatePpi (\r
+ &gEdkiiIoMmuPpiGuid,\r
+ 0,\r
+ NULL,\r
+ (VOID **) &IoMmu\r
+ );\r
+ if (!EFI_ERROR (Status) && (IoMmu != NULL)) {\r
+ return IoMmu;\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or\r
+ OperationBusMasterCommonBuffer64 mapping.\r
+\r
+ @param Pages The number of pages to allocate.\r
+ @param HostAddress A pointer to store the base system memory address of the\r
+ allocated range.\r
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to\r
+ access the hosts HostAddress.\r
+ @param Mapping A resulting value to pass to Unmap().\r
+\r
+ @retval EFI_SUCCESS The requested memory pages were allocated.\r
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are\r
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+IoMmuAllocateBuffer (\r
+ IN UINTN Pages,\r
+ OUT VOID **HostAddress,\r
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
+ OUT VOID **Mapping\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN NumberOfBytes;\r
+ EFI_PHYSICAL_ADDRESS HostPhyAddress;\r
+ EDKII_IOMMU_PPI *IoMmu;\r
+\r
+ *HostAddress = NULL;\r
+ *DeviceAddress = 0;\r
+ *Mapping = NULL;\r
+\r
+ IoMmu = GetIoMmu ();\r
+\r
+ if (IoMmu != NULL) {\r
+ Status = IoMmu->AllocateBuffer (\r
+ IoMmu,\r
+ EfiBootServicesData,\r
+ Pages,\r
+ HostAddress,\r
+ 0\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ NumberOfBytes = EFI_PAGES_TO_SIZE (Pages);\r
+ Status = IoMmu->Map (\r
+ IoMmu,\r
+ EdkiiIoMmuOperationBusMasterCommonBuffer,\r
+ *HostAddress,\r
+ &NumberOfBytes,\r
+ DeviceAddress,\r
+ Mapping\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);\r
+ *HostAddress = NULL;\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ Status = IoMmu->SetAttribute (\r
+ IoMmu,\r
+ *Mapping,\r
+ EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ IoMmu->Unmap (IoMmu, *Mapping);\r
+ IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);\r
+ *Mapping = NULL;\r
+ *HostAddress = NULL;\r
+ return Status;\r
+ }\r
+ } else {\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesData,\r
+ Pages,\r
+ &HostPhyAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ *HostAddress = (VOID *) (UINTN) HostPhyAddress;\r
+ *DeviceAddress = HostPhyAddress;\r
+ *Mapping = NULL;\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Frees memory that was allocated with AllocateBuffer().\r
+\r
+ @param Pages The number of pages to free.\r
+ @param HostAddress The base system memory address of the allocated range.\r
+ @param Mapping The mapping value returned from Map().\r
+\r
+**/\r
+VOID\r
+IoMmuFreeBuffer (\r
+ IN UINTN Pages,\r
+ IN VOID *HostAddress,\r
+ IN VOID *Mapping\r
+ )\r
+{\r
+ EDKII_IOMMU_PPI *IoMmu;\r
+\r
+ IoMmu = GetIoMmu ();\r
+\r
+ if (IoMmu != NULL) {\r
+ IoMmu->SetAttribute (IoMmu, Mapping, 0);\r
+ IoMmu->Unmap (IoMmu, Mapping);\r
+ IoMmu->FreeBuffer (IoMmu, Pages, HostAddress);\r
+ } else {\r
+ PeiServicesFreePages (\r
+ (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress,\r
+ Pages\r
+ );\r
+ }\r
+}\r
+\r
+/**\r
+ Provide IO action support.\r
+\r
+ @param[in] PeiDev The opal device need to perform trusted IO.\r
+ @param[in] IoType OPAL_IO_TYPE indicating whether to perform a Trusted Send or Trusted Receive.\r
+ @param[in] SecurityProtocol Security Protocol\r
+ @param[in] SpSpecific Security Protocol Specific\r
+ @param[in] TransferLength Transfer Length of Buffer (in bytes) - always a multiple of 512\r
+ @param[in] Buffer Address of Data to transfer\r
+\r
+ @retval EFI_SUCCESS Perform the IO action success.\r
+ @retval Others Perform the IO action failed.\r
+\r
+**/\r
+EFI_STATUS\r
+PerformTrustedIo (\r
+ OPAL_PEI_DEVICE *PeiDev,\r
+ OPAL_IO_TYPE IoType,\r
+ UINT8 SecurityProtocol,\r
+ UINT16 SpSpecific,\r
+ UINTN TransferLength,\r
+ VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN BufferSizeBlocks;\r
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
+ OPAL_DEVICE_ATA *DevInfoAta;\r
+ AHCI_CONTEXT *AhciContext;\r
+ NVME_CONTEXT *NvmeContext;\r
+\r
+ Status = EFI_DEVICE_ERROR;\r
+ if (PeiDev->DeviceType == OPAL_DEVICE_TYPE_ATA) {\r
+ DevInfoAta = (OPAL_DEVICE_ATA *) PeiDev->Device;\r
+ AhciContext = (AHCI_CONTEXT *) PeiDev->Context;\r
+\r
+ BufferSizeBlocks = TransferLength / 512;\r
+\r
+ ZeroMem( &AtaCommandBlock, sizeof( EFI_ATA_COMMAND_BLOCK ) );\r
+ AtaCommandBlock.AtaCommand = ( IoType == OpalSend ) ? ATA_COMMAND_TRUSTED_SEND : ATA_COMMAND_TRUSTED_RECEIVE;\r
+ AtaCommandBlock.AtaSectorCount = ( UINT8 )BufferSizeBlocks;\r
+ AtaCommandBlock.AtaSectorNumber = ( UINT8 )( BufferSizeBlocks >> 8 );\r
+ AtaCommandBlock.AtaFeatures = SecurityProtocol;\r
+ AtaCommandBlock.AtaCylinderLow = ( UINT8 )( SpSpecific >> 8 );\r
+ AtaCommandBlock.AtaCylinderHigh = ( UINT8 )( SpSpecific );\r
+ AtaCommandBlock.AtaDeviceHead = ATA_DEVICE_LBA;\r
+\r
+\r
+ ZeroMem( AhciContext->Buffer, HDD_PAYLOAD );\r
+ ASSERT( TransferLength <= HDD_PAYLOAD );\r
+\r
+ if (IoType == OpalSend) {\r
+ CopyMem( AhciContext->Buffer, Buffer, TransferLength );\r
+ }\r
+\r
+ Status = AhciPioTransfer(\r
+ AhciContext,\r
+ (UINT8) DevInfoAta->Port,\r
+ (UINT8) DevInfoAta->PortMultiplierPort,\r
+ NULL,\r
+ 0,\r
+ ( IoType == OpalSend ) ? FALSE : TRUE, // i/o direction\r
+ &AtaCommandBlock,\r
+ NULL,\r
+ AhciContext->Buffer,\r
+ (UINT32)TransferLength,\r
+ ATA_TIMEOUT\r
+ );\r
+\r
+ if (IoType == OpalRecv) {\r
+ CopyMem( Buffer, AhciContext->Buffer, TransferLength );\r
+ }\r
+ } else if (PeiDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {\r
+ NvmeContext = (NVME_CONTEXT *) PeiDev->Context;\r
+ Status = NvmeSecuritySendReceive (\r
+ NvmeContext,\r
+ IoType == OpalSend,\r
+ SecurityProtocol,\r
+ SwapBytes16(SpSpecific),\r
+ TransferLength,\r
+ Buffer\r
+ );\r
+ } else {\r
+ DEBUG((DEBUG_ERROR, "DeviceType(%x) not support.\n", PeiDev->DeviceType));\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send a security protocol command to a device that receives data and/or the result\r
+ of one or more commands sent by SendData.\r
+\r
+ The ReceiveData function sends a security protocol command to the given MediaId.\r
+ The security protocol command sent is defined by SecurityProtocolId and contains\r
+ the security protocol specific data SecurityProtocolSpecificData. The function\r
+ returns the data from the security protocol command in PayloadBuffer.\r
+\r
+ For devices supporting the SCSI command set, the security protocol command is sent\r
+ using the SECURITY PROTOCOL IN command defined in SPC-4.\r
+\r
+ For devices supporting the ATA command set, the security protocol command is sent\r
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize\r
+ is non-zero.\r
+\r
+ If the PayloadBufferSize is zero, the security protocol command is sent using the\r
+ Trusted Non-Data command defined in ATA8-ACS.\r
+\r
+ If PayloadBufferSize is too small to store the available data from the security\r
+ protocol command, the function shall copy PayloadBufferSize bytes into the\r
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.\r
+\r
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,\r
+ the function shall return EFI_INVALID_PARAMETER.\r
+\r
+ If the given MediaId does not support security protocol commands, the function shall\r
+ return EFI_UNSUPPORTED. If there is no media in the device, the function returns\r
+ EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,\r
+ the function returns EFI_MEDIA_CHANGED.\r
+\r
+ If the security protocol fails to complete within the Timeout period, the function\r
+ shall return EFI_TIMEOUT.\r
+\r
+ If the security protocol command completes without an error, the function shall\r
+ return EFI_SUCCESS. If the security protocol command completes with an error, the\r
+ function shall return EFI_DEVICE_ERROR.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId ID of the medium to receive data from.\r
+ @param Timeout The timeout, in 100ns units, to use for the execution\r
+ of the security protocol command. A Timeout value of 0\r
+ means that this function will wait indefinitely for the\r
+ security protocol command to execute. If Timeout is greater\r
+ than zero, then this function will return EFI_TIMEOUT\r
+ if the time required to execute the receive data command\r
+ is greater than Timeout.\r
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of\r
+ the security protocol command to be sent.\r
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
+ of the security protocol command to be sent.\r
+ @param PayloadBufferSize Size in bytes of the payload data buffer.\r
+ @param PayloadBuffer A pointer to a destination buffer to store the security\r
+ protocol command specific payload data for the security\r
+ protocol command. The caller is responsible for having\r
+ either implicit or explicit ownership of the buffer.\r
+ @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the\r
+ data written to the payload data buffer.\r
+\r
+ @retval EFI_SUCCESS The security protocol command completed successfully.\r
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available\r
+ data from the device. The PayloadBuffer contains the truncated data.\r
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.\r
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and\r
+ PayloadBufferSize is non-zero.\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security\r
+ protocol command to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SecurityReceiveData (\r
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN UINT64 Timeout,\r
+ IN UINT8 SecurityProtocolId,\r
+ IN UINT16 SecurityProtocolSpecificData,\r
+ IN UINTN PayloadBufferSize,\r
+ OUT VOID *PayloadBuffer,\r
+ OUT UINTN *PayloadTransferSize\r
+ )\r
+{\r
+ OPAL_PEI_DEVICE *PeiDev;\r
+\r
+ PeiDev = OPAL_PEI_DEVICE_FROM_THIS (This);\r
+ if (PeiDev == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return PerformTrustedIo (\r
+ PeiDev,\r
+ OpalRecv,\r
+ SecurityProtocolId,\r
+ SecurityProtocolSpecificData,\r
+ PayloadBufferSize,\r
+ PayloadBuffer\r
+ );\r
+}\r
+\r
+/**\r
+ Send a security protocol command to a device.\r
+\r
+ The SendData function sends a security protocol command containing the payload\r
+ PayloadBuffer to the given MediaId. The security protocol command sent is\r
+ defined by SecurityProtocolId and contains the security protocol specific data\r
+ SecurityProtocolSpecificData. If the underlying protocol command requires a\r
+ specific padding for the command payload, the SendData function shall add padding\r
+ bytes to the command payload to satisfy the padding requirements.\r
+\r
+ For devices supporting the SCSI command set, the security protocol command is sent\r
+ using the SECURITY PROTOCOL OUT command defined in SPC-4.\r
+\r
+ For devices supporting the ATA command set, the security protocol command is sent\r
+ using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize\r
+ is non-zero. If the PayloadBufferSize is zero, the security protocol command is\r
+ sent using the Trusted Non-Data command defined in ATA8-ACS.\r
+\r
+ If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall\r
+ return EFI_INVALID_PARAMETER.\r
+\r
+ If the given MediaId does not support security protocol commands, the function\r
+ shall return EFI_UNSUPPORTED. If there is no media in the device, the function\r
+ returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the\r
+ device, the function returns EFI_MEDIA_CHANGED.\r
+\r
+ If the security protocol fails to complete within the Timeout period, the function\r
+ shall return EFI_TIMEOUT.\r
+\r
+ If the security protocol command completes without an error, the function shall return\r
+ EFI_SUCCESS. If the security protocol command completes with an error, the function\r
+ shall return EFI_DEVICE_ERROR.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId ID of the medium to receive data from.\r
+ @param Timeout The timeout, in 100ns units, to use for the execution\r
+ of the security protocol command. A Timeout value of 0\r
+ means that this function will wait indefinitely for the\r
+ security protocol command to execute. If Timeout is greater\r
+ than zero, then this function will return EFI_TIMEOUT\r
+ if the time required to execute the send data command\r
+ is greater than Timeout.\r
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of\r
+ the security protocol command to be sent.\r
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
+ of the security protocol command to be sent.\r
+ @param PayloadBufferSize Size in bytes of the payload data buffer.\r
+ @param PayloadBuffer A pointer to a destination buffer to store the security\r
+ protocol command specific payload data for the security\r
+ protocol command.\r
+\r
+ @retval EFI_SUCCESS The security protocol command completed successfully.\r
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.\r
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security\r
+ protocol command to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SecuritySendData (\r
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN UINT64 Timeout,\r
+ IN UINT8 SecurityProtocolId,\r
+ IN UINT16 SecurityProtocolSpecificData,\r
+ IN UINTN PayloadBufferSize,\r
+ IN VOID *PayloadBuffer\r
+ )\r
+{\r
+ OPAL_PEI_DEVICE *PeiDev;\r
+\r
+ PeiDev = OPAL_PEI_DEVICE_FROM_THIS (This);\r
+ if (PeiDev == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return PerformTrustedIo (\r
+ PeiDev,\r
+ OpalSend,\r
+ SecurityProtocolId,\r
+ SecurityProtocolSpecificData,\r
+ PayloadBufferSize,\r
+ PayloadBuffer\r
+ );\r
+\r
+}\r
+\r
+/**\r
+ Save/Restore RootPort configuration space.\r
+\r
+ @param[in] DevInfoNvme Pointer to NVMe device info.\r
+ @param[in] SaveAction TRUE: Save, FALSE: Restore\r
+ @param[in,out] PcieConfBufferList Configuration space data buffer for save/restore\r
+\r
+ @return PCIE base address of this RootPort\r
+**/\r
+UINTN\r
+SaveRestoreRootportConfSpace (\r
+ IN OPAL_DEVICE_NVME *DevInfoNvme,\r
+ IN BOOLEAN SaveAction,\r
+ IN OUT UINT8 **PcieConfBufferList\r
+ )\r
+{\r
+ UINTN RpBase;\r
+ UINTN Length;\r
+ OPAL_PCI_DEVICE *DevNode;\r
+ UINT8 *StorePcieConfData;\r
+ UINTN Index;\r
+\r
+ Length = 0;\r
+ Index = 0;\r
+ RpBase = 0;\r
+\r
+ while (sizeof (OPAL_DEVICE_NVME) + Length < DevInfoNvme->Length) {\r
+ DevNode = (OPAL_PCI_DEVICE *)((UINT8*)DevInfoNvme->PciBridgeNode + Length);\r
+ RpBase = PCI_LIB_ADDRESS (DevNode->Bus, DevNode->Device, DevNode->Function, 0x0);\r
+\r
+ if (PcieConfBufferList != NULL) {\r
+ if (SaveAction) {\r
+ StorePcieConfData = (UINT8 *) AllocateZeroPool (OPAL_PCIE_ROOTPORT_SAVESIZE);\r
+ ASSERT (StorePcieConfData != NULL);\r
+ OpalPciRead (StorePcieConfData, RpBase, OPAL_PCIE_ROOTPORT_SAVESIZE);\r
+ PcieConfBufferList[Index] = StorePcieConfData;\r
+ } else {\r
+ // Skip PCIe Command & Status registers\r
+ StorePcieConfData = PcieConfBufferList[Index];\r
+ OpalPciWrite (RpBase, StorePcieConfData, 4);\r
+ OpalPciWrite (RpBase + 8, StorePcieConfData + 8, OPAL_PCIE_ROOTPORT_SAVESIZE - 8);\r
+\r
+ FreePool (StorePcieConfData);\r
+ }\r
+ }\r
+\r
+ Length += sizeof (OPAL_PCI_DEVICE);\r
+ Index ++;\r
+ }\r
+\r
+ return RpBase;\r
+}\r
+\r
+/**\r
+ Configure RootPort for downstream PCIe NAND devices.\r
+\r
+ @param[in] RpBase - PCIe configuration space address of this RootPort\r
+ @param[in] BusNumber - Bus number\r
+ @param[in] MemoryBase - Memory base address\r
+ @param[in] MemoryLength - Memory size\r
+\r
+**/\r
+VOID\r
+ConfigureRootPortForPcieNand (\r
+ IN UINTN RpBase,\r
+ IN UINTN BusNumber,\r
+ IN UINT32 MemoryBase,\r
+ IN UINT32 MemoryLength\r
+ )\r
+{\r
+ UINT32 MemoryLimit;\r
+\r
+ DEBUG ((DEBUG_INFO, "ConfigureRootPortForPcieNand, BusNumber: %x, MemoryBase: %x, MemoryLength: %x\n",\r
+ BusNumber, MemoryBase, MemoryLength));\r
+\r
+ if (MemoryLength == 0) {\r
+ MemoryLimit = MemoryBase;\r
+ } else {\r
+ MemoryLimit = MemoryBase + MemoryLength + 0xFFFFF; // 1M\r
+ }\r
+\r
+ ///\r
+ /// Configue PCIE configuration space for RootPort\r
+ ///\r
+ PciWrite8 (RpBase + NVME_PCIE_BNUM + 1, (UINT8) BusNumber); // Secondary Bus Number registers\r
+ PciWrite8 (RpBase + NVME_PCIE_BNUM + 2, (UINT8) BusNumber); // Subordinate Bus Number registers\r
+ PciWrite8 (RpBase + NVME_PCIE_IOBL, 0xFF); // I/O Base registers\r
+ PciWrite8 (RpBase + NVME_PCIE_IOBL + 1, 0x00); // I/O Limit registers\r
+ PciWrite16 (RpBase + NVME_PCIE_MBL, (UINT16) RShiftU64 ((UINTN)MemoryBase, 16)); // Memory Base register\r
+ PciWrite16 (RpBase + NVME_PCIE_MBL + 2, (UINT16) RShiftU64 ((UINTN)MemoryLimit, 16)); // Memory Limit register\r
+ PciWrite16 (RpBase + NVME_PCIE_PMBL, 0xFFFF); // Prefetchable Memory Base registers\r
+ PciWrite16 (RpBase + NVME_PCIE_PMBL + 2, 0x0000); // Prefetchable Memory Limit registers\r
+ PciWrite32 (RpBase + NVME_PCIE_PMBU32, 0xFFFFFFFF); // Prefetchable Memory Upper Base registers\r
+ PciWrite32 (RpBase + NVME_PCIE_PMLU32, 0x00000000); // Prefetchable Memory Upper Limit registers\r
+}\r
+\r
+/**\r
+\r
+ The function returns whether or not the device is Opal Locked.\r
+ TRUE means that the device is partially or fully locked.\r
+ This will perform a Level 0 Discovery and parse the locking feature descriptor\r
+\r
+ @param[in] OpalDev Opal object to determine if locked.\r
+ @param[out] BlockSidSupported Whether device support BlockSid feature.\r
+\r
+**/\r
+BOOLEAN\r
+IsOpalDeviceLocked(\r
+ OPAL_PEI_DEVICE *OpalDev,\r
+ BOOLEAN *BlockSidSupported\r
+ )\r
+{\r
+ OPAL_SESSION Session;\r
+ OPAL_DISK_SUPPORT_ATTRIBUTE SupportedAttributes;\r
+ TCG_LOCKING_FEATURE_DESCRIPTOR LockingFeature;\r
+ UINT16 OpalBaseComId;\r
+ TCG_RESULT Ret;\r
+\r
+ Session.Sscp = &OpalDev->Sscp;\r
+ Session.MediaId = 0;\r
+\r
+ Ret = OpalGetSupportedAttributesInfo (&Session, &SupportedAttributes, &OpalBaseComId);\r
+ if (Ret != TcgResultSuccess) {\r
+ return FALSE;\r
+ }\r
+\r
+ Session.OpalBaseComId = OpalBaseComId;\r
+ *BlockSidSupported = SupportedAttributes.BlockSid == 1 ? TRUE : FALSE;\r
+\r
+ Ret = OpalGetLockingInfo(&Session, &LockingFeature);\r
+ if (Ret != TcgResultSuccess) {\r
+ return FALSE;\r
+ }\r
+\r
+ return OpalDeviceLocked (&SupportedAttributes, &LockingFeature);\r
+}\r
+\r
+/**\r
+ Unlock OPAL password for S3.\r
+\r
+ @param[in] OpalDev Opal object to unlock.\r
+\r
+**/\r
+VOID\r
+UnlockOpalPassword (\r
+ IN OPAL_PEI_DEVICE *OpalDev\r
+ )\r
+{\r
+ TCG_RESULT Result;\r
+ OPAL_SESSION Session;\r
+ BOOLEAN BlockSidSupport;\r
+ UINT32 PpStorageFlags;\r
+ BOOLEAN BlockSIDEnabled;\r
+\r
+ BlockSidSupport = FALSE;\r
+ if (IsOpalDeviceLocked (OpalDev, &BlockSidSupport)) {\r
+ ZeroMem(&Session, sizeof (Session));\r
+ Session.Sscp = &OpalDev->Sscp;\r
+ Session.MediaId = 0;\r
+ Session.OpalBaseComId = OpalDev->Device->OpalBaseComId;\r
+\r
+ Result = OpalUtilUpdateGlobalLockingRange (\r
+ &Session,\r
+ OpalDev->Device->Password,\r
+ OpalDev->Device->PasswordLength,\r
+ FALSE,\r
+ FALSE\r
+ );\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "%a() OpalUtilUpdateGlobalLockingRange() Result = 0x%x\n",\r
+ __FUNCTION__,\r
+ Result\r
+ ));\r
+ }\r
+\r
+ PpStorageFlags = Tcg2PhysicalPresenceLibGetManagementFlags ();\r
+ if ((PpStorageFlags & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID) != 0) {\r
+ BlockSIDEnabled = TRUE;\r
+ } else {\r
+ BlockSIDEnabled = FALSE;\r
+ }\r
+ if (BlockSIDEnabled && BlockSidSupport) {\r
+ ZeroMem(&Session, sizeof (Session));\r
+ Session.Sscp = &OpalDev->Sscp;\r
+ Session.MediaId = 0;\r
+ Session.OpalBaseComId = OpalDev->Device->OpalBaseComId;\r
+ Result = OpalBlockSid (&Session, TRUE);\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "%a() OpalBlockSid() Result = 0x%x\n",\r
+ __FUNCTION__,\r
+ Result\r
+ ));\r
+ }\r
+}\r
+\r
+/**\r
+ Unlock ATA OPAL password for S3.\r
+\r
+**/\r
+VOID\r
+UnlockOpalPasswordAta (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 *DevInfo;\r
+ OPAL_DEVICE_ATA TempDevInfoAta;\r
+ OPAL_DEVICE_ATA *DevInfoAta;\r
+ UINTN DevInfoLengthAta;\r
+ UINT8 Bus;\r
+ UINT8 Device;\r
+ UINT8 Function;\r
+ OPAL_PEI_DEVICE OpalDev;\r
+ UINT8 BaseClassCode;\r
+ UINT8 SubClassCode;\r
+ UINT8 SataCmdSt;\r
+ AHCI_CONTEXT AhciContext;\r
+ UINT32 AhciBar;\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
+\r
+ //\r
+ // Get ATA OPAL device info from LockBox.\r
+ //\r
+ DevInfo = (UINT8 *) &TempDevInfoAta;\r
+ DevInfoLengthAta = sizeof (OPAL_DEVICE_ATA);\r
+ Status = RestoreLockBox (&mOpalDeviceAtaGuid, DevInfo, &DevInfoLengthAta);\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ DevInfo = AllocatePages (EFI_SIZE_TO_PAGES (DevInfoLengthAta));\r
+ if (DevInfo != NULL) {\r
+ Status = RestoreLockBox (&mOpalDeviceAtaGuid, DevInfo, &DevInfoLengthAta);\r
+ }\r
+ }\r
+ if (EFI_ERROR (Status) || (DevInfo == NULL)) {\r
+ return;\r
+ }\r
+\r
+ for (DevInfoAta = (OPAL_DEVICE_ATA *) DevInfo;\r
+ (UINTN) DevInfoAta < ((UINTN) DevInfo + DevInfoLengthAta);\r
+ DevInfoAta = (OPAL_DEVICE_ATA *) ((UINTN) DevInfoAta + DevInfoAta->Length)) {\r
+ Bus = DevInfoAta->Device.Bus;\r
+ Device = DevInfoAta->Device.Device;\r
+ Function = DevInfoAta->Device.Function;\r
+\r
+ SataCmdSt = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET));\r
+ PciWrite8 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), 0x6);\r
+\r
+ BaseClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0B));\r
+ SubClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0A));\r
+ if ((BaseClassCode != PCI_CLASS_MASS_STORAGE) ||\r
+ ((SubClassCode != PCI_CLASS_MASS_STORAGE_SATADPA) && (SubClassCode != PCI_CLASS_MASS_STORAGE_RAID))) {\r
+ DEBUG ((DEBUG_ERROR, "%a() ClassCode/SubClassCode are not supported\n", __FUNCTION__));\r
+ } else {\r
+ AhciBar = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24));\r
+ PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24), DevInfoAta->BarAddr);\r
+\r
+ ZeroMem (&AhciContext, sizeof (AHCI_CONTEXT));\r
+ AhciContext.AhciBar = DevInfoAta->BarAddr;\r
+ AhciAllocateResource (&AhciContext);\r
+ Status = AhciModeInitialize (&AhciContext, (UINT8)DevInfoAta->Port);\r
+ ASSERT_EFI_ERROR (Status);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "%a() AhciModeInitialize() error, Status: %r\n", __FUNCTION__, Status));\r
+ }\r
+\r
+ OpalDev.Signature = OPAL_PEI_DEVICE_SIGNATURE;\r
+ OpalDev.Sscp.ReceiveData = SecurityReceiveData;\r
+ OpalDev.Sscp.SendData = SecuritySendData;\r
+ OpalDev.DeviceType = OPAL_DEVICE_TYPE_ATA;\r
+ OpalDev.Device = (OPAL_DEVICE_COMMON *) DevInfoAta;\r
+ OpalDev.Context = &AhciContext;\r
+\r
+ UnlockOpalPassword (&OpalDev);\r
+\r
+ AhciFreeResource (&AhciContext);\r
+ PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24), AhciBar);\r
+ }\r
+ PciWrite8 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), SataCmdSt);\r
+ }\r
+\r
+ ZeroMem (DevInfo, DevInfoLengthAta);\r
+ if ((UINTN) DevInfo != (UINTN) &TempDevInfoAta) {\r
+ FreePages (DevInfo, EFI_SIZE_TO_PAGES (DevInfoLengthAta));\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
+}\r
+\r
+/**\r
+ Unlock NVMe OPAL password for S3.\r
+\r
+**/\r
+VOID\r
+UnlockOpalPasswordNvme (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 *DevInfo;\r
+ OPAL_DEVICE_NVME TempDevInfoNvme;\r
+ OPAL_DEVICE_NVME *DevInfoNvme;\r
+ UINTN DevInfoLengthNvme;\r
+ UINT8 Bus;\r
+ UINT8 Device;\r
+ UINT8 Function;\r
+ OPAL_PEI_DEVICE OpalDev;\r
+ UINT8 BaseClassCode;\r
+ UINT8 SubClassCode;\r
+ UINT8 ProgInt;\r
+ UINT8 NvmeCmdSt;\r
+ UINT8 *StorePcieConfDataList[16];\r
+ UINTN RpBase;\r
+ UINTN MemoryBase;\r
+ UINTN MemoryLength;\r
+ NVME_CONTEXT NvmeContext;\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
+\r
+ //\r
+ // Get NVMe OPAL device info from LockBox.\r
+ //\r
+ DevInfo = (UINT8 *) &TempDevInfoNvme;\r
+ DevInfoLengthNvme = sizeof (OPAL_DEVICE_NVME);\r
+ Status = RestoreLockBox (&mOpalDeviceNvmeGuid, DevInfo, &DevInfoLengthNvme);\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ DevInfo = AllocatePages (EFI_SIZE_TO_PAGES (DevInfoLengthNvme));\r
+ if (DevInfo != NULL) {\r
+ Status = RestoreLockBox (&mOpalDeviceNvmeGuid, DevInfo, &DevInfoLengthNvme);\r
+ }\r
+ }\r
+ if (EFI_ERROR (Status) || (DevInfo == NULL)) {\r
+ return;\r
+ }\r
+\r
+ for (DevInfoNvme = (OPAL_DEVICE_NVME *) DevInfo;\r
+ (UINTN) DevInfoNvme < ((UINTN) DevInfo + DevInfoLengthNvme);\r
+ DevInfoNvme = (OPAL_DEVICE_NVME *) ((UINTN) DevInfoNvme + DevInfoNvme->Length)) {\r
+ Bus = DevInfoNvme->Device.Bus;\r
+ Device = DevInfoNvme->Device.Device;\r
+ Function = DevInfoNvme->Device.Function;\r
+\r
+ RpBase = 0;\r
+ NvmeCmdSt = 0;\r
+\r
+ ///\r
+ /// Save original RootPort configuration space to heap\r
+ ///\r
+ RpBase = SaveRestoreRootportConfSpace (\r
+ DevInfoNvme,\r
+ TRUE, // save\r
+ StorePcieConfDataList\r
+ );\r
+ MemoryBase = DevInfoNvme->BarAddr;\r
+ MemoryLength = 0;\r
+ ConfigureRootPortForPcieNand (RpBase, Bus, (UINT32) MemoryBase, (UINT32) MemoryLength);\r
+\r
+ ///\r
+ /// Enable PCIE decode for RootPort\r
+ ///\r
+ NvmeCmdSt = PciRead8 (RpBase + NVME_PCIE_PCICMD);\r
+ PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0x6);\r
+\r
+ BaseClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0B));\r
+ SubClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0A));\r
+ ProgInt = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x09));\r
+ if ((BaseClassCode != PCI_CLASS_MASS_STORAGE) ||\r
+ (SubClassCode != PCI_CLASS_MASS_STORAGE_NVM) ||\r
+ (ProgInt != PCI_IF_NVMHCI)) {\r
+ DEBUG ((DEBUG_ERROR, "%a() ClassCode/SubClassCode/PI are not supported\n", __FUNCTION__));\r
+ } else {\r
+ ZeroMem (&NvmeContext, sizeof (NVME_CONTEXT));\r
+ NvmeContext.Nbar = DevInfoNvme->BarAddr;\r
+ NvmeContext.PciBase = PCI_LIB_ADDRESS (Bus, Device, Function, 0x0);\r
+ NvmeContext.NvmeInitWaitTime = 0;\r
+ NvmeContext.Nsid = DevInfoNvme->NvmeNamespaceId;\r
+ NvmeAllocateResource (&NvmeContext);\r
+ Status = NvmeControllerInit (&NvmeContext);\r
+\r
+ OpalDev.Signature = OPAL_PEI_DEVICE_SIGNATURE;\r
+ OpalDev.Sscp.ReceiveData = SecurityReceiveData;\r
+ OpalDev.Sscp.SendData = SecuritySendData;\r
+ OpalDev.DeviceType = OPAL_DEVICE_TYPE_NVME;\r
+ OpalDev.Device = (OPAL_DEVICE_COMMON *) DevInfoNvme;\r
+ OpalDev.Context = &NvmeContext;\r
+\r
+ UnlockOpalPassword (&OpalDev);\r
+\r
+ Status = NvmeControllerExit (&NvmeContext);\r
+ NvmeFreeResource (&NvmeContext);\r
+ }\r
+\r
+ ASSERT (RpBase != 0);\r
+ PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0);\r
+ RpBase = SaveRestoreRootportConfSpace (\r
+ DevInfoNvme,\r
+ FALSE, // restore\r
+ StorePcieConfDataList\r
+ );\r
+ PciWrite8 (RpBase + NVME_PCIE_PCICMD, NvmeCmdSt);\r
+ }\r
+\r
+ ZeroMem (DevInfo, DevInfoLengthNvme);\r
+ if ((UINTN) DevInfo != (UINTN) &TempDevInfoNvme) {\r
+ FreePages (DevInfo, EFI_SIZE_TO_PAGES (DevInfoLengthNvme));\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
+}\r
+\r
+/**\r
+ Unlock OPAL password for S3.\r
+\r
+**/\r
+VOID\r
+OpalPasswordS3 (\r
+ VOID\r
+ )\r
+{\r
+ UnlockOpalPasswordAta ();\r
+ UnlockOpalPasswordNvme ();\r
+}\r
+\r
+/**\r
+ Entry point of the notification callback function itself within the PEIM.\r
+ It is to unlock OPAL password for S3.\r
+\r
+ @param PeiServices Indirect reference to the PEI Services Table.\r
+ @param NotifyDescriptor Address of the notification descriptor data structure.\r
+ @param Ppi Address of the PPI that was installed.\r
+\r
+ @return Status of the notification.\r
+ The status code returned from this function is ignored.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalPasswordEndOfPeiNotify(\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,\r
+ IN VOID *Ppi\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_BOOT_MODE BootMode;\r
+\r
+ Status = PeiServicesGetBootMode (&BootMode);\r
+ ASSERT_EFI_ERROR (Status);\r
+ if (BootMode != BOOT_ON_S3_RESUME) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - enter at S3 resume\n", __FUNCTION__));\r
+\r
+ OpalPasswordS3 ();\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - exit at S3 resume\n", __FUNCTION__));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_PEI_NOTIFY_DESCRIPTOR mOpalPasswordEndOfPeiNotifyDesc = {\r
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+ &gEfiEndOfPeiSignalPpiGuid,\r
+ OpalPasswordEndOfPeiNotify\r
+};\r
+\r
+/**\r
+ Main entry for this module.\r
+\r
+ @param FileHandle Handle of the file being invoked.\r
+ @param PeiServices Pointer to PEI Services table.\r
+\r
+ @return Status from PeiServicesNotifyPpi.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalPasswordPeiInit (\r
+ IN EFI_PEI_FILE_HANDLE FileHandle,\r
+ IN CONST EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = PeiServicesNotifyPpi (&mOpalPasswordEndOfPeiNotifyDesc);\r
+ ASSERT_EFI_ERROR (Status);\r
+ return Status;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+ Opal Password PEI driver which is used to unlock Opal Password for S3.\r
+\r
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _OPAL_PASSWORD_PEI_H_\r
+#define _OPAL_PASSWORD_PEI_H_\r
+\r
+#include <PiPei.h>\r
+#include <IndustryStandard/Atapi.h>\r
+#include <IndustryStandard/Pci.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/PciLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/PeimEntryPoint.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/LockBoxLib.h>\r
+#include <Library/TcgStorageOpalLib.h>\r
+#include <Library/Tcg2PhysicalPresenceLib.h>\r
+\r
+#include <Protocol/StorageSecurityCommand.h>\r
+\r
+#include <Ppi/IoMmu.h>\r
+\r
+#include "OpalPasswordCommon.h"\r
+#include "OpalAhciMode.h"\r
+#include "OpalNvmeMode.h"\r
+\r
+//\r
+// Time out Value for ATA pass through protocol\r
+//\r
+#define ATA_TIMEOUT 30000000\r
+\r
+//\r
+// The payload Length of HDD related ATA commands\r
+//\r
+#define HDD_PAYLOAD 512\r
+//\r
+// According to ATA spec, the max Length of hdd password is 32 bytes\r
+//\r
+#define OPAL_PASSWORD_MAX_LENGTH 32\r
+\r
+#pragma pack(1)\r
+\r
+/**\r
+* Opal I/O Type utilized by the Trusted IO callback\r
+*\r
+* The type indicates if the I/O is a send or receive\r
+*/\r
+typedef enum {\r
+ //\r
+ // I/O is a TCG Trusted Send command\r
+ //\r
+ OpalSend,\r
+\r
+ //\r
+ // I/O is a TCG Trusted Receive command\r
+ //\r
+ OpalRecv\r
+} OPAL_IO_TYPE;\r
+\r
+#define OPAL_PEI_DEVICE_SIGNATURE SIGNATURE_32 ('o', 'p', 'd', 's')\r
+\r
+typedef struct {\r
+ UINTN Signature;\r
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL Sscp;\r
+ UINT8 DeviceType;\r
+ OPAL_DEVICE_COMMON *Device;\r
+ VOID *Context;\r
+} OPAL_PEI_DEVICE;\r
+\r
+#define OPAL_PEI_DEVICE_FROM_THIS(a) CR (a, OPAL_PEI_DEVICE, Sscp, OPAL_PEI_DEVICE_SIGNATURE)\r
+\r
+#pragma pack()\r
+\r
+/**\r
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or\r
+ OperationBusMasterCommonBuffer64 mapping.\r
+\r
+ @param Pages The number of pages to allocate.\r
+ @param HostAddress A pointer to store the base system memory address of the\r
+ allocated range.\r
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to\r
+ access the hosts HostAddress.\r
+ @param Mapping A resulting value to pass to Unmap().\r
+\r
+ @retval EFI_SUCCESS The requested memory pages were allocated.\r
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are\r
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+IoMmuAllocateBuffer (\r
+ IN UINTN Pages,\r
+ OUT VOID **HostAddress,\r
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
+ OUT VOID **Mapping\r
+ );\r
+\r
+/**\r
+ Frees memory that was allocated with AllocateBuffer().\r
+\r
+ @param Pages The number of pages to free.\r
+ @param HostAddress The base system memory address of the allocated range.\r
+ @param Mapping The mapping value returned from Map().\r
+\r
+**/\r
+VOID\r
+IoMmuFreeBuffer (\r
+ IN UINTN Pages,\r
+ IN VOID *HostAddress,\r
+ IN VOID *Mapping\r
+ );\r
+\r
+#endif // _OPAL_PASSWORD_PEI_H_\r
+\r
--- /dev/null
+## @file\r
+# This is a Opal Password PEI driver.\r
+#\r
+# Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = OpalPasswordPei\r
+ FILE_GUID = DED60489-979C-4B5A-8EE4-4068B0CC38DC\r
+ MODULE_TYPE = PEIM\r
+ VERSION_STRING = 1.0\r
+ ENTRY_POINT = OpalPasswordPeiInit\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64\r
+#\r
+\r
+[Sources]\r
+ OpalPasswordPei.c\r
+ OpalPasswordPei.h\r
+ OpalPasswordCommon.h\r
+ OpalAhciMode.c\r
+ OpalAhciMode.h\r
+ OpalNvmeMode.c\r
+ OpalNvmeMode.h\r
+ OpalNvmeReg.h\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ SecurityPkg/SecurityPkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+ PeimEntryPoint\r
+ PeiServicesLib\r
+ DebugLib\r
+ IoLib\r
+ PciLib\r
+ BaseLib\r
+ BaseMemoryLib\r
+ MemoryAllocationLib\r
+ TimerLib\r
+ HobLib\r
+ LockBoxLib\r
+ TcgStorageOpalLib\r
+ Tcg2PhysicalPresenceLib\r
+\r
+[Ppis]\r
+ gEdkiiIoMmuPpiGuid ## SOMETIMES_CONSUMES\r
+ gEfiEndOfPeiSignalPpiGuid ## NOTIFY\r
+\r
+[Depex]\r
+ gEfiPeiMasterBootModePpiGuid\r