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