]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.c
SecurityPkg/OpalPassword: Add PCD to skip password prompt
[mirror_edk2.git] / SecurityPkg / Tcg / Opal / OpalPassword / OpalPasswordPei.c
CommitLineData
112e584b
SZ
1/** @file\r
2 Opal Password PEI driver which is used to unlock Opal Password for S3.\r
3\r
a3efbc29 4Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>\r
289b714b 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
112e584b
SZ
6\r
7**/\r
8\r
9#include "OpalPasswordPei.h"\r
10\r
a3efbc29 11EFI_GUID mOpalDeviceLockBoxGuid = OPAL_DEVICE_LOCKBOX_GUID;\r
112e584b 12\r
112e584b
SZ
13\r
14/**\r
15 Send a security protocol command to a device that receives data and/or the result\r
16 of one or more commands sent by SendData.\r
17\r
18 The ReceiveData function sends a security protocol command to the given MediaId.\r
19 The security protocol command sent is defined by SecurityProtocolId and contains\r
20 the security protocol specific data SecurityProtocolSpecificData. The function\r
21 returns the data from the security protocol command in PayloadBuffer.\r
22\r
23 For devices supporting the SCSI command set, the security protocol command is sent\r
24 using the SECURITY PROTOCOL IN command defined in SPC-4.\r
25\r
26 For devices supporting the ATA command set, the security protocol command is sent\r
27 using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize\r
28 is non-zero.\r
29\r
30 If the PayloadBufferSize is zero, the security protocol command is sent using the\r
31 Trusted Non-Data command defined in ATA8-ACS.\r
32\r
33 If PayloadBufferSize is too small to store the available data from the security\r
34 protocol command, the function shall copy PayloadBufferSize bytes into the\r
35 PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.\r
36\r
37 If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,\r
38 the function shall return EFI_INVALID_PARAMETER.\r
39\r
40 If the given MediaId does not support security protocol commands, the function shall\r
41 return EFI_UNSUPPORTED. If there is no media in the device, the function returns\r
42 EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,\r
43 the function returns EFI_MEDIA_CHANGED.\r
44\r
45 If the security protocol fails to complete within the Timeout period, the function\r
46 shall return EFI_TIMEOUT.\r
47\r
48 If the security protocol command completes without an error, the function shall\r
49 return EFI_SUCCESS. If the security protocol command completes with an error, the\r
50 function shall return EFI_DEVICE_ERROR.\r
51\r
52 @param This Indicates a pointer to the calling context.\r
53 @param MediaId ID of the medium to receive data from.\r
54 @param Timeout The timeout, in 100ns units, to use for the execution\r
55 of the security protocol command. A Timeout value of 0\r
56 means that this function will wait indefinitely for the\r
57 security protocol command to execute. If Timeout is greater\r
58 than zero, then this function will return EFI_TIMEOUT\r
59 if the time required to execute the receive data command\r
60 is greater than Timeout.\r
61 @param SecurityProtocolId The value of the "Security Protocol" parameter of\r
62 the security protocol command to be sent.\r
63 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
64 of the security protocol command to be sent.\r
65 @param PayloadBufferSize Size in bytes of the payload data buffer.\r
66 @param PayloadBuffer A pointer to a destination buffer to store the security\r
67 protocol command specific payload data for the security\r
68 protocol command. The caller is responsible for having\r
69 either implicit or explicit ownership of the buffer.\r
70 @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the\r
71 data written to the payload data buffer.\r
72\r
73 @retval EFI_SUCCESS The security protocol command completed successfully.\r
74 @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available\r
75 data from the device. The PayloadBuffer contains the truncated data.\r
76 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.\r
77 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.\r
78 @retval EFI_NO_MEDIA There is no media in the device.\r
79 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
80 @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and\r
81 PayloadBufferSize is non-zero.\r
82 @retval EFI_TIMEOUT A timeout occurred while waiting for the security\r
83 protocol command to execute.\r
84\r
85**/\r
86EFI_STATUS\r
87EFIAPI\r
88SecurityReceiveData (\r
89 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,\r
90 IN UINT32 MediaId,\r
91 IN UINT64 Timeout,\r
92 IN UINT8 SecurityProtocolId,\r
93 IN UINT16 SecurityProtocolSpecificData,\r
94 IN UINTN PayloadBufferSize,\r
95 OUT VOID *PayloadBuffer,\r
96 OUT UINTN *PayloadTransferSize\r
97 )\r
98{\r
99 OPAL_PEI_DEVICE *PeiDev;\r
100\r
101 PeiDev = OPAL_PEI_DEVICE_FROM_THIS (This);\r
102 if (PeiDev == NULL) {\r
103 return EFI_DEVICE_ERROR;\r
104 }\r
105\r
a3efbc29
HW
106 return PeiDev->SscPpi->ReceiveData (\r
107 PeiDev->SscPpi,\r
108 PeiDev->DeviceIndex,\r
109 SSC_PPI_GENERIC_TIMEOUT,\r
110 SecurityProtocolId,\r
111 SecurityProtocolSpecificData,\r
112 PayloadBufferSize,\r
113 PayloadBuffer,\r
114 PayloadTransferSize\r
115 );\r
112e584b
SZ
116}\r
117\r
118/**\r
119 Send a security protocol command to a device.\r
120\r
121 The SendData function sends a security protocol command containing the payload\r
122 PayloadBuffer to the given MediaId. The security protocol command sent is\r
123 defined by SecurityProtocolId and contains the security protocol specific data\r
124 SecurityProtocolSpecificData. If the underlying protocol command requires a\r
125 specific padding for the command payload, the SendData function shall add padding\r
126 bytes to the command payload to satisfy the padding requirements.\r
127\r
128 For devices supporting the SCSI command set, the security protocol command is sent\r
129 using the SECURITY PROTOCOL OUT command defined in SPC-4.\r
130\r
131 For devices supporting the ATA command set, the security protocol command is sent\r
132 using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize\r
133 is non-zero. If the PayloadBufferSize is zero, the security protocol command is\r
134 sent using the Trusted Non-Data command defined in ATA8-ACS.\r
135\r
136 If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall\r
137 return EFI_INVALID_PARAMETER.\r
138\r
139 If the given MediaId does not support security protocol commands, the function\r
140 shall return EFI_UNSUPPORTED. If there is no media in the device, the function\r
141 returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the\r
142 device, the function returns EFI_MEDIA_CHANGED.\r
143\r
144 If the security protocol fails to complete within the Timeout period, the function\r
145 shall return EFI_TIMEOUT.\r
146\r
147 If the security protocol command completes without an error, the function shall return\r
148 EFI_SUCCESS. If the security protocol command completes with an error, the function\r
149 shall return EFI_DEVICE_ERROR.\r
150\r
151 @param This Indicates a pointer to the calling context.\r
152 @param MediaId ID of the medium to receive data from.\r
153 @param Timeout The timeout, in 100ns units, to use for the execution\r
154 of the security protocol command. A Timeout value of 0\r
155 means that this function will wait indefinitely for the\r
156 security protocol command to execute. If Timeout is greater\r
157 than zero, then this function will return EFI_TIMEOUT\r
158 if the time required to execute the send data command\r
159 is greater than Timeout.\r
160 @param SecurityProtocolId The value of the "Security Protocol" parameter of\r
161 the security protocol command to be sent.\r
162 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
163 of the security protocol command to be sent.\r
164 @param PayloadBufferSize Size in bytes of the payload data buffer.\r
165 @param PayloadBuffer A pointer to a destination buffer to store the security\r
166 protocol command specific payload data for the security\r
167 protocol command.\r
168\r
169 @retval EFI_SUCCESS The security protocol command completed successfully.\r
170 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.\r
171 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.\r
172 @retval EFI_NO_MEDIA There is no media in the device.\r
173 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
174 @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.\r
175 @retval EFI_TIMEOUT A timeout occurred while waiting for the security\r
176 protocol command to execute.\r
177\r
178**/\r
179EFI_STATUS\r
180EFIAPI\r
181SecuritySendData (\r
182 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,\r
183 IN UINT32 MediaId,\r
184 IN UINT64 Timeout,\r
185 IN UINT8 SecurityProtocolId,\r
186 IN UINT16 SecurityProtocolSpecificData,\r
187 IN UINTN PayloadBufferSize,\r
188 IN VOID *PayloadBuffer\r
189 )\r
190{\r
191 OPAL_PEI_DEVICE *PeiDev;\r
192\r
193 PeiDev = OPAL_PEI_DEVICE_FROM_THIS (This);\r
194 if (PeiDev == NULL) {\r
195 return EFI_DEVICE_ERROR;\r
196 }\r
197\r
a3efbc29
HW
198 return PeiDev->SscPpi->SendData (\r
199 PeiDev->SscPpi,\r
200 PeiDev->DeviceIndex,\r
201 SSC_PPI_GENERIC_TIMEOUT,\r
202 SecurityProtocolId,\r
203 SecurityProtocolSpecificData,\r
204 PayloadBufferSize,\r
205 PayloadBuffer\r
206 );\r
112e584b
SZ
207}\r
208\r
209/**\r
210\r
211 The function returns whether or not the device is Opal Locked.\r
212 TRUE means that the device is partially or fully locked.\r
213 This will perform a Level 0 Discovery and parse the locking feature descriptor\r
214\r
215 @param[in] OpalDev Opal object to determine if locked.\r
216 @param[out] BlockSidSupported Whether device support BlockSid feature.\r
217\r
218**/\r
219BOOLEAN\r
220IsOpalDeviceLocked(\r
221 OPAL_PEI_DEVICE *OpalDev,\r
222 BOOLEAN *BlockSidSupported\r
223 )\r
224{\r
225 OPAL_SESSION Session;\r
226 OPAL_DISK_SUPPORT_ATTRIBUTE SupportedAttributes;\r
227 TCG_LOCKING_FEATURE_DESCRIPTOR LockingFeature;\r
228 UINT16 OpalBaseComId;\r
229 TCG_RESULT Ret;\r
230\r
231 Session.Sscp = &OpalDev->Sscp;\r
232 Session.MediaId = 0;\r
233\r
234 Ret = OpalGetSupportedAttributesInfo (&Session, &SupportedAttributes, &OpalBaseComId);\r
235 if (Ret != TcgResultSuccess) {\r
236 return FALSE;\r
237 }\r
238\r
239 Session.OpalBaseComId = OpalBaseComId;\r
240 *BlockSidSupported = SupportedAttributes.BlockSid == 1 ? TRUE : FALSE;\r
241\r
242 Ret = OpalGetLockingInfo(&Session, &LockingFeature);\r
243 if (Ret != TcgResultSuccess) {\r
244 return FALSE;\r
245 }\r
246\r
247 return OpalDeviceLocked (&SupportedAttributes, &LockingFeature);\r
248}\r
249\r
250/**\r
251 Unlock OPAL password for S3.\r
252\r
253 @param[in] OpalDev Opal object to unlock.\r
254\r
255**/\r
256VOID\r
257UnlockOpalPassword (\r
258 IN OPAL_PEI_DEVICE *OpalDev\r
259 )\r
260{\r
261 TCG_RESULT Result;\r
262 OPAL_SESSION Session;\r
263 BOOLEAN BlockSidSupport;\r
264 UINT32 PpStorageFlags;\r
265 BOOLEAN BlockSIDEnabled;\r
266\r
267 BlockSidSupport = FALSE;\r
268 if (IsOpalDeviceLocked (OpalDev, &BlockSidSupport)) {\r
269 ZeroMem(&Session, sizeof (Session));\r
270 Session.Sscp = &OpalDev->Sscp;\r
271 Session.MediaId = 0;\r
272 Session.OpalBaseComId = OpalDev->Device->OpalBaseComId;\r
273\r
274 Result = OpalUtilUpdateGlobalLockingRange (\r
275 &Session,\r
276 OpalDev->Device->Password,\r
277 OpalDev->Device->PasswordLength,\r
278 FALSE,\r
279 FALSE\r
280 );\r
281 DEBUG ((\r
282 DEBUG_INFO,\r
283 "%a() OpalUtilUpdateGlobalLockingRange() Result = 0x%x\n",\r
284 __FUNCTION__,\r
285 Result\r
286 ));\r
287 }\r
288\r
289 PpStorageFlags = Tcg2PhysicalPresenceLibGetManagementFlags ();\r
290 if ((PpStorageFlags & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID) != 0) {\r
291 BlockSIDEnabled = TRUE;\r
292 } else {\r
293 BlockSIDEnabled = FALSE;\r
294 }\r
295 if (BlockSIDEnabled && BlockSidSupport) {\r
40d32e79 296 DEBUG ((DEBUG_INFO, "OpalPassword: S3 phase send BlockSid command to device!\n"));\r
112e584b
SZ
297 ZeroMem(&Session, sizeof (Session));\r
298 Session.Sscp = &OpalDev->Sscp;\r
299 Session.MediaId = 0;\r
300 Session.OpalBaseComId = OpalDev->Device->OpalBaseComId;\r
301 Result = OpalBlockSid (&Session, TRUE);\r
302 DEBUG ((\r
303 DEBUG_INFO,\r
304 "%a() OpalBlockSid() Result = 0x%x\n",\r
305 __FUNCTION__,\r
306 Result\r
307 ));\r
308 }\r
309}\r
310\r
311/**\r
a3efbc29
HW
312 Unlock the OPAL NVM Express and ATA devices for S3.\r
313\r
314 @param[in] SscPpi Pointer to the EDKII_PEI_STORAGE_SECURITY_CMD_PPI instance.\r
112e584b
SZ
315\r
316**/\r
317VOID\r
a3efbc29
HW
318UnlockOpalPasswordDevices (\r
319 IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI *SscPpi\r
112e584b
SZ
320 )\r
321{\r
a3efbc29
HW
322 EFI_STATUS Status;\r
323 UINT8 *DevInfoBuffer;\r
324 UINT8 DummyData;\r
325 OPAL_DEVICE_LOCKBOX_DATA *DevInfo;\r
326 UINTN DevInfoLength;\r
327 EFI_DEVICE_PATH_PROTOCOL *SscDevicePath;\r
328 UINTN SscDevicePathLength;\r
329 UINTN SscDeviceNum;\r
330 UINTN SscDeviceIndex;\r
331 OPAL_PEI_DEVICE OpalDev;\r
112e584b
SZ
332\r
333 //\r
a3efbc29 334 // Get OPAL devices info from LockBox.\r
112e584b 335 //\r
a3efbc29
HW
336 DevInfoBuffer = &DummyData;\r
337 DevInfoLength = sizeof (DummyData);\r
338 Status = RestoreLockBox (&mOpalDeviceLockBoxGuid, DevInfoBuffer, &DevInfoLength);\r
112e584b 339 if (Status == EFI_BUFFER_TOO_SMALL) {\r
a3efbc29
HW
340 DevInfoBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DevInfoLength));\r
341 if (DevInfoBuffer != NULL) {\r
342 Status = RestoreLockBox (&mOpalDeviceLockBoxGuid, DevInfoBuffer, &DevInfoLength);\r
112e584b
SZ
343 }\r
344 }\r
a3efbc29
HW
345 if (DevInfoBuffer == NULL || DevInfoBuffer == &DummyData) {\r
346 return;\r
347 } else if (EFI_ERROR (Status)) {\r
348 FreePages (DevInfoBuffer, EFI_SIZE_TO_PAGES (DevInfoLength));\r
112e584b
SZ
349 return;\r
350 }\r
351\r
112e584b 352 //\r
a3efbc29 353 // Go through all the devices managed by the SSC PPI instance.\r
112e584b 354 //\r
a3efbc29
HW
355 Status = SscPpi->GetNumberofDevices (SscPpi, &SscDeviceNum);\r
356 if (EFI_ERROR (Status)) {\r
357 goto Exit;\r
112e584b 358 }\r
a3efbc29
HW
359 for (SscDeviceIndex = 1; SscDeviceIndex <= SscDeviceNum; SscDeviceIndex++) {\r
360 Status = SscPpi->GetDevicePath (\r
361 SscPpi,\r
362 SscDeviceIndex,\r
363 &SscDevicePathLength,\r
364 &SscDevicePath\r
365 );\r
366 if (SscDevicePathLength <= sizeof (EFI_DEVICE_PATH_PROTOCOL)) {\r
367 //\r
368 // Device path validity check.\r
369 //\r
370 continue;\r
112e584b
SZ
371 }\r
372\r
a3efbc29
HW
373 //\r
374 // Search the device in the restored LockBox.\r
375 //\r
376 for (DevInfo = (OPAL_DEVICE_LOCKBOX_DATA *) DevInfoBuffer;\r
377 (UINTN) DevInfo < ((UINTN) DevInfoBuffer + DevInfoLength);\r
378 DevInfo = (OPAL_DEVICE_LOCKBOX_DATA *) ((UINTN) DevInfo + DevInfo->Length)) {\r
379 //\r
380 // Find the matching device.\r
381 //\r
382 if ((DevInfo->DevicePathLength >= SscDevicePathLength) &&\r
383 (CompareMem (\r
384 DevInfo->DevicePath,\r
385 SscDevicePath,\r
386 SscDevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)) == 0)) {\r
387 OpalDev.Signature = OPAL_PEI_DEVICE_SIGNATURE;\r
388 OpalDev.Sscp.ReceiveData = SecurityReceiveData;\r
389 OpalDev.Sscp.SendData = SecuritySendData;\r
390 OpalDev.Device = DevInfo;\r
391 OpalDev.Context = NULL;\r
392 OpalDev.SscPpi = SscPpi;\r
393 OpalDev.DeviceIndex = SscDeviceIndex;\r
394 UnlockOpalPassword (&OpalDev);\r
395 break;\r
396 }\r
397 }\r
112e584b
SZ
398 }\r
399\r
a3efbc29
HW
400Exit:\r
401 ZeroMem (DevInfoBuffer, DevInfoLength);\r
402 FreePages (DevInfoBuffer, EFI_SIZE_TO_PAGES (DevInfoLength));\r
112e584b 403\r
112e584b
SZ
404}\r
405\r
406/**\r
a3efbc29 407 One notified function at the installation of EDKII_PEI_STORAGE_SECURITY_CMD_PPI.\r
112e584b
SZ
408 It is to unlock OPAL password for S3.\r
409\r
a3efbc29
HW
410 @param[in] PeiServices Indirect reference to the PEI Services Table.\r
411 @param[in] NotifyDescriptor Address of the notification descriptor data structure.\r
412 @param[in] Ppi Address of the PPI that was installed.\r
112e584b
SZ
413\r
414 @return Status of the notification.\r
415 The status code returned from this function is ignored.\r
a3efbc29 416\r
112e584b
SZ
417**/\r
418EFI_STATUS\r
419EFIAPI\r
a3efbc29
HW
420OpalPasswordStorageSecurityPpiNotify (\r
421 IN EFI_PEI_SERVICES **PeiServices,\r
422 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,\r
423 IN VOID *Ppi\r
112e584b
SZ
424 )\r
425{\r
a3efbc29 426 DEBUG ((DEBUG_INFO, "%a entered at S3 resume!\n", __FUNCTION__));\r
112e584b 427\r
a3efbc29 428 UnlockOpalPasswordDevices ((EDKII_PEI_STORAGE_SECURITY_CMD_PPI *) Ppi);\r
112e584b 429\r
a3efbc29 430 DEBUG ((DEBUG_INFO, "%a exit at S3 resume!\n", __FUNCTION__));\r
112e584b
SZ
431\r
432 return EFI_SUCCESS;\r
433}\r
434\r
a3efbc29
HW
435\r
436EFI_PEI_NOTIFY_DESCRIPTOR mOpalPasswordStorageSecurityPpiNotifyDesc = {\r
112e584b 437 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
a3efbc29
HW
438 &gEdkiiPeiStorageSecurityCommandPpiGuid,\r
439 OpalPasswordStorageSecurityPpiNotify\r
112e584b
SZ
440};\r
441\r
a3efbc29 442\r
112e584b
SZ
443/**\r
444 Main entry for this module.\r
445\r
446 @param FileHandle Handle of the file being invoked.\r
447 @param PeiServices Pointer to PEI Services table.\r
448\r
449 @return Status from PeiServicesNotifyPpi.\r
450\r
451**/\r
452EFI_STATUS\r
453EFIAPI\r
454OpalPasswordPeiInit (\r
455 IN EFI_PEI_FILE_HANDLE FileHandle,\r
456 IN CONST EFI_PEI_SERVICES **PeiServices\r
457 )\r
458{\r
a3efbc29
HW
459 EFI_STATUS Status;\r
460 EFI_BOOT_MODE BootMode;\r
461\r
462 Status = PeiServicesGetBootMode (&BootMode);\r
463 if ((EFI_ERROR (Status)) || (BootMode != BOOT_ON_S3_RESUME)) {\r
464 return EFI_UNSUPPORTED;\r
465 }\r
112e584b 466\r
a3efbc29
HW
467 DEBUG ((DEBUG_INFO, "%a: Enters in S3 path.\n", __FUNCTION__));\r
468\r
469 Status = PeiServicesNotifyPpi (&mOpalPasswordStorageSecurityPpiNotifyDesc);\r
112e584b
SZ
470 ASSERT_EFI_ERROR (Status);\r
471 return Status;\r
472}\r