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
;
64 EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*mGcdMemSpace
= NULL
;
65 UINTN mNumberOfDescriptors
= 0;
68 Add new bridge node or nvme device info to the device list.
70 @param[in] BusNum The bus number.
71 @param[in] DevNum The device number.
72 @param[in] FuncNum The function number.
73 @param[in] Dev The device which need to add device node info.
85 PCI_DEVICE
*DeviceNode
;
87 DevList
= AllocateZeroPool (sizeof (PCI_DEVICE
) + Dev
->Length
);
88 ASSERT (DevList
!= NULL
);
90 if (Dev
->Length
!= 0) {
91 CopyMem (DevList
, Dev
->PciBridgeNode
, Dev
->Length
);
92 FreePool (Dev
->PciBridgeNode
);
95 DeviceNode
= (PCI_DEVICE
*) (DevList
+ Dev
->Length
);
97 DeviceNode
->BusNum
= BusNum
;
98 DeviceNode
->DevNum
= DevNum
;
99 DeviceNode
->FuncNum
= FuncNum
;
101 Dev
->Length
+= sizeof (PCI_DEVICE
);
102 Dev
->PciBridgeNode
= (PCI_DEVICE
*)DevList
;
106 Extract device info from the input device path.
108 @param[in] DevicePath Device path info for the device.
109 @param[in,out] Dev The device which new inputed.
113 ExtractDeviceInfoFromDevicePath (
114 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
115 IN OUT OPAL_SMM_DEVICE
*Dev
118 EFI_DEVICE_PATH_PROTOCOL
*TmpDevPath
;
119 EFI_DEVICE_PATH_PROTOCOL
*TmpDevPath2
;
120 PCI_DEVICE_PATH
*PciDevPath
;
121 SATA_DEVICE_PATH
*SataDevPath
;
122 NVME_NAMESPACE_DEVICE_PATH
*NvmeDevPath
;
125 TmpDevPath
= DevicePath
;
126 Dev
->DeviceType
= OPAL_DEVICE_TYPE_UNKNOWN
;
128 while (!IsDevicePathEnd(TmpDevPath
)) {
129 if (TmpDevPath
->Type
== MESSAGING_DEVICE_PATH
&& TmpDevPath
->SubType
== MSG_SATA_DP
) {
133 SataDevPath
= ( SATA_DEVICE_PATH
* )TmpDevPath
;
134 Dev
->SataPort
= SataDevPath
->HBAPortNumber
;
135 Dev
->SataPortMultiplierPort
= SataDevPath
->PortMultiplierPortNumber
;
136 Dev
->DeviceType
= OPAL_DEVICE_TYPE_SATA
;
138 } else if (TmpDevPath
->Type
== MESSAGING_DEVICE_PATH
&& TmpDevPath
->SubType
== MSG_NVME_NAMESPACE_DP
) {
142 NvmeDevPath
= ( NVME_NAMESPACE_DEVICE_PATH
* )TmpDevPath
;
143 Dev
->NvmeNamespaceId
= NvmeDevPath
->NamespaceId
;
144 Dev
->DeviceType
= OPAL_DEVICE_TYPE_NVME
;
147 TmpDevPath
= NextDevicePathNode (TmpDevPath
);
151 // Get bridge node info for the nvme device.
154 TmpDevPath
= DevicePath
;
155 TmpDevPath2
= NextDevicePathNode (DevicePath
);
156 while (!IsDevicePathEnd(TmpDevPath2
)) {
157 if (TmpDevPath
->Type
== HARDWARE_DEVICE_PATH
&& TmpDevPath
->SubType
== HW_PCI_DP
) {
158 PciDevPath
= (PCI_DEVICE_PATH
*) TmpDevPath
;
159 if ((TmpDevPath2
->Type
== MESSAGING_DEVICE_PATH
&& TmpDevPath2
->SubType
== MSG_NVME_NAMESPACE_DP
)||
160 (TmpDevPath2
->Type
== MESSAGING_DEVICE_PATH
&& TmpDevPath2
->SubType
== MSG_SATA_DP
)) {
161 Dev
->BusNum
= (UINT32
)BusNum
;
162 Dev
->DevNum
= PciDevPath
->Device
;
163 Dev
->FuncNum
= PciDevPath
->Function
;
165 AddPciDeviceNode((UINT32
)BusNum
, PciDevPath
->Device
, PciDevPath
->Function
, Dev
);
166 if (TmpDevPath2
->Type
== HARDWARE_DEVICE_PATH
&& TmpDevPath2
->SubType
== HW_PCI_DP
) {
167 BusNum
= PciRead8 (PCI_LIB_ADDRESS (BusNum
, PciDevPath
->Device
, PciDevPath
->Function
, NVME_PCIE_SEC_BNUM
));
172 TmpDevPath
= NextDevicePathNode (TmpDevPath
);
173 TmpDevPath2
= NextDevicePathNode (TmpDevPath2
);
179 The function returns whether or not the device is Opal Locked.
180 TRUE means that the device is partially or fully locked.
181 This will perform a Level 0 Discovery and parse the locking feature descriptor
183 @param[in] OpalDev Opal object to determine if locked
188 OPAL_SMM_DEVICE
*OpalDev
191 OPAL_SESSION Session
;
192 OPAL_DISK_SUPPORT_ATTRIBUTE SupportedAttributes
;
193 TCG_LOCKING_FEATURE_DESCRIPTOR LockingFeature
;
194 UINT16 OpalBaseComId
;
197 Session
.Sscp
= &OpalDev
->Sscp
;
200 Ret
= OpalGetSupportedAttributesInfo (&Session
, &SupportedAttributes
, &OpalBaseComId
);
201 if (Ret
!= TcgResultSuccess
) {
205 OpalDev
->OpalBaseComId
= OpalBaseComId
;
206 Session
.OpalBaseComId
= OpalBaseComId
;
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
;
350 ZeroMem (StorePcieConfDataList
, sizeof (StorePcieConfDataList
));
351 Status
= EFI_DEVICE_ERROR
;
354 // try to unlock all locked hdd disks.
356 for (Entry
= mSmmDeviceList
.ForwardLink
; Entry
!= &mSmmDeviceList
; Entry
= Entry
->ForwardLink
) {
357 OpalDev
= BASE_CR(Entry
, OPAL_SMM_DEVICE
, Link
);
363 /// Configure RootPort for PCIe AHCI/NVME devices.
365 if (OpalDev
->DeviceType
== OPAL_DEVICE_TYPE_NVME
) {
367 /// Save original RootPort configuration space to heap
369 RpBase
= SaveRestoreRootportConfSpace (
372 StorePcieConfDataList
374 MemoryBase
= mNvmeContext
.Nbar
;
376 ConfigureRootPortForPcieNand (RpBase
, OpalDev
->BusNum
, (UINT32
) MemoryBase
, (UINT32
) MemoryLength
);
379 /// Enable PCIE decode for RootPort
381 SataCmdSt
= PciRead8 (RpBase
+ NVME_PCIE_PCICMD
);
382 PciWrite8 (RpBase
+ NVME_PCIE_PCICMD
, 0x6);
384 SataCmdSt
= PciRead8 (PCI_LIB_ADDRESS (OpalDev
->BusNum
, OpalDev
->DevNum
, OpalDev
->FuncNum
, NVME_PCIE_PCICMD
));
385 PciWrite8 (PCI_LIB_ADDRESS (OpalDev
->BusNum
, OpalDev
->DevNum
, OpalDev
->FuncNum
, NVME_PCIE_PCICMD
), 0x6);
388 BaseClassCode
= PciRead8 (PCI_LIB_ADDRESS (OpalDev
->BusNum
, OpalDev
->DevNum
, OpalDev
->FuncNum
, 0x0B));
389 SubClassCode
= PciRead8 (PCI_LIB_ADDRESS (OpalDev
->BusNum
, OpalDev
->DevNum
, OpalDev
->FuncNum
, 0x0A));
390 ProgInt
= PciRead8 (PCI_LIB_ADDRESS (OpalDev
->BusNum
, OpalDev
->DevNum
, OpalDev
->FuncNum
, 0x09));
391 if (BaseClassCode
!= PCI_CLASS_MASS_STORAGE
) {
392 Status
= EFI_INVALID_PARAMETER
;
396 Status
= EFI_DEVICE_ERROR
;
397 if (OpalDev
->DeviceType
== OPAL_DEVICE_TYPE_SATA
) {
398 if ((SubClassCode
== PCI_CLASS_MASS_STORAGE_AHCI
) || (SubClassCode
== PCI_CLASS_MASS_STORAGE_RAID
)) {
399 Status
= GetAhciBaseAddress (OpalDev
->BusNum
, OpalDev
->DevNum
, OpalDev
->FuncNum
);
400 if (EFI_ERROR (Status
)) {
401 DEBUG ((DEBUG_ERROR
, "GetAhciBaseAddress error, Status: %r\n", Status
));
404 Status
= AhciModeInitialize ((UINT8
)OpalDev
->SataPort
);
405 ASSERT_EFI_ERROR (Status
);
406 if (EFI_ERROR (Status
)) {
407 DEBUG ((DEBUG_ERROR
, "AhciModeInitialize error, Status: %r\n", Status
));
411 DEBUG ((DEBUG_ERROR
, "SubClassCode not support for SATA device\n"));
413 } else if (OpalDev
->DeviceType
== OPAL_DEVICE_TYPE_NVME
) {
414 if (SubClassCode
== PCI_CLASS_MASS_STORAGE_NVM
) {
415 if (ProgInt
!= PCI_IF_NVMHCI
) {
416 DEBUG ((DEBUG_ERROR
, "PI not support, skipped\n"));
417 Status
= EFI_NOT_FOUND
;
421 mNvmeContext
.PciBase
= PCI_LIB_ADDRESS (OpalDev
->BusNum
, OpalDev
->DevNum
, OpalDev
->FuncNum
, 0x0);
422 mNvmeContext
.NvmeInitWaitTime
= 0;
423 mNvmeContext
.Nsid
= OpalDev
->NvmeNamespaceId
;
424 Status
= NvmeControllerInit (&mNvmeContext
);
426 DEBUG ((DEBUG_ERROR
, "SubClassCode not support for NVME device\n"));
429 DEBUG ((DEBUG_ERROR
, "Invalid Devicetype\n"));
433 Status
= EFI_DEVICE_ERROR
;
434 if (IsOpalDeviceLocked(OpalDev
)) {
435 ZeroMem(&Session
, sizeof(Session
));
436 Session
.Sscp
= &OpalDev
->Sscp
;
438 Session
.OpalBaseComId
= OpalDev
->OpalBaseComId
;
441 Result
= OpalBlockSid (&Session
, TRUE
);
442 if (Result
!= TcgResultSuccess
) {
447 Result
= OpalSupportUnlock (&Session
, OpalDev
->Password
, OpalDev
->PasswordLength
, NULL
);
448 if (Result
== TcgResultSuccess
) {
449 Status
= EFI_SUCCESS
;
453 if (OpalDev
->DeviceType
== OPAL_DEVICE_TYPE_NVME
) {
454 if (SubClassCode
== PCI_CLASS_MASS_STORAGE_NVM
) {
455 Status
= NvmeControllerExit (&mNvmeContext
);
460 if (OpalDev
->DeviceType
== OPAL_DEVICE_TYPE_NVME
) {
461 ASSERT (RpBase
!= 0);
462 PciWrite8 (RpBase
+ NVME_PCIE_PCICMD
, 0);
463 RpBase
= SaveRestoreRootportConfSpace (
466 StorePcieConfDataList
468 PciWrite8 (RpBase
+ NVME_PCIE_PCICMD
, SataCmdSt
);
470 PciWrite8 (PCI_LIB_ADDRESS (OpalDev
->BusNum
, OpalDev
->DevNum
, OpalDev
->FuncNum
, NVME_PCIE_PCICMD
), SataCmdSt
);
473 if (EFI_ERROR (Status
)) {
483 Main entry point for an SMM handler dispatch or communicate-based callback.
485 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
486 @param[in] Context Points to an optional handler context which was specified when the
487 handler was registered.
488 @param[in,out] CommBuffer A pointer to a collection of Data in memory that will
489 be conveyed from a non-SMM environment into an SMM environment.
490 @param[in,out] CommBufferSize The Size of the CommBuffer.
492 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
493 should still be called.
494 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
496 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
498 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
502 S3SleepEntryCallBack (
503 IN EFI_HANDLE DispatchHandle
,
504 IN CONST VOID
*Context OPTIONAL
,
505 IN OUT VOID
*CommBuffer OPTIONAL
,
506 IN OUT UINTN
*CommBufferSize OPTIONAL
517 S3_BOOT_SCRIPT_LIB_WIDTH Width
;
519 OPAL_DISK_AND_PASSWORD_INFO
*PciDev
;
520 OPAL_HC_PCI_REGISTER_SAVE
*HcRegisterSaveListPtr
;
522 OPAL_SMM_DEVICE
*SmmDev
;
525 Status
= EFI_SUCCESS
;
527 mOpalDeviceList
= OpalSupportGetOpalDeviceList();
529 for (Entry
= mOpalDeviceList
->ForwardLink
; Entry
!= mOpalDeviceList
; Entry
= Entry
->ForwardLink
) {
530 PciDev
= BASE_CR (Entry
, OPAL_DISK_AND_PASSWORD_INFO
, Link
);
532 SmmDev
= AllocateZeroPool (sizeof (OPAL_SMM_DEVICE
));
533 if (SmmDev
== NULL
) {
534 return EFI_OUT_OF_RESOURCES
;
536 SmmDev
->Signature
= OPAL_SMM_DEVICE_SIGNATURE
;
538 ExtractDeviceInfoFromDevicePath(&PciDev
->OpalDevicePath
, SmmDev
);
540 SmmDev
->PasswordLength
= PciDev
->PasswordLength
;
541 CopyMem(&(SmmDev
->Password
), PciDev
->Password
, OPAL_PASSWORD_MAX_LENGTH
);
543 SmmDev
->Sscp
.ReceiveData
= SecurityReceiveData
;
544 SmmDev
->Sscp
.SendData
= SecuritySendData
;
546 InsertHeadList (&mSmmDeviceList
, &SmmDev
->Link
);
548 if (SmmDev
->DeviceType
== OPAL_DEVICE_TYPE_NVME
) {
553 // Save register Data for S3. Sata controller only.
555 Bus
= SmmDev
->BusNum
;
556 Device
= SmmDev
->DevNum
;
557 Function
= SmmDev
->FuncNum
;
559 ASSERT (SmmDev
->DeviceType
== OPAL_DEVICE_TYPE_SATA
);
560 HcRegisterSaveListPtr
= (OPAL_HC_PCI_REGISTER_SAVE
*) mSataHcRegisterSaveTemplate
;
561 Count
= sizeof (mSataHcRegisterSaveTemplate
) / sizeof (OPAL_HC_PCI_REGISTER_SAVE
);
563 for (Index
= 0; Index
< Count
; Index
+= 1) {
564 Offset
= HcRegisterSaveListPtr
[Index
].Address
;
565 Width
= HcRegisterSaveListPtr
[Index
].Width
;
568 case S3BootScriptWidthUint8
:
569 Data
= (UINT32
)PciRead8 (PCI_LIB_ADDRESS(Bus
,Device
,Function
,Offset
));
571 case S3BootScriptWidthUint16
:
572 Data
= (UINT32
)PciRead16 (PCI_LIB_ADDRESS(Bus
,Device
,Function
,Offset
));
574 case S3BootScriptWidthUint32
:
575 Data
= PciRead32 (PCI_LIB_ADDRESS(Bus
,Device
,Function
,Offset
));
582 Address
= S3_BOOT_SCRIPT_LIB_PCI_ADDRESS (Bus
, Device
, Function
, Offset
);
583 Status
= S3BootScriptSavePciCfgWrite (Width
, Address
, 1, &Data
);
584 if (EFI_ERROR (Status
)) {
590 if (!IsListEmpty (mOpalDeviceList
)) {
591 Status
= S3BootScriptSaveIoWrite (S3BootScriptWidthUint8
, 0xB2, 1, &mSwSmiValue
);
592 ASSERT_EFI_ERROR (Status
);
599 OpalPassword Notification for SMM EndOfDxe protocol.
601 @param[in] Protocol Points to the protocol's unique identifier.
602 @param[in] Interface Points to the interface instance.
603 @param[in] Handle The handle on which the interface was installed.
605 @retval EFI_SUCCESS Notification runs successfully.
609 OpalPasswordEndOfDxeNotification (
610 IN CONST EFI_GUID
*Protocol
,
615 UINTN NumberOfDescriptors
;
616 EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*MemSpaceMap
;
619 Status
= gDS
->GetMemorySpaceMap (&NumberOfDescriptors
, &MemSpaceMap
);
620 if (EFI_ERROR (Status
)) {
624 mGcdMemSpace
= AllocateCopyPool (NumberOfDescriptors
* sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR
), MemSpaceMap
);
625 if (EFI_ERROR (Status
)) {
626 gBS
->FreePool (MemSpaceMap
);
630 mNumberOfDescriptors
= NumberOfDescriptors
;
631 gBS
->FreePool (MemSpaceMap
);
637 Main entry for this driver.
639 @param ImageHandle Image handle this driver.
640 @param SystemTable Pointer to SystemTable.
642 @retval EFI_SUCESS This function always complete successfully.
647 OpalPasswordSmmInit (
648 IN EFI_HANDLE ImageHandle
,
649 IN EFI_SYSTEM_TABLE
*SystemTable
653 EFI_SMM_SW_DISPATCH2_PROTOCOL
*SwDispatch
;
654 EFI_SMM_SX_DISPATCH2_PROTOCOL
*SxDispatch
;
656 EFI_SMM_SW_REGISTER_CONTEXT Context
;
657 EFI_HANDLE S3SleepEntryHandle
;
658 EFI_SMM_SX_REGISTER_CONTEXT EntryRegisterContext
;
659 EFI_SMM_VARIABLE_PROTOCOL
*SmmVariable
;
660 OPAL_EXTRA_INFO_VAR OpalExtraInfo
;
662 EFI_EVENT EndOfDxeEvent
;
663 EFI_PHYSICAL_ADDRESS Address
;
667 S3SleepEntryHandle
= NULL
;
668 ZeroMem (&mNvmeContext
, sizeof (NVME_CONTEXT
));
670 Status
= gSmst
->SmmLocateProtocol (
671 &gEfiSmmSwDispatch2ProtocolGuid
,
675 ASSERT_EFI_ERROR (Status
);
676 if (EFI_ERROR (Status
)) {
677 DEBUG((DEBUG_ERROR
, " SmmLocateProtocol gEfiSmmSwDispatch2ProtocolGuid fail, Status: %r\n", Status
));
681 Status
= gSmst
->SmmLocateProtocol (
682 &gEfiSmmSxDispatch2ProtocolGuid
,
686 ASSERT_EFI_ERROR (Status
);
687 if (EFI_ERROR (Status
)) {
688 DEBUG((DEBUG_ERROR
, " SmmLocateProtocol gEfiSmmSxDispatch2ProtocolGuid fail, Status: %r\n", Status
));
693 // Preallocate a 512 bytes Buffer to perform trusted I/O.
694 // Assume this is big enough for unlock commands
695 // It's because DMA can not access smmram stack at the cmd execution.
697 Address
= 0xFFFFFFFF;
698 Status
= gBS
->AllocatePages (
701 EFI_SIZE_TO_PAGES (SMM_SIZE_ALLOC_BYTES
),
704 if (EFI_ERROR (Status
)) {
705 DEBUG((DEBUG_ERROR
, " AllocatePages for SATA DAM fail, Status: %r\n", Status
));
706 return EFI_OUT_OF_RESOURCES
;
709 mBuffer
= (VOID
*)(UINTN
)Address
;
710 ZeroMem ((VOID
*)(UINTN
)mBuffer
, SMM_SIZE_ALLOC_BYTES
);
713 // Preallocate resource for AHCI transfer descriptor.
715 Status
= AhciAllocateResource ();
716 if (EFI_ERROR (Status
)) {
717 DEBUG((DEBUG_ERROR
, " AhciAllocateResource fail, Status: %r\n", Status
));
718 Status
= EFI_OUT_OF_RESOURCES
;
723 // Preallocate resource for NVMe configuration space.
725 Status
= NvmeAllocateResource (ImageHandle
, &mNvmeContext
);
726 if (EFI_ERROR (Status
)) {
727 DEBUG((DEBUG_ERROR
, " NvmeAllocateResource fail, Status: %r\n", Status
));
728 Status
= EFI_OUT_OF_RESOURCES
;
733 // Register a S3 entry callback function to store ATA host controller context to boot script.
734 // These boot scripts would be invoked at S3 path to recovery ATA host controller h/w context
735 // for executing HDD unlock cmd.
737 EntryRegisterContext
.Type
= SxS3
;
738 EntryRegisterContext
.Phase
= SxEntry
;
739 Status
= SxDispatch
->Register (
741 S3SleepEntryCallBack
,
742 &EntryRegisterContext
,
745 ASSERT_EFI_ERROR (Status
);
746 if (EFI_ERROR (Status
)) {
751 // Register Opal password smm unlock handler
753 Context
.SwSmiInputValue
= (UINTN
) -1;
754 Status
= SwDispatch
->Register (
756 SmmUnlockOpalPassword
,
760 ASSERT_EFI_ERROR (Status
);
761 if (EFI_ERROR (Status
)) {
762 DEBUG((DEBUG_ERROR
, " SwDispatch->Register fail, Status: %r\n", Status
));
767 // trigger smi to unlock hdd if it's locked.
769 mSwSmiValue
= (UINT8
) Context
.SwSmiInputValue
;
772 // Create event to record GCD descriptors at end of dxe for judging AHCI/NVMe PCI Bar
773 // is in MMIO space to avoid attack.
775 Status
= gSmst
->SmmRegisterProtocolNotify (&gEfiSmmEndOfDxeProtocolGuid
, OpalPasswordEndOfDxeNotification
, &EndOfDxeEvent
);
776 if (EFI_ERROR (Status
)) {
777 DEBUG((DEBUG_ERROR
, "OpalPasswordSmm: Register SmmEndOfDxe fail, Status: %r\n", Status
));
780 Status
= gSmst
->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid
, NULL
, (VOID
**)&SmmVariable
);
781 if (!EFI_ERROR (Status
)) {
782 DataSize
= sizeof (OPAL_EXTRA_INFO_VAR
);
783 Status
= SmmVariable
->SmmGetVariable (
784 OPAL_EXTRA_INFO_VAR_NAME
,
785 &gOpalExtraInfoVariableGuid
,
790 if (!EFI_ERROR (Status
)) {
791 mSendBlockSID
= OpalExtraInfo
.EnableBlockSid
;
798 if (S3SleepEntryHandle
!= NULL
) {
799 SxDispatch
->UnRegister (SxDispatch
, S3SleepEntryHandle
);
804 NvmeFreeResource (&mNvmeContext
);
806 if (mBuffer
!= NULL
) {
807 gBS
->FreePages ((EFI_PHYSICAL_ADDRESS
)(UINTN
) mBuffer
, EFI_SIZE_TO_PAGES (SMM_SIZE_ALLOC_BYTES
));
814 Provide Io action support.
816 @param[in] SmmDev the opal device need to perform trust io.
817 @param[in] IoType OPAL_IO_TYPE indicating whether to perform a Trusted Send or Trusted Receive.
818 @param[in] SecurityProtocol Security Protocol
819 @param[in] SpSpecific Security Protocol Specific
820 @param[in] TransferLength Transfer Length of Buffer (in bytes) - always a multiple of 512
821 @param[in] Buffer Address of Data to transfer
823 @retval TcgResultSuccess Perform the io action success.
824 @retval TcgResultFailure Perform the io action failed.
829 OPAL_SMM_DEVICE
*SmmDev
,
831 UINT8 SecurityProtocol
,
833 UINTN TransferLength
,
838 UINTN BufferSizeBlocks
;
839 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
841 Status
= EFI_DEVICE_ERROR
;
842 if (SmmDev
->DeviceType
== OPAL_DEVICE_TYPE_SATA
) {
843 BufferSizeBlocks
= TransferLength
/ 512;
845 ZeroMem( &AtaCommandBlock
, sizeof( EFI_ATA_COMMAND_BLOCK
) );
846 AtaCommandBlock
.AtaCommand
= ( IoType
== OpalSend
) ? ATA_COMMAND_TRUSTED_SEND
: ATA_COMMAND_TRUSTED_RECEIVE
;
847 AtaCommandBlock
.AtaSectorCount
= ( UINT8
)BufferSizeBlocks
;
848 AtaCommandBlock
.AtaSectorNumber
= ( UINT8
)( BufferSizeBlocks
>> 8 );
849 AtaCommandBlock
.AtaFeatures
= SecurityProtocol
;
850 AtaCommandBlock
.AtaCylinderLow
= ( UINT8
)( SpSpecific
>> 8 );
851 AtaCommandBlock
.AtaCylinderHigh
= ( UINT8
)( SpSpecific
);
852 AtaCommandBlock
.AtaDeviceHead
= ATA_DEVICE_LBA
;
855 ZeroMem( mBuffer
, HDD_PAYLOAD
);
856 ASSERT( TransferLength
<= HDD_PAYLOAD
);
858 if (IoType
== OpalSend
) {
859 CopyMem( mBuffer
, Buffer
, TransferLength
);
862 Status
= AhciPioTransfer(
864 (UINT8
) SmmDev
->SataPort
,
865 (UINT8
) SmmDev
->SataPortMultiplierPort
,
868 ( IoType
== OpalSend
) ? FALSE
: TRUE
, // i/o direction
872 (UINT32
)TransferLength
,
876 if (IoType
== OpalRecv
) {
877 CopyMem( Buffer
, mBuffer
, TransferLength
);
879 } else if (SmmDev
->DeviceType
== OPAL_DEVICE_TYPE_NVME
) {
880 Status
= NvmeSecuritySendReceive (
884 SwapBytes16(SpSpecific
),
889 DEBUG((DEBUG_ERROR
, "DeviceType(%x) not support.\n", SmmDev
->DeviceType
));
896 Send a security protocol command to a device that receives data and/or the result
897 of one or more commands sent by SendData.
899 The ReceiveData function sends a security protocol command to the given MediaId.
900 The security protocol command sent is defined by SecurityProtocolId and contains
901 the security protocol specific data SecurityProtocolSpecificData. The function
902 returns the data from the security protocol command in PayloadBuffer.
904 For devices supporting the SCSI command set, the security protocol command is sent
905 using the SECURITY PROTOCOL IN command defined in SPC-4.
907 For devices supporting the ATA command set, the security protocol command is sent
908 using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
911 If the PayloadBufferSize is zero, the security protocol command is sent using the
912 Trusted Non-Data command defined in ATA8-ACS.
914 If PayloadBufferSize is too small to store the available data from the security
915 protocol command, the function shall copy PayloadBufferSize bytes into the
916 PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
918 If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
919 the function shall return EFI_INVALID_PARAMETER.
921 If the given MediaId does not support security protocol commands, the function shall
922 return EFI_UNSUPPORTED. If there is no media in the device, the function returns
923 EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
924 the function returns EFI_MEDIA_CHANGED.
926 If the security protocol fails to complete within the Timeout period, the function
927 shall return EFI_TIMEOUT.
929 If the security protocol command completes without an error, the function shall
930 return EFI_SUCCESS. If the security protocol command completes with an error, the
931 function shall return EFI_DEVICE_ERROR.
933 @param This Indicates a pointer to the calling context.
934 @param MediaId ID of the medium to receive data from.
935 @param Timeout The timeout, in 100ns units, to use for the execution
936 of the security protocol command. A Timeout value of 0
937 means that this function will wait indefinitely for the
938 security protocol command to execute. If Timeout is greater
939 than zero, then this function will return EFI_TIMEOUT
940 if the time required to execute the receive data command
941 is greater than Timeout.
942 @param SecurityProtocolId The value of the "Security Protocol" parameter of
943 the security protocol command to be sent.
944 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
945 of the security protocol command to be sent.
946 @param PayloadBufferSize Size in bytes of the payload data buffer.
947 @param PayloadBuffer A pointer to a destination buffer to store the security
948 protocol command specific payload data for the security
949 protocol command. The caller is responsible for having
950 either implicit or explicit ownership of the buffer.
951 @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
952 data written to the payload data buffer.
954 @retval EFI_SUCCESS The security protocol command completed successfully.
955 @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
956 data from the device. The PayloadBuffer contains the truncated data.
957 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
958 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
959 @retval EFI_NO_MEDIA There is no media in the device.
960 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
961 @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
962 PayloadBufferSize is non-zero.
963 @retval EFI_TIMEOUT A timeout occurred while waiting for the security
964 protocol command to execute.
969 SecurityReceiveData (
970 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
*This
,
973 IN UINT8 SecurityProtocolId
,
974 IN UINT16 SecurityProtocolSpecificData
,
975 IN UINTN PayloadBufferSize
,
976 OUT VOID
*PayloadBuffer
,
977 OUT UINTN
*PayloadTransferSize
980 OPAL_SMM_DEVICE
*SmmDev
;
982 SmmDev
= OPAL_SMM_DEVICE_FROM_THIS (This
);
983 if (SmmDev
== NULL
) {
984 return EFI_DEVICE_ERROR
;
987 return PerformTrustedIo (
991 SecurityProtocolSpecificData
,
998 Send a security protocol command to a device.
1000 The SendData function sends a security protocol command containing the payload
1001 PayloadBuffer to the given MediaId. The security protocol command sent is
1002 defined by SecurityProtocolId and contains the security protocol specific data
1003 SecurityProtocolSpecificData. If the underlying protocol command requires a
1004 specific padding for the command payload, the SendData function shall add padding
1005 bytes to the command payload to satisfy the padding requirements.
1007 For devices supporting the SCSI command set, the security protocol command is sent
1008 using the SECURITY PROTOCOL OUT command defined in SPC-4.
1010 For devices supporting the ATA command set, the security protocol command is sent
1011 using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
1012 is non-zero. If the PayloadBufferSize is zero, the security protocol command is
1013 sent using the Trusted Non-Data command defined in ATA8-ACS.
1015 If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
1016 return EFI_INVALID_PARAMETER.
1018 If the given MediaId does not support security protocol commands, the function
1019 shall return EFI_UNSUPPORTED. If there is no media in the device, the function
1020 returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
1021 device, the function returns EFI_MEDIA_CHANGED.
1023 If the security protocol fails to complete within the Timeout period, the function
1024 shall return EFI_TIMEOUT.
1026 If the security protocol command completes without an error, the function shall return
1027 EFI_SUCCESS. If the security protocol command completes with an error, the function
1028 shall return EFI_DEVICE_ERROR.
1030 @param This Indicates a pointer to the calling context.
1031 @param MediaId ID of the medium to receive data from.
1032 @param Timeout The timeout, in 100ns units, to use for the execution
1033 of the security protocol command. A Timeout value of 0
1034 means that this function will wait indefinitely for the
1035 security protocol command to execute. If Timeout is greater
1036 than zero, then this function will return EFI_TIMEOUT
1037 if the time required to execute the send data command
1038 is greater than Timeout.
1039 @param SecurityProtocolId The value of the "Security Protocol" parameter of
1040 the security protocol command to be sent.
1041 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
1042 of the security protocol command to be sent.
1043 @param PayloadBufferSize Size in bytes of the payload data buffer.
1044 @param PayloadBuffer A pointer to a destination buffer to store the security
1045 protocol command specific payload data for the security
1048 @retval EFI_SUCCESS The security protocol command completed successfully.
1049 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
1050 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
1051 @retval EFI_NO_MEDIA There is no media in the device.
1052 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1053 @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
1054 @retval EFI_TIMEOUT A timeout occurred while waiting for the security
1055 protocol command to execute.
1061 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
*This
,
1064 IN UINT8 SecurityProtocolId
,
1065 IN UINT16 SecurityProtocolSpecificData
,
1066 IN UINTN PayloadBufferSize
,
1067 IN VOID
*PayloadBuffer
1070 OPAL_SMM_DEVICE
*SmmDev
;
1072 SmmDev
= OPAL_SMM_DEVICE_FROM_THIS (This
);
1073 if (SmmDev
== NULL
) {
1074 return EFI_DEVICE_ERROR
;
1077 return PerformTrustedIo (
1081 SecurityProtocolSpecificData
,