]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.c
SecurityPkg OpalPasswordSmm: Consume SmmIoLib.
[mirror_edk2.git] / SecurityPkg / Tcg / Opal / OpalPasswordSmm / OpalPasswordSmm.c
1 /** @file
2 Opal password smm driver which is used to support Opal security feature at s3 path.
3
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
9
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.
12
13 **/
14
15 #include "OpalPasswordSmm.h"
16
17 #define SMM_SIZE_ALLOC_BYTES (512)
18 #define RESPONSE_SIZE (200)
19
20 #define PCI_CLASS_MASS_STORAGE_AHCI (0x06)
21
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
27
28 //
29 // To unlock the Intel SATA controller at S3 Resume, restored the following registers.
30 //
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},
47 };
48
49
50 UINT8 mSwSmiValue;
51 LIST_ENTRY *mOpalDeviceList;
52 LIST_ENTRY mSmmDeviceList = INITIALIZE_LIST_HEAD_VARIABLE (mSmmDeviceList);
53
54 BOOLEAN mSendBlockSID = FALSE;
55
56 // AHCI
57 UINT32 mAhciBar = 0;
58 EFI_AHCI_REGISTERS mAhciRegisters;
59 VOID *mBuffer = NULL; // DMA can not read/write Data to smram, so we pre-allocates Buffer from AcpiNVS.
60 //
61 // NVME
62 NVME_CONTEXT mNvmeContext;
63
64 /**
65 Add new bridge node or nvme device info to the device list.
66
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.
71
72 **/
73 VOID
74 AddPciDeviceNode (
75 UINT32 BusNum,
76 UINT32 DevNum,
77 UINT32 FuncNum,
78 OPAL_SMM_DEVICE *Dev
79 )
80 {
81 UINT8 *DevList;
82 PCI_DEVICE *DeviceNode;
83
84 DevList = AllocateZeroPool (sizeof (PCI_DEVICE) + Dev->Length);
85 ASSERT (DevList != NULL);
86
87 if (Dev->Length != 0) {
88 CopyMem (DevList, Dev->PciBridgeNode, Dev->Length);
89 FreePool (Dev->PciBridgeNode);
90 }
91
92 DeviceNode = (PCI_DEVICE *) (DevList + Dev->Length);
93
94 DeviceNode->BusNum = BusNum;
95 DeviceNode->DevNum = DevNum;
96 DeviceNode->FuncNum = FuncNum;
97
98 Dev->Length += sizeof (PCI_DEVICE);
99 Dev->PciBridgeNode = (PCI_DEVICE *)DevList;
100 }
101
102 /**
103 Extract device info from the input device path.
104
105 @param[in] DevicePath Device path info for the device.
106 @param[in,out] Dev The device which new inputed.
107
108 **/
109 VOID
110 ExtractDeviceInfoFromDevicePath (
111 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
112 IN OUT OPAL_SMM_DEVICE *Dev
113 )
114 {
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;
120 UINTN BusNum;
121
122 TmpDevPath = DevicePath;
123 Dev->DeviceType = OPAL_DEVICE_TYPE_UNKNOWN;
124
125 while (!IsDevicePathEnd(TmpDevPath)) {
126 if (TmpDevPath->Type == MESSAGING_DEVICE_PATH && TmpDevPath->SubType == MSG_SATA_DP) {
127 //
128 // SATA
129 //
130 SataDevPath = ( SATA_DEVICE_PATH* )TmpDevPath;
131 Dev->SataPort = SataDevPath->HBAPortNumber;
132 Dev->SataPortMultiplierPort = SataDevPath->PortMultiplierPortNumber;
133 Dev->DeviceType = OPAL_DEVICE_TYPE_SATA;
134 break;
135 } else if (TmpDevPath->Type == MESSAGING_DEVICE_PATH && TmpDevPath->SubType == MSG_NVME_NAMESPACE_DP) {
136 //
137 // NVMe
138 //
139 NvmeDevPath = ( NVME_NAMESPACE_DEVICE_PATH* )TmpDevPath;
140 Dev->NvmeNamespaceId = NvmeDevPath->NamespaceId;
141 Dev->DeviceType = OPAL_DEVICE_TYPE_NVME;
142 break;
143 }
144 TmpDevPath = NextDevicePathNode (TmpDevPath);
145 }
146
147 //
148 // Get bridge node info for the nvme device.
149 //
150 BusNum = 0;
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;
161 } else {
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));
165 }
166 }
167 }
168
169 TmpDevPath = NextDevicePathNode (TmpDevPath);
170 TmpDevPath2 = NextDevicePathNode (TmpDevPath2);
171 }
172 }
173
174 /**
175
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
179
180 @param[in] OpalDev Opal object to determine if locked
181 @param[out] BlockSidSupported Whether device support BlockSid feature.
182
183 **/
184 BOOLEAN
185 IsOpalDeviceLocked(
186 OPAL_SMM_DEVICE *OpalDev,
187 BOOLEAN *BlockSidSupported
188 )
189 {
190 OPAL_SESSION Session;
191 OPAL_DISK_SUPPORT_ATTRIBUTE SupportedAttributes;
192 TCG_LOCKING_FEATURE_DESCRIPTOR LockingFeature;
193 UINT16 OpalBaseComId;
194 TCG_RESULT Ret;
195
196 Session.Sscp = &OpalDev->Sscp;
197 Session.MediaId = 0;
198
199 Ret = OpalGetSupportedAttributesInfo (&Session, &SupportedAttributes, &OpalBaseComId);
200 if (Ret != TcgResultSuccess) {
201 return FALSE;
202 }
203
204 OpalDev->OpalBaseComId = OpalBaseComId;
205 Session.OpalBaseComId = OpalBaseComId;
206 *BlockSidSupported = SupportedAttributes.BlockSid == 1 ? TRUE : FALSE;
207
208 Ret = OpalGetLockingInfo(&Session, &LockingFeature);
209 if (Ret != TcgResultSuccess) {
210 return FALSE;
211 }
212
213 return OpalDeviceLocked (&SupportedAttributes, &LockingFeature);
214 }
215
216 /**
217 Save/Restore RootPort configuration space.
218
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
222
223 @retval - PCIE base address of this RootPort
224 **/
225 UINTN
226 SaveRestoreRootportConfSpace (
227 IN OPAL_SMM_DEVICE *DeviceNode,
228 IN BOOLEAN SaveAction,
229 IN OUT UINT8 **PcieConfBufferList
230 )
231 {
232 UINTN RpBase;
233 UINTN Length;
234 PCI_DEVICE *DevNode;
235 UINT8 *StorePcieConfData;
236 UINTN Index;
237
238 Length = 0;
239 Index = 0;
240 RpBase = 0;
241
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);
245
246 if (PcieConfBufferList != NULL) {
247 if (SaveAction) {
248 StorePcieConfData = (UINT8 *) AllocateZeroPool (OPAL_PCIE_ROOTPORT_SAVESIZE);
249 ASSERT (StorePcieConfData != NULL);
250 OpalPciRead (StorePcieConfData, RpBase, OPAL_PCIE_ROOTPORT_SAVESIZE);
251 PcieConfBufferList[Index] = StorePcieConfData;
252 } else {
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);
257
258 FreePool (StorePcieConfData);
259 }
260 }
261
262 Length += sizeof (PCI_DEVICE);
263 Index ++;
264 }
265
266 return RpBase;
267 }
268
269 /**
270 Configure RootPort for downstream PCIe NAND devices.
271
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
276
277 **/
278 VOID
279 ConfigureRootPortForPcieNand (
280 IN UINTN RpBase,
281 IN UINTN BusNumber,
282 IN UINT32 MemoryBase,
283 IN UINT32 MemoryLength
284 )
285 {
286 UINT32 MemoryLimit;
287
288 DEBUG ((DEBUG_INFO, "ConfigureRootPortForPcieNand, BusNumber: %x, MemoryBase: %x, MemoryLength: %x\n",
289 BusNumber, MemoryBase, MemoryLength));
290
291 if (MemoryLength == 0) {
292 MemoryLimit = MemoryBase;
293 } else {
294 MemoryLimit = MemoryBase + MemoryLength + 0xFFFFF; // 1M
295 }
296
297 ///
298 /// Configue PCIE configuration space for RootPort
299 ///
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
310 }
311
312
313 /**
314 Dispatch function for a Software SMI handler.
315
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.
322
323 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
324 should still be called.
325 @retval Others Other execution results.
326 **/
327 EFI_STATUS
328 EFIAPI
329 SmmUnlockOpalPassword (
330 IN EFI_HANDLE DispatchHandle,
331 IN CONST VOID *RegisterContext,
332 IN OUT VOID *CommBuffer,
333 IN OUT UINTN *CommBufferSize
334 )
335 {
336 EFI_STATUS Status;
337 OPAL_SMM_DEVICE *OpalDev;
338 LIST_ENTRY *Entry;
339 UINT8 BaseClassCode;
340 UINT8 SubClassCode;
341 UINT8 ProgInt;
342 TCG_RESULT Result;
343 UINT8 SataCmdSt;
344 UINT8 *StorePcieConfDataList[16];
345 UINTN RpBase;
346 UINTN MemoryBase;
347 UINTN MemoryLength;
348 OPAL_SESSION Session;
349 BOOLEAN BlockSidSupport;
350
351 ZeroMem (StorePcieConfDataList, sizeof (StorePcieConfDataList));
352 Status = EFI_DEVICE_ERROR;
353
354 //
355 // try to unlock all locked hdd disks.
356 //
357 for (Entry = mSmmDeviceList.ForwardLink; Entry != &mSmmDeviceList; Entry = Entry->ForwardLink) {
358 OpalDev = BASE_CR(Entry, OPAL_SMM_DEVICE, Link);
359
360 RpBase = 0;
361 SataCmdSt = 0;
362
363 ///
364 /// Configure RootPort for PCIe AHCI/NVME devices.
365 ///
366 if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
367 ///
368 /// Save original RootPort configuration space to heap
369 ///
370 RpBase = SaveRestoreRootportConfSpace (
371 OpalDev,
372 TRUE,
373 StorePcieConfDataList
374 );
375 MemoryBase = mNvmeContext.Nbar;
376 MemoryLength = 0;
377 ConfigureRootPortForPcieNand (RpBase, OpalDev->BusNum, (UINT32) MemoryBase, (UINT32) MemoryLength);
378
379 ///
380 /// Enable PCIE decode for RootPort
381 ///
382 SataCmdSt = PciRead8 (RpBase + NVME_PCIE_PCICMD);
383 PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0x6);
384 } else {
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);
387 }
388
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;
394 break;
395 }
396
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));
403 goto done;
404 }
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));
409 goto done;
410 }
411 } else {
412 DEBUG ((DEBUG_ERROR, "SubClassCode not support for SATA device\n"));
413 }
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;
419 goto done;
420 }
421
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);
426 } else {
427 DEBUG ((DEBUG_ERROR, "SubClassCode not support for NVME device\n"));
428 }
429 } else {
430 DEBUG ((DEBUG_ERROR, "Invalid Devicetype\n"));
431 goto done;
432 }
433
434 Status = EFI_DEVICE_ERROR;
435 BlockSidSupport = FALSE;
436 if (IsOpalDeviceLocked (OpalDev, &BlockSidSupport)) {
437 ZeroMem(&Session, sizeof(Session));
438 Session.Sscp = &OpalDev->Sscp;
439 Session.MediaId = 0;
440 Session.OpalBaseComId = OpalDev->OpalBaseComId;
441
442 Result = OpalSupportUnlock (&Session, OpalDev->Password, OpalDev->PasswordLength, NULL);
443 if (Result == TcgResultSuccess) {
444 Status = EFI_SUCCESS;
445 }
446 }
447
448 if (mSendBlockSID && BlockSidSupport) {
449 Result = OpalBlockSid (&Session, TRUE);
450 if (Result != TcgResultSuccess) {
451 break;
452 }
453 }
454
455 if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
456 if (SubClassCode == PCI_CLASS_MASS_STORAGE_NVM) {
457 Status = NvmeControllerExit (&mNvmeContext);
458 }
459 }
460
461 done:
462 if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
463 ASSERT (RpBase != 0);
464 PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0);
465 RpBase = SaveRestoreRootportConfSpace (
466 OpalDev,
467 FALSE, // restore
468 StorePcieConfDataList
469 );
470 PciWrite8 (RpBase + NVME_PCIE_PCICMD, SataCmdSt);
471 } else {
472 PciWrite8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD), SataCmdSt);
473 }
474
475 if (EFI_ERROR (Status)) {
476 break;
477 }
478 }
479
480 return Status;
481 }
482
483 /**
484 The function extracts device information from OpalDeviceList and creat SmmDeviceList used for S3.
485
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.
488
489 @retval EFI_SUCCESS Create SmmDeviceList successfully.
490 @retval Others Other execution results.
491 **/
492 EFI_STATUS
493 CreateSmmDeviceList (
494 IN LIST_ENTRY *OpalDeviceList,
495 IN OUT LIST_ENTRY *SmmDeviceList
496 )
497 {
498 LIST_ENTRY *Entry;
499 OPAL_DISK_AND_PASSWORD_INFO *PciDev;
500 OPAL_SMM_DEVICE *SmmDev;
501
502 for (Entry = OpalDeviceList->ForwardLink; Entry != OpalDeviceList; Entry = Entry->ForwardLink) {
503 PciDev = BASE_CR (Entry, OPAL_DISK_AND_PASSWORD_INFO, Link);
504
505 SmmDev = AllocateZeroPool (sizeof (OPAL_SMM_DEVICE));
506 if (SmmDev == NULL) {
507 return EFI_OUT_OF_RESOURCES;
508 }
509 SmmDev->Signature = OPAL_SMM_DEVICE_SIGNATURE;
510
511 ExtractDeviceInfoFromDevicePath(&PciDev->OpalDevicePath, SmmDev);
512
513 SmmDev->PasswordLength = PciDev->PasswordLength;
514 CopyMem(&(SmmDev->Password), PciDev->Password, OPAL_PASSWORD_MAX_LENGTH);
515
516 SmmDev->Sscp.ReceiveData = SecurityReceiveData;
517 SmmDev->Sscp.SendData = SecuritySendData;
518
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));
524
525 InsertHeadList (SmmDeviceList, &SmmDev->Link);
526 }
527
528 return EFI_SUCCESS;
529 }
530
531 /**
532 Main entry point for an SMM handler dispatch or communicate-based callback.
533
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.
540
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
544 still be called.
545 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
546 be called.
547 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
548 **/
549 EFI_STATUS
550 EFIAPI
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
556 )
557 {
558 UINTN Bus;
559 UINTN Device;
560 UINTN Function;
561 UINTN Index;
562 EFI_STATUS Status;
563 LIST_ENTRY *Entry;
564 UINTN Offset;
565 UINT64 Address;
566 S3_BOOT_SCRIPT_LIB_WIDTH Width;
567 UINT32 Data;
568 OPAL_HC_PCI_REGISTER_SAVE *HcRegisterSaveListPtr;
569 UINTN Count;
570 OPAL_SMM_DEVICE *SmmDev;
571
572 Data = 0;
573 Status = EFI_SUCCESS;
574
575 mOpalDeviceList = OpalSupportGetOpalDeviceList();
576 if (IsListEmpty (mOpalDeviceList)) {
577 //
578 // No Opal enabled device. Do nothing.
579 //
580 return EFI_SUCCESS;
581 }
582
583 if (IsListEmpty (&mSmmDeviceList)) {
584 //
585 // mSmmDeviceList for S3 is empty, creat it by mOpalDeviceList.
586 //
587 Status = CreateSmmDeviceList (mOpalDeviceList, &mSmmDeviceList);
588 if (EFI_ERROR (Status)) {
589 return Status;
590 }
591 }
592
593 //
594 // Go through SmmDeviceList to save register data for S3
595 //
596 for (Entry = mSmmDeviceList.ForwardLink; Entry != &mSmmDeviceList; Entry = Entry->ForwardLink) {
597 SmmDev = BASE_CR (Entry, OPAL_SMM_DEVICE, Link);
598
599 if (SmmDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
600 continue;
601 }
602
603 //
604 // Save register Data for S3. Sata controller only.
605 //
606 Bus = SmmDev->BusNum;
607 Device = SmmDev->DevNum;
608 Function = SmmDev->FuncNum;
609
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);
613
614 for (Index = 0; Index < Count; Index += 1) {
615 Offset = HcRegisterSaveListPtr[Index].Address;
616 Width = HcRegisterSaveListPtr[Index].Width;
617
618 switch (Width) {
619 case S3BootScriptWidthUint8:
620 Data = (UINT32)PciRead8 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));
621 break;
622 case S3BootScriptWidthUint16:
623 Data = (UINT32)PciRead16 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));
624 break;
625 case S3BootScriptWidthUint32:
626 Data = PciRead32 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));
627 break;
628 default:
629 ASSERT (FALSE);
630 break;
631 }
632
633 Address = S3_BOOT_SCRIPT_LIB_PCI_ADDRESS (Bus, Device, Function, Offset);
634 Status = S3BootScriptSavePciCfgWrite (Width, Address, 1, &Data);
635 if (EFI_ERROR (Status)) {
636 return Status;
637 }
638 }
639 }
640
641 Status = S3BootScriptSaveIoWrite (S3BootScriptWidthUint8, 0xB2, 1, &mSwSmiValue);
642 ASSERT_EFI_ERROR (Status);
643
644 return Status;
645 }
646
647 /**
648 Main entry for this driver.
649
650 @param ImageHandle Image handle this driver.
651 @param SystemTable Pointer to SystemTable.
652
653 @retval EFI_SUCESS This function always complete successfully.
654
655 **/
656 EFI_STATUS
657 EFIAPI
658 OpalPasswordSmmInit (
659 IN EFI_HANDLE ImageHandle,
660 IN EFI_SYSTEM_TABLE *SystemTable
661 )
662 {
663 EFI_STATUS Status;
664 EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
665 EFI_SMM_SX_DISPATCH2_PROTOCOL *SxDispatch;
666 EFI_HANDLE SwHandle;
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;
672 UINTN DataSize;
673 EFI_PHYSICAL_ADDRESS Address;
674
675 mBuffer = NULL;
676 SwHandle = NULL;
677 S3SleepEntryHandle = NULL;
678 ZeroMem (&mNvmeContext, sizeof (NVME_CONTEXT));
679
680 Status = gSmst->SmmLocateProtocol (
681 &gEfiSmmSwDispatch2ProtocolGuid,
682 NULL,
683 (VOID **)&SwDispatch
684 );
685 ASSERT_EFI_ERROR (Status);
686 if (EFI_ERROR (Status)) {
687 DEBUG((DEBUG_ERROR, " SmmLocateProtocol gEfiSmmSwDispatch2ProtocolGuid fail, Status: %r\n", Status));
688 return Status;
689 }
690
691 Status = gSmst->SmmLocateProtocol (
692 &gEfiSmmSxDispatch2ProtocolGuid,
693 NULL,
694 (VOID **)&SxDispatch
695 );
696 ASSERT_EFI_ERROR (Status);
697 if (EFI_ERROR (Status)) {
698 DEBUG((DEBUG_ERROR, " SmmLocateProtocol gEfiSmmSxDispatch2ProtocolGuid fail, Status: %r\n", Status));
699 return Status;
700 }
701
702 //
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.
706 //
707 Address = 0xFFFFFFFF;
708 Status = gBS->AllocatePages (
709 AllocateMaxAddress,
710 EfiACPIMemoryNVS,
711 EFI_SIZE_TO_PAGES (SMM_SIZE_ALLOC_BYTES),
712 &Address
713 );
714 if (EFI_ERROR (Status)) {
715 DEBUG((DEBUG_ERROR, " AllocatePages for SATA DAM fail, Status: %r\n", Status));
716 return EFI_OUT_OF_RESOURCES;
717 }
718
719 mBuffer = (VOID *)(UINTN)Address;
720 ZeroMem ((VOID *)(UINTN)mBuffer, SMM_SIZE_ALLOC_BYTES);
721
722 //
723 // Preallocate resource for AHCI transfer descriptor.
724 //
725 Status = AhciAllocateResource ();
726 if (EFI_ERROR (Status)) {
727 DEBUG((DEBUG_ERROR, " AhciAllocateResource fail, Status: %r\n", Status));
728 Status = EFI_OUT_OF_RESOURCES;
729 goto EXIT;
730 }
731
732 //
733 // Preallocate resource for NVMe configuration space.
734 //
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;
739 goto EXIT;
740 }
741
742 //
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.
746 //
747 EntryRegisterContext.Type = SxS3;
748 EntryRegisterContext.Phase = SxEntry;
749 Status = SxDispatch->Register (
750 SxDispatch,
751 S3SleepEntryCallBack,
752 &EntryRegisterContext,
753 &S3SleepEntryHandle
754 );
755 ASSERT_EFI_ERROR (Status);
756 if (EFI_ERROR (Status)) {
757 goto EXIT;
758 }
759
760 //
761 // Register Opal password smm unlock handler
762 //
763 Context.SwSmiInputValue = (UINTN) -1;
764 Status = SwDispatch->Register (
765 SwDispatch,
766 SmmUnlockOpalPassword,
767 &Context,
768 &SwHandle
769 );
770 ASSERT_EFI_ERROR (Status);
771 if (EFI_ERROR (Status)) {
772 DEBUG((DEBUG_ERROR, " SwDispatch->Register fail, Status: %r\n", Status));
773 goto EXIT;
774 }
775
776 //
777 // trigger smi to unlock hdd if it's locked.
778 //
779 mSwSmiValue = (UINT8) Context.SwSmiInputValue;
780
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,
787 NULL,
788 &DataSize,
789 &OpalExtraInfo
790 );
791 if (!EFI_ERROR (Status)) {
792 mSendBlockSID = OpalExtraInfo.EnableBlockSid;
793 }
794 }
795
796 return EFI_SUCCESS;
797
798 EXIT:
799 if (S3SleepEntryHandle != NULL) {
800 SxDispatch->UnRegister (SxDispatch, S3SleepEntryHandle);
801 }
802
803 AhciFreeResource ();
804
805 NvmeFreeResource (&mNvmeContext);
806
807 if (mBuffer != NULL) {
808 gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN) mBuffer, EFI_SIZE_TO_PAGES (SMM_SIZE_ALLOC_BYTES));
809 }
810
811 return Status;
812 }
813
814 /**
815 Provide Io action support.
816
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
823
824 @retval TcgResultSuccess Perform the io action success.
825 @retval TcgResultFailure Perform the io action failed.
826
827 **/
828 EFI_STATUS
829 PerformTrustedIo (
830 OPAL_SMM_DEVICE *SmmDev,
831 OPAL_IO_TYPE IoType,
832 UINT8 SecurityProtocol,
833 UINT16 SpSpecific,
834 UINTN TransferLength,
835 VOID *Buffer
836 )
837 {
838 EFI_STATUS Status;
839 UINTN BufferSizeBlocks;
840 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
841
842 Status = EFI_DEVICE_ERROR;
843 if (SmmDev->DeviceType == OPAL_DEVICE_TYPE_SATA) {
844 BufferSizeBlocks = TransferLength / 512;
845
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;
854
855
856 ZeroMem( mBuffer, HDD_PAYLOAD );
857 ASSERT( TransferLength <= HDD_PAYLOAD );
858
859 if (IoType == OpalSend) {
860 CopyMem( mBuffer, Buffer, TransferLength );
861 }
862
863 Status = AhciPioTransfer(
864 &mAhciRegisters,
865 (UINT8) SmmDev->SataPort,
866 (UINT8) SmmDev->SataPortMultiplierPort,
867 NULL,
868 0,
869 ( IoType == OpalSend ) ? FALSE : TRUE, // i/o direction
870 &AtaCommandBlock,
871 NULL,
872 mBuffer,
873 (UINT32)TransferLength,
874 ATA_TIMEOUT
875 );
876
877 if (IoType == OpalRecv) {
878 CopyMem( Buffer, mBuffer, TransferLength );
879 }
880 } else if (SmmDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
881 Status = NvmeSecuritySendReceive (
882 &mNvmeContext,
883 IoType == OpalSend,
884 SecurityProtocol,
885 SwapBytes16(SpSpecific),
886 TransferLength,
887 Buffer
888 );
889 } else {
890 DEBUG((DEBUG_ERROR, "DeviceType(%x) not support.\n", SmmDev->DeviceType));
891 }
892
893 return Status;
894 }
895
896 /**
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.
899
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.
904
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.
907
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
910 is non-zero.
911
912 If the PayloadBufferSize is zero, the security protocol command is sent using the
913 Trusted Non-Data command defined in ATA8-ACS.
914
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.
918
919 If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
920 the function shall return EFI_INVALID_PARAMETER.
921
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.
926
927 If the security protocol fails to complete within the Timeout period, the function
928 shall return EFI_TIMEOUT.
929
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.
933
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.
954
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.
966
967 **/
968 EFI_STATUS
969 EFIAPI
970 SecurityReceiveData (
971 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
972 IN UINT32 MediaId,
973 IN UINT64 Timeout,
974 IN UINT8 SecurityProtocolId,
975 IN UINT16 SecurityProtocolSpecificData,
976 IN UINTN PayloadBufferSize,
977 OUT VOID *PayloadBuffer,
978 OUT UINTN *PayloadTransferSize
979 )
980 {
981 OPAL_SMM_DEVICE *SmmDev;
982
983 SmmDev = OPAL_SMM_DEVICE_FROM_THIS (This);
984 if (SmmDev == NULL) {
985 return EFI_DEVICE_ERROR;
986 }
987
988 return PerformTrustedIo (
989 SmmDev,
990 OpalRecv,
991 SecurityProtocolId,
992 SecurityProtocolSpecificData,
993 PayloadBufferSize,
994 PayloadBuffer
995 );
996 }
997
998 /**
999 Send a security protocol command to a device.
1000
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.
1007
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.
1010
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.
1015
1016 If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
1017 return EFI_INVALID_PARAMETER.
1018
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.
1023
1024 If the security protocol fails to complete within the Timeout period, the function
1025 shall return EFI_TIMEOUT.
1026
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.
1030
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
1047 protocol command.
1048
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.
1057
1058 **/
1059 EFI_STATUS
1060 EFIAPI
1061 SecuritySendData (
1062 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
1063 IN UINT32 MediaId,
1064 IN UINT64 Timeout,
1065 IN UINT8 SecurityProtocolId,
1066 IN UINT16 SecurityProtocolSpecificData,
1067 IN UINTN PayloadBufferSize,
1068 IN VOID *PayloadBuffer
1069 )
1070 {
1071 OPAL_SMM_DEVICE *SmmDev;
1072
1073 SmmDev = OPAL_SMM_DEVICE_FROM_THIS (This);
1074 if (SmmDev == NULL) {
1075 return EFI_DEVICE_ERROR;
1076 }
1077
1078 return PerformTrustedIo (
1079 SmmDev,
1080 OpalSend,
1081 SecurityProtocolId,
1082 SecurityProtocolSpecificData,
1083 PayloadBufferSize,
1084 PayloadBuffer
1085 );
1086
1087 }
1088