2 Opal password smm driver which is used to support Opal security feature at s3 path.
4 Copyright (c) 2016, 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 "OpalPasswordSmm.h"
17 #define SMM_SIZE_ALLOC_BYTES (512)
18 #define RESPONSE_SIZE (200)
20 #define PCI_CLASS_MASS_STORAGE_AHCI (0x06)
22 #define OPAL_PCIE_ROOTPORT_SAVESIZE (0x40)
23 #define STORE_INVALID_ROOTPORT_INDEX ((UINT8) -1)
24 #define OPAL_DEVICE_TYPE_SATA 0x1
25 #define OPAL_DEVICE_TYPE_NVME 0x2
26 #define OPAL_DEVICE_TYPE_UNKNOWN 0xFF
29 // To unlock the Intel SATA controller at S3 Resume, restored the following registers.
31 const OPAL_HC_PCI_REGISTER_SAVE mSataHcRegisterSaveTemplate
[] = {
32 {0x9, S3BootScriptWidthUint8
},
33 {0x10, S3BootScriptWidthUint32
},
34 {0x14, S3BootScriptWidthUint32
},
35 {0x18, S3BootScriptWidthUint32
},
36 {0x1C, S3BootScriptWidthUint32
},
37 {0x20, S3BootScriptWidthUint32
},
38 {0x24, S3BootScriptWidthUint32
},
39 {0x3c, S3BootScriptWidthUint8
},
40 {0x3d, S3BootScriptWidthUint8
},
41 {0x40, S3BootScriptWidthUint16
},
42 {0x42, S3BootScriptWidthUint16
},
43 {0x92, S3BootScriptWidthUint16
},
44 {0x94, S3BootScriptWidthUint32
},
45 {0x9C, S3BootScriptWidthUint32
},
46 {0x4, S3BootScriptWidthUint16
},
51 LIST_ENTRY
*mOpalDeviceList
;
52 LIST_ENTRY mSmmDeviceList
= INITIALIZE_LIST_HEAD_VARIABLE (mSmmDeviceList
);
54 BOOLEAN mSendBlockSID
= FALSE
;
58 EFI_AHCI_REGISTERS mAhciRegisters
;
59 VOID
*mBuffer
= NULL
; // DMA can not read/write Data to smram, so we pre-allocates Buffer from AcpiNVS.
62 NVME_CONTEXT mNvmeContext
;
65 Add new bridge node or nvme device info to the device list.
67 @param[in] BusNum The bus number.
68 @param[in] DevNum The device number.
69 @param[in] FuncNum The function number.
70 @param[in] Dev The device which need to add device node info.
82 PCI_DEVICE
*DeviceNode
;
84 DevList
= AllocateZeroPool (sizeof (PCI_DEVICE
) + Dev
->Length
);
85 ASSERT (DevList
!= NULL
);
87 if (Dev
->Length
!= 0) {
88 CopyMem (DevList
, Dev
->PciBridgeNode
, Dev
->Length
);
89 FreePool (Dev
->PciBridgeNode
);
92 DeviceNode
= (PCI_DEVICE
*) (DevList
+ Dev
->Length
);
94 DeviceNode
->BusNum
= BusNum
;
95 DeviceNode
->DevNum
= DevNum
;
96 DeviceNode
->FuncNum
= FuncNum
;
98 Dev
->Length
+= sizeof (PCI_DEVICE
);
99 Dev
->PciBridgeNode
= (PCI_DEVICE
*)DevList
;
103 Extract device info from the input device path.
105 @param[in] DevicePath Device path info for the device.
106 @param[in,out] Dev The device which new inputed.
110 ExtractDeviceInfoFromDevicePath (
111 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
112 IN OUT OPAL_SMM_DEVICE
*Dev
115 EFI_DEVICE_PATH_PROTOCOL
*TmpDevPath
;
116 EFI_DEVICE_PATH_PROTOCOL
*TmpDevPath2
;
117 PCI_DEVICE_PATH
*PciDevPath
;
118 SATA_DEVICE_PATH
*SataDevPath
;
119 NVME_NAMESPACE_DEVICE_PATH
*NvmeDevPath
;
122 TmpDevPath
= DevicePath
;
123 Dev
->DeviceType
= OPAL_DEVICE_TYPE_UNKNOWN
;
125 while (!IsDevicePathEnd(TmpDevPath
)) {
126 if (TmpDevPath
->Type
== MESSAGING_DEVICE_PATH
&& TmpDevPath
->SubType
== MSG_SATA_DP
) {
130 SataDevPath
= ( SATA_DEVICE_PATH
* )TmpDevPath
;
131 Dev
->SataPort
= SataDevPath
->HBAPortNumber
;
132 Dev
->SataPortMultiplierPort
= SataDevPath
->PortMultiplierPortNumber
;
133 Dev
->DeviceType
= OPAL_DEVICE_TYPE_SATA
;
135 } else if (TmpDevPath
->Type
== MESSAGING_DEVICE_PATH
&& TmpDevPath
->SubType
== MSG_NVME_NAMESPACE_DP
) {
139 NvmeDevPath
= ( NVME_NAMESPACE_DEVICE_PATH
* )TmpDevPath
;
140 Dev
->NvmeNamespaceId
= NvmeDevPath
->NamespaceId
;
141 Dev
->DeviceType
= OPAL_DEVICE_TYPE_NVME
;
144 TmpDevPath
= NextDevicePathNode (TmpDevPath
);
148 // Get bridge node info for the nvme device.
151 TmpDevPath
= DevicePath
;
152 TmpDevPath2
= NextDevicePathNode (DevicePath
);
153 while (!IsDevicePathEnd(TmpDevPath2
)) {
154 if (TmpDevPath
->Type
== HARDWARE_DEVICE_PATH
&& TmpDevPath
->SubType
== HW_PCI_DP
) {
155 PciDevPath
= (PCI_DEVICE_PATH
*) TmpDevPath
;
156 if ((TmpDevPath2
->Type
== MESSAGING_DEVICE_PATH
&& TmpDevPath2
->SubType
== MSG_NVME_NAMESPACE_DP
)||
157 (TmpDevPath2
->Type
== MESSAGING_DEVICE_PATH
&& TmpDevPath2
->SubType
== MSG_SATA_DP
)) {
158 Dev
->BusNum
= (UINT32
)BusNum
;
159 Dev
->DevNum
= PciDevPath
->Device
;
160 Dev
->FuncNum
= PciDevPath
->Function
;
162 AddPciDeviceNode((UINT32
)BusNum
, PciDevPath
->Device
, PciDevPath
->Function
, Dev
);
163 if (TmpDevPath2
->Type
== HARDWARE_DEVICE_PATH
&& TmpDevPath2
->SubType
== HW_PCI_DP
) {
164 BusNum
= PciRead8 (PCI_LIB_ADDRESS (BusNum
, PciDevPath
->Device
, PciDevPath
->Function
, NVME_PCIE_SEC_BNUM
));
169 TmpDevPath
= NextDevicePathNode (TmpDevPath
);
170 TmpDevPath2
= NextDevicePathNode (TmpDevPath2
);
176 The function returns whether or not the device is Opal Locked.
177 TRUE means that the device is partially or fully locked.
178 This will perform a Level 0 Discovery and parse the locking feature descriptor
180 @param[in] OpalDev Opal object to determine if locked
181 @param[out] BlockSidSupported Whether device support BlockSid feature.
186 OPAL_SMM_DEVICE
*OpalDev
,
187 BOOLEAN
*BlockSidSupported
190 OPAL_SESSION Session
;
191 OPAL_DISK_SUPPORT_ATTRIBUTE SupportedAttributes
;
192 TCG_LOCKING_FEATURE_DESCRIPTOR LockingFeature
;
193 UINT16 OpalBaseComId
;
196 Session
.Sscp
= &OpalDev
->Sscp
;
199 Ret
= OpalGetSupportedAttributesInfo (&Session
, &SupportedAttributes
, &OpalBaseComId
);
200 if (Ret
!= TcgResultSuccess
) {
204 OpalDev
->OpalBaseComId
= OpalBaseComId
;
205 Session
.OpalBaseComId
= OpalBaseComId
;
206 *BlockSidSupported
= SupportedAttributes
.BlockSid
== 1 ? TRUE
: FALSE
;
208 Ret
= OpalGetLockingInfo(&Session
, &LockingFeature
);
209 if (Ret
!= TcgResultSuccess
) {
213 return OpalDeviceLocked (&SupportedAttributes
, &LockingFeature
);
217 Save/Restore RootPort configuration space.
219 @param[in] DeviceNode - The device node.
220 @param[in] SaveAction - TRUE: Save, FALSE: Restore
221 @param[in,out] PcieConfBufferList - Configuration space data buffer for save/restore
223 @retval - PCIE base address of this RootPort
226 SaveRestoreRootportConfSpace (
227 IN OPAL_SMM_DEVICE
*DeviceNode
,
228 IN BOOLEAN SaveAction
,
229 IN OUT UINT8
**PcieConfBufferList
235 UINT8
*StorePcieConfData
;
242 while (Length
< DeviceNode
->Length
) {
243 DevNode
= (PCI_DEVICE
*)((UINT8
*)DeviceNode
->PciBridgeNode
+ Length
);
244 RpBase
= PCI_LIB_ADDRESS (DevNode
->BusNum
, DevNode
->DevNum
, DevNode
->FuncNum
, 0x0);
246 if (PcieConfBufferList
!= NULL
) {
248 StorePcieConfData
= (UINT8
*) AllocateZeroPool (OPAL_PCIE_ROOTPORT_SAVESIZE
);
249 ASSERT (StorePcieConfData
!= NULL
);
250 OpalPciRead (StorePcieConfData
, RpBase
, OPAL_PCIE_ROOTPORT_SAVESIZE
);
251 PcieConfBufferList
[Index
] = StorePcieConfData
;
253 // Skip PCIe Command & Status registers
254 StorePcieConfData
= PcieConfBufferList
[Index
];
255 OpalPciWrite (RpBase
, StorePcieConfData
, 4);
256 OpalPciWrite (RpBase
+ 8, StorePcieConfData
+ 8, OPAL_PCIE_ROOTPORT_SAVESIZE
- 8);
258 FreePool (StorePcieConfData
);
262 Length
+= sizeof (PCI_DEVICE
);
270 Configure RootPort for downstream PCIe NAND devices.
272 @param[in] RpBase - PCIe configuration space address of this RootPort
273 @param[in] BusNumber - Bus number
274 @param[in] MemoryBase - Memory base address
275 @param[in] MemoryLength - Memory size
279 ConfigureRootPortForPcieNand (
282 IN UINT32 MemoryBase
,
283 IN UINT32 MemoryLength
288 DEBUG ((DEBUG_INFO
, "ConfigureRootPortForPcieNand, BusNumber: %x, MemoryBase: %x, MemoryLength: %x\n",
289 BusNumber
, MemoryBase
, MemoryLength
));
291 if (MemoryLength
== 0) {
292 MemoryLimit
= MemoryBase
;
294 MemoryLimit
= MemoryBase
+ MemoryLength
+ 0xFFFFF; // 1M
298 /// Configue PCIE configuration space for RootPort
300 PciWrite8 (RpBase
+ NVME_PCIE_BNUM
+ 1, (UINT8
) BusNumber
); // Secondary Bus Number registers
301 PciWrite8 (RpBase
+ NVME_PCIE_BNUM
+ 2, (UINT8
) BusNumber
); // Subordinate Bus Number registers
302 PciWrite8 (RpBase
+ NVME_PCIE_IOBL
, 0xFF); // I/O Base registers
303 PciWrite8 (RpBase
+ NVME_PCIE_IOBL
+ 1, 0x00); // I/O Limit registers
304 PciWrite16 (RpBase
+ NVME_PCIE_MBL
, (UINT16
) RShiftU64 ((UINTN
)MemoryBase
, 16)); // Memory Base register
305 PciWrite16 (RpBase
+ NVME_PCIE_MBL
+ 2, (UINT16
) RShiftU64 ((UINTN
)MemoryLimit
, 16)); // Memory Limit register
306 PciWrite16 (RpBase
+ NVME_PCIE_PMBL
, 0xFFFF); // Prefetchable Memory Base registers
307 PciWrite16 (RpBase
+ NVME_PCIE_PMBL
+ 2, 0x0000); // Prefetchable Memory Limit registers
308 PciWrite32 (RpBase
+ NVME_PCIE_PMBU32
, 0xFFFFFFFF); // Prefetchable Memory Upper Base registers
309 PciWrite32 (RpBase
+ NVME_PCIE_PMLU32
, 0x00000000); // Prefetchable Memory Upper Limit registers
314 Dispatch function for a Software SMI handler.
316 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
317 @param[in] RegisterContext Points to an optional handler context which was specified when the
318 handler was registered.
319 @param[in, out] CommBuffer A pointer to a collection of Data in memory that will
320 be conveyed from a non-SMM environment into an SMM environment.
321 @param[in, out] CommBufferSize The Size of the CommBuffer.
323 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
324 should still be called.
325 @retval Others Other execution results.
329 SmmUnlockOpalPassword (
330 IN EFI_HANDLE DispatchHandle
,
331 IN CONST VOID
*RegisterContext
,
332 IN OUT VOID
*CommBuffer
,
333 IN OUT UINTN
*CommBufferSize
337 OPAL_SMM_DEVICE
*OpalDev
;
344 UINT8
*StorePcieConfDataList
[16];
348 OPAL_SESSION Session
;
349 BOOLEAN BlockSidSupport
;
351 ZeroMem (StorePcieConfDataList
, sizeof (StorePcieConfDataList
));
352 Status
= EFI_DEVICE_ERROR
;
355 // try to unlock all locked hdd disks.
357 for (Entry
= mSmmDeviceList
.ForwardLink
; Entry
!= &mSmmDeviceList
; Entry
= Entry
->ForwardLink
) {
358 OpalDev
= BASE_CR(Entry
, OPAL_SMM_DEVICE
, Link
);
364 /// Configure RootPort for PCIe AHCI/NVME devices.
366 if (OpalDev
->DeviceType
== OPAL_DEVICE_TYPE_NVME
) {
368 /// Save original RootPort configuration space to heap
370 RpBase
= SaveRestoreRootportConfSpace (
373 StorePcieConfDataList
375 MemoryBase
= mNvmeContext
.Nbar
;
377 ConfigureRootPortForPcieNand (RpBase
, OpalDev
->BusNum
, (UINT32
) MemoryBase
, (UINT32
) MemoryLength
);
380 /// Enable PCIE decode for RootPort
382 SataCmdSt
= PciRead8 (RpBase
+ NVME_PCIE_PCICMD
);
383 PciWrite8 (RpBase
+ NVME_PCIE_PCICMD
, 0x6);
385 SataCmdSt
= PciRead8 (PCI_LIB_ADDRESS (OpalDev
->BusNum
, OpalDev
->DevNum
, OpalDev
->FuncNum
, NVME_PCIE_PCICMD
));
386 PciWrite8 (PCI_LIB_ADDRESS (OpalDev
->BusNum
, OpalDev
->DevNum
, OpalDev
->FuncNum
, NVME_PCIE_PCICMD
), 0x6);
389 BaseClassCode
= PciRead8 (PCI_LIB_ADDRESS (OpalDev
->BusNum
, OpalDev
->DevNum
, OpalDev
->FuncNum
, 0x0B));
390 SubClassCode
= PciRead8 (PCI_LIB_ADDRESS (OpalDev
->BusNum
, OpalDev
->DevNum
, OpalDev
->FuncNum
, 0x0A));
391 ProgInt
= PciRead8 (PCI_LIB_ADDRESS (OpalDev
->BusNum
, OpalDev
->DevNum
, OpalDev
->FuncNum
, 0x09));
392 if (BaseClassCode
!= PCI_CLASS_MASS_STORAGE
) {
393 Status
= EFI_INVALID_PARAMETER
;
397 Status
= EFI_DEVICE_ERROR
;
398 if (OpalDev
->DeviceType
== OPAL_DEVICE_TYPE_SATA
) {
399 if ((SubClassCode
== PCI_CLASS_MASS_STORAGE_AHCI
) || (SubClassCode
== PCI_CLASS_MASS_STORAGE_RAID
)) {
400 Status
= GetAhciBaseAddress (OpalDev
->BusNum
, OpalDev
->DevNum
, OpalDev
->FuncNum
);
401 if (EFI_ERROR (Status
)) {
402 DEBUG ((DEBUG_ERROR
, "GetAhciBaseAddress error, Status: %r\n", Status
));
405 Status
= AhciModeInitialize ((UINT8
)OpalDev
->SataPort
);
406 ASSERT_EFI_ERROR (Status
);
407 if (EFI_ERROR (Status
)) {
408 DEBUG ((DEBUG_ERROR
, "AhciModeInitialize error, Status: %r\n", Status
));
412 DEBUG ((DEBUG_ERROR
, "SubClassCode not support for SATA device\n"));
414 } else if (OpalDev
->DeviceType
== OPAL_DEVICE_TYPE_NVME
) {
415 if (SubClassCode
== PCI_CLASS_MASS_STORAGE_NVM
) {
416 if (ProgInt
!= PCI_IF_NVMHCI
) {
417 DEBUG ((DEBUG_ERROR
, "PI not support, skipped\n"));
418 Status
= EFI_NOT_FOUND
;
422 mNvmeContext
.PciBase
= PCI_LIB_ADDRESS (OpalDev
->BusNum
, OpalDev
->DevNum
, OpalDev
->FuncNum
, 0x0);
423 mNvmeContext
.NvmeInitWaitTime
= 0;
424 mNvmeContext
.Nsid
= OpalDev
->NvmeNamespaceId
;
425 Status
= NvmeControllerInit (&mNvmeContext
);
427 DEBUG ((DEBUG_ERROR
, "SubClassCode not support for NVME device\n"));
430 DEBUG ((DEBUG_ERROR
, "Invalid Devicetype\n"));
434 Status
= EFI_DEVICE_ERROR
;
435 BlockSidSupport
= FALSE
;
436 if (IsOpalDeviceLocked (OpalDev
, &BlockSidSupport
)) {
437 ZeroMem(&Session
, sizeof(Session
));
438 Session
.Sscp
= &OpalDev
->Sscp
;
440 Session
.OpalBaseComId
= OpalDev
->OpalBaseComId
;
442 Result
= OpalSupportUnlock (&Session
, OpalDev
->Password
, OpalDev
->PasswordLength
, NULL
);
443 if (Result
== TcgResultSuccess
) {
444 Status
= EFI_SUCCESS
;
448 if (mSendBlockSID
&& BlockSidSupport
) {
449 Result
= OpalBlockSid (&Session
, TRUE
);
450 if (Result
!= TcgResultSuccess
) {
455 if (OpalDev
->DeviceType
== OPAL_DEVICE_TYPE_NVME
) {
456 if (SubClassCode
== PCI_CLASS_MASS_STORAGE_NVM
) {
457 Status
= NvmeControllerExit (&mNvmeContext
);
462 if (OpalDev
->DeviceType
== OPAL_DEVICE_TYPE_NVME
) {
463 ASSERT (RpBase
!= 0);
464 PciWrite8 (RpBase
+ NVME_PCIE_PCICMD
, 0);
465 RpBase
= SaveRestoreRootportConfSpace (
468 StorePcieConfDataList
470 PciWrite8 (RpBase
+ NVME_PCIE_PCICMD
, SataCmdSt
);
472 PciWrite8 (PCI_LIB_ADDRESS (OpalDev
->BusNum
, OpalDev
->DevNum
, OpalDev
->FuncNum
, NVME_PCIE_PCICMD
), SataCmdSt
);
475 if (EFI_ERROR (Status
)) {
484 The function extracts device information from OpalDeviceList and creat SmmDeviceList used for S3.
486 @param[in] OpalDeviceList Opal device list created at POST which contains the information of OPAL_DISK_AND_PASSWORD_INFO
487 @param[in,out] SmmDeviceList Opal Smm device list to be created and used for unlocking devices at S3 resume.
489 @retval EFI_SUCCESS Create SmmDeviceList successfully.
490 @retval Others Other execution results.
493 CreateSmmDeviceList (
494 IN LIST_ENTRY
*OpalDeviceList
,
495 IN OUT LIST_ENTRY
*SmmDeviceList
499 OPAL_DISK_AND_PASSWORD_INFO
*PciDev
;
500 OPAL_SMM_DEVICE
*SmmDev
;
502 for (Entry
= OpalDeviceList
->ForwardLink
; Entry
!= OpalDeviceList
; Entry
= Entry
->ForwardLink
) {
503 PciDev
= BASE_CR (Entry
, OPAL_DISK_AND_PASSWORD_INFO
, Link
);
505 SmmDev
= AllocateZeroPool (sizeof (OPAL_SMM_DEVICE
));
506 if (SmmDev
== NULL
) {
507 return EFI_OUT_OF_RESOURCES
;
509 SmmDev
->Signature
= OPAL_SMM_DEVICE_SIGNATURE
;
511 ExtractDeviceInfoFromDevicePath(&PciDev
->OpalDevicePath
, SmmDev
);
513 SmmDev
->PasswordLength
= PciDev
->PasswordLength
;
514 CopyMem(&(SmmDev
->Password
), PciDev
->Password
, OPAL_PASSWORD_MAX_LENGTH
);
516 SmmDev
->Sscp
.ReceiveData
= SecurityReceiveData
;
517 SmmDev
->Sscp
.SendData
= SecuritySendData
;
519 DEBUG ((DEBUG_INFO
, "Opal SMM: Insert device node to SmmDeviceList:\n"));
520 DEBUG ((DEBUG_INFO
, "DeviceType:%x, Bus:%d, Dev:%d, Fun:%d\n", \
521 SmmDev
->DeviceType
, SmmDev
->BusNum
, SmmDev
->DevNum
, SmmDev
->FuncNum
));
522 DEBUG ((DEBUG_INFO
, "SataPort:%x, MultiplierPort:%x, NvmeNamespaceId:%x\n", \
523 SmmDev
->SataPort
, SmmDev
->SataPortMultiplierPort
, SmmDev
->NvmeNamespaceId
));
525 InsertHeadList (SmmDeviceList
, &SmmDev
->Link
);
532 Main entry point for an SMM handler dispatch or communicate-based callback.
534 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
535 @param[in] Context Points to an optional handler context which was specified when the
536 handler was registered.
537 @param[in,out] CommBuffer A pointer to a collection of Data in memory that will
538 be conveyed from a non-SMM environment into an SMM environment.
539 @param[in,out] CommBufferSize The Size of the CommBuffer.
541 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
542 should still be called.
543 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
545 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
547 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
551 S3SleepEntryCallBack (
552 IN EFI_HANDLE DispatchHandle
,
553 IN CONST VOID
*Context OPTIONAL
,
554 IN OUT VOID
*CommBuffer OPTIONAL
,
555 IN OUT UINTN
*CommBufferSize OPTIONAL
566 S3_BOOT_SCRIPT_LIB_WIDTH Width
;
568 OPAL_HC_PCI_REGISTER_SAVE
*HcRegisterSaveListPtr
;
570 OPAL_SMM_DEVICE
*SmmDev
;
573 Status
= EFI_SUCCESS
;
575 mOpalDeviceList
= OpalSupportGetOpalDeviceList();
576 if (IsListEmpty (mOpalDeviceList
)) {
578 // No Opal enabled device. Do nothing.
583 if (IsListEmpty (&mSmmDeviceList
)) {
585 // mSmmDeviceList for S3 is empty, creat it by mOpalDeviceList.
587 Status
= CreateSmmDeviceList (mOpalDeviceList
, &mSmmDeviceList
);
588 if (EFI_ERROR (Status
)) {
594 // Go through SmmDeviceList to save register data for S3
596 for (Entry
= mSmmDeviceList
.ForwardLink
; Entry
!= &mSmmDeviceList
; Entry
= Entry
->ForwardLink
) {
597 SmmDev
= BASE_CR (Entry
, OPAL_SMM_DEVICE
, Link
);
599 if (SmmDev
->DeviceType
== OPAL_DEVICE_TYPE_NVME
) {
604 // Save register Data for S3. Sata controller only.
606 Bus
= SmmDev
->BusNum
;
607 Device
= SmmDev
->DevNum
;
608 Function
= SmmDev
->FuncNum
;
610 ASSERT (SmmDev
->DeviceType
== OPAL_DEVICE_TYPE_SATA
);
611 HcRegisterSaveListPtr
= (OPAL_HC_PCI_REGISTER_SAVE
*) mSataHcRegisterSaveTemplate
;
612 Count
= sizeof (mSataHcRegisterSaveTemplate
) / sizeof (OPAL_HC_PCI_REGISTER_SAVE
);
614 for (Index
= 0; Index
< Count
; Index
+= 1) {
615 Offset
= HcRegisterSaveListPtr
[Index
].Address
;
616 Width
= HcRegisterSaveListPtr
[Index
].Width
;
619 case S3BootScriptWidthUint8
:
620 Data
= (UINT32
)PciRead8 (PCI_LIB_ADDRESS(Bus
,Device
,Function
,Offset
));
622 case S3BootScriptWidthUint16
:
623 Data
= (UINT32
)PciRead16 (PCI_LIB_ADDRESS(Bus
,Device
,Function
,Offset
));
625 case S3BootScriptWidthUint32
:
626 Data
= PciRead32 (PCI_LIB_ADDRESS(Bus
,Device
,Function
,Offset
));
633 Address
= S3_BOOT_SCRIPT_LIB_PCI_ADDRESS (Bus
, Device
, Function
, Offset
);
634 Status
= S3BootScriptSavePciCfgWrite (Width
, Address
, 1, &Data
);
635 if (EFI_ERROR (Status
)) {
641 Status
= S3BootScriptSaveIoWrite (S3BootScriptWidthUint8
, 0xB2, 1, &mSwSmiValue
);
642 ASSERT_EFI_ERROR (Status
);
648 Main entry for this driver.
650 @param ImageHandle Image handle this driver.
651 @param SystemTable Pointer to SystemTable.
653 @retval EFI_SUCESS This function always complete successfully.
658 OpalPasswordSmmInit (
659 IN EFI_HANDLE ImageHandle
,
660 IN EFI_SYSTEM_TABLE
*SystemTable
664 EFI_SMM_SW_DISPATCH2_PROTOCOL
*SwDispatch
;
665 EFI_SMM_SX_DISPATCH2_PROTOCOL
*SxDispatch
;
667 EFI_SMM_SW_REGISTER_CONTEXT Context
;
668 EFI_HANDLE S3SleepEntryHandle
;
669 EFI_SMM_SX_REGISTER_CONTEXT EntryRegisterContext
;
670 EFI_SMM_VARIABLE_PROTOCOL
*SmmVariable
;
671 OPAL_EXTRA_INFO_VAR OpalExtraInfo
;
673 EFI_PHYSICAL_ADDRESS Address
;
677 S3SleepEntryHandle
= NULL
;
678 ZeroMem (&mNvmeContext
, sizeof (NVME_CONTEXT
));
680 Status
= gSmst
->SmmLocateProtocol (
681 &gEfiSmmSwDispatch2ProtocolGuid
,
685 ASSERT_EFI_ERROR (Status
);
686 if (EFI_ERROR (Status
)) {
687 DEBUG((DEBUG_ERROR
, " SmmLocateProtocol gEfiSmmSwDispatch2ProtocolGuid fail, Status: %r\n", Status
));
691 Status
= gSmst
->SmmLocateProtocol (
692 &gEfiSmmSxDispatch2ProtocolGuid
,
696 ASSERT_EFI_ERROR (Status
);
697 if (EFI_ERROR (Status
)) {
698 DEBUG((DEBUG_ERROR
, " SmmLocateProtocol gEfiSmmSxDispatch2ProtocolGuid fail, Status: %r\n", Status
));
703 // Preallocate a 512 bytes Buffer to perform trusted I/O.
704 // Assume this is big enough for unlock commands
705 // It's because DMA can not access smmram stack at the cmd execution.
707 Address
= 0xFFFFFFFF;
708 Status
= gBS
->AllocatePages (
711 EFI_SIZE_TO_PAGES (SMM_SIZE_ALLOC_BYTES
),
714 if (EFI_ERROR (Status
)) {
715 DEBUG((DEBUG_ERROR
, " AllocatePages for SATA DAM fail, Status: %r\n", Status
));
716 return EFI_OUT_OF_RESOURCES
;
719 mBuffer
= (VOID
*)(UINTN
)Address
;
720 ZeroMem ((VOID
*)(UINTN
)mBuffer
, SMM_SIZE_ALLOC_BYTES
);
723 // Preallocate resource for AHCI transfer descriptor.
725 Status
= AhciAllocateResource ();
726 if (EFI_ERROR (Status
)) {
727 DEBUG((DEBUG_ERROR
, " AhciAllocateResource fail, Status: %r\n", Status
));
728 Status
= EFI_OUT_OF_RESOURCES
;
733 // Preallocate resource for NVMe configuration space.
735 Status
= NvmeAllocateResource (ImageHandle
, &mNvmeContext
);
736 if (EFI_ERROR (Status
)) {
737 DEBUG((DEBUG_ERROR
, " NvmeAllocateResource fail, Status: %r\n", Status
));
738 Status
= EFI_OUT_OF_RESOURCES
;
743 // Register a S3 entry callback function to store ATA host controller context to boot script.
744 // These boot scripts would be invoked at S3 path to recovery ATA host controller h/w context
745 // for executing HDD unlock cmd.
747 EntryRegisterContext
.Type
= SxS3
;
748 EntryRegisterContext
.Phase
= SxEntry
;
749 Status
= SxDispatch
->Register (
751 S3SleepEntryCallBack
,
752 &EntryRegisterContext
,
755 ASSERT_EFI_ERROR (Status
);
756 if (EFI_ERROR (Status
)) {
761 // Register Opal password smm unlock handler
763 Context
.SwSmiInputValue
= (UINTN
) -1;
764 Status
= SwDispatch
->Register (
766 SmmUnlockOpalPassword
,
770 ASSERT_EFI_ERROR (Status
);
771 if (EFI_ERROR (Status
)) {
772 DEBUG((DEBUG_ERROR
, " SwDispatch->Register fail, Status: %r\n", Status
));
777 // trigger smi to unlock hdd if it's locked.
779 mSwSmiValue
= (UINT8
) Context
.SwSmiInputValue
;
781 Status
= gSmst
->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid
, NULL
, (VOID
**)&SmmVariable
);
782 if (!EFI_ERROR (Status
)) {
783 DataSize
= sizeof (OPAL_EXTRA_INFO_VAR
);
784 Status
= SmmVariable
->SmmGetVariable (
785 OPAL_EXTRA_INFO_VAR_NAME
,
786 &gOpalExtraInfoVariableGuid
,
791 if (!EFI_ERROR (Status
)) {
792 mSendBlockSID
= OpalExtraInfo
.EnableBlockSid
;
799 if (S3SleepEntryHandle
!= NULL
) {
800 SxDispatch
->UnRegister (SxDispatch
, S3SleepEntryHandle
);
805 NvmeFreeResource (&mNvmeContext
);
807 if (mBuffer
!= NULL
) {
808 gBS
->FreePages ((EFI_PHYSICAL_ADDRESS
)(UINTN
) mBuffer
, EFI_SIZE_TO_PAGES (SMM_SIZE_ALLOC_BYTES
));
815 Provide Io action support.
817 @param[in] SmmDev the opal device need to perform trust io.
818 @param[in] IoType OPAL_IO_TYPE indicating whether to perform a Trusted Send or Trusted Receive.
819 @param[in] SecurityProtocol Security Protocol
820 @param[in] SpSpecific Security Protocol Specific
821 @param[in] TransferLength Transfer Length of Buffer (in bytes) - always a multiple of 512
822 @param[in] Buffer Address of Data to transfer
824 @retval TcgResultSuccess Perform the io action success.
825 @retval TcgResultFailure Perform the io action failed.
830 OPAL_SMM_DEVICE
*SmmDev
,
832 UINT8 SecurityProtocol
,
834 UINTN TransferLength
,
839 UINTN BufferSizeBlocks
;
840 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
842 Status
= EFI_DEVICE_ERROR
;
843 if (SmmDev
->DeviceType
== OPAL_DEVICE_TYPE_SATA
) {
844 BufferSizeBlocks
= TransferLength
/ 512;
846 ZeroMem( &AtaCommandBlock
, sizeof( EFI_ATA_COMMAND_BLOCK
) );
847 AtaCommandBlock
.AtaCommand
= ( IoType
== OpalSend
) ? ATA_COMMAND_TRUSTED_SEND
: ATA_COMMAND_TRUSTED_RECEIVE
;
848 AtaCommandBlock
.AtaSectorCount
= ( UINT8
)BufferSizeBlocks
;
849 AtaCommandBlock
.AtaSectorNumber
= ( UINT8
)( BufferSizeBlocks
>> 8 );
850 AtaCommandBlock
.AtaFeatures
= SecurityProtocol
;
851 AtaCommandBlock
.AtaCylinderLow
= ( UINT8
)( SpSpecific
>> 8 );
852 AtaCommandBlock
.AtaCylinderHigh
= ( UINT8
)( SpSpecific
);
853 AtaCommandBlock
.AtaDeviceHead
= ATA_DEVICE_LBA
;
856 ZeroMem( mBuffer
, HDD_PAYLOAD
);
857 ASSERT( TransferLength
<= HDD_PAYLOAD
);
859 if (IoType
== OpalSend
) {
860 CopyMem( mBuffer
, Buffer
, TransferLength
);
863 Status
= AhciPioTransfer(
865 (UINT8
) SmmDev
->SataPort
,
866 (UINT8
) SmmDev
->SataPortMultiplierPort
,
869 ( IoType
== OpalSend
) ? FALSE
: TRUE
, // i/o direction
873 (UINT32
)TransferLength
,
877 if (IoType
== OpalRecv
) {
878 CopyMem( Buffer
, mBuffer
, TransferLength
);
880 } else if (SmmDev
->DeviceType
== OPAL_DEVICE_TYPE_NVME
) {
881 Status
= NvmeSecuritySendReceive (
885 SwapBytes16(SpSpecific
),
890 DEBUG((DEBUG_ERROR
, "DeviceType(%x) not support.\n", SmmDev
->DeviceType
));
897 Send a security protocol command to a device that receives data and/or the result
898 of one or more commands sent by SendData.
900 The ReceiveData function sends a security protocol command to the given MediaId.
901 The security protocol command sent is defined by SecurityProtocolId and contains
902 the security protocol specific data SecurityProtocolSpecificData. The function
903 returns the data from the security protocol command in PayloadBuffer.
905 For devices supporting the SCSI command set, the security protocol command is sent
906 using the SECURITY PROTOCOL IN command defined in SPC-4.
908 For devices supporting the ATA command set, the security protocol command is sent
909 using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
912 If the PayloadBufferSize is zero, the security protocol command is sent using the
913 Trusted Non-Data command defined in ATA8-ACS.
915 If PayloadBufferSize is too small to store the available data from the security
916 protocol command, the function shall copy PayloadBufferSize bytes into the
917 PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
919 If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
920 the function shall return EFI_INVALID_PARAMETER.
922 If the given MediaId does not support security protocol commands, the function shall
923 return EFI_UNSUPPORTED. If there is no media in the device, the function returns
924 EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
925 the function returns EFI_MEDIA_CHANGED.
927 If the security protocol fails to complete within the Timeout period, the function
928 shall return EFI_TIMEOUT.
930 If the security protocol command completes without an error, the function shall
931 return EFI_SUCCESS. If the security protocol command completes with an error, the
932 function shall return EFI_DEVICE_ERROR.
934 @param This Indicates a pointer to the calling context.
935 @param MediaId ID of the medium to receive data from.
936 @param Timeout The timeout, in 100ns units, to use for the execution
937 of the security protocol command. A Timeout value of 0
938 means that this function will wait indefinitely for the
939 security protocol command to execute. If Timeout is greater
940 than zero, then this function will return EFI_TIMEOUT
941 if the time required to execute the receive data command
942 is greater than Timeout.
943 @param SecurityProtocolId The value of the "Security Protocol" parameter of
944 the security protocol command to be sent.
945 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
946 of the security protocol command to be sent.
947 @param PayloadBufferSize Size in bytes of the payload data buffer.
948 @param PayloadBuffer A pointer to a destination buffer to store the security
949 protocol command specific payload data for the security
950 protocol command. The caller is responsible for having
951 either implicit or explicit ownership of the buffer.
952 @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
953 data written to the payload data buffer.
955 @retval EFI_SUCCESS The security protocol command completed successfully.
956 @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
957 data from the device. The PayloadBuffer contains the truncated data.
958 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
959 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
960 @retval EFI_NO_MEDIA There is no media in the device.
961 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
962 @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
963 PayloadBufferSize is non-zero.
964 @retval EFI_TIMEOUT A timeout occurred while waiting for the security
965 protocol command to execute.
970 SecurityReceiveData (
971 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
*This
,
974 IN UINT8 SecurityProtocolId
,
975 IN UINT16 SecurityProtocolSpecificData
,
976 IN UINTN PayloadBufferSize
,
977 OUT VOID
*PayloadBuffer
,
978 OUT UINTN
*PayloadTransferSize
981 OPAL_SMM_DEVICE
*SmmDev
;
983 SmmDev
= OPAL_SMM_DEVICE_FROM_THIS (This
);
984 if (SmmDev
== NULL
) {
985 return EFI_DEVICE_ERROR
;
988 return PerformTrustedIo (
992 SecurityProtocolSpecificData
,
999 Send a security protocol command to a device.
1001 The SendData function sends a security protocol command containing the payload
1002 PayloadBuffer to the given MediaId. The security protocol command sent is
1003 defined by SecurityProtocolId and contains the security protocol specific data
1004 SecurityProtocolSpecificData. If the underlying protocol command requires a
1005 specific padding for the command payload, the SendData function shall add padding
1006 bytes to the command payload to satisfy the padding requirements.
1008 For devices supporting the SCSI command set, the security protocol command is sent
1009 using the SECURITY PROTOCOL OUT command defined in SPC-4.
1011 For devices supporting the ATA command set, the security protocol command is sent
1012 using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
1013 is non-zero. If the PayloadBufferSize is zero, the security protocol command is
1014 sent using the Trusted Non-Data command defined in ATA8-ACS.
1016 If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
1017 return EFI_INVALID_PARAMETER.
1019 If the given MediaId does not support security protocol commands, the function
1020 shall return EFI_UNSUPPORTED. If there is no media in the device, the function
1021 returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
1022 device, the function returns EFI_MEDIA_CHANGED.
1024 If the security protocol fails to complete within the Timeout period, the function
1025 shall return EFI_TIMEOUT.
1027 If the security protocol command completes without an error, the function shall return
1028 EFI_SUCCESS. If the security protocol command completes with an error, the function
1029 shall return EFI_DEVICE_ERROR.
1031 @param This Indicates a pointer to the calling context.
1032 @param MediaId ID of the medium to receive data from.
1033 @param Timeout The timeout, in 100ns units, to use for the execution
1034 of the security protocol command. A Timeout value of 0
1035 means that this function will wait indefinitely for the
1036 security protocol command to execute. If Timeout is greater
1037 than zero, then this function will return EFI_TIMEOUT
1038 if the time required to execute the send data command
1039 is greater than Timeout.
1040 @param SecurityProtocolId The value of the "Security Protocol" parameter of
1041 the security protocol command to be sent.
1042 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
1043 of the security protocol command to be sent.
1044 @param PayloadBufferSize Size in bytes of the payload data buffer.
1045 @param PayloadBuffer A pointer to a destination buffer to store the security
1046 protocol command specific payload data for the security
1049 @retval EFI_SUCCESS The security protocol command completed successfully.
1050 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
1051 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
1052 @retval EFI_NO_MEDIA There is no media in the device.
1053 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1054 @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
1055 @retval EFI_TIMEOUT A timeout occurred while waiting for the security
1056 protocol command to execute.
1062 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
*This
,
1065 IN UINT8 SecurityProtocolId
,
1066 IN UINT16 SecurityProtocolSpecificData
,
1067 IN UINTN PayloadBufferSize
,
1068 IN VOID
*PayloadBuffer
1071 OPAL_SMM_DEVICE
*SmmDev
;
1073 SmmDev
= OPAL_SMM_DEVICE_FROM_THIS (This
);
1074 if (SmmDev
== NULL
) {
1075 return EFI_DEVICE_ERROR
;
1078 return PerformTrustedIo (
1082 SecurityProtocolSpecificData
,