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