]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.c
SecurityPkg: OpalPasswordSmm: Add Opal password Smm driver.
[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
182 **/
183 BOOLEAN
184 IsOpalDeviceLocked(
185 OPAL_SMM_DEVICE *OpalDev
186 )
187 {
188 OPAL_SESSION Session;
189 OPAL_DISK_SUPPORT_ATTRIBUTE SupportedAttributes;
190 TCG_LOCKING_FEATURE_DESCRIPTOR LockingFeature;
191 UINT16 OpalBaseComId;
192 TCG_RESULT Ret;
193
194 Session.Sscp = &OpalDev->Sscp;
195 Session.MediaId = 0;
196
197 Ret = OpalGetSupportedAttributesInfo (&Session, &SupportedAttributes, &OpalBaseComId);
198 if (Ret != TcgResultSuccess) {
199 return FALSE;
200 }
201
202 OpalDev->OpalBaseComId = OpalBaseComId;
203 Session.OpalBaseComId = OpalBaseComId;
204
205 Ret = OpalGetLockingInfo(&Session, &LockingFeature);
206 if (Ret != TcgResultSuccess) {
207 return FALSE;
208 }
209
210 return OpalDeviceLocked (&SupportedAttributes, &LockingFeature);
211 }
212
213 /**
214 Save/Restore RootPort configuration space.
215
216 @param[in] DeviceNode - The device node.
217 @param[in] SaveAction - TRUE: Save, FALSE: Restore
218 @param[in,out] PcieConfBufferList - Configuration space data buffer for save/restore
219
220 @retval - PCIE base address of this RootPort
221 **/
222 UINTN
223 SaveRestoreRootportConfSpace (
224 IN OPAL_SMM_DEVICE *DeviceNode,
225 IN BOOLEAN SaveAction,
226 IN OUT UINT8 **PcieConfBufferList
227 )
228 {
229 UINTN RpBase;
230 UINTN Length;
231 PCI_DEVICE *DevNode;
232 UINT8 *StorePcieConfData;
233 UINTN Index;
234
235 Length = 0;
236 Index = 0;
237 RpBase = 0;
238
239 while (Length < DeviceNode->Length) {
240 DevNode = (PCI_DEVICE *)((UINT8*)DeviceNode->PciBridgeNode + Length);
241 RpBase = PCI_LIB_ADDRESS (DevNode->BusNum, DevNode->DevNum, DevNode->FuncNum, 0x0);
242
243 if (PcieConfBufferList != NULL) {
244 if (SaveAction) {
245 StorePcieConfData = (UINT8 *) AllocateZeroPool (OPAL_PCIE_ROOTPORT_SAVESIZE);
246 ASSERT (StorePcieConfData != NULL);
247 OpalPciRead (StorePcieConfData, RpBase, OPAL_PCIE_ROOTPORT_SAVESIZE);
248 PcieConfBufferList[Index] = StorePcieConfData;
249 } else {
250 // Skip PCIe Command & Status registers
251 StorePcieConfData = PcieConfBufferList[Index];
252 OpalPciWrite (RpBase, StorePcieConfData, 4);
253 OpalPciWrite (RpBase + 8, StorePcieConfData + 8, OPAL_PCIE_ROOTPORT_SAVESIZE - 8);
254
255 FreePool (StorePcieConfData);
256 }
257 }
258
259 Length += sizeof (PCI_DEVICE);
260 Index ++;
261 }
262
263 return RpBase;
264 }
265
266 /**
267 Configure RootPort for downstream PCIe NAND devices.
268
269 @param[in] RpBase - PCIe configuration space address of this RootPort
270 @param[in] BusNumber - Bus number
271 @param[in] MemoryBase - Memory base address
272 @param[in] MemoryLength - Memory size
273
274 **/
275 VOID
276 ConfigureRootPortForPcieNand (
277 IN UINTN RpBase,
278 IN UINTN BusNumber,
279 IN UINT32 MemoryBase,
280 IN UINT32 MemoryLength
281 )
282 {
283 UINT32 MemoryLimit;
284
285 DEBUG ((DEBUG_INFO, "ConfigureRootPortForPcieNand, BusNumber: %x, MemoryBase: %x, MemoryLength: %x\n",
286 BusNumber, MemoryBase, MemoryLength));
287
288 if (MemoryLength == 0) {
289 MemoryLimit = MemoryBase;
290 } else {
291 MemoryLimit = MemoryBase + MemoryLength + 0xFFFFF; // 1M
292 }
293
294 ///
295 /// Configue PCIE configuration space for RootPort
296 ///
297 PciWrite8 (RpBase + NVME_PCIE_BNUM + 1, (UINT8) BusNumber); // Secondary Bus Number registers
298 PciWrite8 (RpBase + NVME_PCIE_BNUM + 2, (UINT8) BusNumber); // Subordinate Bus Number registers
299 PciWrite8 (RpBase + NVME_PCIE_IOBL, 0xFF); // I/O Base registers
300 PciWrite8 (RpBase + NVME_PCIE_IOBL + 1, 0x00); // I/O Limit registers
301 PciWrite16 (RpBase + NVME_PCIE_MBL, (UINT16) RShiftU64 ((UINTN)MemoryBase, 16)); // Memory Base register
302 PciWrite16 (RpBase + NVME_PCIE_MBL + 2, (UINT16) RShiftU64 ((UINTN)MemoryLimit, 16)); // Memory Limit register
303 PciWrite16 (RpBase + NVME_PCIE_PMBL, 0xFFFF); // Prefetchable Memory Base registers
304 PciWrite16 (RpBase + NVME_PCIE_PMBL + 2, 0x0000); // Prefetchable Memory Limit registers
305 PciWrite32 (RpBase + NVME_PCIE_PMBU32, 0xFFFFFFFF); // Prefetchable Memory Upper Base registers
306 PciWrite32 (RpBase + NVME_PCIE_PMLU32, 0x00000000); // Prefetchable Memory Upper Limit registers
307 }
308
309
310 /**
311 Dispatch function for a Software SMI handler.
312
313 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
314 @param[in] RegisterContext Points to an optional handler context which was specified when the
315 handler was registered.
316 @param[in, out] CommBuffer A pointer to a collection of Data in memory that will
317 be conveyed from a non-SMM environment into an SMM environment.
318 @param[in, out] CommBufferSize The Size of the CommBuffer.
319
320 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
321 should still be called.
322 @retval Others Other execution results.
323 **/
324 EFI_STATUS
325 EFIAPI
326 SmmUnlockOpalPassword (
327 IN EFI_HANDLE DispatchHandle,
328 IN CONST VOID *RegisterContext,
329 IN OUT VOID *CommBuffer,
330 IN OUT UINTN *CommBufferSize
331 )
332 {
333 EFI_STATUS Status;
334 OPAL_SMM_DEVICE *OpalDev;
335 LIST_ENTRY *Entry;
336 UINT8 BaseClassCode;
337 UINT8 SubClassCode;
338 UINT8 ProgInt;
339 TCG_RESULT Result;
340 UINT8 SataCmdSt;
341 UINT8 *StorePcieConfDataList[16];
342 UINTN RpBase;
343 UINTN MemoryBase;
344 UINTN MemoryLength;
345 OPAL_SESSION Session;
346
347 ZeroMem (StorePcieConfDataList, sizeof (StorePcieConfDataList));
348 Status = EFI_DEVICE_ERROR;
349
350 //
351 // try to unlock all locked hdd disks.
352 //
353 for (Entry = mSmmDeviceList.ForwardLink; Entry != &mSmmDeviceList; Entry = Entry->ForwardLink) {
354 OpalDev = BASE_CR(Entry, OPAL_SMM_DEVICE, Link);
355
356 RpBase = 0;
357 SataCmdSt = 0;
358
359 ///
360 /// Configure RootPort for PCIe AHCI/NVME devices.
361 ///
362 if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
363 ///
364 /// Save original RootPort configuration space to heap
365 ///
366 RpBase = SaveRestoreRootportConfSpace (
367 OpalDev,
368 TRUE,
369 StorePcieConfDataList
370 );
371 MemoryBase = mNvmeContext.Nbar;
372 MemoryLength = 0;
373 ConfigureRootPortForPcieNand (RpBase, OpalDev->BusNum, (UINT32) MemoryBase, (UINT32) MemoryLength);
374
375 ///
376 /// Enable PCIE decode for RootPort
377 ///
378 SataCmdSt = PciRead8 (RpBase + NVME_PCIE_PCICMD);
379 PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0x6);
380 } else {
381 SataCmdSt = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD));
382 PciWrite8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD), 0x6);
383 }
384
385 BaseClassCode = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0B));
386 SubClassCode = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0A));
387 ProgInt = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x09));
388 if (BaseClassCode != PCI_CLASS_MASS_STORAGE) {
389 Status = EFI_INVALID_PARAMETER;
390 break;
391 }
392
393 Status = EFI_DEVICE_ERROR;
394 if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_SATA) {
395 if ((SubClassCode == PCI_CLASS_MASS_STORAGE_AHCI) || (SubClassCode == PCI_CLASS_MASS_STORAGE_RAID)) {
396 Status = GetAhciBaseAddress (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum);
397 if (EFI_ERROR (Status)) {
398 DEBUG ((DEBUG_ERROR, "GetAhciBaseAddress error, Status: %r\n", Status));
399 goto done;
400 }
401 Status = AhciModeInitialize ((UINT8)OpalDev->SataPort);
402 ASSERT_EFI_ERROR (Status);
403 if (EFI_ERROR (Status)) {
404 DEBUG ((DEBUG_ERROR, "AhciModeInitialize error, Status: %r\n", Status));
405 goto done;
406 }
407 } else {
408 DEBUG ((DEBUG_ERROR, "SubClassCode not support for SATA device\n"));
409 }
410 } else if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
411 if (SubClassCode == PCI_CLASS_MASS_STORAGE_NVM) {
412 if (ProgInt != PCI_IF_NVMHCI) {
413 DEBUG ((DEBUG_ERROR, "PI not support, skipped\n"));
414 Status = EFI_NOT_FOUND;
415 goto done;
416 }
417
418 mNvmeContext.PciBase = PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0);
419 mNvmeContext.NvmeInitWaitTime = 0;
420 mNvmeContext.Nsid = OpalDev->NvmeNamespaceId;
421 Status = NvmeControllerInit (&mNvmeContext);
422 } else {
423 DEBUG ((DEBUG_ERROR, "SubClassCode not support for NVME device\n"));
424 }
425 } else {
426 DEBUG ((DEBUG_ERROR, "Invalid Devicetype\n"));
427 goto done;
428 }
429
430 Status = EFI_DEVICE_ERROR;
431 if (IsOpalDeviceLocked(OpalDev)) {
432 ZeroMem(&Session, sizeof(Session));
433 Session.Sscp = &OpalDev->Sscp;
434 Session.MediaId = 0;
435 Session.OpalBaseComId = OpalDev->OpalBaseComId;
436
437 if (mSendBlockSID) {
438 Result = OpalBlockSid (&Session, TRUE);
439 if (Result != TcgResultSuccess) {
440 break;
441 }
442 }
443
444 Result = OpalSupportUnlock (&Session, OpalDev->Password, OpalDev->PasswordLength, NULL);
445 if (Result == TcgResultSuccess) {
446 Status = EFI_SUCCESS;
447 }
448 }
449
450 if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
451 if (SubClassCode == PCI_CLASS_MASS_STORAGE_NVM) {
452 Status = NvmeControllerExit (&mNvmeContext);
453 }
454 }
455
456 done:
457 if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
458 ASSERT (RpBase != 0);
459 PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0);
460 RpBase = SaveRestoreRootportConfSpace (
461 OpalDev,
462 FALSE, // restore
463 StorePcieConfDataList
464 );
465 PciWrite8 (RpBase + NVME_PCIE_PCICMD, SataCmdSt);
466 } else {
467 PciWrite8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD), SataCmdSt);
468 }
469
470 if (EFI_ERROR (Status)) {
471 break;
472 }
473 }
474
475 return Status;
476 }
477
478
479 /**
480 Main entry point for an SMM handler dispatch or communicate-based callback.
481
482 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
483 @param[in] Context Points to an optional handler context which was specified when the
484 handler was registered.
485 @param[in,out] CommBuffer A pointer to a collection of Data in memory that will
486 be conveyed from a non-SMM environment into an SMM environment.
487 @param[in,out] CommBufferSize The Size of the CommBuffer.
488
489 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
490 should still be called.
491 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
492 still be called.
493 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
494 be called.
495 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
496 **/
497 EFI_STATUS
498 EFIAPI
499 S3SleepEntryCallBack (
500 IN EFI_HANDLE DispatchHandle,
501 IN CONST VOID *Context OPTIONAL,
502 IN OUT VOID *CommBuffer OPTIONAL,
503 IN OUT UINTN *CommBufferSize OPTIONAL
504 )
505 {
506 UINTN Bus;
507 UINTN Device;
508 UINTN Function;
509 UINTN Index;
510 EFI_STATUS Status;
511 LIST_ENTRY *Entry;
512 UINTN Offset;
513 UINT64 Address;
514 S3_BOOT_SCRIPT_LIB_WIDTH Width;
515 UINT32 Data;
516 OPAL_DISK_AND_PASSWORD_INFO *PciDev;
517 OPAL_HC_PCI_REGISTER_SAVE *HcRegisterSaveListPtr;
518 UINTN Count;
519 OPAL_SMM_DEVICE *SmmDev;
520
521 Data = 0;
522 Status = EFI_SUCCESS;
523
524 mOpalDeviceList = OpalSupportGetOpalDeviceList();
525
526 for (Entry = mOpalDeviceList->ForwardLink; Entry != mOpalDeviceList; Entry = Entry->ForwardLink) {
527 PciDev = BASE_CR (Entry, OPAL_DISK_AND_PASSWORD_INFO, Link);
528
529 SmmDev = AllocateZeroPool (sizeof (OPAL_SMM_DEVICE));
530 if (SmmDev == NULL) {
531 return EFI_OUT_OF_RESOURCES;
532 }
533 SmmDev->Signature = OPAL_SMM_DEVICE_SIGNATURE;
534
535 ExtractDeviceInfoFromDevicePath(&PciDev->OpalDevicePath, SmmDev);
536
537 SmmDev->PasswordLength = PciDev->PasswordLength;
538 CopyMem(&(SmmDev->Password), PciDev->Password, OPAL_PASSWORD_MAX_LENGTH);
539
540 SmmDev->Sscp.ReceiveData = SecurityReceiveData;
541 SmmDev->Sscp.SendData = SecuritySendData;
542
543 InsertHeadList (&mSmmDeviceList, &SmmDev->Link);
544
545 if (SmmDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
546 continue;
547 }
548
549 //
550 // Save register Data for S3. Sata controller only.
551 //
552 Bus = SmmDev->BusNum;
553 Device = SmmDev->DevNum;
554 Function = SmmDev->FuncNum;
555
556 ASSERT (SmmDev->DeviceType == OPAL_DEVICE_TYPE_SATA);
557 HcRegisterSaveListPtr = (OPAL_HC_PCI_REGISTER_SAVE *) mSataHcRegisterSaveTemplate;
558 Count = sizeof (mSataHcRegisterSaveTemplate) / sizeof (OPAL_HC_PCI_REGISTER_SAVE);
559
560 for (Index = 0; Index < Count; Index += 1) {
561 Offset = HcRegisterSaveListPtr[Index].Address;
562 Width = HcRegisterSaveListPtr[Index].Width;
563
564 switch (Width) {
565 case S3BootScriptWidthUint8:
566 Data = (UINT32)PciRead8 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));
567 break;
568 case S3BootScriptWidthUint16:
569 Data = (UINT32)PciRead16 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));
570 break;
571 case S3BootScriptWidthUint32:
572 Data = PciRead32 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));
573 break;
574 default:
575 ASSERT (FALSE);
576 break;
577 }
578
579 Address = S3_BOOT_SCRIPT_LIB_PCI_ADDRESS (Bus, Device, Function, Offset);
580 Status = S3BootScriptSavePciCfgWrite (Width, Address, 1, &Data);
581 if (EFI_ERROR (Status)) {
582 return Status;
583 }
584 }
585 }
586
587 if (!IsListEmpty (mOpalDeviceList)) {
588 Status = S3BootScriptSaveIoWrite (S3BootScriptWidthUint8, 0xB2, 1, &mSwSmiValue);
589 ASSERT_EFI_ERROR (Status);
590 }
591
592 return Status;
593 }
594
595 /**
596 Main entry for this driver.
597
598 @param ImageHandle Image handle this driver.
599 @param SystemTable Pointer to SystemTable.
600
601 @retval EFI_SUCESS This function always complete successfully.
602
603 **/
604 EFI_STATUS
605 EFIAPI
606 OpalPasswordSmmInit (
607 IN EFI_HANDLE ImageHandle,
608 IN EFI_SYSTEM_TABLE *SystemTable
609 )
610 {
611 EFI_STATUS Status;
612 EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
613 EFI_SMM_SX_DISPATCH2_PROTOCOL *SxDispatch;
614 EFI_HANDLE SwHandle;
615 EFI_SMM_SW_REGISTER_CONTEXT Context;
616 EFI_HANDLE S3SleepEntryHandle;
617 EFI_SMM_SX_REGISTER_CONTEXT EntryRegisterContext;
618 EFI_SMM_VARIABLE_PROTOCOL *SmmVariable;
619 OPAL_EXTRA_INFO_VAR OpalExtraInfo;
620 UINTN DataSize;
621 EFI_PHYSICAL_ADDRESS Address;
622
623 mBuffer = NULL;
624 SwHandle = NULL;
625 S3SleepEntryHandle = NULL;
626 ZeroMem (&mNvmeContext, sizeof (NVME_CONTEXT));
627
628 Status = gSmst->SmmLocateProtocol (
629 &gEfiSmmSwDispatch2ProtocolGuid,
630 NULL,
631 (VOID **)&SwDispatch
632 );
633 ASSERT_EFI_ERROR (Status);
634 if (EFI_ERROR (Status)) {
635 DEBUG((DEBUG_ERROR, " SmmLocateProtocol gEfiSmmSwDispatch2ProtocolGuid fail, Status: %r\n", Status));
636 return Status;
637 }
638
639 Status = gSmst->SmmLocateProtocol (
640 &gEfiSmmSxDispatch2ProtocolGuid,
641 NULL,
642 (VOID **)&SxDispatch
643 );
644 ASSERT_EFI_ERROR (Status);
645 if (EFI_ERROR (Status)) {
646 DEBUG((DEBUG_ERROR, " SmmLocateProtocol gEfiSmmSxDispatch2ProtocolGuid fail, Status: %r\n", Status));
647 return Status;
648 }
649
650 //
651 // Preallocate a 512 bytes Buffer to perform trusted I/O.
652 // Assume this is big enough for unlock commands
653 // It's because DMA can not access smmram stack at the cmd execution.
654 //
655 Address = 0xFFFFFFFF;
656 Status = gBS->AllocatePages (
657 AllocateMaxAddress,
658 EfiACPIMemoryNVS,
659 EFI_SIZE_TO_PAGES (SMM_SIZE_ALLOC_BYTES),
660 &Address
661 );
662 if (EFI_ERROR (Status)) {
663 DEBUG((DEBUG_ERROR, " AllocatePages for SATA DAM fail, Status: %r\n", Status));
664 return EFI_OUT_OF_RESOURCES;
665 }
666
667 mBuffer = (VOID *)(UINTN)Address;
668 ZeroMem ((VOID *)(UINTN)mBuffer, SMM_SIZE_ALLOC_BYTES);
669
670 //
671 // Preallocate resource for AHCI transfer descriptor.
672 //
673 Status = AhciAllocateResource ();
674 if (EFI_ERROR (Status)) {
675 DEBUG((DEBUG_ERROR, " AhciAllocateResource fail, Status: %r\n", Status));
676 Status = EFI_OUT_OF_RESOURCES;
677 goto EXIT;
678 }
679
680 //
681 // Preallocate resource for NVMe configuration space.
682 //
683 Status = NvmeAllocateResource (ImageHandle, &mNvmeContext);
684 if (EFI_ERROR (Status)) {
685 DEBUG((DEBUG_ERROR, " NvmeAllocateResource fail, Status: %r\n", Status));
686 Status = EFI_OUT_OF_RESOURCES;
687 goto EXIT;
688 }
689
690 //
691 // Register a S3 entry callback function to store ATA host controller context to boot script.
692 // These boot scripts would be invoked at S3 path to recovery ATA host controller h/w context
693 // for executing HDD unlock cmd.
694 //
695 EntryRegisterContext.Type = SxS3;
696 EntryRegisterContext.Phase = SxEntry;
697 Status = SxDispatch->Register (
698 SxDispatch,
699 S3SleepEntryCallBack,
700 &EntryRegisterContext,
701 &S3SleepEntryHandle
702 );
703 ASSERT_EFI_ERROR (Status);
704 if (EFI_ERROR (Status)) {
705 goto EXIT;
706 }
707
708 //
709 // Register Opal password smm unlock handler
710 //
711 Context.SwSmiInputValue = (UINTN) -1;
712 Status = SwDispatch->Register (
713 SwDispatch,
714 SmmUnlockOpalPassword,
715 &Context,
716 &SwHandle
717 );
718 ASSERT_EFI_ERROR (Status);
719 if (EFI_ERROR (Status)) {
720 DEBUG((DEBUG_ERROR, " SwDispatch->Register fail, Status: %r\n", Status));
721 goto EXIT;
722 }
723
724 //
725 // trigger smi to unlock hdd if it's locked.
726 //
727 mSwSmiValue = (UINT8) Context.SwSmiInputValue;
728
729 Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&SmmVariable);
730 if (!EFI_ERROR (Status)) {
731 DataSize = sizeof (OPAL_EXTRA_INFO_VAR);
732 Status = SmmVariable->SmmGetVariable (
733 OPAL_EXTRA_INFO_VAR_NAME,
734 &gOpalExtraInfoVariableGuid,
735 NULL,
736 &DataSize,
737 &OpalExtraInfo
738 );
739 if (!EFI_ERROR (Status)) {
740 mSendBlockSID = OpalExtraInfo.EnableBlockSid;
741 }
742 }
743
744 return EFI_SUCCESS;
745
746 EXIT:
747 if (S3SleepEntryHandle != NULL) {
748 SxDispatch->UnRegister (SxDispatch, S3SleepEntryHandle);
749 }
750
751 AhciFreeResource ();
752
753 NvmeFreeResource (&mNvmeContext);
754
755 if (mBuffer != NULL) {
756 gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN) mBuffer, EFI_SIZE_TO_PAGES (SMM_SIZE_ALLOC_BYTES));
757 }
758
759 return Status;
760 }
761
762 /**
763 Provide Io action support.
764
765 @param[in] SmmDev the opal device need to perform trust io.
766 @param[in] IoType OPAL_IO_TYPE indicating whether to perform a Trusted Send or Trusted Receive.
767 @param[in] SecurityProtocol Security Protocol
768 @param[in] SpSpecific Security Protocol Specific
769 @param[in] TransferLength Transfer Length of Buffer (in bytes) - always a multiple of 512
770 @param[in] Buffer Address of Data to transfer
771
772 @retval TcgResultSuccess Perform the io action success.
773 @retval TcgResultFailure Perform the io action failed.
774
775 **/
776 EFI_STATUS
777 PerformTrustedIo (
778 OPAL_SMM_DEVICE *SmmDev,
779 OPAL_IO_TYPE IoType,
780 UINT8 SecurityProtocol,
781 UINT16 SpSpecific,
782 UINTN TransferLength,
783 VOID *Buffer
784 )
785 {
786 EFI_STATUS Status;
787 UINTN BufferSizeBlocks;
788 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
789
790 Status = EFI_DEVICE_ERROR;
791 if (SmmDev->DeviceType == OPAL_DEVICE_TYPE_SATA) {
792 BufferSizeBlocks = TransferLength / 512;
793
794 ZeroMem( &AtaCommandBlock, sizeof( EFI_ATA_COMMAND_BLOCK ) );
795 AtaCommandBlock.AtaCommand = ( IoType == OpalSend ) ? ATA_COMMAND_TRUSTED_SEND : ATA_COMMAND_TRUSTED_RECEIVE;
796 AtaCommandBlock.AtaSectorCount = ( UINT8 )BufferSizeBlocks;
797 AtaCommandBlock.AtaSectorNumber = ( UINT8 )( BufferSizeBlocks >> 8 );
798 AtaCommandBlock.AtaFeatures = SecurityProtocol;
799 AtaCommandBlock.AtaCylinderLow = ( UINT8 )( SpSpecific >> 8 );
800 AtaCommandBlock.AtaCylinderHigh = ( UINT8 )( SpSpecific );
801 AtaCommandBlock.AtaDeviceHead = ATA_DEVICE_LBA;
802
803
804 ZeroMem( mBuffer, HDD_PAYLOAD );
805 ASSERT( TransferLength <= HDD_PAYLOAD );
806
807 if (IoType == OpalSend) {
808 CopyMem( mBuffer, Buffer, TransferLength );
809 }
810
811 Status = AhciPioTransfer(
812 &mAhciRegisters,
813 (UINT8) SmmDev->SataPort,
814 (UINT8) SmmDev->SataPortMultiplierPort,
815 NULL,
816 0,
817 ( IoType == OpalSend ) ? FALSE : TRUE, // i/o direction
818 &AtaCommandBlock,
819 NULL,
820 mBuffer,
821 (UINT32)TransferLength,
822 ATA_TIMEOUT
823 );
824
825 if (IoType == OpalRecv) {
826 CopyMem( Buffer, mBuffer, TransferLength );
827 }
828 } else if (SmmDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
829 Status = NvmeSecuritySendReceive (
830 &mNvmeContext,
831 IoType == OpalSend,
832 SecurityProtocol,
833 SwapBytes16(SpSpecific),
834 TransferLength,
835 Buffer
836 );
837 } else {
838 DEBUG((DEBUG_ERROR, "DeviceType(%x) not support.\n", SmmDev->DeviceType));
839 }
840
841 return Status;
842 }
843
844 /**
845 Send a security protocol command to a device that receives data and/or the result
846 of one or more commands sent by SendData.
847
848 The ReceiveData function sends a security protocol command to the given MediaId.
849 The security protocol command sent is defined by SecurityProtocolId and contains
850 the security protocol specific data SecurityProtocolSpecificData. The function
851 returns the data from the security protocol command in PayloadBuffer.
852
853 For devices supporting the SCSI command set, the security protocol command is sent
854 using the SECURITY PROTOCOL IN command defined in SPC-4.
855
856 For devices supporting the ATA command set, the security protocol command is sent
857 using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
858 is non-zero.
859
860 If the PayloadBufferSize is zero, the security protocol command is sent using the
861 Trusted Non-Data command defined in ATA8-ACS.
862
863 If PayloadBufferSize is too small to store the available data from the security
864 protocol command, the function shall copy PayloadBufferSize bytes into the
865 PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
866
867 If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
868 the function shall return EFI_INVALID_PARAMETER.
869
870 If the given MediaId does not support security protocol commands, the function shall
871 return EFI_UNSUPPORTED. If there is no media in the device, the function returns
872 EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
873 the function returns EFI_MEDIA_CHANGED.
874
875 If the security protocol fails to complete within the Timeout period, the function
876 shall return EFI_TIMEOUT.
877
878 If the security protocol command completes without an error, the function shall
879 return EFI_SUCCESS. If the security protocol command completes with an error, the
880 function shall return EFI_DEVICE_ERROR.
881
882 @param This Indicates a pointer to the calling context.
883 @param MediaId ID of the medium to receive data from.
884 @param Timeout The timeout, in 100ns units, to use for the execution
885 of the security protocol command. A Timeout value of 0
886 means that this function will wait indefinitely for the
887 security protocol command to execute. If Timeout is greater
888 than zero, then this function will return EFI_TIMEOUT
889 if the time required to execute the receive data command
890 is greater than Timeout.
891 @param SecurityProtocolId The value of the "Security Protocol" parameter of
892 the security protocol command to be sent.
893 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
894 of the security protocol command to be sent.
895 @param PayloadBufferSize Size in bytes of the payload data buffer.
896 @param PayloadBuffer A pointer to a destination buffer to store the security
897 protocol command specific payload data for the security
898 protocol command. The caller is responsible for having
899 either implicit or explicit ownership of the buffer.
900 @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
901 data written to the payload data buffer.
902
903 @retval EFI_SUCCESS The security protocol command completed successfully.
904 @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
905 data from the device. The PayloadBuffer contains the truncated data.
906 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
907 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
908 @retval EFI_NO_MEDIA There is no media in the device.
909 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
910 @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
911 PayloadBufferSize is non-zero.
912 @retval EFI_TIMEOUT A timeout occurred while waiting for the security
913 protocol command to execute.
914
915 **/
916 EFI_STATUS
917 EFIAPI
918 SecurityReceiveData (
919 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
920 IN UINT32 MediaId,
921 IN UINT64 Timeout,
922 IN UINT8 SecurityProtocolId,
923 IN UINT16 SecurityProtocolSpecificData,
924 IN UINTN PayloadBufferSize,
925 OUT VOID *PayloadBuffer,
926 OUT UINTN *PayloadTransferSize
927 )
928 {
929 OPAL_SMM_DEVICE *SmmDev;
930
931 SmmDev = OPAL_SMM_DEVICE_FROM_THIS (This);
932 if (SmmDev == NULL) {
933 return EFI_DEVICE_ERROR;
934 }
935
936 return PerformTrustedIo (
937 SmmDev,
938 OpalRecv,
939 SecurityProtocolId,
940 SecurityProtocolSpecificData,
941 PayloadBufferSize,
942 PayloadBuffer
943 );
944 }
945
946 /**
947 Send a security protocol command to a device.
948
949 The SendData function sends a security protocol command containing the payload
950 PayloadBuffer to the given MediaId. The security protocol command sent is
951 defined by SecurityProtocolId and contains the security protocol specific data
952 SecurityProtocolSpecificData. If the underlying protocol command requires a
953 specific padding for the command payload, the SendData function shall add padding
954 bytes to the command payload to satisfy the padding requirements.
955
956 For devices supporting the SCSI command set, the security protocol command is sent
957 using the SECURITY PROTOCOL OUT command defined in SPC-4.
958
959 For devices supporting the ATA command set, the security protocol command is sent
960 using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
961 is non-zero. If the PayloadBufferSize is zero, the security protocol command is
962 sent using the Trusted Non-Data command defined in ATA8-ACS.
963
964 If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
965 return EFI_INVALID_PARAMETER.
966
967 If the given MediaId does not support security protocol commands, the function
968 shall return EFI_UNSUPPORTED. If there is no media in the device, the function
969 returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
970 device, the function returns EFI_MEDIA_CHANGED.
971
972 If the security protocol fails to complete within the Timeout period, the function
973 shall return EFI_TIMEOUT.
974
975 If the security protocol command completes without an error, the function shall return
976 EFI_SUCCESS. If the security protocol command completes with an error, the function
977 shall return EFI_DEVICE_ERROR.
978
979 @param This Indicates a pointer to the calling context.
980 @param MediaId ID of the medium to receive data from.
981 @param Timeout The timeout, in 100ns units, to use for the execution
982 of the security protocol command. A Timeout value of 0
983 means that this function will wait indefinitely for the
984 security protocol command to execute. If Timeout is greater
985 than zero, then this function will return EFI_TIMEOUT
986 if the time required to execute the send data command
987 is greater than Timeout.
988 @param SecurityProtocolId The value of the "Security Protocol" parameter of
989 the security protocol command to be sent.
990 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
991 of the security protocol command to be sent.
992 @param PayloadBufferSize Size in bytes of the payload data buffer.
993 @param PayloadBuffer A pointer to a destination buffer to store the security
994 protocol command specific payload data for the security
995 protocol command.
996
997 @retval EFI_SUCCESS The security protocol command completed successfully.
998 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
999 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
1000 @retval EFI_NO_MEDIA There is no media in the device.
1001 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1002 @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
1003 @retval EFI_TIMEOUT A timeout occurred while waiting for the security
1004 protocol command to execute.
1005
1006 **/
1007 EFI_STATUS
1008 EFIAPI
1009 SecuritySendData (
1010 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
1011 IN UINT32 MediaId,
1012 IN UINT64 Timeout,
1013 IN UINT8 SecurityProtocolId,
1014 IN UINT16 SecurityProtocolSpecificData,
1015 IN UINTN PayloadBufferSize,
1016 IN VOID *PayloadBuffer
1017 )
1018 {
1019 OPAL_SMM_DEVICE *SmmDev;
1020
1021 SmmDev = OPAL_SMM_DEVICE_FROM_THIS (This);
1022 if (SmmDev == NULL) {
1023 return EFI_DEVICE_ERROR;
1024 }
1025
1026 return PerformTrustedIo (
1027 SmmDev,
1028 OpalSend,
1029 SecurityProtocolId,
1030 SecurityProtocolSpecificData,
1031 PayloadBufferSize,
1032 PayloadBuffer
1033 );
1034
1035 }
1036