diff --git a/drivers/nvme/NvmCtrlLib.h b/drivers/nvme/NvmCtrlLib.h index a8d2973..ca93b04 100644 --- a/drivers/nvme/NvmCtrlLib.h +++ b/drivers/nvme/NvmCtrlLib.h @@ -147,4 +147,6 @@ EFI_STATUS EFIAPI NvmeInitialize (IN UINTN NvmeHcPciBase); EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *NvmeGetPassthru(void); +EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *NvmeGetSecurityInterface(void); + #endif diff --git a/drivers/nvme/NvmExpress.c b/drivers/nvme/NvmExpress.c index 6df8bd5..d0bdf87 100644 --- a/drivers/nvme/NvmExpress.c +++ b/drivers/nvme/NvmExpress.c @@ -29,9 +29,25 @@ NvmCtrlPlatformInfo NvmCtrlInfo = { {1,0,0} }; EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *NvmeGetPassthru(void) { - return (void *)&mNvmeCtrlPrivate->Passthru; + return (void *)&mNvmeCtrlPrivate->Passthru; } +EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *NvmeGetSecurityInterface(void) +{ + NVME_DEVICE_PRIVATE_DATA *device = mMultiNvmeDrive[0]; + EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *security; + + if (device == NULL) + return NULL; + + security = &device->StorageSecurity; + if (security->SendData == NULL || security->ReceiveData == NULL) + return NULL; + + return security; +} + + // // Template for NVM Express Pass Thru Mode data structure. // @@ -151,6 +167,17 @@ EnumerateNvmeDevNamespace ( CopyMem (&Device->NamespaceData, NamespaceData, sizeof (NVME_ADMIN_NAMESPACE_DATA)); mMultiNvmeDrive[NamespaceId - 1] = Device; //NamespaceId is 1 based + // + // Create StorageSecurityProtocol Instance + // + Device->StorageSecurity.ReceiveData = NvmeStorageSecurityReceiveData; + Device->StorageSecurity.SendData = NvmeStorageSecuritySendData; + DEBUG_NVME((EFI_D_INFO, "## SECURITY_SEND_RECEIVE %d ####\n", (Private->ControllerData->Oacs & SECURITY_SEND_RECEIVE_SUPPORTED))); + if ((Private->ControllerData->Oacs & SECURITY_SEND_RECEIVE_SUPPORTED) == 0) { + Device->StorageSecurity.ReceiveData = NULL; + Device->StorageSecurity.SendData = NULL; + } + // // Dump NvmExpress Identify Namespace Data // @@ -392,7 +419,7 @@ NvmeGetMediaInfo ( EFI_STATUS EFIAPI NvmeReadBlocks ( - IN UINTN DeviceIndex, + IN UINTN DeviceIndex __attribute__((unused)), IN EFI_PEI_LBA StartLBA, IN UINTN BufferSize, OUT VOID *Buffer @@ -400,8 +427,6 @@ NvmeReadBlocks ( { EFI_STATUS Status; - DeviceIndex = DeviceIndex; - Status = NvmeBlockIoReadBlocks(&mMultiNvmeDrive[0]->BlockIo, 0, StartLBA, BufferSize, Buffer); return Status; @@ -423,7 +448,7 @@ NvmeReadBlocks ( EFI_STATUS EFIAPI NvmeWriteBlocks ( - IN UINTN DeviceIndex, + IN UINTN DeviceIndex __attribute__((unused)), IN EFI_LBA StartLBA, IN UINTN DataSize, IN VOID *DataAddress @@ -431,8 +456,6 @@ NvmeWriteBlocks ( { EFI_STATUS Status; - DeviceIndex = DeviceIndex; - Status = NvmeBlockIoWriteBlocks(&mMultiNvmeDrive[0]->BlockIo, 0, StartLBA, DataSize, DataAddress); return Status; diff --git a/drivers/nvme/NvmExpress.h b/drivers/nvme/NvmExpress.h index b91fe0e..2abef50 100644 --- a/drivers/nvme/NvmExpress.h +++ b/drivers/nvme/NvmExpress.h @@ -22,6 +22,7 @@ #include #include "NvmInternal.h" +#include "protocol/StorageSecurityCommand.h" #define nvme_dbg(a, ...) { printf(__VA_ARGS__); } #define DEBUG_NVME(a) (nvme_dbg a) @@ -219,6 +220,7 @@ struct _NVME_DEVICE_PRIVATE_DATA { NVME_CONTROLLER_PRIVATE_DATA *Controller; + EFI_STORAGE_SECURITY_COMMAND_PROTOCOL StorageSecurity; }; // diff --git a/drivers/nvme/NvmExpressBlockIo.c b/drivers/nvme/NvmExpressBlockIo.c index 4d37d89..a045b1f 100644 --- a/drivers/nvme/NvmExpressBlockIo.c +++ b/drivers/nvme/NvmExpressBlockIo.c @@ -337,15 +337,13 @@ EFI_STATUS EFIAPI NvmeBlockIoReset ( IN EFI_BLOCK_IO_PROTOCOL *This, - IN BOOLEAN ExtendedVerification + IN BOOLEAN ExtendedVerification __attribute__((unused)) ) { NVME_CONTROLLER_PRIVATE_DATA *Private; NVME_DEVICE_PRIVATE_DATA *Device; EFI_STATUS Status; - ExtendedVerification = ExtendedVerification; - if (This == NULL) { return EFI_INVALID_PARAMETER; } @@ -584,7 +582,6 @@ TrustTransferNvmeDevice ( EFI_NVM_EXPRESS_COMMAND Command; EFI_NVM_EXPRESS_COMPLETION Completion; EFI_STATUS Status; - UINT16 SpecificData; ZeroMem (&CommandPacket, sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET)); ZeroMem (&Command, sizeof (EFI_NVM_EXPRESS_COMMAND)); @@ -593,22 +590,17 @@ TrustTransferNvmeDevice ( 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->Cdw10 = (UINT32)((SecurityProtocolId << 24) | (SecurityProtocolSpecificData << 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->Cdw10 = (UINT32)((SecurityProtocolId << 24) | (SecurityProtocolSpecificData << 8)); CommandPacket.NvmeCmd->Cdw11 = (UINT32)TransferLength; } @@ -635,3 +627,221 @@ TrustTransferNvmeDevice ( return Status; } +/** + Send a security protocol command to a device that receives data and/or the result + of one or more commands sent by SendData. + + The ReceiveData function sends a security protocol command to the given MediaId. + The security protocol command sent is defined by SecurityProtocolId and contains + the security protocol specific data SecurityProtocolSpecificData. The function + returns the data from the security protocol command in PayloadBuffer. + + For devices supporting the SCSI command set, the security protocol command is sent + using the SECURITY PROTOCOL IN command defined in SPC-4. + + For devices supporting the ATA command set, the security protocol command is sent + using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize + is non-zero. + + If the PayloadBufferSize is zero, the security protocol command is sent using the + Trusted Non-Data command defined in ATA8-ACS. + + If PayloadBufferSize is too small to store the available data from the security + protocol command, the function shall copy PayloadBufferSize bytes into the + PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL. + + If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero, + the function shall return EFI_INVALID_PARAMETER. + + If the given MediaId does not support security protocol commands, the function shall + return EFI_UNSUPPORTED. If there is no media in the device, the function returns + EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device, + the function returns EFI_MEDIA_CHANGED. + + If the security protocol fails to complete within the Timeout period, the function + shall return EFI_TIMEOUT. + + If the security protocol command completes without an error, the function shall + return EFI_SUCCESS. If the security protocol command completes with an error, the + function shall return EFI_DEVICE_ERROR. + + @param This Indicates a pointer to the calling context. + @param MediaId ID of the medium to receive data from. + @param Timeout The timeout, in 100ns units, to use for the execution + of the security protocol command. A Timeout value of 0 + means that this function will wait indefinitely for the + security protocol command to execute. If Timeout is greater + than zero, then this function will return EFI_TIMEOUT + if the time required to execute the receive data command + is greater than Timeout. + @param SecurityProtocolId The value of the "Security Protocol" parameter of + the security protocol command to be sent. + @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter + of the security protocol command to be sent. + @param PayloadBufferSize Size in bytes of the payload data buffer. + @param PayloadBuffer A pointer to a destination buffer to store the security + protocol command specific payload data for the security + protocol command. The caller is responsible for having + either implicit or explicit ownership of the buffer. + @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the + data written to the payload data buffer. + + @retval EFI_SUCCESS The security protocol command completed successfully. + @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available + data from the device. The PayloadBuffer contains the truncated data. + @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands. + @retval EFI_DEVICE_ERROR The security protocol command completed with an error. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and + PayloadBufferSize is non-zero. + @retval EFI_TIMEOUT A timeout occurred while waiting for the security + protocol command to execute. + +**/ +EFI_STATUS +EFIAPI +NvmeStorageSecurityReceiveData ( + IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This, + IN UINT32 MediaId, + IN UINT64 Timeout, + IN UINT8 SecurityProtocolId, + IN UINT16 SecurityProtocolSpecificData, + IN UINTN PayloadBufferSize, + OUT VOID *PayloadBuffer, + OUT UINTN *PayloadTransferSize +) +{ + EFI_STATUS Status; + NVME_DEVICE_PRIVATE_DATA *Device; + + Status = EFI_SUCCESS; + + if ((PayloadBuffer == NULL) || (PayloadTransferSize == NULL) || (PayloadBufferSize == 0)) + return EFI_INVALID_PARAMETER; + + Device = NVME_DEVICE_PRIVATE_DATA_FROM_STORAGE_SECURITY(This); + + if (MediaId != Device->BlockIo.Media->MediaId) + return EFI_MEDIA_CHANGED; + + if (!Device->BlockIo.Media->MediaPresent) + return EFI_NO_MEDIA; + + Status = TrustTransferNvmeDevice( + Device->Controller, + 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 MediaId. The security protocol command sent is + defined by SecurityProtocolId and contains the security protocol specific data + SecurityProtocolSpecificData. If the underlying protocol command requires a + specific padding for the command payload, the SendData function shall add padding + bytes to the command payload to satisfy the padding requirements. + + For devices supporting the SCSI command set, the security protocol command is sent + using the SECURITY PROTOCOL OUT command defined in SPC-4. + + For devices supporting the ATA command set, the security protocol command is sent + using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize + is non-zero. If the PayloadBufferSize is zero, the security protocol command is + sent using the Trusted Non-Data command defined in ATA8-ACS. + + If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall + return EFI_INVALID_PARAMETER. + + If the given MediaId does not support security protocol commands, the function + shall return EFI_UNSUPPORTED. If there is no media in the device, the function + returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the + device, the function returns EFI_MEDIA_CHANGED. + + If the security protocol fails to complete within the Timeout period, the function + shall return EFI_TIMEOUT. + + If the security protocol command completes without an error, the function shall return + EFI_SUCCESS. If the security protocol command completes with an error, the function + shall return EFI_DEVICE_ERROR. + + @param This Indicates a pointer to the calling context. + @param MediaId ID of the medium to receive data from. + @param Timeout The timeout, in 100ns units, to use for the execution + of the security protocol command. A Timeout value of 0 + means that this function will wait indefinitely for the + security protocol command to execute. If Timeout is greater + than zero, then this function will return EFI_TIMEOUT + if the time required to execute the send data command + is greater than Timeout. + @param SecurityProtocolId The value of the "Security Protocol" parameter of + the security protocol command to be sent. + @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter + of the security protocol command to be sent. + @param PayloadBufferSize Size in bytes of the payload data buffer. + @param PayloadBuffer A pointer to a destination buffer to store the security + protocol command specific payload data for the security + protocol command. + + @retval EFI_SUCCESS The security protocol command completed successfully. + @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands. + @retval EFI_DEVICE_ERROR The security protocol command completed with an error. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero. + @retval EFI_TIMEOUT A timeout occurred while waiting for the security + protocol command to execute. + +**/ +EFI_STATUS +EFIAPI +NvmeStorageSecuritySendData( + IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This, + IN UINT32 MediaId, + IN UINT64 Timeout, + IN UINT8 SecurityProtocolId, + IN UINT16 SecurityProtocolSpecificData, + IN UINTN PayloadBufferSize, + IN VOID *PayloadBuffer +) +{ + EFI_STATUS Status; + NVME_DEVICE_PRIVATE_DATA *Device; + + Status = EFI_SUCCESS; + + if ((PayloadBuffer == NULL) && (PayloadBufferSize != 0)) + return EFI_INVALID_PARAMETER; + + Device = NVME_DEVICE_PRIVATE_DATA_FROM_STORAGE_SECURITY(This); + + if (MediaId != Device->BlockIo.Media->MediaId) + return EFI_MEDIA_CHANGED; + + if (!Device->BlockIo.Media->MediaPresent) + return EFI_NO_MEDIA; + + Status = TrustTransferNvmeDevice( + Device->Controller, + PayloadBuffer, + SecurityProtocolId, + SecurityProtocolSpecificData, + PayloadBufferSize, + TRUE, + Timeout, + NULL + ); + + return Status; +} + diff --git a/drivers/nvme/NvmExpressBlockIo.h b/drivers/nvme/NvmExpressBlockIo.h index 69595ce..587b33d 100644 --- a/drivers/nvme/NvmExpressBlockIo.h +++ b/drivers/nvme/NvmExpressBlockIo.h @@ -109,4 +109,163 @@ NvmeBlockIoFlushBlocks ( IN EFI_BLOCK_IO_PROTOCOL *This ); +/** + Send a security protocol command to a device that receives data and/or the result + of one or more commands sent by SendData. + + The ReceiveData function sends a security protocol command to the given MediaId. + The security protocol command sent is defined by SecurityProtocolId and contains + the security protocol specific data SecurityProtocolSpecificData. The function + returns the data from the security protocol command in PayloadBuffer. + + For devices supporting the SCSI command set, the security protocol command is sent + using the SECURITY PROTOCOL IN command defined in SPC-4. + + For devices supporting the ATA command set, the security protocol command is sent + using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize + is non-zero. + + If the PayloadBufferSize is zero, the security protocol command is sent using the + Trusted Non-Data command defined in ATA8-ACS. + + If PayloadBufferSize is too small to store the available data from the security + protocol command, the function shall copy PayloadBufferSize bytes into the + PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL. + + If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero, + the function shall return EFI_INVALID_PARAMETER. + + If the given MediaId does not support security protocol commands, the function shall + return EFI_UNSUPPORTED. If there is no media in the device, the function returns + EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device, + the function returns EFI_MEDIA_CHANGED. + + If the security protocol fails to complete within the Timeout period, the function + shall return EFI_TIMEOUT. + + If the security protocol command completes without an error, the function shall + return EFI_SUCCESS. If the security protocol command completes with an error, the + function shall return EFI_DEVICE_ERROR. + + @param This Indicates a pointer to the calling context. + @param MediaId ID of the medium to receive data from. + @param Timeout The timeout, in 100ns units, to use for the execution + of the security protocol command. A Timeout value of 0 + means that this function will wait indefinitely for the + security protocol command to execute. If Timeout is greater + than zero, then this function will return EFI_TIMEOUT + if the time required to execute the receive data command + is greater than Timeout. + @param SecurityProtocolId The value of the "Security Protocol" parameter of + the security protocol command to be sent. + @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter + of the security protocol command to be sent. + @param PayloadBufferSize Size in bytes of the payload data buffer. + @param PayloadBuffer A pointer to a destination buffer to store the security + protocol command specific payload data for the security + protocol command. The caller is responsible for having + either implicit or explicit ownership of the buffer. + @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the + data written to the payload data buffer. + + @retval EFI_SUCCESS The security protocol command completed successfully. + @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available + data from the device. The PayloadBuffer contains the truncated data. + @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands. + @retval EFI_DEVICE_ERROR The security protocol command completed with an error. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and + PayloadBufferSize is non-zero. + @retval EFI_TIMEOUT A timeout occurred while waiting for the security + protocol command to execute. + +**/ +EFI_STATUS +EFIAPI +NvmeStorageSecurityReceiveData ( + IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This, + IN UINT32 MediaId, + IN UINT64 Timeout, + IN UINT8 SecurityProtocolId, + IN UINT16 SecurityProtocolSpecificData, + IN UINTN PayloadBufferSize, + OUT VOID *PayloadBuffer, + OUT UINTN *PayloadTransferSize +); + +/** + Send a security protocol command to a device. + + The SendData function sends a security protocol command containing the payload + PayloadBuffer to the given MediaId. The security protocol command sent is + defined by SecurityProtocolId and contains the security protocol specific data + SecurityProtocolSpecificData. If the underlying protocol command requires a + specific padding for the command payload, the SendData function shall add padding + bytes to the command payload to satisfy the padding requirements. + + For devices supporting the SCSI command set, the security protocol command is sent + using the SECURITY PROTOCOL OUT command defined in SPC-4. + + For devices supporting the ATA command set, the security protocol command is sent + using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize + is non-zero. If the PayloadBufferSize is zero, the security protocol command is + sent using the Trusted Non-Data command defined in ATA8-ACS. + + If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall + return EFI_INVALID_PARAMETER. + + If the given MediaId does not support security protocol commands, the function + shall return EFI_UNSUPPORTED. If there is no media in the device, the function + returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the + device, the function returns EFI_MEDIA_CHANGED. + + If the security protocol fails to complete within the Timeout period, the function + shall return EFI_TIMEOUT. + + If the security protocol command completes without an error, the function shall return + EFI_SUCCESS. If the security protocol command completes with an error, the function + shall return EFI_DEVICE_ERROR. + + @param This Indicates a pointer to the calling context. + @param MediaId ID of the medium to receive data from. + @param Timeout The timeout, in 100ns units, to use for the execution + of the security protocol command. A Timeout value of 0 + means that this function will wait indefinitely for the + security protocol command to execute. If Timeout is greater + than zero, then this function will return EFI_TIMEOUT + if the time required to execute the receive data command + is greater than Timeout. + @param SecurityProtocolId The value of the "Security Protocol" parameter of + the security protocol command to be sent. + @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter + of the security protocol command to be sent. + @param PayloadBufferSize Size in bytes of the payload data buffer. + @param PayloadBuffer A pointer to a destination buffer to store the security + protocol command specific payload data for the security + protocol command. + + @retval EFI_SUCCESS The security protocol command completed successfully. + @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands. + @retval EFI_DEVICE_ERROR The security protocol command completed with an error. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero. + @retval EFI_TIMEOUT A timeout occurred while waiting for the security + protocol command to execute. + +**/ +EFI_STATUS +EFIAPI +NvmeStorageSecuritySendData ( + IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This, + IN UINT32 MediaId, + IN UINT64 Timeout, + IN UINT8 SecurityProtocolId, + IN UINT16 SecurityProtocolSpecificData, + IN UINTN PayloadBufferSize, + IN VOID *PayloadBuffer +); + + #endif diff --git a/drivers/nvme/NvmExpressHci.c b/drivers/nvme/NvmExpressHci.c index 6496cec..f5fffae 100644 --- a/drivers/nvme/NvmExpressHci.c +++ b/drivers/nvme/NvmExpressHci.c @@ -951,7 +951,7 @@ NvmeControllerInit ( DEBUG_NVME ((EFI_D_INFO, " CQES : 0x%x\n", Private->ControllerData->Cqes)); DEBUG_NVME ((EFI_D_INFO, " NN : 0x%x\n", Private->ControllerData->Nn)); DEBUG_NVME ((EFI_D_INFO, " Oncs : 0x%x\n", Private->ControllerData->Oncs)); - + DEBUG_NVME ((EFI_D_INFO, " Oacs : 0x%x\n", Private->ControllerData->Oacs)); // // Create two I/O completion queues. diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c index 80457b2..c762ddf 100644 --- a/drivers/nvme/nvme.c +++ b/drivers/nvme/nvme.c @@ -123,11 +123,14 @@ static storage_t nvme_storage = { static EFI_HANDLE nvme_handle; static EFI_GUID nvme_pass_thru_guid = EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL_GUID; +static EFI_GUID nvme_security_guid = EFI_STORAGE_SECURITY_COMMAND_PROTOCOL_GUID; static EFI_STATUS nvme_drv_init(EFI_SYSTEM_TABLE *st) { EFI_STATUS ret; boot_dev_t *boot_dev; + EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *StorageSecurity; + EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *nvme_passthru; boot_dev = get_boot_media(); if (!boot_dev) @@ -141,8 +144,18 @@ static EFI_STATUS nvme_drv_init(EFI_SYSTEM_TABLE *st) if (EFI_ERROR(ret)) return ret; - EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *nvme_passthru = NvmeGetPassthru(); + StorageSecurity = NvmeGetSecurityInterface(); + if (StorageSecurity != NULL) { + ret = uefi_call_wrapper(st->BootServices->InstallProtocolInterface, + 4, + &nvme_handle, + &nvme_security_guid, + EFI_NATIVE_INTERFACE, + StorageSecurity + ); + } + nvme_passthru = NvmeGetPassthru(); return uefi_call_wrapper(st->BootServices->InstallProtocolInterface, 4, &nvme_handle, &nvme_pass_thru_guid, EFI_NATIVE_INTERFACE, nvme_passthru); } @@ -165,6 +178,14 @@ static EFI_STATUS nvme_drv_exit(EFI_SYSTEM_TABLE *st) ret = uefi_call_wrapper(st->BootServices->UninstallProtocolInterface, 3, nvme_handle, &nvme_pass_thru_guid, nvme_interface); + ret = uefi_call_wrapper(st->BootServices->HandleProtocol, 3, + nvme_handle, &nvme_security_guid, (VOID **)&nvme_interface); + if (EFI_ERROR(ret)) + return ret; + + ret = uefi_call_wrapper(st->BootServices->UninstallProtocolInterface, 3, + nvme_handle, &nvme_security_guid, nvme_interface); + return ret; } diff --git a/include/libefiwrapper/protocol/StorageSecurityCommand.h b/include/libefiwrapper/protocol/StorageSecurityCommand.h new file mode 100644 index 0000000..4f806af --- /dev/null +++ b/include/libefiwrapper/protocol/StorageSecurityCommand.h @@ -0,0 +1,212 @@ +/** @file + EFI Storage Security Command Protocol as defined in UEFI 2.3.1 specification. + This protocol is used to abstract mass storage devices to allow code running in + the EFI boot services environment to send security protocol commands to mass + storage devices without specific knowledge of the type of device or controller + that manages the device. + + Copyright (c) 2011, 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 __STORAGE_SECURITY_COMMAND_H__ +#define __STORAGE_SECURITY_COMMAND_H__ + +#define EFI_STORAGE_SECURITY_COMMAND_PROTOCOL_GUID \ + { \ + 0xC88B0B6D, 0x0DFC, 0x49A7, {0x9C, 0xB4, 0x49, 0x07, 0x4B, 0x4C, 0x3A, 0x78 } \ + } + +typedef struct _EFI_STORAGE_SECURITY_COMMAND_PROTOCOL EFI_STORAGE_SECURITY_COMMAND_PROTOCOL; + +/** + Send a security protocol command to a device that receives data and/or the result + of one or more commands sent by SendData. + + The ReceiveData function sends a security protocol command to the given MediaId. + The security protocol command sent is defined by SecurityProtocolId and contains + the security protocol specific data SecurityProtocolSpecificData. The function + returns the data from the security protocol command in PayloadBuffer. + + For devices supporting the SCSI command set, the security protocol command is sent + using the SECURITY PROTOCOL IN command defined in SPC-4. + + For devices supporting the ATA command set, the security protocol command is sent + using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize + is non-zero. + + If the PayloadBufferSize is zero, the security protocol command is sent using the + Trusted Non-Data command defined in ATA8-ACS. + + If PayloadBufferSize is too small to store the available data from the security + protocol command, the function shall copy PayloadBufferSize bytes into the + PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL. + + If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero, + the function shall return EFI_INVALID_PARAMETER. + + If the given MediaId does not support security protocol commands, the function shall + return EFI_UNSUPPORTED. If there is no media in the device, the function returns + EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device, + the function returns EFI_MEDIA_CHANGED. + + If the security protocol fails to complete within the Timeout period, the function + shall return EFI_TIMEOUT. + + If the security protocol command completes without an error, the function shall + return EFI_SUCCESS. If the security protocol command completes with an error, the + function shall return EFI_DEVICE_ERROR. + + @param This Indicates a pointer to the calling context. + @param MediaId ID of the medium to receive data from. + @param Timeout The timeout, in 100ns units, to use for the execution + of the security protocol command. A Timeout value of 0 + means that this function will wait indefinitely for the + security protocol command to execute. If Timeout is greater + than zero, then this function will return EFI_TIMEOUT if the + time required to execute the receive data command is greater than Timeout. + @param SecurityProtocolId The value of the "Security Protocol" parameter of + the security protocol command to be sent. + @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter + of the security protocol command to be sent. + @param PayloadBufferSize Size in bytes of the payload data buffer. + @param PayloadBuffer A pointer to a destination buffer to store the security + protocol command specific payload data for the security + protocol command. The caller is responsible for having + either implicit or explicit ownership of the buffer. + @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the + data written to the payload data buffer. + + @retval EFI_SUCCESS The security protocol command completed successfully. + @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available + data from the device. The PayloadBuffer contains the truncated data. + @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands. + @retval EFI_DEVICE_ERROR The security protocol command completed with an error. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and + PayloadBufferSize is non-zero. + @retval EFI_TIMEOUT A timeout occurred while waiting for the security + protocol command to execute. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_STORAGE_SECURITY_RECEIVE_DATA)( + IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This, + IN UINT32 MediaId, + IN UINT64 Timeout, + IN UINT8 SecurityProtocolId, + IN UINT16 SecurityProtocolSpecificData, + IN UINTN PayloadBufferSize, + OUT VOID *PayloadBuffer, + OUT UINTN *PayloadTransferSize + ); + +/** + Send a security protocol command to a device. + + The SendData function sends a security protocol command containing the payload + PayloadBuffer to the given MediaId. The security protocol command sent is + defined by SecurityProtocolId and contains the security protocol specific data + SecurityProtocolSpecificData. If the underlying protocol command requires a + specific padding for the command payload, the SendData function shall add padding + bytes to the command payload to satisfy the padding requirements. + + For devices supporting the SCSI command set, the security protocol command is sent + using the SECURITY PROTOCOL OUT command defined in SPC-4. + + For devices supporting the ATA command set, the security protocol command is sent + using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize + is non-zero. If the PayloadBufferSize is zero, the security protocol command is + sent using the Trusted Non-Data command defined in ATA8-ACS. + + If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall + return EFI_INVALID_PARAMETER. + + If the given MediaId does not support security protocol commands, the function + shall return EFI_UNSUPPORTED. If there is no media in the device, the function + returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the + device, the function returns EFI_MEDIA_CHANGED. + + If the security protocol fails to complete within the Timeout period, the function + shall return EFI_TIMEOUT. + + If the security protocol command completes without an error, the function shall return + EFI_SUCCESS. If the security protocol command completes with an error, the function + shall return EFI_DEVICE_ERROR. + + @param This Indicates a pointer to the calling context. + @param MediaId ID of the medium to receive data from. + @param Timeout The timeout, in 100ns units, to use for the execution + of the security protocol command. A Timeout value of 0 + means that this function will wait indefinitely for the + security protocol command to execute. If Timeout is greater + than zero, then this function will return EFI_TIMEOUT if the + time required to execute the receive data command is greater than Timeout. + @param SecurityProtocolId The value of the "Security Protocol" parameter of + the security protocol command to be sent. + @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter + of the security protocol command to be sent. + @param PayloadBufferSize Size in bytes of the payload data buffer. + @param PayloadBuffer A pointer to a destination buffer to store the security + protocol command specific payload data for the security + protocol command. + + @retval EFI_SUCCESS The security protocol command completed successfully. + @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands. + @retval EFI_DEVICE_ERROR The security protocol command completed with an error. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero. + @retval EFI_TIMEOUT A timeout occurred while waiting for the security + protocol command to execute. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_STORAGE_SECURITY_SEND_DATA) ( + IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This, + IN UINT32 MediaId, + IN UINT64 Timeout, + IN UINT8 SecurityProtocolId, + IN UINT16 SecurityProtocolSpecificData, + IN UINTN PayloadBufferSize, + IN VOID *PayloadBuffer +); + +/// +/// The EFI_STORAGE_SECURITY_COMMAND_PROTOCOL is used to send security protocol +/// commands to a mass storage device. Two types of security protocol commands +/// are supported. SendData sends a command with data to a device. ReceiveData +/// sends a command that receives data and/or the result of one or more commands +/// sent by SendData. +/// +/// The security protocol command formats supported shall be based on the definition +/// of the SECURITY PROTOCOL IN and SECURITY PROTOCOL OUT commands defined in SPC-4. +/// If the device uses the SCSI command set, no translation is needed in the firmware +/// and the firmware can package the parameters into a SECURITY PROTOCOL IN or SECURITY +/// PROTOCOL OUT command and send the command to the device. If the device uses a +/// non-SCSI command set, the firmware shall map the command and data payload to the +/// corresponding command and payload format defined in the non-SCSI command set +/// (for example, TRUSTED RECEIVE and TRUSTED SEND in ATA8-ACS). +/// +/// The firmware shall automatically add an EFI_STORAGE_SECURITY_COMMAND_PROTOCOL +/// for any storage devices detected during system boot that support SPC-4, ATA8-ACS +/// or their successors. +/// +struct _EFI_STORAGE_SECURITY_COMMAND_PROTOCOL { + EFI_STORAGE_SECURITY_RECEIVE_DATA ReceiveData; + EFI_STORAGE_SECURITY_SEND_DATA SendData; +}; + +extern EFI_GUID gEfiStorageSecurityCommandProtocolGuid; + +#endif