]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.c
SecurityPkg OpalPasswordPei: Go next when AhciModeInitialize is failed
[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
638 ZeroMem(&Session, sizeof (Session));\r
639 Session.Sscp = &OpalDev->Sscp;\r
640 Session.MediaId = 0;\r
641 Session.OpalBaseComId = OpalDev->Device->OpalBaseComId;\r
642 Result = OpalBlockSid (&Session, TRUE);\r
643 DEBUG ((\r
644 DEBUG_INFO,\r
645 "%a() OpalBlockSid() Result = 0x%x\n",\r
646 __FUNCTION__,\r
647 Result\r
648 ));\r
649 }\r
650}\r
651\r
652/**\r
653 Unlock ATA OPAL password for S3.\r
654\r
655**/\r
656VOID\r
657UnlockOpalPasswordAta (\r
658 VOID\r
659 )\r
660{\r
661 EFI_STATUS Status;\r
662 UINT8 *DevInfo;\r
663 OPAL_DEVICE_ATA TempDevInfoAta;\r
664 OPAL_DEVICE_ATA *DevInfoAta;\r
665 UINTN DevInfoLengthAta;\r
666 UINT8 Bus;\r
667 UINT8 Device;\r
668 UINT8 Function;\r
669 OPAL_PEI_DEVICE OpalDev;\r
670 UINT8 BaseClassCode;\r
671 UINT8 SubClassCode;\r
672 UINT8 SataCmdSt;\r
673 AHCI_CONTEXT AhciContext;\r
674 UINT32 AhciBar;\r
675\r
676 DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
677\r
678 //\r
679 // Get ATA OPAL device info from LockBox.\r
680 //\r
681 DevInfo = (UINT8 *) &TempDevInfoAta;\r
682 DevInfoLengthAta = sizeof (OPAL_DEVICE_ATA);\r
683 Status = RestoreLockBox (&mOpalDeviceAtaGuid, DevInfo, &DevInfoLengthAta);\r
684 if (Status == EFI_BUFFER_TOO_SMALL) {\r
685 DevInfo = AllocatePages (EFI_SIZE_TO_PAGES (DevInfoLengthAta));\r
686 if (DevInfo != NULL) {\r
687 Status = RestoreLockBox (&mOpalDeviceAtaGuid, DevInfo, &DevInfoLengthAta);\r
688 }\r
689 }\r
690 if (EFI_ERROR (Status) || (DevInfo == NULL)) {\r
691 return;\r
692 }\r
693\r
694 for (DevInfoAta = (OPAL_DEVICE_ATA *) DevInfo;\r
695 (UINTN) DevInfoAta < ((UINTN) DevInfo + DevInfoLengthAta);\r
696 DevInfoAta = (OPAL_DEVICE_ATA *) ((UINTN) DevInfoAta + DevInfoAta->Length)) {\r
697 Bus = DevInfoAta->Device.Bus;\r
698 Device = DevInfoAta->Device.Device;\r
699 Function = DevInfoAta->Device.Function;\r
700\r
701 SataCmdSt = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET));\r
702 PciWrite8 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), 0x6);\r
703\r
704 BaseClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0B));\r
705 SubClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0A));\r
706 if ((BaseClassCode != PCI_CLASS_MASS_STORAGE) ||\r
707 ((SubClassCode != PCI_CLASS_MASS_STORAGE_SATADPA) && (SubClassCode != PCI_CLASS_MASS_STORAGE_RAID))) {\r
708 DEBUG ((DEBUG_ERROR, "%a() ClassCode/SubClassCode are not supported\n", __FUNCTION__));\r
709 } else {\r
710 AhciBar = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24));\r
711 PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24), DevInfoAta->BarAddr);\r
712\r
713 ZeroMem (&AhciContext, sizeof (AHCI_CONTEXT));\r
714 AhciContext.AhciBar = DevInfoAta->BarAddr;\r
715 AhciAllocateResource (&AhciContext);\r
716 Status = AhciModeInitialize (&AhciContext, (UINT8)DevInfoAta->Port);\r
717 ASSERT_EFI_ERROR (Status);\r
718 if (EFI_ERROR (Status)) {\r
719 DEBUG ((DEBUG_ERROR, "%a() AhciModeInitialize() error, Status: %r\n", __FUNCTION__, Status));\r
e3df050e
SZ
720 } else {\r
721 OpalDev.Signature = OPAL_PEI_DEVICE_SIGNATURE;\r
722 OpalDev.Sscp.ReceiveData = SecurityReceiveData;\r
723 OpalDev.Sscp.SendData = SecuritySendData;\r
724 OpalDev.DeviceType = OPAL_DEVICE_TYPE_ATA;\r
725 OpalDev.Device = (OPAL_DEVICE_COMMON *) DevInfoAta;\r
726 OpalDev.Context = &AhciContext;\r
727\r
728 UnlockOpalPassword (&OpalDev);\r
112e584b 729 }\r
112e584b
SZ
730 AhciFreeResource (&AhciContext);\r
731 PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24), AhciBar);\r
732 }\r
733 PciWrite8 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), SataCmdSt);\r
734 }\r
735\r
736 ZeroMem (DevInfo, DevInfoLengthAta);\r
737 if ((UINTN) DevInfo != (UINTN) &TempDevInfoAta) {\r
738 FreePages (DevInfo, EFI_SIZE_TO_PAGES (DevInfoLengthAta));\r
739 }\r
740\r
741 DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
742}\r
743\r
744/**\r
745 Unlock NVMe OPAL password for S3.\r
746\r
747**/\r
748VOID\r
749UnlockOpalPasswordNvme (\r
750 VOID\r
751 )\r
752{\r
753 EFI_STATUS Status;\r
754 UINT8 *DevInfo;\r
755 OPAL_DEVICE_NVME TempDevInfoNvme;\r
756 OPAL_DEVICE_NVME *DevInfoNvme;\r
757 UINTN DevInfoLengthNvme;\r
758 UINT8 Bus;\r
759 UINT8 Device;\r
760 UINT8 Function;\r
761 OPAL_PEI_DEVICE OpalDev;\r
762 UINT8 BaseClassCode;\r
763 UINT8 SubClassCode;\r
764 UINT8 ProgInt;\r
765 UINT8 NvmeCmdSt;\r
766 UINT8 *StorePcieConfDataList[16];\r
767 UINTN RpBase;\r
768 UINTN MemoryBase;\r
769 UINTN MemoryLength;\r
770 NVME_CONTEXT NvmeContext;\r
771\r
772 DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
773\r
774 //\r
775 // Get NVMe OPAL device info from LockBox.\r
776 //\r
777 DevInfo = (UINT8 *) &TempDevInfoNvme;\r
778 DevInfoLengthNvme = sizeof (OPAL_DEVICE_NVME);\r
779 Status = RestoreLockBox (&mOpalDeviceNvmeGuid, DevInfo, &DevInfoLengthNvme);\r
780 if (Status == EFI_BUFFER_TOO_SMALL) {\r
781 DevInfo = AllocatePages (EFI_SIZE_TO_PAGES (DevInfoLengthNvme));\r
782 if (DevInfo != NULL) {\r
783 Status = RestoreLockBox (&mOpalDeviceNvmeGuid, DevInfo, &DevInfoLengthNvme);\r
784 }\r
785 }\r
786 if (EFI_ERROR (Status) || (DevInfo == NULL)) {\r
787 return;\r
788 }\r
789\r
790 for (DevInfoNvme = (OPAL_DEVICE_NVME *) DevInfo;\r
791 (UINTN) DevInfoNvme < ((UINTN) DevInfo + DevInfoLengthNvme);\r
792 DevInfoNvme = (OPAL_DEVICE_NVME *) ((UINTN) DevInfoNvme + DevInfoNvme->Length)) {\r
793 Bus = DevInfoNvme->Device.Bus;\r
794 Device = DevInfoNvme->Device.Device;\r
795 Function = DevInfoNvme->Device.Function;\r
796\r
797 RpBase = 0;\r
798 NvmeCmdSt = 0;\r
799\r
800 ///\r
801 /// Save original RootPort configuration space to heap\r
802 ///\r
803 RpBase = SaveRestoreRootportConfSpace (\r
804 DevInfoNvme,\r
805 TRUE, // save\r
806 StorePcieConfDataList\r
807 );\r
808 MemoryBase = DevInfoNvme->BarAddr;\r
809 MemoryLength = 0;\r
810 ConfigureRootPortForPcieNand (RpBase, Bus, (UINT32) MemoryBase, (UINT32) MemoryLength);\r
811\r
812 ///\r
813 /// Enable PCIE decode for RootPort\r
814 ///\r
815 NvmeCmdSt = PciRead8 (RpBase + NVME_PCIE_PCICMD);\r
816 PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0x6);\r
817\r
818 BaseClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0B));\r
819 SubClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0A));\r
820 ProgInt = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x09));\r
821 if ((BaseClassCode != PCI_CLASS_MASS_STORAGE) ||\r
822 (SubClassCode != PCI_CLASS_MASS_STORAGE_NVM) ||\r
823 (ProgInt != PCI_IF_NVMHCI)) {\r
824 DEBUG ((DEBUG_ERROR, "%a() ClassCode/SubClassCode/PI are not supported\n", __FUNCTION__));\r
825 } else {\r
826 ZeroMem (&NvmeContext, sizeof (NVME_CONTEXT));\r
827 NvmeContext.Nbar = DevInfoNvme->BarAddr;\r
828 NvmeContext.PciBase = PCI_LIB_ADDRESS (Bus, Device, Function, 0x0);\r
829 NvmeContext.NvmeInitWaitTime = 0;\r
830 NvmeContext.Nsid = DevInfoNvme->NvmeNamespaceId;\r
831 NvmeAllocateResource (&NvmeContext);\r
832 Status = NvmeControllerInit (&NvmeContext);\r
833\r
834 OpalDev.Signature = OPAL_PEI_DEVICE_SIGNATURE;\r
835 OpalDev.Sscp.ReceiveData = SecurityReceiveData;\r
836 OpalDev.Sscp.SendData = SecuritySendData;\r
837 OpalDev.DeviceType = OPAL_DEVICE_TYPE_NVME;\r
838 OpalDev.Device = (OPAL_DEVICE_COMMON *) DevInfoNvme;\r
839 OpalDev.Context = &NvmeContext;\r
840\r
841 UnlockOpalPassword (&OpalDev);\r
842\r
843 Status = NvmeControllerExit (&NvmeContext);\r
844 NvmeFreeResource (&NvmeContext);\r
845 }\r
846\r
847 ASSERT (RpBase != 0);\r
848 PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0);\r
849 RpBase = SaveRestoreRootportConfSpace (\r
850 DevInfoNvme,\r
851 FALSE, // restore\r
852 StorePcieConfDataList\r
853 );\r
854 PciWrite8 (RpBase + NVME_PCIE_PCICMD, NvmeCmdSt);\r
855 }\r
856\r
857 ZeroMem (DevInfo, DevInfoLengthNvme);\r
858 if ((UINTN) DevInfo != (UINTN) &TempDevInfoNvme) {\r
859 FreePages (DevInfo, EFI_SIZE_TO_PAGES (DevInfoLengthNvme));\r
860 }\r
861\r
862 DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
863}\r
864\r
865/**\r
866 Unlock OPAL password for S3.\r
867\r
868**/\r
869VOID\r
870OpalPasswordS3 (\r
871 VOID\r
872 )\r
873{\r
874 UnlockOpalPasswordAta ();\r
875 UnlockOpalPasswordNvme ();\r
876}\r
877\r
878/**\r
879 Entry point of the notification callback function itself within the PEIM.\r
880 It is to unlock OPAL password for S3.\r
881\r
882 @param PeiServices Indirect reference to the PEI Services Table.\r
883 @param NotifyDescriptor Address of the notification descriptor data structure.\r
884 @param Ppi Address of the PPI that was installed.\r
885\r
886 @return Status of the notification.\r
887 The status code returned from this function is ignored.\r
888**/\r
889EFI_STATUS\r
890EFIAPI\r
891OpalPasswordEndOfPeiNotify(\r
892 IN EFI_PEI_SERVICES **PeiServices,\r
893 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,\r
894 IN VOID *Ppi\r
895 )\r
896{\r
897 EFI_STATUS Status;\r
898 EFI_BOOT_MODE BootMode;\r
899\r
900 Status = PeiServicesGetBootMode (&BootMode);\r
901 ASSERT_EFI_ERROR (Status);\r
902 if (BootMode != BOOT_ON_S3_RESUME) {\r
903 return EFI_UNSUPPORTED;\r
904 }\r
905\r
906 DEBUG ((DEBUG_INFO, "%a() - enter at S3 resume\n", __FUNCTION__));\r
907\r
908 OpalPasswordS3 ();\r
909\r
910 DEBUG ((DEBUG_INFO, "%a() - exit at S3 resume\n", __FUNCTION__));\r
911\r
912 return EFI_SUCCESS;\r
913}\r
914\r
915EFI_PEI_NOTIFY_DESCRIPTOR mOpalPasswordEndOfPeiNotifyDesc = {\r
916 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
917 &gEfiEndOfPeiSignalPpiGuid,\r
918 OpalPasswordEndOfPeiNotify\r
919};\r
920\r
921/**\r
922 Main entry for this module.\r
923\r
924 @param FileHandle Handle of the file being invoked.\r
925 @param PeiServices Pointer to PEI Services table.\r
926\r
927 @return Status from PeiServicesNotifyPpi.\r
928\r
929**/\r
930EFI_STATUS\r
931EFIAPI\r
932OpalPasswordPeiInit (\r
933 IN EFI_PEI_FILE_HANDLE FileHandle,\r
934 IN CONST EFI_PEI_SERVICES **PeiServices\r
935 )\r
936{\r
937 EFI_STATUS Status;\r
938\r
939 Status = PeiServicesNotifyPpi (&mOpalPasswordEndOfPeiNotifyDesc);\r
940 ASSERT_EFI_ERROR (Status);\r
941 return Status;\r
942}\r
943\r