]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.c
SecurityPkg/OpalPassword: Add support for pyrite 2.0 devices.
[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
4Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "OpalPasswordPei.h"\r
16\r
17EFI_GUID mOpalDeviceAtaGuid = OPAL_DEVICE_ATA_GUID;\r
18EFI_GUID mOpalDeviceNvmeGuid = OPAL_DEVICE_NVME_GUID;\r
19\r
20#define OPAL_PCIE_ROOTPORT_SAVESIZE (0x40)\r
21#define STORE_INVALID_ROOTPORT_INDEX ((UINT8) -1)\r
22\r
23/**\r
24 Get IOMMU PPI.\r
25\r
26 @return Pointer to IOMMU PPI.\r
27\r
28**/\r
29EDKII_IOMMU_PPI *\r
30GetIoMmu (\r
31 VOID\r
32 )\r
33{\r
34 EFI_STATUS Status;\r
35 EDKII_IOMMU_PPI *IoMmu;\r
36\r
37 IoMmu = NULL;\r
38 Status = PeiServicesLocatePpi (\r
39 &gEdkiiIoMmuPpiGuid,\r
40 0,\r
41 NULL,\r
42 (VOID **) &IoMmu\r
43 );\r
44 if (!EFI_ERROR (Status) && (IoMmu != NULL)) {\r
45 return IoMmu;\r
46 }\r
47\r
48 return NULL;\r
49}\r
50\r
51/**\r
52 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or\r
53 OperationBusMasterCommonBuffer64 mapping.\r
54\r
55 @param Pages The number of pages to allocate.\r
56 @param HostAddress A pointer to store the base system memory address of the\r
57 allocated range.\r
58 @param DeviceAddress The resulting map address for the bus master PCI controller to use to\r
59 access the hosts HostAddress.\r
60 @param Mapping A resulting value to pass to Unmap().\r
61\r
62 @retval EFI_SUCCESS The requested memory pages were allocated.\r
63 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are\r
64 MEMORY_WRITE_COMBINE and MEMORY_CACHED.\r
65 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
66 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
67\r
68**/\r
69EFI_STATUS\r
70IoMmuAllocateBuffer (\r
71 IN UINTN Pages,\r
72 OUT VOID **HostAddress,\r
73 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
74 OUT VOID **Mapping\r
75 )\r
76{\r
77 EFI_STATUS Status;\r
78 UINTN NumberOfBytes;\r
79 EFI_PHYSICAL_ADDRESS HostPhyAddress;\r
80 EDKII_IOMMU_PPI *IoMmu;\r
81\r
82 *HostAddress = NULL;\r
83 *DeviceAddress = 0;\r
84 *Mapping = NULL;\r
85\r
86 IoMmu = GetIoMmu ();\r
87\r
88 if (IoMmu != NULL) {\r
89 Status = IoMmu->AllocateBuffer (\r
90 IoMmu,\r
91 EfiBootServicesData,\r
92 Pages,\r
93 HostAddress,\r
94 0\r
95 );\r
96 if (EFI_ERROR (Status)) {\r
97 return EFI_OUT_OF_RESOURCES;\r
98 }\r
99\r
100 NumberOfBytes = EFI_PAGES_TO_SIZE (Pages);\r
101 Status = IoMmu->Map (\r
102 IoMmu,\r
103 EdkiiIoMmuOperationBusMasterCommonBuffer,\r
104 *HostAddress,\r
105 &NumberOfBytes,\r
106 DeviceAddress,\r
107 Mapping\r
108 );\r
109 if (EFI_ERROR (Status)) {\r
110 IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);\r
111 *HostAddress = NULL;\r
112 return EFI_OUT_OF_RESOURCES;\r
113 }\r
114 Status = IoMmu->SetAttribute (\r
115 IoMmu,\r
116 *Mapping,\r
117 EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE\r
118 );\r
119 if (EFI_ERROR (Status)) {\r
120 IoMmu->Unmap (IoMmu, *Mapping);\r
121 IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);\r
122 *Mapping = NULL;\r
123 *HostAddress = NULL;\r
124 return Status;\r
125 }\r
126 } else {\r
127 Status = PeiServicesAllocatePages (\r
128 EfiBootServicesData,\r
129 Pages,\r
130 &HostPhyAddress\r
131 );\r
132 if (EFI_ERROR (Status)) {\r
133 return EFI_OUT_OF_RESOURCES;\r
134 }\r
135 *HostAddress = (VOID *) (UINTN) HostPhyAddress;\r
136 *DeviceAddress = HostPhyAddress;\r
137 *Mapping = NULL;\r
138 }\r
139 return Status;\r
140}\r
141\r
142/**\r
143 Frees memory that was allocated with AllocateBuffer().\r
144\r
145 @param Pages The number of pages to free.\r
146 @param HostAddress The base system memory address of the allocated range.\r
147 @param Mapping The mapping value returned from Map().\r
148\r
149**/\r
150VOID\r
151IoMmuFreeBuffer (\r
152 IN UINTN Pages,\r
153 IN VOID *HostAddress,\r
154 IN VOID *Mapping\r
155 )\r
156{\r
157 EDKII_IOMMU_PPI *IoMmu;\r
158\r
159 IoMmu = GetIoMmu ();\r
160\r
161 if (IoMmu != NULL) {\r
162 IoMmu->SetAttribute (IoMmu, Mapping, 0);\r
163 IoMmu->Unmap (IoMmu, Mapping);\r
164 IoMmu->FreeBuffer (IoMmu, Pages, HostAddress);\r
165 } else {\r
166 PeiServicesFreePages (\r
167 (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress,\r
168 Pages\r
169 );\r
170 }\r
171}\r
172\r
173/**\r
174 Provide IO action support.\r
175\r
176 @param[in] PeiDev The opal device need to perform trusted IO.\r
177 @param[in] IoType OPAL_IO_TYPE indicating whether to perform a Trusted Send or Trusted Receive.\r
178 @param[in] SecurityProtocol Security Protocol\r
179 @param[in] SpSpecific Security Protocol Specific\r
180 @param[in] TransferLength Transfer Length of Buffer (in bytes) - always a multiple of 512\r
181 @param[in] Buffer Address of Data to transfer\r
182\r
183 @retval EFI_SUCCESS Perform the IO action success.\r
184 @retval Others Perform the IO action failed.\r
185\r
186**/\r
187EFI_STATUS\r
188PerformTrustedIo (\r
189 OPAL_PEI_DEVICE *PeiDev,\r
190 OPAL_IO_TYPE IoType,\r
191 UINT8 SecurityProtocol,\r
192 UINT16 SpSpecific,\r
193 UINTN TransferLength,\r
194 VOID *Buffer\r
195 )\r
196{\r
197 EFI_STATUS Status;\r
198 UINTN BufferSizeBlocks;\r
199 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
200 OPAL_DEVICE_ATA *DevInfoAta;\r
201 AHCI_CONTEXT *AhciContext;\r
202 NVME_CONTEXT *NvmeContext;\r
203\r
204 Status = EFI_DEVICE_ERROR;\r
205 if (PeiDev->DeviceType == OPAL_DEVICE_TYPE_ATA) {\r
206 DevInfoAta = (OPAL_DEVICE_ATA *) PeiDev->Device;\r
207 AhciContext = (AHCI_CONTEXT *) PeiDev->Context;\r
208\r
209 BufferSizeBlocks = TransferLength / 512;\r
210\r
211 ZeroMem( &AtaCommandBlock, sizeof( EFI_ATA_COMMAND_BLOCK ) );\r
212 AtaCommandBlock.AtaCommand = ( IoType == OpalSend ) ? ATA_COMMAND_TRUSTED_SEND : ATA_COMMAND_TRUSTED_RECEIVE;\r
213 AtaCommandBlock.AtaSectorCount = ( UINT8 )BufferSizeBlocks;\r
214 AtaCommandBlock.AtaSectorNumber = ( UINT8 )( BufferSizeBlocks >> 8 );\r
215 AtaCommandBlock.AtaFeatures = SecurityProtocol;\r
216 AtaCommandBlock.AtaCylinderLow = ( UINT8 )( SpSpecific >> 8 );\r
217 AtaCommandBlock.AtaCylinderHigh = ( UINT8 )( SpSpecific );\r
218 AtaCommandBlock.AtaDeviceHead = ATA_DEVICE_LBA;\r
219\r
220\r
221 ZeroMem( AhciContext->Buffer, HDD_PAYLOAD );\r
222 ASSERT( TransferLength <= HDD_PAYLOAD );\r
223\r
224 if (IoType == OpalSend) {\r
225 CopyMem( AhciContext->Buffer, Buffer, TransferLength );\r
226 }\r
227\r
228 Status = AhciPioTransfer(\r
229 AhciContext,\r
230 (UINT8) DevInfoAta->Port,\r
231 (UINT8) DevInfoAta->PortMultiplierPort,\r
232 NULL,\r
233 0,\r
234 ( IoType == OpalSend ) ? FALSE : TRUE, // i/o direction\r
235 &AtaCommandBlock,\r
236 NULL,\r
237 AhciContext->Buffer,\r
238 (UINT32)TransferLength,\r
239 ATA_TIMEOUT\r
240 );\r
241\r
242 if (IoType == OpalRecv) {\r
243 CopyMem( Buffer, AhciContext->Buffer, TransferLength );\r
244 }\r
245 } else if (PeiDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {\r
246 NvmeContext = (NVME_CONTEXT *) PeiDev->Context;\r
247 Status = NvmeSecuritySendReceive (\r
248 NvmeContext,\r
249 IoType == OpalSend,\r
250 SecurityProtocol,\r
251 SwapBytes16(SpSpecific),\r
252 TransferLength,\r
253 Buffer\r
254 );\r
255 } else {\r
256 DEBUG((DEBUG_ERROR, "DeviceType(%x) not support.\n", PeiDev->DeviceType));\r
257 }\r
258\r
259 return Status;\r
260}\r
261\r
262/**\r
263 Send a security protocol command to a device that receives data and/or the result\r
264 of one or more commands sent by SendData.\r
265\r
266 The ReceiveData function sends a security protocol command to the given MediaId.\r
267 The security protocol command sent is defined by SecurityProtocolId and contains\r
268 the security protocol specific data SecurityProtocolSpecificData. The function\r
269 returns the data from the security protocol command in PayloadBuffer.\r
270\r
271 For devices supporting the SCSI command set, the security protocol command is sent\r
272 using the SECURITY PROTOCOL IN command defined in SPC-4.\r
273\r
274 For devices supporting the ATA command set, the security protocol command is sent\r
275 using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize\r
276 is non-zero.\r
277\r
278 If the PayloadBufferSize is zero, the security protocol command is sent using the\r
279 Trusted Non-Data command defined in ATA8-ACS.\r
280\r
281 If PayloadBufferSize is too small to store the available data from the security\r
282 protocol command, the function shall copy PayloadBufferSize bytes into the\r
283 PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.\r
284\r
285 If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,\r
286 the function shall return EFI_INVALID_PARAMETER.\r
287\r
288 If the given MediaId does not support security protocol commands, the function shall\r
289 return EFI_UNSUPPORTED. If there is no media in the device, the function returns\r
290 EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,\r
291 the function returns EFI_MEDIA_CHANGED.\r
292\r
293 If the security protocol fails to complete within the Timeout period, the function\r
294 shall return EFI_TIMEOUT.\r
295\r
296 If the security protocol command completes without an error, the function shall\r
297 return EFI_SUCCESS. If the security protocol command completes with an error, the\r
298 function shall return EFI_DEVICE_ERROR.\r
299\r
300 @param This Indicates a pointer to the calling context.\r
301 @param MediaId ID of the medium to receive data from.\r
302 @param Timeout The timeout, in 100ns units, to use for the execution\r
303 of the security protocol command. A Timeout value of 0\r
304 means that this function will wait indefinitely for the\r
305 security protocol command to execute. If Timeout is greater\r
306 than zero, then this function will return EFI_TIMEOUT\r
307 if the time required to execute the receive data command\r
308 is greater than Timeout.\r
309 @param SecurityProtocolId The value of the "Security Protocol" parameter of\r
310 the security protocol command to be sent.\r
311 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
312 of the security protocol command to be sent.\r
313 @param PayloadBufferSize Size in bytes of the payload data buffer.\r
314 @param PayloadBuffer A pointer to a destination buffer to store the security\r
315 protocol command specific payload data for the security\r
316 protocol command. The caller is responsible for having\r
317 either implicit or explicit ownership of the buffer.\r
318 @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the\r
319 data written to the payload data buffer.\r
320\r
321 @retval EFI_SUCCESS The security protocol command completed successfully.\r
322 @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available\r
323 data from the device. The PayloadBuffer contains the truncated data.\r
324 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.\r
325 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.\r
326 @retval EFI_NO_MEDIA There is no media in the device.\r
327 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
328 @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and\r
329 PayloadBufferSize is non-zero.\r
330 @retval EFI_TIMEOUT A timeout occurred while waiting for the security\r
331 protocol command to execute.\r
332\r
333**/\r
334EFI_STATUS\r
335EFIAPI\r
336SecurityReceiveData (\r
337 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,\r
338 IN UINT32 MediaId,\r
339 IN UINT64 Timeout,\r
340 IN UINT8 SecurityProtocolId,\r
341 IN UINT16 SecurityProtocolSpecificData,\r
342 IN UINTN PayloadBufferSize,\r
343 OUT VOID *PayloadBuffer,\r
344 OUT UINTN *PayloadTransferSize\r
345 )\r
346{\r
347 OPAL_PEI_DEVICE *PeiDev;\r
348\r
349 PeiDev = OPAL_PEI_DEVICE_FROM_THIS (This);\r
350 if (PeiDev == NULL) {\r
351 return EFI_DEVICE_ERROR;\r
352 }\r
353\r
354 return PerformTrustedIo (\r
355 PeiDev,\r
356 OpalRecv,\r
357 SecurityProtocolId,\r
358 SecurityProtocolSpecificData,\r
359 PayloadBufferSize,\r
360 PayloadBuffer\r
361 );\r
362}\r
363\r
364/**\r
365 Send a security protocol command to a device.\r
366\r
367 The SendData function sends a security protocol command containing the payload\r
368 PayloadBuffer to the given MediaId. The security protocol command sent is\r
369 defined by SecurityProtocolId and contains the security protocol specific data\r
370 SecurityProtocolSpecificData. If the underlying protocol command requires a\r
371 specific padding for the command payload, the SendData function shall add padding\r
372 bytes to the command payload to satisfy the padding requirements.\r
373\r
374 For devices supporting the SCSI command set, the security protocol command is sent\r
375 using the SECURITY PROTOCOL OUT command defined in SPC-4.\r
376\r
377 For devices supporting the ATA command set, the security protocol command is sent\r
378 using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize\r
379 is non-zero. If the PayloadBufferSize is zero, the security protocol command is\r
380 sent using the Trusted Non-Data command defined in ATA8-ACS.\r
381\r
382 If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall\r
383 return EFI_INVALID_PARAMETER.\r
384\r
385 If the given MediaId does not support security protocol commands, the function\r
386 shall return EFI_UNSUPPORTED. If there is no media in the device, the function\r
387 returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the\r
388 device, the function returns EFI_MEDIA_CHANGED.\r
389\r
390 If the security protocol fails to complete within the Timeout period, the function\r
391 shall return EFI_TIMEOUT.\r
392\r
393 If the security protocol command completes without an error, the function shall return\r
394 EFI_SUCCESS. If the security protocol command completes with an error, the function\r
395 shall return EFI_DEVICE_ERROR.\r
396\r
397 @param This Indicates a pointer to the calling context.\r
398 @param MediaId ID of the medium to receive data from.\r
399 @param Timeout The timeout, in 100ns units, to use for the execution\r
400 of the security protocol command. A Timeout value of 0\r
401 means that this function will wait indefinitely for the\r
402 security protocol command to execute. If Timeout is greater\r
403 than zero, then this function will return EFI_TIMEOUT\r
404 if the time required to execute the send data command\r
405 is greater than Timeout.\r
406 @param SecurityProtocolId The value of the "Security Protocol" parameter of\r
407 the security protocol command to be sent.\r
408 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
409 of the security protocol command to be sent.\r
410 @param PayloadBufferSize Size in bytes of the payload data buffer.\r
411 @param PayloadBuffer A pointer to a destination buffer to store the security\r
412 protocol command specific payload data for the security\r
413 protocol command.\r
414\r
415 @retval EFI_SUCCESS The security protocol command completed successfully.\r
416 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.\r
417 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.\r
418 @retval EFI_NO_MEDIA There is no media in the device.\r
419 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
420 @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.\r
421 @retval EFI_TIMEOUT A timeout occurred while waiting for the security\r
422 protocol command to execute.\r
423\r
424**/\r
425EFI_STATUS\r
426EFIAPI\r
427SecuritySendData (\r
428 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,\r
429 IN UINT32 MediaId,\r
430 IN UINT64 Timeout,\r
431 IN UINT8 SecurityProtocolId,\r
432 IN UINT16 SecurityProtocolSpecificData,\r
433 IN UINTN PayloadBufferSize,\r
434 IN VOID *PayloadBuffer\r
435 )\r
436{\r
437 OPAL_PEI_DEVICE *PeiDev;\r
438\r
439 PeiDev = OPAL_PEI_DEVICE_FROM_THIS (This);\r
440 if (PeiDev == NULL) {\r
441 return EFI_DEVICE_ERROR;\r
442 }\r
443\r
444 return PerformTrustedIo (\r
445 PeiDev,\r
446 OpalSend,\r
447 SecurityProtocolId,\r
448 SecurityProtocolSpecificData,\r
449 PayloadBufferSize,\r
450 PayloadBuffer\r
451 );\r
452\r
453}\r
454\r
455/**\r
456 Save/Restore RootPort configuration space.\r
457\r
458 @param[in] DevInfoNvme Pointer to NVMe device info.\r
459 @param[in] SaveAction TRUE: Save, FALSE: Restore\r
460 @param[in,out] PcieConfBufferList Configuration space data buffer for save/restore\r
461\r
462 @return PCIE base address of this RootPort\r
463**/\r
464UINTN\r
465SaveRestoreRootportConfSpace (\r
466 IN OPAL_DEVICE_NVME *DevInfoNvme,\r
467 IN BOOLEAN SaveAction,\r
468 IN OUT UINT8 **PcieConfBufferList\r
469 )\r
470{\r
471 UINTN RpBase;\r
472 UINTN Length;\r
473 OPAL_PCI_DEVICE *DevNode;\r
474 UINT8 *StorePcieConfData;\r
475 UINTN Index;\r
476\r
477 Length = 0;\r
478 Index = 0;\r
479 RpBase = 0;\r
480\r
481 while (sizeof (OPAL_DEVICE_NVME) + Length < DevInfoNvme->Length) {\r
482 DevNode = (OPAL_PCI_DEVICE *)((UINT8*)DevInfoNvme->PciBridgeNode + Length);\r
483 RpBase = PCI_LIB_ADDRESS (DevNode->Bus, DevNode->Device, DevNode->Function, 0x0);\r
484\r
485 if (PcieConfBufferList != NULL) {\r
486 if (SaveAction) {\r
487 StorePcieConfData = (UINT8 *) AllocateZeroPool (OPAL_PCIE_ROOTPORT_SAVESIZE);\r
488 ASSERT (StorePcieConfData != NULL);\r
489 OpalPciRead (StorePcieConfData, RpBase, OPAL_PCIE_ROOTPORT_SAVESIZE);\r
490 PcieConfBufferList[Index] = StorePcieConfData;\r
491 } else {\r
492 // Skip PCIe Command & Status registers\r
493 StorePcieConfData = PcieConfBufferList[Index];\r
494 OpalPciWrite (RpBase, StorePcieConfData, 4);\r
495 OpalPciWrite (RpBase + 8, StorePcieConfData + 8, OPAL_PCIE_ROOTPORT_SAVESIZE - 8);\r
496\r
497 FreePool (StorePcieConfData);\r
498 }\r
499 }\r
500\r
501 Length += sizeof (OPAL_PCI_DEVICE);\r
502 Index ++;\r
503 }\r
504\r
505 return RpBase;\r
506}\r
507\r
508/**\r
509 Configure RootPort for downstream PCIe NAND devices.\r
510\r
511 @param[in] RpBase - PCIe configuration space address of this RootPort\r
512 @param[in] BusNumber - Bus number\r
513 @param[in] MemoryBase - Memory base address\r
514 @param[in] MemoryLength - Memory size\r
515\r
516**/\r
517VOID\r
518ConfigureRootPortForPcieNand (\r
519 IN UINTN RpBase,\r
520 IN UINTN BusNumber,\r
521 IN UINT32 MemoryBase,\r
522 IN UINT32 MemoryLength\r
523 )\r
524{\r
525 UINT32 MemoryLimit;\r
526\r
527 DEBUG ((DEBUG_INFO, "ConfigureRootPortForPcieNand, BusNumber: %x, MemoryBase: %x, MemoryLength: %x\n",\r
528 BusNumber, MemoryBase, MemoryLength));\r
529\r
530 if (MemoryLength == 0) {\r
531 MemoryLimit = MemoryBase;\r
532 } else {\r
533 MemoryLimit = MemoryBase + MemoryLength + 0xFFFFF; // 1M\r
534 }\r
535\r
536 ///\r
537 /// Configue PCIE configuration space for RootPort\r
538 ///\r
539 PciWrite8 (RpBase + NVME_PCIE_BNUM + 1, (UINT8) BusNumber); // Secondary Bus Number registers\r
540 PciWrite8 (RpBase + NVME_PCIE_BNUM + 2, (UINT8) BusNumber); // Subordinate Bus Number registers\r
541 PciWrite8 (RpBase + NVME_PCIE_IOBL, 0xFF); // I/O Base registers\r
542 PciWrite8 (RpBase + NVME_PCIE_IOBL + 1, 0x00); // I/O Limit registers\r
543 PciWrite16 (RpBase + NVME_PCIE_MBL, (UINT16) RShiftU64 ((UINTN)MemoryBase, 16)); // Memory Base register\r
544 PciWrite16 (RpBase + NVME_PCIE_MBL + 2, (UINT16) RShiftU64 ((UINTN)MemoryLimit, 16)); // Memory Limit register\r
545 PciWrite16 (RpBase + NVME_PCIE_PMBL, 0xFFFF); // Prefetchable Memory Base registers\r
546 PciWrite16 (RpBase + NVME_PCIE_PMBL + 2, 0x0000); // Prefetchable Memory Limit registers\r
547 PciWrite32 (RpBase + NVME_PCIE_PMBU32, 0xFFFFFFFF); // Prefetchable Memory Upper Base registers\r
548 PciWrite32 (RpBase + NVME_PCIE_PMLU32, 0x00000000); // Prefetchable Memory Upper Limit registers\r
549}\r
550\r
551/**\r
552\r
553 The function returns whether or not the device is Opal Locked.\r
554 TRUE means that the device is partially or fully locked.\r
555 This will perform a Level 0 Discovery and parse the locking feature descriptor\r
556\r
557 @param[in] OpalDev Opal object to determine if locked.\r
558 @param[out] BlockSidSupported Whether device support BlockSid feature.\r
559\r
560**/\r
561BOOLEAN\r
562IsOpalDeviceLocked(\r
563 OPAL_PEI_DEVICE *OpalDev,\r
564 BOOLEAN *BlockSidSupported\r
565 )\r
566{\r
567 OPAL_SESSION Session;\r
568 OPAL_DISK_SUPPORT_ATTRIBUTE SupportedAttributes;\r
569 TCG_LOCKING_FEATURE_DESCRIPTOR LockingFeature;\r
570 UINT16 OpalBaseComId;\r
571 TCG_RESULT Ret;\r
572\r
573 Session.Sscp = &OpalDev->Sscp;\r
574 Session.MediaId = 0;\r
575\r
576 Ret = OpalGetSupportedAttributesInfo (&Session, &SupportedAttributes, &OpalBaseComId);\r
577 if (Ret != TcgResultSuccess) {\r
578 return FALSE;\r
579 }\r
580\r
581 Session.OpalBaseComId = OpalBaseComId;\r
582 *BlockSidSupported = SupportedAttributes.BlockSid == 1 ? TRUE : FALSE;\r
583\r
584 Ret = OpalGetLockingInfo(&Session, &LockingFeature);\r
585 if (Ret != TcgResultSuccess) {\r
586 return FALSE;\r
587 }\r
588\r
589 return OpalDeviceLocked (&SupportedAttributes, &LockingFeature);\r
590}\r
591\r
592/**\r
593 Unlock OPAL password for S3.\r
594\r
595 @param[in] OpalDev Opal object to unlock.\r
596\r
597**/\r
598VOID\r
599UnlockOpalPassword (\r
600 IN OPAL_PEI_DEVICE *OpalDev\r
601 )\r
602{\r
603 TCG_RESULT Result;\r
604 OPAL_SESSION Session;\r
605 BOOLEAN BlockSidSupport;\r
606 UINT32 PpStorageFlags;\r
607 BOOLEAN BlockSIDEnabled;\r
608\r
609 BlockSidSupport = FALSE;\r
610 if (IsOpalDeviceLocked (OpalDev, &BlockSidSupport)) {\r
611 ZeroMem(&Session, sizeof (Session));\r
612 Session.Sscp = &OpalDev->Sscp;\r
613 Session.MediaId = 0;\r
614 Session.OpalBaseComId = OpalDev->Device->OpalBaseComId;\r
615\r
616 Result = OpalUtilUpdateGlobalLockingRange (\r
617 &Session,\r
618 OpalDev->Device->Password,\r
619 OpalDev->Device->PasswordLength,\r
620 FALSE,\r
621 FALSE\r
622 );\r
623 DEBUG ((\r
624 DEBUG_INFO,\r
625 "%a() OpalUtilUpdateGlobalLockingRange() Result = 0x%x\n",\r
626 __FUNCTION__,\r
627 Result\r
628 ));\r
629 }\r
630\r
631 PpStorageFlags = Tcg2PhysicalPresenceLibGetManagementFlags ();\r
632 if ((PpStorageFlags & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID) != 0) {\r
633 BlockSIDEnabled = TRUE;\r
634 } else {\r
635 BlockSIDEnabled = FALSE;\r
636 }\r
637 if (BlockSIDEnabled && BlockSidSupport) {\r
40d32e79 638 DEBUG ((DEBUG_INFO, "OpalPassword: S3 phase send BlockSid command to device!\n"));\r
112e584b
SZ
639 ZeroMem(&Session, sizeof (Session));\r
640 Session.Sscp = &OpalDev->Sscp;\r
641 Session.MediaId = 0;\r
642 Session.OpalBaseComId = OpalDev->Device->OpalBaseComId;\r
643 Result = OpalBlockSid (&Session, TRUE);\r
644 DEBUG ((\r
645 DEBUG_INFO,\r
646 "%a() OpalBlockSid() Result = 0x%x\n",\r
647 __FUNCTION__,\r
648 Result\r
649 ));\r
650 }\r
651}\r
652\r
653/**\r
654 Unlock ATA OPAL password for S3.\r
655\r
656**/\r
657VOID\r
658UnlockOpalPasswordAta (\r
659 VOID\r
660 )\r
661{\r
662 EFI_STATUS Status;\r
663 UINT8 *DevInfo;\r
664 OPAL_DEVICE_ATA TempDevInfoAta;\r
665 OPAL_DEVICE_ATA *DevInfoAta;\r
666 UINTN DevInfoLengthAta;\r
667 UINT8 Bus;\r
668 UINT8 Device;\r
669 UINT8 Function;\r
670 OPAL_PEI_DEVICE OpalDev;\r
671 UINT8 BaseClassCode;\r
672 UINT8 SubClassCode;\r
673 UINT8 SataCmdSt;\r
674 AHCI_CONTEXT AhciContext;\r
675 UINT32 AhciBar;\r
676\r
677 DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
678\r
679 //\r
680 // Get ATA OPAL device info from LockBox.\r
681 //\r
682 DevInfo = (UINT8 *) &TempDevInfoAta;\r
683 DevInfoLengthAta = sizeof (OPAL_DEVICE_ATA);\r
684 Status = RestoreLockBox (&mOpalDeviceAtaGuid, DevInfo, &DevInfoLengthAta);\r
685 if (Status == EFI_BUFFER_TOO_SMALL) {\r
686 DevInfo = AllocatePages (EFI_SIZE_TO_PAGES (DevInfoLengthAta));\r
687 if (DevInfo != NULL) {\r
688 Status = RestoreLockBox (&mOpalDeviceAtaGuid, DevInfo, &DevInfoLengthAta);\r
689 }\r
690 }\r
691 if (EFI_ERROR (Status) || (DevInfo == NULL)) {\r
692 return;\r
693 }\r
694\r
695 for (DevInfoAta = (OPAL_DEVICE_ATA *) DevInfo;\r
696 (UINTN) DevInfoAta < ((UINTN) DevInfo + DevInfoLengthAta);\r
697 DevInfoAta = (OPAL_DEVICE_ATA *) ((UINTN) DevInfoAta + DevInfoAta->Length)) {\r
698 Bus = DevInfoAta->Device.Bus;\r
699 Device = DevInfoAta->Device.Device;\r
700 Function = DevInfoAta->Device.Function;\r
701\r
702 SataCmdSt = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET));\r
703 PciWrite8 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), 0x6);\r
704\r
705 BaseClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0B));\r
706 SubClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0A));\r
707 if ((BaseClassCode != PCI_CLASS_MASS_STORAGE) ||\r
708 ((SubClassCode != PCI_CLASS_MASS_STORAGE_SATADPA) && (SubClassCode != PCI_CLASS_MASS_STORAGE_RAID))) {\r
709 DEBUG ((DEBUG_ERROR, "%a() ClassCode/SubClassCode are not supported\n", __FUNCTION__));\r
710 } else {\r
711 AhciBar = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24));\r
712 PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24), DevInfoAta->BarAddr);\r
713\r
714 ZeroMem (&AhciContext, sizeof (AHCI_CONTEXT));\r
715 AhciContext.AhciBar = DevInfoAta->BarAddr;\r
716 AhciAllocateResource (&AhciContext);\r
717 Status = AhciModeInitialize (&AhciContext, (UINT8)DevInfoAta->Port);\r
718 ASSERT_EFI_ERROR (Status);\r
719 if (EFI_ERROR (Status)) {\r
720 DEBUG ((DEBUG_ERROR, "%a() AhciModeInitialize() error, Status: %r\n", __FUNCTION__, Status));\r
e3df050e
SZ
721 } else {\r
722 OpalDev.Signature = OPAL_PEI_DEVICE_SIGNATURE;\r
723 OpalDev.Sscp.ReceiveData = SecurityReceiveData;\r
724 OpalDev.Sscp.SendData = SecuritySendData;\r
725 OpalDev.DeviceType = OPAL_DEVICE_TYPE_ATA;\r
726 OpalDev.Device = (OPAL_DEVICE_COMMON *) DevInfoAta;\r
727 OpalDev.Context = &AhciContext;\r
728\r
729 UnlockOpalPassword (&OpalDev);\r
112e584b 730 }\r
112e584b
SZ
731 AhciFreeResource (&AhciContext);\r
732 PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24), AhciBar);\r
733 }\r
734 PciWrite8 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), SataCmdSt);\r
735 }\r
736\r
737 ZeroMem (DevInfo, DevInfoLengthAta);\r
738 if ((UINTN) DevInfo != (UINTN) &TempDevInfoAta) {\r
739 FreePages (DevInfo, EFI_SIZE_TO_PAGES (DevInfoLengthAta));\r
740 }\r
741\r
742 DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
743}\r
744\r
745/**\r
746 Unlock NVMe OPAL password for S3.\r
747\r
748**/\r
749VOID\r
750UnlockOpalPasswordNvme (\r
751 VOID\r
752 )\r
753{\r
754 EFI_STATUS Status;\r
755 UINT8 *DevInfo;\r
756 OPAL_DEVICE_NVME TempDevInfoNvme;\r
757 OPAL_DEVICE_NVME *DevInfoNvme;\r
758 UINTN DevInfoLengthNvme;\r
759 UINT8 Bus;\r
760 UINT8 Device;\r
761 UINT8 Function;\r
762 OPAL_PEI_DEVICE OpalDev;\r
763 UINT8 BaseClassCode;\r
764 UINT8 SubClassCode;\r
765 UINT8 ProgInt;\r
766 UINT8 NvmeCmdSt;\r
767 UINT8 *StorePcieConfDataList[16];\r
768 UINTN RpBase;\r
769 UINTN MemoryBase;\r
770 UINTN MemoryLength;\r
771 NVME_CONTEXT NvmeContext;\r
772\r
773 DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
774\r
775 //\r
776 // Get NVMe OPAL device info from LockBox.\r
777 //\r
778 DevInfo = (UINT8 *) &TempDevInfoNvme;\r
779 DevInfoLengthNvme = sizeof (OPAL_DEVICE_NVME);\r
780 Status = RestoreLockBox (&mOpalDeviceNvmeGuid, DevInfo, &DevInfoLengthNvme);\r
781 if (Status == EFI_BUFFER_TOO_SMALL) {\r
782 DevInfo = AllocatePages (EFI_SIZE_TO_PAGES (DevInfoLengthNvme));\r
783 if (DevInfo != NULL) {\r
784 Status = RestoreLockBox (&mOpalDeviceNvmeGuid, DevInfo, &DevInfoLengthNvme);\r
785 }\r
786 }\r
787 if (EFI_ERROR (Status) || (DevInfo == NULL)) {\r
788 return;\r
789 }\r
790\r
791 for (DevInfoNvme = (OPAL_DEVICE_NVME *) DevInfo;\r
792 (UINTN) DevInfoNvme < ((UINTN) DevInfo + DevInfoLengthNvme);\r
793 DevInfoNvme = (OPAL_DEVICE_NVME *) ((UINTN) DevInfoNvme + DevInfoNvme->Length)) {\r
794 Bus = DevInfoNvme->Device.Bus;\r
795 Device = DevInfoNvme->Device.Device;\r
796 Function = DevInfoNvme->Device.Function;\r
797\r
798 RpBase = 0;\r
799 NvmeCmdSt = 0;\r
800\r
801 ///\r
802 /// Save original RootPort configuration space to heap\r
803 ///\r
804 RpBase = SaveRestoreRootportConfSpace (\r
805 DevInfoNvme,\r
806 TRUE, // save\r
807 StorePcieConfDataList\r
808 );\r
809 MemoryBase = DevInfoNvme->BarAddr;\r
810 MemoryLength = 0;\r
811 ConfigureRootPortForPcieNand (RpBase, Bus, (UINT32) MemoryBase, (UINT32) MemoryLength);\r
812\r
813 ///\r
814 /// Enable PCIE decode for RootPort\r
815 ///\r
816 NvmeCmdSt = PciRead8 (RpBase + NVME_PCIE_PCICMD);\r
817 PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0x6);\r
818\r
819 BaseClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0B));\r
820 SubClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0A));\r
821 ProgInt = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x09));\r
822 if ((BaseClassCode != PCI_CLASS_MASS_STORAGE) ||\r
823 (SubClassCode != PCI_CLASS_MASS_STORAGE_NVM) ||\r
824 (ProgInt != PCI_IF_NVMHCI)) {\r
825 DEBUG ((DEBUG_ERROR, "%a() ClassCode/SubClassCode/PI are not supported\n", __FUNCTION__));\r
826 } else {\r
827 ZeroMem (&NvmeContext, sizeof (NVME_CONTEXT));\r
828 NvmeContext.Nbar = DevInfoNvme->BarAddr;\r
829 NvmeContext.PciBase = PCI_LIB_ADDRESS (Bus, Device, Function, 0x0);\r
830 NvmeContext.NvmeInitWaitTime = 0;\r
831 NvmeContext.Nsid = DevInfoNvme->NvmeNamespaceId;\r
832 NvmeAllocateResource (&NvmeContext);\r
833 Status = NvmeControllerInit (&NvmeContext);\r
834\r
835 OpalDev.Signature = OPAL_PEI_DEVICE_SIGNATURE;\r
836 OpalDev.Sscp.ReceiveData = SecurityReceiveData;\r
837 OpalDev.Sscp.SendData = SecuritySendData;\r
838 OpalDev.DeviceType = OPAL_DEVICE_TYPE_NVME;\r
839 OpalDev.Device = (OPAL_DEVICE_COMMON *) DevInfoNvme;\r
840 OpalDev.Context = &NvmeContext;\r
841\r
842 UnlockOpalPassword (&OpalDev);\r
843\r
844 Status = NvmeControllerExit (&NvmeContext);\r
845 NvmeFreeResource (&NvmeContext);\r
846 }\r
847\r
848 ASSERT (RpBase != 0);\r
849 PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0);\r
850 RpBase = SaveRestoreRootportConfSpace (\r
851 DevInfoNvme,\r
852 FALSE, // restore\r
853 StorePcieConfDataList\r
854 );\r
855 PciWrite8 (RpBase + NVME_PCIE_PCICMD, NvmeCmdSt);\r
856 }\r
857\r
858 ZeroMem (DevInfo, DevInfoLengthNvme);\r
859 if ((UINTN) DevInfo != (UINTN) &TempDevInfoNvme) {\r
860 FreePages (DevInfo, EFI_SIZE_TO_PAGES (DevInfoLengthNvme));\r
861 }\r
862\r
863 DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
864}\r
865\r
866/**\r
867 Unlock OPAL password for S3.\r
868\r
869**/\r
870VOID\r
871OpalPasswordS3 (\r
872 VOID\r
873 )\r
874{\r
875 UnlockOpalPasswordAta ();\r
876 UnlockOpalPasswordNvme ();\r
877}\r
878\r
879/**\r
880 Entry point of the notification callback function itself within the PEIM.\r
881 It is to unlock OPAL password for S3.\r
882\r
883 @param PeiServices Indirect reference to the PEI Services Table.\r
884 @param NotifyDescriptor Address of the notification descriptor data structure.\r
885 @param Ppi Address of the PPI that was installed.\r
886\r
887 @return Status of the notification.\r
888 The status code returned from this function is ignored.\r
889**/\r
890EFI_STATUS\r
891EFIAPI\r
892OpalPasswordEndOfPeiNotify(\r
893 IN EFI_PEI_SERVICES **PeiServices,\r
894 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,\r
895 IN VOID *Ppi\r
896 )\r
897{\r
898 EFI_STATUS Status;\r
899 EFI_BOOT_MODE BootMode;\r
900\r
901 Status = PeiServicesGetBootMode (&BootMode);\r
902 ASSERT_EFI_ERROR (Status);\r
903 if (BootMode != BOOT_ON_S3_RESUME) {\r
904 return EFI_UNSUPPORTED;\r
905 }\r
906\r
907 DEBUG ((DEBUG_INFO, "%a() - enter at S3 resume\n", __FUNCTION__));\r
908\r
909 OpalPasswordS3 ();\r
910\r
911 DEBUG ((DEBUG_INFO, "%a() - exit at S3 resume\n", __FUNCTION__));\r
912\r
913 return EFI_SUCCESS;\r
914}\r
915\r
916EFI_PEI_NOTIFY_DESCRIPTOR mOpalPasswordEndOfPeiNotifyDesc = {\r
917 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
918 &gEfiEndOfPeiSignalPpiGuid,\r
919 OpalPasswordEndOfPeiNotify\r
920};\r
921\r
922/**\r
923 Main entry for this module.\r
924\r
925 @param FileHandle Handle of the file being invoked.\r
926 @param PeiServices Pointer to PEI Services table.\r
927\r
928 @return Status from PeiServicesNotifyPpi.\r
929\r
930**/\r
931EFI_STATUS\r
932EFIAPI\r
933OpalPasswordPeiInit (\r
934 IN EFI_PEI_FILE_HANDLE FileHandle,\r
935 IN CONST EFI_PEI_SERVICES **PeiServices\r
936 )\r
937{\r
938 EFI_STATUS Status;\r
939\r
940 Status = PeiServicesNotifyPpi (&mOpalPasswordEndOfPeiNotifyDesc);\r
941 ASSERT_EFI_ERROR (Status);\r
942 return Status;\r
943}\r
944\r