1 /** @file
2   The NvmExpressPei driver is used to manage non-volatile memory subsystem
3   which follows NVM Express specification at PEI phase.
4 
5   Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
6 
7   SPDX-License-Identifier: BSD-2-Clause-Patent
8 
9 **/
10 
11 #include "NvmExpressPei.h"
12 
13 /**
14   Trust transfer data from/to NVM Express device.
15 
16   This function performs one NVMe transaction to do a trust transfer from/to NVM
17   Express device.
18 
19   @param[in]     Private           The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA
20                                    data structure.
21   @param[in,out] Buffer            The pointer to the current transaction buffer.
22   @param[in]     SecurityProtocolId
23                                    The value of the "Security Protocol" parameter
24                                    of the security protocol command to be sent.
25   @param[in]     SecurityProtocolSpecificData
26                                    The value of the "Security Protocol Specific"
27                                    parameter of the security protocol command to
28                                    be sent.
29   @param[in]     TransferLength    The block number or sector count of the transfer.
30   @param[in]     IsTrustSend       Indicates whether it is a trust send operation
31                                    or not.
32   @param[in]     Timeout           The timeout, in 100ns units, to use for the
33                                    execution of the security protocol command.
34                                    A Timeout value of 0 means that this function
35                                    will wait indefinitely for the security protocol
36                                    command to execute. If Timeout is greater than
37                                    zero, then this function will return EFI_TIMEOUT
38                                    if the time required to execute the receive
39                                    data command is greater than Timeout.
40   @param[out]    TransferLengthOut A pointer to a buffer to store the size in bytes
41                                    of the data written to the buffer. Ignore it
42                                    when IsTrustSend is TRUE.
43 
44   @retval EFI_SUCCESS    The data transfer is complete successfully.
45   @return others         Some error occurs when transferring data.
46 
47 **/
48 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)49 TrustTransferNvmeDevice (
50   IN     PEI_NVME_CONTROLLER_PRIVATE_DATA    *Private,
51   IN OUT VOID                                *Buffer,
52   IN     UINT8                               SecurityProtocolId,
53   IN     UINT16                              SecurityProtocolSpecificData,
54   IN     UINTN                               TransferLength,
55   IN     BOOLEAN                             IsTrustSend,
56   IN     UINT64                              Timeout,
57      OUT UINTN                               *TransferLengthOut
58   )
59 {
60   EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET          CommandPacket;
61   EFI_NVM_EXPRESS_COMMAND                           Command;
62   EFI_NVM_EXPRESS_COMPLETION                        Completion;
63   EFI_STATUS                                        Status;
64   UINT16                                            SpecificData;
65   EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI               *NvmePassThru;
66 
67   NvmePassThru = &Private->NvmePassThruPpi;
68   ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
69   ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
70   ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
71 
72   CommandPacket.NvmeCmd        = &Command;
73   CommandPacket.NvmeCompletion = &Completion;
74 
75   //
76   // Change Endianness of SecurityProtocolSpecificData
77   //
78   SpecificData = (((SecurityProtocolSpecificData << 8) & 0xFF00) | (SecurityProtocolSpecificData >> 8));
79 
80   if (IsTrustSend) {
81     Command.Cdw0.Opcode          = NVME_ADMIN_SECURITY_SEND_CMD;
82     CommandPacket.TransferBuffer = Buffer;
83     CommandPacket.TransferLength = (UINT32)TransferLength;
84     CommandPacket.NvmeCmd->Cdw10 = (UINT32)((SecurityProtocolId << 24) | (SpecificData << 8));
85     CommandPacket.NvmeCmd->Cdw11 = (UINT32)TransferLength;
86   } else {
87     Command.Cdw0.Opcode          = NVME_ADMIN_SECURITY_RECEIVE_CMD;
88     CommandPacket.TransferBuffer = Buffer;
89     CommandPacket.TransferLength = (UINT32)TransferLength;
90     CommandPacket.NvmeCmd->Cdw10 = (UINT32)((SecurityProtocolId << 24) | (SpecificData << 8));
91     CommandPacket.NvmeCmd->Cdw11 = (UINT32)TransferLength;
92   }
93 
94   CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
95   CommandPacket.NvmeCmd->Nsid  = NVME_CONTROLLER_NSID;
96   CommandPacket.CommandTimeout = Timeout;
97   CommandPacket.QueueType      = NVME_ADMIN_QUEUE;
98 
99   Status = NvmePassThru->PassThru (
100                            NvmePassThru,
101                            NVME_CONTROLLER_NSID,
102                            &CommandPacket
103                            );
104 
105   if (!IsTrustSend) {
106     if (EFI_ERROR (Status))  {
107       *TransferLengthOut = 0;
108     } else {
109       *TransferLengthOut = (UINTN) TransferLength;
110     }
111   }
112 
113   return Status;
114 }
115 
116 /**
117   Gets the count of storage security devices that one specific driver detects.
118 
119   @param[in]  This               The PPI instance pointer.
120   @param[out] NumberofDevices    The number of storage security devices discovered.
121 
122   @retval EFI_SUCCESS              The operation performed successfully.
123   @retval EFI_INVALID_PARAMETER    The parameters are invalid.
124 
125 **/
126 EFI_STATUS
127 EFIAPI
NvmeStorageSecurityGetDeviceNo(IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI * This,OUT UINTN * NumberofDevices)128 NvmeStorageSecurityGetDeviceNo (
129   IN  EDKII_PEI_STORAGE_SECURITY_CMD_PPI    *This,
130   OUT UINTN                                 *NumberofDevices
131   )
132 {
133   PEI_NVME_CONTROLLER_PRIVATE_DATA    *Private;
134 
135   if (This == NULL || NumberofDevices == NULL) {
136     return EFI_INVALID_PARAMETER;
137   }
138 
139   Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
140   *NumberofDevices = Private->ActiveNamespaceNum;
141 
142   return EFI_SUCCESS;
143 }
144 
145 /**
146   Gets the device path of a specific storage security device.
147 
148   @param[in]  This                 The PPI instance pointer.
149   @param[in]  DeviceIndex          Specifies the storage security device to which
150                                    the function wants to talk. Because the driver
151                                    that implements Storage Security Command PPIs
152                                    will manage multiple storage devices, the PPIs
153                                    that want to talk to a single device must specify
154                                    the device index that was assigned during the
155                                    enumeration process. This index is a number from
156                                    one to NumberofDevices.
157   @param[out] DevicePathLength     The length of the device path in bytes specified
158                                    by DevicePath.
159   @param[out] DevicePath           The device path of storage security device.
160                                    This field re-uses EFI Device Path Protocol as
161                                    defined by Section 10.2 EFI Device Path Protocol
162                                    of UEFI 2.7 Specification.
163 
164   @retval EFI_SUCCESS              The operation succeeds.
165   @retval EFI_INVALID_PARAMETER    DevicePathLength or DevicePath is NULL.
166   @retval EFI_NOT_FOUND            The specified storage security device not found.
167   @retval EFI_OUT_OF_RESOURCES     The operation fails due to lack of resources.
168 
169 **/
170 EFI_STATUS
171 EFIAPI
NvmeStorageSecurityGetDevicePath(IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI * This,IN UINTN DeviceIndex,OUT UINTN * DevicePathLength,OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath)172 NvmeStorageSecurityGetDevicePath (
173   IN  EDKII_PEI_STORAGE_SECURITY_CMD_PPI  *This,
174   IN  UINTN                               DeviceIndex,
175   OUT UINTN                               *DevicePathLength,
176   OUT EFI_DEVICE_PATH_PROTOCOL            **DevicePath
177   )
178 {
179   PEI_NVME_CONTROLLER_PRIVATE_DATA         *Private;
180 
181   if (This == NULL || DevicePathLength == NULL || DevicePath == NULL) {
182     return EFI_INVALID_PARAMETER;
183   }
184 
185   Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
186   if ((DeviceIndex == 0) || (DeviceIndex > Private->ActiveNamespaceNum)) {
187     return EFI_INVALID_PARAMETER;
188   }
189 
190   return NvmeBuildDevicePath (
191            Private,
192            Private->NamespaceInfo[DeviceIndex-1].NamespaceId,
193            Private->NamespaceInfo[DeviceIndex-1].NamespaceUuid,
194            DevicePathLength,
195            DevicePath
196            );
197 }
198 
199 /**
200   Send a security protocol command to a device that receives data and/or the result
201   of one or more commands sent by SendData.
202 
203   The ReceiveData function sends a security protocol command to the given DeviceIndex.
204   The security protocol command sent is defined by SecurityProtocolId and contains
205   the security protocol specific data SecurityProtocolSpecificData. The function
206   returns the data from the security protocol command in PayloadBuffer.
207 
208   For devices supporting the SCSI command set, the security protocol command is sent
209   using the SECURITY PROTOCOL IN command defined in SPC-4.
210 
211   For devices supporting the ATA command set, the security protocol command is sent
212   using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
213   is non-zero.
214 
215   If the PayloadBufferSize is zero, the security protocol command is sent using the
216   Trusted Non-Data command defined in ATA8-ACS.
217 
218   If PayloadBufferSize is too small to store the available data from the security
219   protocol command, the function shall copy PayloadBufferSize bytes into the
220   PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
221 
222   If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
223   the function shall return EFI_INVALID_PARAMETER.
224 
225   If the given DeviceIndex does not support security protocol commands, the function
226   shall return EFI_UNSUPPORTED.
227 
228   If the security protocol fails to complete within the Timeout period, the function
229   shall return EFI_TIMEOUT.
230 
231   If the security protocol command completes without an error, the function shall
232   return EFI_SUCCESS. If the security protocol command completes with an error, the
233   function shall return EFI_DEVICE_ERROR.
234 
235   @param[in]  This             The PPI instance pointer.
236   @param[in]  DeviceIndex      Specifies the storage security device to which the
237                                function wants to talk. Because the driver that
238                                implements Storage Security Command PPIs will manage
239                                multiple storage devices, the PPIs that want to talk
240                                to a single device must specify the device index
241                                that was assigned during the enumeration process.
242                                This index is a number from one to NumberofDevices.
243   @param[in]  Timeout          The timeout, in 100ns units, to use for the execution
244                                of the security protocol command. A Timeout value
245                                of 0 means that this function will wait indefinitely
246                                for the security protocol command to execute. If
247                                Timeout is greater than zero, then this function
248                                will return EFI_TIMEOUT if the time required to
249                                execute the receive data command is greater than
250                                Timeout.
251   @param[in]  SecurityProtocolId
252                                The value of the "Security Protocol" parameter of
253                                the security protocol command to be sent.
254   @param[in]  SecurityProtocolSpecificData
255                                The value of the "Security Protocol Specific"
256                                parameter of the security protocol command to be
257                                sent.
258   @param[in]  PayloadBufferSize
259                                Size in bytes of the payload data buffer.
260   @param[out] PayloadBuffer    A pointer to a destination buffer to store the
261                                security protocol command specific payload data
262                                for the security protocol command. The caller is
263                                responsible for having either implicit or explicit
264                                ownership of the buffer.
265   @param[out] PayloadTransferSize
266                                A pointer to a buffer to store the size in bytes
267                                of the data written to the payload data buffer.
268 
269   @retval EFI_SUCCESS                  The security protocol command completed
270                                        successfully.
271   @retval EFI_WARN_BUFFER_TOO_SMALL    The PayloadBufferSize was too small to
272                                        store the available data from the device.
273                                        The PayloadBuffer contains the truncated
274                                        data.
275   @retval EFI_UNSUPPORTED              The given DeviceIndex does not support
276                                        security protocol commands.
277   @retval EFI_DEVICE_ERROR             The security protocol command completed
278                                        with an error.
279   @retval EFI_INVALID_PARAMETER        The PayloadBuffer or PayloadTransferSize
280                                        is NULL and PayloadBufferSize is non-zero.
281   @retval EFI_TIMEOUT                  A timeout occurred while waiting for the
282                                        security protocol command to execute.
283 
284 **/
285 EFI_STATUS
286 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)287 NvmeStorageSecurityReceiveData (
288   IN  EDKII_PEI_STORAGE_SECURITY_CMD_PPI  *This,
289   IN  UINTN                               DeviceIndex,
290   IN  UINT64                              Timeout,
291   IN  UINT8                               SecurityProtocolId,
292   IN  UINT16                              SecurityProtocolSpecificData,
293   IN  UINTN                               PayloadBufferSize,
294   OUT VOID                                *PayloadBuffer,
295   OUT UINTN                               *PayloadTransferSize
296   )
297 {
298   PEI_NVME_CONTROLLER_PRIVATE_DATA    *Private;
299   EFI_STATUS                          Status;
300 
301   if ((PayloadBuffer == NULL) || (PayloadTransferSize == NULL) || (PayloadBufferSize == 0)) {
302     return EFI_INVALID_PARAMETER;
303   }
304 
305   Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
306 
307   Status = TrustTransferNvmeDevice (
308              Private,
309              PayloadBuffer,
310              SecurityProtocolId,
311              SecurityProtocolSpecificData,
312              PayloadBufferSize,
313              FALSE,
314              Timeout,
315              PayloadTransferSize
316              );
317 
318   return Status;
319 }
320 
321 /**
322   Send a security protocol command to a device.
323 
324   The SendData function sends a security protocol command containing the payload
325   PayloadBuffer to the given DeviceIndex. The security protocol command sent is
326   defined by SecurityProtocolId and contains the security protocol specific data
327   SecurityProtocolSpecificData. If the underlying protocol command requires a
328   specific padding for the command payload, the SendData function shall add padding
329   bytes to the command payload to satisfy the padding requirements.
330 
331   For devices supporting the SCSI command set, the security protocol command is
332   sent using the SECURITY PROTOCOL OUT command defined in SPC-4.
333 
334   For devices supporting the ATA command set, the security protocol command is
335   sent using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
336   is non-zero. If the PayloadBufferSize is zero, the security protocol command
337   is sent using the Trusted Non-Data command defined in ATA8-ACS.
338 
339   If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
340   return EFI_INVALID_PARAMETER.
341 
342   If the given DeviceIndex does not support security protocol commands, the function
343   shall return EFI_UNSUPPORTED.
344 
345   If the security protocol fails to complete within the Timeout period, the function
346   shall return EFI_TIMEOUT.
347 
348   If the security protocol command completes without an error, the function shall
349   return EFI_SUCCESS. If the security protocol command completes with an error,
350   the functio shall return EFI_DEVICE_ERROR.
351 
352   @param[in] This              The PPI instance pointer.
353   @param[in] DeviceIndex       The ID of the device.
354   @param[in] Timeout           The timeout, in 100ns units, to use for the execution
355                                of the security protocol command. A Timeout value
356                                of 0 means that this function will wait indefinitely
357                                for the security protocol command to execute. If
358                                Timeout is greater than zero, then this function
359                                will return EFI_TIMEOUT if the time required to
360                                execute the receive data command is greater than
361                                Timeout.
362   @param[in] SecurityProtocolId
363                                The value of the "Security Protocol" parameter of
364                                the security protocol command to be sent.
365   @param[in] SecurityProtocolSpecificData
366                                The value of the "Security Protocol Specific"
367                                parameter of the security protocol command to be
368                                sent.
369   @param[in] PayloadBufferSize Size in bytes of the payload data buffer.
370   @param[in] PayloadBuffer     A pointer to a destination buffer to store the
371                                security protocol command specific payload data
372                                for the security protocol command.
373 
374   @retval EFI_SUCCESS              The security protocol command completed successfully.
375   @retval EFI_UNSUPPORTED          The given DeviceIndex does not support security
376                                    protocol commands.
377   @retval EFI_DEVICE_ERROR         The security protocol command completed with
378                                    an error.
379   @retval EFI_INVALID_PARAMETER    The PayloadBuffer is NULL and PayloadBufferSize
380                                    is non-zero.
381   @retval EFI_TIMEOUT              A timeout occurred while waiting for the security
382                                    protocol command to execute.
383 
384 **/
385 EFI_STATUS
386 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)387 NvmeStorageSecuritySendData (
388   IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI  *This,
389   IN UINTN                               DeviceIndex,
390   IN UINT64                              Timeout,
391   IN UINT8                               SecurityProtocolId,
392   IN UINT16                              SecurityProtocolSpecificData,
393   IN UINTN                               PayloadBufferSize,
394   IN VOID                                *PayloadBuffer
395   )
396 {
397   PEI_NVME_CONTROLLER_PRIVATE_DATA    *Private;
398   EFI_STATUS                          Status;
399 
400   if ((PayloadBuffer == NULL) && (PayloadBufferSize != 0)) {
401     return EFI_INVALID_PARAMETER;
402   }
403 
404   Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
405 
406   Status = TrustTransferNvmeDevice (
407              Private,
408              PayloadBuffer,
409              SecurityProtocolId,
410              SecurityProtocolSpecificData,
411              PayloadBufferSize,
412              TRUE,
413              Timeout,
414              NULL
415              );
416 
417   return Status;
418 }
419