2 Opal Password PEI driver which is used to unlock Opal Password for S3.
4 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "OpalPasswordPei.h"
17 EFI_GUID mOpalDeviceAtaGuid
= OPAL_DEVICE_ATA_GUID
;
18 EFI_GUID mOpalDeviceNvmeGuid
= OPAL_DEVICE_NVME_GUID
;
20 #define OPAL_PCIE_ROOTPORT_SAVESIZE (0x40)
21 #define STORE_INVALID_ROOTPORT_INDEX ((UINT8) -1)
26 @return Pointer to IOMMU PPI.
35 EDKII_IOMMU_PPI
*IoMmu
;
38 Status
= PeiServicesLocatePpi (
44 if (!EFI_ERROR (Status
) && (IoMmu
!= NULL
)) {
52 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
53 OperationBusMasterCommonBuffer64 mapping.
55 @param Pages The number of pages to allocate.
56 @param HostAddress A pointer to store the base system memory address of the
58 @param DeviceAddress The resulting map address for the bus master PCI controller to use to
59 access the hosts HostAddress.
60 @param Mapping A resulting value to pass to Unmap().
62 @retval EFI_SUCCESS The requested memory pages were allocated.
63 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
64 MEMORY_WRITE_COMBINE and MEMORY_CACHED.
65 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
66 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
72 OUT VOID
**HostAddress
,
73 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
79 EFI_PHYSICAL_ADDRESS HostPhyAddress
;
80 EDKII_IOMMU_PPI
*IoMmu
;
89 Status
= IoMmu
->AllocateBuffer (
96 if (EFI_ERROR (Status
)) {
97 return EFI_OUT_OF_RESOURCES
;
100 NumberOfBytes
= EFI_PAGES_TO_SIZE (Pages
);
101 Status
= IoMmu
->Map (
103 EdkiiIoMmuOperationBusMasterCommonBuffer
,
109 if (EFI_ERROR (Status
)) {
110 IoMmu
->FreeBuffer (IoMmu
, Pages
, *HostAddress
);
112 return EFI_OUT_OF_RESOURCES
;
114 Status
= IoMmu
->SetAttribute (
117 EDKII_IOMMU_ACCESS_READ
| EDKII_IOMMU_ACCESS_WRITE
119 if (EFI_ERROR (Status
)) {
120 IoMmu
->Unmap (IoMmu
, *Mapping
);
121 IoMmu
->FreeBuffer (IoMmu
, Pages
, *HostAddress
);
127 Status
= PeiServicesAllocatePages (
132 if (EFI_ERROR (Status
)) {
133 return EFI_OUT_OF_RESOURCES
;
135 *HostAddress
= (VOID
*) (UINTN
) HostPhyAddress
;
136 *DeviceAddress
= HostPhyAddress
;
143 Frees memory that was allocated with AllocateBuffer().
145 @param Pages The number of pages to free.
146 @param HostAddress The base system memory address of the allocated range.
147 @param Mapping The mapping value returned from Map().
153 IN VOID
*HostAddress
,
157 EDKII_IOMMU_PPI
*IoMmu
;
162 IoMmu
->SetAttribute (IoMmu
, Mapping
, 0);
163 IoMmu
->Unmap (IoMmu
, Mapping
);
164 IoMmu
->FreeBuffer (IoMmu
, Pages
, HostAddress
);
166 PeiServicesFreePages (
167 (EFI_PHYSICAL_ADDRESS
) (UINTN
) HostAddress
,
174 Provide IO action support.
176 @param[in] PeiDev The opal device need to perform trusted IO.
177 @param[in] IoType OPAL_IO_TYPE indicating whether to perform a Trusted Send or Trusted Receive.
178 @param[in] SecurityProtocol Security Protocol
179 @param[in] SpSpecific Security Protocol Specific
180 @param[in] TransferLength Transfer Length of Buffer (in bytes) - always a multiple of 512
181 @param[in] Buffer Address of Data to transfer
183 @retval EFI_SUCCESS Perform the IO action success.
184 @retval Others Perform the IO action failed.
189 OPAL_PEI_DEVICE
*PeiDev
,
191 UINT8 SecurityProtocol
,
193 UINTN TransferLength
,
198 UINTN BufferSizeBlocks
;
199 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
200 OPAL_DEVICE_ATA
*DevInfoAta
;
201 AHCI_CONTEXT
*AhciContext
;
202 NVME_CONTEXT
*NvmeContext
;
204 Status
= EFI_DEVICE_ERROR
;
205 if (PeiDev
->DeviceType
== OPAL_DEVICE_TYPE_ATA
) {
206 DevInfoAta
= (OPAL_DEVICE_ATA
*) PeiDev
->Device
;
207 AhciContext
= (AHCI_CONTEXT
*) PeiDev
->Context
;
209 BufferSizeBlocks
= TransferLength
/ 512;
211 ZeroMem( &AtaCommandBlock
, sizeof( EFI_ATA_COMMAND_BLOCK
) );
212 AtaCommandBlock
.AtaCommand
= ( IoType
== OpalSend
) ? ATA_COMMAND_TRUSTED_SEND
: ATA_COMMAND_TRUSTED_RECEIVE
;
213 AtaCommandBlock
.AtaSectorCount
= ( UINT8
)BufferSizeBlocks
;
214 AtaCommandBlock
.AtaSectorNumber
= ( UINT8
)( BufferSizeBlocks
>> 8 );
215 AtaCommandBlock
.AtaFeatures
= SecurityProtocol
;
216 AtaCommandBlock
.AtaCylinderLow
= ( UINT8
)( SpSpecific
>> 8 );
217 AtaCommandBlock
.AtaCylinderHigh
= ( UINT8
)( SpSpecific
);
218 AtaCommandBlock
.AtaDeviceHead
= ATA_DEVICE_LBA
;
221 ZeroMem( AhciContext
->Buffer
, HDD_PAYLOAD
);
222 ASSERT( TransferLength
<= HDD_PAYLOAD
);
224 if (IoType
== OpalSend
) {
225 CopyMem( AhciContext
->Buffer
, Buffer
, TransferLength
);
228 Status
= AhciPioTransfer(
230 (UINT8
) DevInfoAta
->Port
,
231 (UINT8
) DevInfoAta
->PortMultiplierPort
,
234 ( IoType
== OpalSend
) ? FALSE
: TRUE
, // i/o direction
238 (UINT32
)TransferLength
,
242 if (IoType
== OpalRecv
) {
243 CopyMem( Buffer
, AhciContext
->Buffer
, TransferLength
);
245 } else if (PeiDev
->DeviceType
== OPAL_DEVICE_TYPE_NVME
) {
246 NvmeContext
= (NVME_CONTEXT
*) PeiDev
->Context
;
247 Status
= NvmeSecuritySendReceive (
251 SwapBytes16(SpSpecific
),
256 DEBUG((DEBUG_ERROR
, "DeviceType(%x) not support.\n", PeiDev
->DeviceType
));
263 Send a security protocol command to a device that receives data and/or the result
264 of one or more commands sent by SendData.
266 The ReceiveData function sends a security protocol command to the given MediaId.
267 The security protocol command sent is defined by SecurityProtocolId and contains
268 the security protocol specific data SecurityProtocolSpecificData. The function
269 returns the data from the security protocol command in PayloadBuffer.
271 For devices supporting the SCSI command set, the security protocol command is sent
272 using the SECURITY PROTOCOL IN command defined in SPC-4.
274 For devices supporting the ATA command set, the security protocol command is sent
275 using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
278 If the PayloadBufferSize is zero, the security protocol command is sent using the
279 Trusted Non-Data command defined in ATA8-ACS.
281 If PayloadBufferSize is too small to store the available data from the security
282 protocol command, the function shall copy PayloadBufferSize bytes into the
283 PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
285 If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
286 the function shall return EFI_INVALID_PARAMETER.
288 If the given MediaId does not support security protocol commands, the function shall
289 return EFI_UNSUPPORTED. If there is no media in the device, the function returns
290 EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
291 the function returns EFI_MEDIA_CHANGED.
293 If the security protocol fails to complete within the Timeout period, the function
294 shall return EFI_TIMEOUT.
296 If the security protocol command completes without an error, the function shall
297 return EFI_SUCCESS. If the security protocol command completes with an error, the
298 function shall return EFI_DEVICE_ERROR.
300 @param This Indicates a pointer to the calling context.
301 @param MediaId ID of the medium to receive data from.
302 @param Timeout The timeout, in 100ns units, to use for the execution
303 of the security protocol command. A Timeout value of 0
304 means that this function will wait indefinitely for the
305 security protocol command to execute. If Timeout is greater
306 than zero, then this function will return EFI_TIMEOUT
307 if the time required to execute the receive data command
308 is greater than Timeout.
309 @param SecurityProtocolId The value of the "Security Protocol" parameter of
310 the security protocol command to be sent.
311 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
312 of the security protocol command to be sent.
313 @param PayloadBufferSize Size in bytes of the payload data buffer.
314 @param PayloadBuffer A pointer to a destination buffer to store the security
315 protocol command specific payload data for the security
316 protocol command. The caller is responsible for having
317 either implicit or explicit ownership of the buffer.
318 @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
319 data written to the payload data buffer.
321 @retval EFI_SUCCESS The security protocol command completed successfully.
322 @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
323 data from the device. The PayloadBuffer contains the truncated data.
324 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
325 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
326 @retval EFI_NO_MEDIA There is no media in the device.
327 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
328 @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
329 PayloadBufferSize is non-zero.
330 @retval EFI_TIMEOUT A timeout occurred while waiting for the security
331 protocol command to execute.
336 SecurityReceiveData (
337 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
*This
,
340 IN UINT8 SecurityProtocolId
,
341 IN UINT16 SecurityProtocolSpecificData
,
342 IN UINTN PayloadBufferSize
,
343 OUT VOID
*PayloadBuffer
,
344 OUT UINTN
*PayloadTransferSize
347 OPAL_PEI_DEVICE
*PeiDev
;
349 PeiDev
= OPAL_PEI_DEVICE_FROM_THIS (This
);
350 if (PeiDev
== NULL
) {
351 return EFI_DEVICE_ERROR
;
354 return PerformTrustedIo (
358 SecurityProtocolSpecificData
,
365 Send a security protocol command to a device.
367 The SendData function sends a security protocol command containing the payload
368 PayloadBuffer to the given MediaId. The security protocol command sent is
369 defined by SecurityProtocolId and contains the security protocol specific data
370 SecurityProtocolSpecificData. If the underlying protocol command requires a
371 specific padding for the command payload, the SendData function shall add padding
372 bytes to the command payload to satisfy the padding requirements.
374 For devices supporting the SCSI command set, the security protocol command is sent
375 using the SECURITY PROTOCOL OUT command defined in SPC-4.
377 For devices supporting the ATA command set, the security protocol command is sent
378 using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
379 is non-zero. If the PayloadBufferSize is zero, the security protocol command is
380 sent using the Trusted Non-Data command defined in ATA8-ACS.
382 If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
383 return EFI_INVALID_PARAMETER.
385 If the given MediaId does not support security protocol commands, the function
386 shall return EFI_UNSUPPORTED. If there is no media in the device, the function
387 returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
388 device, the function returns EFI_MEDIA_CHANGED.
390 If the security protocol fails to complete within the Timeout period, the function
391 shall return EFI_TIMEOUT.
393 If the security protocol command completes without an error, the function shall return
394 EFI_SUCCESS. If the security protocol command completes with an error, the function
395 shall return EFI_DEVICE_ERROR.
397 @param This Indicates a pointer to the calling context.
398 @param MediaId ID of the medium to receive data from.
399 @param Timeout The timeout, in 100ns units, to use for the execution
400 of the security protocol command. A Timeout value of 0
401 means that this function will wait indefinitely for the
402 security protocol command to execute. If Timeout is greater
403 than zero, then this function will return EFI_TIMEOUT
404 if the time required to execute the send data command
405 is greater than Timeout.
406 @param SecurityProtocolId The value of the "Security Protocol" parameter of
407 the security protocol command to be sent.
408 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
409 of the security protocol command to be sent.
410 @param PayloadBufferSize Size in bytes of the payload data buffer.
411 @param PayloadBuffer A pointer to a destination buffer to store the security
412 protocol command specific payload data for the security
415 @retval EFI_SUCCESS The security protocol command completed successfully.
416 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
417 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
418 @retval EFI_NO_MEDIA There is no media in the device.
419 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
420 @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
421 @retval EFI_TIMEOUT A timeout occurred while waiting for the security
422 protocol command to execute.
428 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
*This
,
431 IN UINT8 SecurityProtocolId
,
432 IN UINT16 SecurityProtocolSpecificData
,
433 IN UINTN PayloadBufferSize
,
434 IN VOID
*PayloadBuffer
437 OPAL_PEI_DEVICE
*PeiDev
;
439 PeiDev
= OPAL_PEI_DEVICE_FROM_THIS (This
);
440 if (PeiDev
== NULL
) {
441 return EFI_DEVICE_ERROR
;
444 return PerformTrustedIo (
448 SecurityProtocolSpecificData
,
456 Save/Restore RootPort configuration space.
458 @param[in] DevInfoNvme Pointer to NVMe device info.
459 @param[in] SaveAction TRUE: Save, FALSE: Restore
460 @param[in,out] PcieConfBufferList Configuration space data buffer for save/restore
462 @return PCIE base address of this RootPort
465 SaveRestoreRootportConfSpace (
466 IN OPAL_DEVICE_NVME
*DevInfoNvme
,
467 IN BOOLEAN SaveAction
,
468 IN OUT UINT8
**PcieConfBufferList
473 OPAL_PCI_DEVICE
*DevNode
;
474 UINT8
*StorePcieConfData
;
481 while (sizeof (OPAL_DEVICE_NVME
) + Length
< DevInfoNvme
->Length
) {
482 DevNode
= (OPAL_PCI_DEVICE
*)((UINT8
*)DevInfoNvme
->PciBridgeNode
+ Length
);
483 RpBase
= PCI_LIB_ADDRESS (DevNode
->Bus
, DevNode
->Device
, DevNode
->Function
, 0x0);
485 if (PcieConfBufferList
!= NULL
) {
487 StorePcieConfData
= (UINT8
*) AllocateZeroPool (OPAL_PCIE_ROOTPORT_SAVESIZE
);
488 ASSERT (StorePcieConfData
!= NULL
);
489 OpalPciRead (StorePcieConfData
, RpBase
, OPAL_PCIE_ROOTPORT_SAVESIZE
);
490 PcieConfBufferList
[Index
] = StorePcieConfData
;
492 // Skip PCIe Command & Status registers
493 StorePcieConfData
= PcieConfBufferList
[Index
];
494 OpalPciWrite (RpBase
, StorePcieConfData
, 4);
495 OpalPciWrite (RpBase
+ 8, StorePcieConfData
+ 8, OPAL_PCIE_ROOTPORT_SAVESIZE
- 8);
497 FreePool (StorePcieConfData
);
501 Length
+= sizeof (OPAL_PCI_DEVICE
);
509 Configure RootPort for downstream PCIe NAND devices.
511 @param[in] RpBase - PCIe configuration space address of this RootPort
512 @param[in] BusNumber - Bus number
513 @param[in] MemoryBase - Memory base address
514 @param[in] MemoryLength - Memory size
518 ConfigureRootPortForPcieNand (
521 IN UINT32 MemoryBase
,
522 IN UINT32 MemoryLength
527 DEBUG ((DEBUG_INFO
, "ConfigureRootPortForPcieNand, BusNumber: %x, MemoryBase: %x, MemoryLength: %x\n",
528 BusNumber
, MemoryBase
, MemoryLength
));
530 if (MemoryLength
== 0) {
531 MemoryLimit
= MemoryBase
;
533 MemoryLimit
= MemoryBase
+ MemoryLength
+ 0xFFFFF; // 1M
537 /// Configue PCIE configuration space for RootPort
539 PciWrite8 (RpBase
+ NVME_PCIE_BNUM
+ 1, (UINT8
) BusNumber
); // Secondary Bus Number registers
540 PciWrite8 (RpBase
+ NVME_PCIE_BNUM
+ 2, (UINT8
) BusNumber
); // Subordinate Bus Number registers
541 PciWrite8 (RpBase
+ NVME_PCIE_IOBL
, 0xFF); // I/O Base registers
542 PciWrite8 (RpBase
+ NVME_PCIE_IOBL
+ 1, 0x00); // I/O Limit registers
543 PciWrite16 (RpBase
+ NVME_PCIE_MBL
, (UINT16
) RShiftU64 ((UINTN
)MemoryBase
, 16)); // Memory Base register
544 PciWrite16 (RpBase
+ NVME_PCIE_MBL
+ 2, (UINT16
) RShiftU64 ((UINTN
)MemoryLimit
, 16)); // Memory Limit register
545 PciWrite16 (RpBase
+ NVME_PCIE_PMBL
, 0xFFFF); // Prefetchable Memory Base registers
546 PciWrite16 (RpBase
+ NVME_PCIE_PMBL
+ 2, 0x0000); // Prefetchable Memory Limit registers
547 PciWrite32 (RpBase
+ NVME_PCIE_PMBU32
, 0xFFFFFFFF); // Prefetchable Memory Upper Base registers
548 PciWrite32 (RpBase
+ NVME_PCIE_PMLU32
, 0x00000000); // Prefetchable Memory Upper Limit registers
553 The function returns whether or not the device is Opal Locked.
554 TRUE means that the device is partially or fully locked.
555 This will perform a Level 0 Discovery and parse the locking feature descriptor
557 @param[in] OpalDev Opal object to determine if locked.
558 @param[out] BlockSidSupported Whether device support BlockSid feature.
563 OPAL_PEI_DEVICE
*OpalDev
,
564 BOOLEAN
*BlockSidSupported
567 OPAL_SESSION Session
;
568 OPAL_DISK_SUPPORT_ATTRIBUTE SupportedAttributes
;
569 TCG_LOCKING_FEATURE_DESCRIPTOR LockingFeature
;
570 UINT16 OpalBaseComId
;
573 Session
.Sscp
= &OpalDev
->Sscp
;
576 Ret
= OpalGetSupportedAttributesInfo (&Session
, &SupportedAttributes
, &OpalBaseComId
);
577 if (Ret
!= TcgResultSuccess
) {
581 Session
.OpalBaseComId
= OpalBaseComId
;
582 *BlockSidSupported
= SupportedAttributes
.BlockSid
== 1 ? TRUE
: FALSE
;
584 Ret
= OpalGetLockingInfo(&Session
, &LockingFeature
);
585 if (Ret
!= TcgResultSuccess
) {
589 return OpalDeviceLocked (&SupportedAttributes
, &LockingFeature
);
593 Unlock OPAL password for S3.
595 @param[in] OpalDev Opal object to unlock.
600 IN OPAL_PEI_DEVICE
*OpalDev
604 OPAL_SESSION Session
;
605 BOOLEAN BlockSidSupport
;
606 UINT32 PpStorageFlags
;
607 BOOLEAN BlockSIDEnabled
;
609 BlockSidSupport
= FALSE
;
610 if (IsOpalDeviceLocked (OpalDev
, &BlockSidSupport
)) {
611 ZeroMem(&Session
, sizeof (Session
));
612 Session
.Sscp
= &OpalDev
->Sscp
;
614 Session
.OpalBaseComId
= OpalDev
->Device
->OpalBaseComId
;
616 Result
= OpalUtilUpdateGlobalLockingRange (
618 OpalDev
->Device
->Password
,
619 OpalDev
->Device
->PasswordLength
,
625 "%a() OpalUtilUpdateGlobalLockingRange() Result = 0x%x\n",
631 PpStorageFlags
= Tcg2PhysicalPresenceLibGetManagementFlags ();
632 if ((PpStorageFlags
& TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID
) != 0) {
633 BlockSIDEnabled
= TRUE
;
635 BlockSIDEnabled
= FALSE
;
637 if (BlockSIDEnabled
&& BlockSidSupport
) {
638 ZeroMem(&Session
, sizeof (Session
));
639 Session
.Sscp
= &OpalDev
->Sscp
;
641 Session
.OpalBaseComId
= OpalDev
->Device
->OpalBaseComId
;
642 Result
= OpalBlockSid (&Session
, TRUE
);
645 "%a() OpalBlockSid() Result = 0x%x\n",
653 Unlock ATA OPAL password for S3.
657 UnlockOpalPasswordAta (
663 OPAL_DEVICE_ATA TempDevInfoAta
;
664 OPAL_DEVICE_ATA
*DevInfoAta
;
665 UINTN DevInfoLengthAta
;
669 OPAL_PEI_DEVICE OpalDev
;
673 AHCI_CONTEXT AhciContext
;
676 DEBUG ((DEBUG_INFO
, "%a() - enter\n", __FUNCTION__
));
679 // Get ATA OPAL device info from LockBox.
681 DevInfo
= (UINT8
*) &TempDevInfoAta
;
682 DevInfoLengthAta
= sizeof (OPAL_DEVICE_ATA
);
683 Status
= RestoreLockBox (&mOpalDeviceAtaGuid
, DevInfo
, &DevInfoLengthAta
);
684 if (Status
== EFI_BUFFER_TOO_SMALL
) {
685 DevInfo
= AllocatePages (EFI_SIZE_TO_PAGES (DevInfoLengthAta
));
686 if (DevInfo
!= NULL
) {
687 Status
= RestoreLockBox (&mOpalDeviceAtaGuid
, DevInfo
, &DevInfoLengthAta
);
690 if (EFI_ERROR (Status
) || (DevInfo
== NULL
)) {
694 for (DevInfoAta
= (OPAL_DEVICE_ATA
*) DevInfo
;
695 (UINTN
) DevInfoAta
< ((UINTN
) DevInfo
+ DevInfoLengthAta
);
696 DevInfoAta
= (OPAL_DEVICE_ATA
*) ((UINTN
) DevInfoAta
+ DevInfoAta
->Length
)) {
697 Bus
= DevInfoAta
->Device
.Bus
;
698 Device
= DevInfoAta
->Device
.Device
;
699 Function
= DevInfoAta
->Device
.Function
;
701 SataCmdSt
= PciRead8 (PCI_LIB_ADDRESS (Bus
, Device
, Function
, PCI_COMMAND_OFFSET
));
702 PciWrite8 (PCI_LIB_ADDRESS (Bus
, Device
, Function
, PCI_COMMAND_OFFSET
), 0x6);
704 BaseClassCode
= PciRead8 (PCI_LIB_ADDRESS (Bus
, Device
, Function
, 0x0B));
705 SubClassCode
= PciRead8 (PCI_LIB_ADDRESS (Bus
, Device
, Function
, 0x0A));
706 if ((BaseClassCode
!= PCI_CLASS_MASS_STORAGE
) ||
707 ((SubClassCode
!= PCI_CLASS_MASS_STORAGE_SATADPA
) && (SubClassCode
!= PCI_CLASS_MASS_STORAGE_RAID
))) {
708 DEBUG ((DEBUG_ERROR
, "%a() ClassCode/SubClassCode are not supported\n", __FUNCTION__
));
710 AhciBar
= PciRead32 (PCI_LIB_ADDRESS (Bus
, Device
, Function
, 0x24));
711 PciWrite32 (PCI_LIB_ADDRESS (Bus
, Device
, Function
, 0x24), DevInfoAta
->BarAddr
);
713 ZeroMem (&AhciContext
, sizeof (AHCI_CONTEXT
));
714 AhciContext
.AhciBar
= DevInfoAta
->BarAddr
;
715 AhciAllocateResource (&AhciContext
);
716 Status
= AhciModeInitialize (&AhciContext
, (UINT8
)DevInfoAta
->Port
);
717 ASSERT_EFI_ERROR (Status
);
718 if (EFI_ERROR (Status
)) {
719 DEBUG ((DEBUG_ERROR
, "%a() AhciModeInitialize() error, Status: %r\n", __FUNCTION__
, Status
));
722 OpalDev
.Signature
= OPAL_PEI_DEVICE_SIGNATURE
;
723 OpalDev
.Sscp
.ReceiveData
= SecurityReceiveData
;
724 OpalDev
.Sscp
.SendData
= SecuritySendData
;
725 OpalDev
.DeviceType
= OPAL_DEVICE_TYPE_ATA
;
726 OpalDev
.Device
= (OPAL_DEVICE_COMMON
*) DevInfoAta
;
727 OpalDev
.Context
= &AhciContext
;
729 UnlockOpalPassword (&OpalDev
);
731 AhciFreeResource (&AhciContext
);
732 PciWrite32 (PCI_LIB_ADDRESS (Bus
, Device
, Function
, 0x24), AhciBar
);
734 PciWrite8 (PCI_LIB_ADDRESS (Bus
, Device
, Function
, PCI_COMMAND_OFFSET
), SataCmdSt
);
737 ZeroMem (DevInfo
, DevInfoLengthAta
);
738 if ((UINTN
) DevInfo
!= (UINTN
) &TempDevInfoAta
) {
739 FreePages (DevInfo
, EFI_SIZE_TO_PAGES (DevInfoLengthAta
));
742 DEBUG ((DEBUG_INFO
, "%a() - exit\n", __FUNCTION__
));
746 Unlock NVMe OPAL password for S3.
750 UnlockOpalPasswordNvme (
756 OPAL_DEVICE_NVME TempDevInfoNvme
;
757 OPAL_DEVICE_NVME
*DevInfoNvme
;
758 UINTN DevInfoLengthNvme
;
762 OPAL_PEI_DEVICE OpalDev
;
767 UINT8
*StorePcieConfDataList
[16];
771 NVME_CONTEXT NvmeContext
;
773 DEBUG ((DEBUG_INFO
, "%a() - enter\n", __FUNCTION__
));
776 // Get NVMe OPAL device info from LockBox.
778 DevInfo
= (UINT8
*) &TempDevInfoNvme
;
779 DevInfoLengthNvme
= sizeof (OPAL_DEVICE_NVME
);
780 Status
= RestoreLockBox (&mOpalDeviceNvmeGuid
, DevInfo
, &DevInfoLengthNvme
);
781 if (Status
== EFI_BUFFER_TOO_SMALL
) {
782 DevInfo
= AllocatePages (EFI_SIZE_TO_PAGES (DevInfoLengthNvme
));
783 if (DevInfo
!= NULL
) {
784 Status
= RestoreLockBox (&mOpalDeviceNvmeGuid
, DevInfo
, &DevInfoLengthNvme
);
787 if (EFI_ERROR (Status
) || (DevInfo
== NULL
)) {
791 for (DevInfoNvme
= (OPAL_DEVICE_NVME
*) DevInfo
;
792 (UINTN
) DevInfoNvme
< ((UINTN
) DevInfo
+ DevInfoLengthNvme
);
793 DevInfoNvme
= (OPAL_DEVICE_NVME
*) ((UINTN
) DevInfoNvme
+ DevInfoNvme
->Length
)) {
794 Bus
= DevInfoNvme
->Device
.Bus
;
795 Device
= DevInfoNvme
->Device
.Device
;
796 Function
= DevInfoNvme
->Device
.Function
;
802 /// Save original RootPort configuration space to heap
804 RpBase
= SaveRestoreRootportConfSpace (
807 StorePcieConfDataList
809 MemoryBase
= DevInfoNvme
->BarAddr
;
811 ConfigureRootPortForPcieNand (RpBase
, Bus
, (UINT32
) MemoryBase
, (UINT32
) MemoryLength
);
814 /// Enable PCIE decode for RootPort
816 NvmeCmdSt
= PciRead8 (RpBase
+ NVME_PCIE_PCICMD
);
817 PciWrite8 (RpBase
+ NVME_PCIE_PCICMD
, 0x6);
819 BaseClassCode
= PciRead8 (PCI_LIB_ADDRESS (Bus
, Device
, Function
, 0x0B));
820 SubClassCode
= PciRead8 (PCI_LIB_ADDRESS (Bus
, Device
, Function
, 0x0A));
821 ProgInt
= PciRead8 (PCI_LIB_ADDRESS (Bus
, Device
, Function
, 0x09));
822 if ((BaseClassCode
!= PCI_CLASS_MASS_STORAGE
) ||
823 (SubClassCode
!= PCI_CLASS_MASS_STORAGE_NVM
) ||
824 (ProgInt
!= PCI_IF_NVMHCI
)) {
825 DEBUG ((DEBUG_ERROR
, "%a() ClassCode/SubClassCode/PI are not supported\n", __FUNCTION__
));
827 ZeroMem (&NvmeContext
, sizeof (NVME_CONTEXT
));
828 NvmeContext
.Nbar
= DevInfoNvme
->BarAddr
;
829 NvmeContext
.PciBase
= PCI_LIB_ADDRESS (Bus
, Device
, Function
, 0x0);
830 NvmeContext
.NvmeInitWaitTime
= 0;
831 NvmeContext
.Nsid
= DevInfoNvme
->NvmeNamespaceId
;
832 NvmeAllocateResource (&NvmeContext
);
833 Status
= NvmeControllerInit (&NvmeContext
);
835 OpalDev
.Signature
= OPAL_PEI_DEVICE_SIGNATURE
;
836 OpalDev
.Sscp
.ReceiveData
= SecurityReceiveData
;
837 OpalDev
.Sscp
.SendData
= SecuritySendData
;
838 OpalDev
.DeviceType
= OPAL_DEVICE_TYPE_NVME
;
839 OpalDev
.Device
= (OPAL_DEVICE_COMMON
*) DevInfoNvme
;
840 OpalDev
.Context
= &NvmeContext
;
842 UnlockOpalPassword (&OpalDev
);
844 Status
= NvmeControllerExit (&NvmeContext
);
845 NvmeFreeResource (&NvmeContext
);
848 ASSERT (RpBase
!= 0);
849 PciWrite8 (RpBase
+ NVME_PCIE_PCICMD
, 0);
850 RpBase
= SaveRestoreRootportConfSpace (
853 StorePcieConfDataList
855 PciWrite8 (RpBase
+ NVME_PCIE_PCICMD
, NvmeCmdSt
);
858 ZeroMem (DevInfo
, DevInfoLengthNvme
);
859 if ((UINTN
) DevInfo
!= (UINTN
) &TempDevInfoNvme
) {
860 FreePages (DevInfo
, EFI_SIZE_TO_PAGES (DevInfoLengthNvme
));
863 DEBUG ((DEBUG_INFO
, "%a() - exit\n", __FUNCTION__
));
867 Unlock OPAL password for S3.
875 UnlockOpalPasswordAta ();
876 UnlockOpalPasswordNvme ();
880 Entry point of the notification callback function itself within the PEIM.
881 It is to unlock OPAL password for S3.
883 @param PeiServices Indirect reference to the PEI Services Table.
884 @param NotifyDescriptor Address of the notification descriptor data structure.
885 @param Ppi Address of the PPI that was installed.
887 @return Status of the notification.
888 The status code returned from this function is ignored.
892 OpalPasswordEndOfPeiNotify(
893 IN EFI_PEI_SERVICES
**PeiServices
,
894 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDesc
,
899 EFI_BOOT_MODE BootMode
;
901 Status
= PeiServicesGetBootMode (&BootMode
);
902 ASSERT_EFI_ERROR (Status
);
903 if (BootMode
!= BOOT_ON_S3_RESUME
) {
904 return EFI_UNSUPPORTED
;
907 DEBUG ((DEBUG_INFO
, "%a() - enter at S3 resume\n", __FUNCTION__
));
911 DEBUG ((DEBUG_INFO
, "%a() - exit at S3 resume\n", __FUNCTION__
));
916 EFI_PEI_NOTIFY_DESCRIPTOR mOpalPasswordEndOfPeiNotifyDesc
= {
917 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
918 &gEfiEndOfPeiSignalPpiGuid
,
919 OpalPasswordEndOfPeiNotify
923 Main entry for this module.
925 @param FileHandle Handle of the file being invoked.
926 @param PeiServices Pointer to PEI Services table.
928 @return Status from PeiServicesNotifyPpi.
933 OpalPasswordPeiInit (
934 IN EFI_PEI_FILE_HANDLE FileHandle
,
935 IN CONST EFI_PEI_SERVICES
**PeiServices
940 Status
= PeiServicesNotifyPpi (&mOpalPasswordEndOfPeiNotifyDesc
);
941 ASSERT_EFI_ERROR (Status
);