]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.c
MdeModulePkg/NvmExpressDxe: Add SecurityStorageProtocol support
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / NvmExpressDxe / NvmExpressBlockIo.c
index e7d76513221794326e79783360efebef514ff09c..6cb2f92e8dded76b4f42f0687e4094f09b7b56c8 100644 (file)
@@ -345,6 +345,10 @@ NvmeBlockIoReset (
 \r
   Status  = NvmeControllerInit (Private);\r
 \r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
   gBS->RestoreTPL (OldTpl);\r
 \r
   return Status;\r
@@ -555,3 +559,325 @@ NvmeBlockIoFlushBlocks (
 \r
   return Status;\r
 }\r
+\r
+/**\r
+  Trust transfer data from/to NVMe device.\r
+\r
+  This function performs one NVMe transaction to do a trust transfer from/to NVMe device.\r
+\r
+  @param  Private                      The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+  @param  Buffer                       The pointer to the current transaction buffer.\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  TransferLength               The block number or sector count of the transfer.\r
+  @param  IsTrustSend                  Indicates whether it is a trust send operation or not.\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  TransferLengthOut            A pointer to a buffer to store the size in bytes of the data\r
+                                       written to the buffer. Ignore it when IsTrustSend is TRUE.\r
+\r
+  @retval EFI_SUCCESS       The data transfer is complete successfully.\r
+  @return others            Some error occurs when transferring data.\r
+\r
+**/\r
+EFI_STATUS\r
+TrustTransferNvmeDevice (\r
+  IN OUT NVME_CONTROLLER_PRIVATE_DATA      *Private,\r
+  IN OUT VOID                              *Buffer,\r
+  IN UINT8                                 SecurityProtocolId,\r
+  IN UINT16                                SecurityProtocolSpecificData,\r
+  IN UINTN                                 TransferLength,\r
+  IN BOOLEAN                               IsTrustSend,\r
+  IN UINT64                                Timeout,\r
+  OUT UINTN                                *TransferLengthOut\r
+  )\r
+{\r
+  EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
+  EFI_NVM_EXPRESS_COMMAND                  Command;\r
+  EFI_NVM_EXPRESS_COMPLETION               Completion;\r
+  EFI_STATUS                               Status;\r
+  UINT16                                   SpecificData;\r
+\r
+  ZeroMem (&CommandPacket, sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
+  ZeroMem (&Command, sizeof (EFI_NVM_EXPRESS_COMMAND));\r
+  ZeroMem (&Completion, sizeof (EFI_NVM_EXPRESS_COMPLETION));\r
+\r
+  CommandPacket.NvmeCmd        = &Command;\r
+  CommandPacket.NvmeCompletion = &Completion;\r
+\r
+  // \r
+  // Change Endianness of SecurityProtocolSpecificData\r
+  //\r
+  SpecificData = (((SecurityProtocolSpecificData << 8) & 0xFF00) | (SecurityProtocolSpecificData >> 8));\r
+\r
+  if (IsTrustSend) {\r
+    Command.Cdw0.Opcode          = NVME_ADMIN_SECURITY_SEND_CMD;\r
+    CommandPacket.TransferBuffer = Buffer;\r
+    CommandPacket.TransferLength = (UINT32)TransferLength;\r
+    CommandPacket.NvmeCmd->Cdw10 = (UINT32)((SecurityProtocolId << 24) | (SpecificData << 8));\r
+    CommandPacket.NvmeCmd->Cdw11 = (UINT32)TransferLength;\r
+  } else {\r
+    Command.Cdw0.Opcode          = NVME_ADMIN_SECURITY_RECEIVE_CMD;\r
+    CommandPacket.TransferBuffer = Buffer;\r
+    CommandPacket.TransferLength = (UINT32)TransferLength;\r
+    CommandPacket.NvmeCmd->Cdw10 = (UINT32)((SecurityProtocolId << 24) | (SpecificData << 8));\r
+    CommandPacket.NvmeCmd->Cdw11 = (UINT32)TransferLength;\r
+  }\r
+\r
+  CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;\r
+  CommandPacket.NvmeCmd->Nsid  = NVME_CONTROLLER_ID;\r
+  CommandPacket.CommandTimeout = Timeout;\r
+  CommandPacket.QueueType      = NVME_ADMIN_QUEUE;\r
+\r
+  Status = Private->Passthru.PassThru (\r
+                               &Private->Passthru,\r
+                               NVME_CONTROLLER_ID,\r
+                               &CommandPacket,\r
+                               NULL\r
+                               );\r
+\r
+  if (!IsTrustSend) {\r
+    if (EFI_ERROR (Status))  {\r
+      *TransferLengthOut = 0;\r
+    } else {\r
+      *TransferLengthOut = (UINTN) TransferLength;\r
+    }\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
+NvmeStorageSecurityReceiveData (\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
+  EFI_STATUS                       Status;\r
+  NVME_DEVICE_PRIVATE_DATA         *Device;\r
+  \r
+  Status  = EFI_SUCCESS;\r
+\r
+  if ((PayloadBuffer == NULL) || (PayloadTransferSize == NULL) || (PayloadBufferSize == 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Device = NVME_DEVICE_PRIVATE_DATA_FROM_STORAGE_SECURITY (This);\r
+\r
+  if (MediaId != Device->BlockIo.Media->MediaId) {\r
+    return EFI_MEDIA_CHANGED;\r
+  }\r
+\r
+  if (!Device->BlockIo.Media->MediaPresent) {\r
+    return EFI_NO_MEDIA;\r
+  }\r
+\r
+  Status = TrustTransferNvmeDevice (\r
+             Device->Controller,\r
+             PayloadBuffer,\r
+             SecurityProtocolId,\r
+             SecurityProtocolSpecificData,\r
+             PayloadBufferSize,\r
+             FALSE,\r
+             Timeout,\r
+             PayloadTransferSize\r
+             );\r
+\r
+  return Status;\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
+NvmeStorageSecuritySendData (\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
+  EFI_STATUS                       Status; \r
+  NVME_DEVICE_PRIVATE_DATA         *Device;\r
+\r
+  Status  = EFI_SUCCESS;\r
+\r
+  if ((PayloadBuffer == NULL) && (PayloadBufferSize != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Device = NVME_DEVICE_PRIVATE_DATA_FROM_STORAGE_SECURITY (This);\r
+\r
+  if (MediaId != Device->BlockIo.Media->MediaId) {\r
+    return EFI_MEDIA_CHANGED;\r
+  }\r
+\r
+  if (!Device->BlockIo.Media->MediaPresent) {\r
+    return EFI_NO_MEDIA;\r
+  }\r
+\r
+  Status = TrustTransferNvmeDevice (\r
+             Device->Controller,\r
+             PayloadBuffer,\r
+             SecurityProtocolId,\r
+             SecurityProtocolSpecificData,\r
+             PayloadBufferSize,\r
+             TRUE,\r
+             Timeout,\r
+             NULL\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+\r