1 /** @file
2   The AhciPei driver is used to manage ATA hard disk device working under AHCI
3   mode 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 "AhciPei.h"
12 
13 /**
14   Traverse the attached ATA devices list to find out the device with given trust
15   computing device index.
16 
17   @param[in] Private                      A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA
18                                           instance.
19   @param[in] TrustComputingDeviceIndex    The trust computing device index.
20 
21   @retval    The pointer to the PEI_AHCI_ATA_DEVICE_DATA structure of the device
22              info to access.
23 
24 **/
25 PEI_AHCI_ATA_DEVICE_DATA *
SearchTrustComputingDeviceByIndex(IN PEI_AHCI_CONTROLLER_PRIVATE_DATA * Private,IN UINTN TrustComputingDeviceIndex)26 SearchTrustComputingDeviceByIndex (
27   IN PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private,
28   IN UINTN                               TrustComputingDeviceIndex
29   )
30 {
31   PEI_AHCI_ATA_DEVICE_DATA    *DeviceData;
32   LIST_ENTRY                  *Node;
33 
34   Node = GetFirstNode (&Private->DeviceList);
35   while (!IsNull (&Private->DeviceList, Node)) {
36     DeviceData = AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS (Node);
37 
38     if (DeviceData->TrustComputingDeviceIndex == TrustComputingDeviceIndex) {
39       return DeviceData;
40     }
41 
42     Node = GetNextNode (&Private->DeviceList, Node);
43   }
44 
45   return NULL;
46 }
47 
48 /**
49   Gets the count of storage security devices that one specific driver detects.
50 
51   @param[in]  This               The PPI instance pointer.
52   @param[out] NumberofDevices    The number of storage security devices discovered.
53 
54   @retval EFI_SUCCESS              The operation performed successfully.
55   @retval EFI_INVALID_PARAMETER    The parameters are invalid.
56 
57 **/
58 EFI_STATUS
59 EFIAPI
AhciStorageSecurityGetDeviceNo(IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI * This,OUT UINTN * NumberofDevices)60 AhciStorageSecurityGetDeviceNo (
61   IN  EDKII_PEI_STORAGE_SECURITY_CMD_PPI    *This,
62   OUT UINTN                                 *NumberofDevices
63   )
64 {
65   PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private;
66 
67   if (This == NULL || NumberofDevices == NULL) {
68     return EFI_INVALID_PARAMETER;
69   }
70 
71   Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
72   *NumberofDevices = Private->TrustComputingDevices;
73 
74   return EFI_SUCCESS;
75 }
76 
77 /**
78   Gets the device path of a specific storage security device.
79 
80   @param[in]  This                 The PPI instance pointer.
81   @param[in]  DeviceIndex          Specifies the storage security device to which
82                                    the function wants to talk. Because the driver
83                                    that implements Storage Security Command PPIs
84                                    will manage multiple storage devices, the PPIs
85                                    that want to talk to a single device must specify
86                                    the device index that was assigned during the
87                                    enumeration process. This index is a number from
88                                    one to NumberofDevices.
89   @param[out] DevicePathLength     The length of the device path in bytes specified
90                                    by DevicePath.
91   @param[out] DevicePath           The device path of storage security device.
92                                    This field re-uses EFI Device Path Protocol as
93                                    defined by Section 10.2 EFI Device Path Protocol
94                                    of UEFI 2.7 Specification.
95 
96   @retval EFI_SUCCESS              The operation succeeds.
97   @retval EFI_INVALID_PARAMETER    DevicePathLength or DevicePath is NULL.
98   @retval EFI_NOT_FOUND            The specified storage security device not found.
99   @retval EFI_OUT_OF_RESOURCES     The operation fails due to lack of resources.
100 
101 **/
102 EFI_STATUS
103 EFIAPI
AhciStorageSecurityGetDevicePath(IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI * This,IN UINTN DeviceIndex,OUT UINTN * DevicePathLength,OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath)104 AhciStorageSecurityGetDevicePath (
105   IN  EDKII_PEI_STORAGE_SECURITY_CMD_PPI    *This,
106   IN  UINTN                                 DeviceIndex,
107   OUT UINTN                                 *DevicePathLength,
108   OUT EFI_DEVICE_PATH_PROTOCOL              **DevicePath
109   )
110 {
111   PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private;
112   PEI_AHCI_ATA_DEVICE_DATA            *DeviceData;
113   EFI_STATUS                          Status;
114 
115   if (This == NULL || DevicePathLength == NULL || DevicePath == NULL) {
116     return EFI_INVALID_PARAMETER;
117   }
118 
119   Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
120   if ((DeviceIndex == 0) || (DeviceIndex > Private->TrustComputingDevices)) {
121     return EFI_INVALID_PARAMETER;
122   }
123 
124   DeviceData = SearchTrustComputingDeviceByIndex (Private, DeviceIndex);
125   if (DeviceData == NULL) {
126     return EFI_NOT_FOUND;
127   }
128 
129   Status = AhciBuildDevicePath (
130              Private,
131              DeviceData->Port,
132              DeviceData->PortMultiplier,
133              DevicePathLength,
134              DevicePath
135              );
136   if (EFI_ERROR (Status)) {
137     return Status;
138   }
139 
140   return EFI_SUCCESS;
141 }
142 
143 /**
144   Send a security protocol command to a device that receives data and/or the result
145   of one or more commands sent by SendData.
146 
147   The ReceiveData function sends a security protocol command to the given DeviceIndex.
148   The security protocol command sent is defined by SecurityProtocolId and contains
149   the security protocol specific data SecurityProtocolSpecificData. The function
150   returns the data from the security protocol command in PayloadBuffer.
151 
152   For devices supporting the SCSI command set, the security protocol command is sent
153   using the SECURITY PROTOCOL IN command defined in SPC-4.
154 
155   For devices supporting the ATA command set, the security protocol command is sent
156   using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
157   is non-zero.
158 
159   If the PayloadBufferSize is zero, the security protocol command is sent using the
160   Trusted Non-Data command defined in ATA8-ACS.
161 
162   If PayloadBufferSize is too small to store the available data from the security
163   protocol command, the function shall copy PayloadBufferSize bytes into the
164   PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
165 
166   If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
167   the function shall return EFI_INVALID_PARAMETER.
168 
169   If the given DeviceIndex does not support security protocol commands, the function
170   shall return EFI_UNSUPPORTED.
171 
172   If the security protocol fails to complete within the Timeout period, the function
173   shall return EFI_TIMEOUT.
174 
175   If the security protocol command completes without an error, the function shall
176   return EFI_SUCCESS. If the security protocol command completes with an error, the
177   function shall return EFI_DEVICE_ERROR.
178 
179   @param[in]  This             The PPI instance pointer.
180   @param[in]  DeviceIndex      Specifies the storage security device to which the
181                                function wants to talk. Because the driver that
182                                implements Storage Security Command PPIs will manage
183                                multiple storage devices, the PPIs that want to talk
184                                to a single device must specify the device index
185                                that was assigned during the enumeration process.
186                                This index is a number from one to NumberofDevices.
187   @param[in]  Timeout          The timeout, in 100ns units, to use for the execution
188                                of the security protocol command. A Timeout value
189                                of 0 means that this function will wait indefinitely
190                                for the security protocol command to execute. If
191                                Timeout is greater than zero, then this function
192                                will return EFI_TIMEOUT if the time required to
193                                execute the receive data command is greater than
194                                Timeout.
195   @param[in]  SecurityProtocolId
196                                The value of the "Security Protocol" parameter of
197                                the security protocol command to be sent.
198   @param[in]  SecurityProtocolSpecificData
199                                The value of the "Security Protocol Specific"
200                                parameter of the security protocol command to be
201                                sent.
202   @param[in]  PayloadBufferSize
203                                Size in bytes of the payload data buffer.
204   @param[out] PayloadBuffer    A pointer to a destination buffer to store the
205                                security protocol command specific payload data
206                                for the security protocol command. The caller is
207                                responsible for having either implicit or explicit
208                                ownership of the buffer.
209   @param[out] PayloadTransferSize
210                                A pointer to a buffer to store the size in bytes
211                                of the data written to the payload data buffer.
212 
213   @retval EFI_SUCCESS                  The security protocol command completed
214                                        successfully.
215   @retval EFI_WARN_BUFFER_TOO_SMALL    The PayloadBufferSize was too small to
216                                        store the available data from the device.
217                                        The PayloadBuffer contains the truncated
218                                        data.
219   @retval EFI_UNSUPPORTED              The given DeviceIndex does not support
220                                        security protocol commands.
221   @retval EFI_DEVICE_ERROR             The security protocol command completed
222                                        with an error.
223   @retval EFI_INVALID_PARAMETER        The PayloadBuffer or PayloadTransferSize
224                                        is NULL and PayloadBufferSize is non-zero.
225   @retval EFI_TIMEOUT                  A timeout occurred while waiting for the
226                                        security protocol command to execute.
227 
228 **/
229 EFI_STATUS
230 EFIAPI
AhciStorageSecurityReceiveData(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)231 AhciStorageSecurityReceiveData (
232   IN  EDKII_PEI_STORAGE_SECURITY_CMD_PPI    *This,
233   IN  UINTN                                 DeviceIndex,
234   IN  UINT64                                Timeout,
235   IN  UINT8                                 SecurityProtocolId,
236   IN  UINT16                                SecurityProtocolSpecificData,
237   IN  UINTN                                 PayloadBufferSize,
238   OUT VOID                                  *PayloadBuffer,
239   OUT UINTN                                 *PayloadTransferSize
240   )
241 {
242   PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private;
243   PEI_AHCI_ATA_DEVICE_DATA            *DeviceData;
244 
245   if ((PayloadBuffer == NULL) || (PayloadTransferSize == NULL) || (PayloadBufferSize == 0)) {
246     return EFI_INVALID_PARAMETER;
247   }
248 
249   Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
250   if ((DeviceIndex == 0) || (DeviceIndex > Private->TrustComputingDevices)) {
251     return EFI_INVALID_PARAMETER;
252   }
253 
254   DeviceData = SearchTrustComputingDeviceByIndex (Private, DeviceIndex);
255   if (DeviceData == NULL) {
256     return EFI_NOT_FOUND;
257   }
258 
259   ASSERT ((DeviceData->IdentifyData->trusted_computing_support & BIT0) != 0);
260   if ((DeviceData->IdentifyData->trusted_computing_support & BIT0) == 0) {
261     return EFI_UNSUPPORTED;
262   }
263 
264   return TrustTransferAtaDevice (
265            DeviceData,
266            PayloadBuffer,
267            SecurityProtocolId,
268            SecurityProtocolSpecificData,
269            PayloadBufferSize,
270            FALSE,
271            Timeout,
272            PayloadTransferSize
273            );
274 }
275 
276 /**
277   Send a security protocol command to a device.
278 
279   The SendData function sends a security protocol command containing the payload
280   PayloadBuffer to the given DeviceIndex. The security protocol command sent is
281   defined by SecurityProtocolId and contains the security protocol specific data
282   SecurityProtocolSpecificData. If the underlying protocol command requires a
283   specific padding for the command payload, the SendData function shall add padding
284   bytes to the command payload to satisfy the padding requirements.
285 
286   For devices supporting the SCSI command set, the security protocol command is
287   sent using the SECURITY PROTOCOL OUT command defined in SPC-4.
288 
289   For devices supporting the ATA command set, the security protocol command is
290   sent using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
291   is non-zero. If the PayloadBufferSize is zero, the security protocol command
292   is sent using the Trusted Non-Data command defined in ATA8-ACS.
293 
294   If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
295   return EFI_INVALID_PARAMETER.
296 
297   If the given DeviceIndex does not support security protocol commands, the function
298   shall return EFI_UNSUPPORTED.
299 
300   If the security protocol fails to complete within the Timeout period, the function
301   shall return EFI_TIMEOUT.
302 
303   If the security protocol command completes without an error, the function shall
304   return EFI_SUCCESS. If the security protocol command completes with an error,
305   the functio shall return EFI_DEVICE_ERROR.
306 
307   @param[in] This              The PPI instance pointer.
308   @param[in] DeviceIndex       The ID of the device.
309   @param[in] Timeout           The timeout, in 100ns units, to use for the execution
310                                of the security protocol command. A Timeout value
311                                of 0 means that this function will wait indefinitely
312                                for the security protocol command to execute. If
313                                Timeout is greater than zero, then this function
314                                will return EFI_TIMEOUT if the time required to
315                                execute the receive data command is greater than
316                                Timeout.
317   @param[in] SecurityProtocolId
318                                The value of the "Security Protocol" parameter of
319                                the security protocol command to be sent.
320   @param[in] SecurityProtocolSpecificData
321                                The value of the "Security Protocol Specific"
322                                parameter of the security protocol command to be
323                                sent.
324   @param[in] PayloadBufferSize Size in bytes of the payload data buffer.
325   @param[in] PayloadBuffer     A pointer to a destination buffer to store the
326                                security protocol command specific payload data
327                                for the security protocol command.
328 
329   @retval EFI_SUCCESS              The security protocol command completed successfully.
330   @retval EFI_UNSUPPORTED          The given DeviceIndex does not support security
331                                    protocol commands.
332   @retval EFI_DEVICE_ERROR         The security protocol command completed with
333                                    an error.
334   @retval EFI_INVALID_PARAMETER    The PayloadBuffer is NULL and PayloadBufferSize
335                                    is non-zero.
336   @retval EFI_TIMEOUT              A timeout occurred while waiting for the security
337                                    protocol command to execute.
338 
339 **/
340 EFI_STATUS
341 EFIAPI
AhciStorageSecuritySendData(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)342 AhciStorageSecuritySendData (
343   IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI  *This,
344   IN UINTN                               DeviceIndex,
345   IN UINT64                              Timeout,
346   IN UINT8                               SecurityProtocolId,
347   IN UINT16                              SecurityProtocolSpecificData,
348   IN UINTN                               PayloadBufferSize,
349   IN VOID                                *PayloadBuffer
350   )
351 {
352   PEI_AHCI_CONTROLLER_PRIVATE_DATA    *Private;
353   PEI_AHCI_ATA_DEVICE_DATA            *DeviceData;
354 
355   if ((PayloadBuffer == NULL) && (PayloadBufferSize != 0)) {
356     return EFI_INVALID_PARAMETER;
357   }
358 
359   Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY (This);
360   if ((DeviceIndex == 0) || (DeviceIndex > Private->TrustComputingDevices)) {
361     return EFI_INVALID_PARAMETER;
362   }
363 
364   DeviceData = SearchTrustComputingDeviceByIndex (Private, DeviceIndex);
365   if (DeviceData == NULL) {
366     return EFI_NOT_FOUND;
367   }
368 
369   ASSERT ((DeviceData->IdentifyData->trusted_computing_support & BIT0) != 0);
370   if ((DeviceData->IdentifyData->trusted_computing_support & BIT0) == 0) {
371     return EFI_UNSUPPORTED;
372   }
373 
374   return TrustTransferAtaDevice (
375            DeviceData,
376            PayloadBuffer,
377            SecurityProtocolId,
378            SecurityProtocolSpecificData,
379            PayloadBufferSize,
380            TRUE,
381            Timeout,
382            NULL
383            );
384 }
385