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