]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.c
SecurityPkg-Opal(2): Enhance AHCI Bar MMIO region check.
[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 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *mGcdMemSpace = NULL;
65 UINTN mNumberOfDescriptors = 0;
66
67 /**
68 Add new bridge node or nvme device info to the device list.
69
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.
74
75 **/
76 VOID
77 AddPciDeviceNode (
78 UINT32 BusNum,
79 UINT32 DevNum,
80 UINT32 FuncNum,
81 OPAL_SMM_DEVICE *Dev
82 )
83 {
84 UINT8 *DevList;
85 PCI_DEVICE *DeviceNode;
86
87 DevList = AllocateZeroPool (sizeof (PCI_DEVICE) + Dev->Length);
88 ASSERT (DevList != NULL);
89
90 if (Dev->Length != 0) {
91 CopyMem (DevList, Dev->PciBridgeNode, Dev->Length);
92 FreePool (Dev->PciBridgeNode);
93 }
94
95 DeviceNode = (PCI_DEVICE *) (DevList + Dev->Length);
96
97 DeviceNode->BusNum = BusNum;
98 DeviceNode->DevNum = DevNum;
99 DeviceNode->FuncNum = FuncNum;
100
101 Dev->Length += sizeof (PCI_DEVICE);
102 Dev->PciBridgeNode = (PCI_DEVICE *)DevList;
103 }
104
105 /**
106 Extract device info from the input device path.
107
108 @param[in] DevicePath Device path info for the device.
109 @param[in,out] Dev The device which new inputed.
110
111 **/
112 VOID
113 ExtractDeviceInfoFromDevicePath (
114 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
115 IN OUT OPAL_SMM_DEVICE *Dev
116 )
117 {
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;
123 UINTN BusNum;
124
125 TmpDevPath = DevicePath;
126 Dev->DeviceType = OPAL_DEVICE_TYPE_UNKNOWN;
127
128 while (!IsDevicePathEnd(TmpDevPath)) {
129 if (TmpDevPath->Type == MESSAGING_DEVICE_PATH && TmpDevPath->SubType == MSG_SATA_DP) {
130 //
131 // SATA
132 //
133 SataDevPath = ( SATA_DEVICE_PATH* )TmpDevPath;
134 Dev->SataPort = SataDevPath->HBAPortNumber;
135 Dev->SataPortMultiplierPort = SataDevPath->PortMultiplierPortNumber;
136 Dev->DeviceType = OPAL_DEVICE_TYPE_SATA;
137 break;
138 } else if (TmpDevPath->Type == MESSAGING_DEVICE_PATH && TmpDevPath->SubType == MSG_NVME_NAMESPACE_DP) {
139 //
140 // NVMe
141 //
142 NvmeDevPath = ( NVME_NAMESPACE_DEVICE_PATH* )TmpDevPath;
143 Dev->NvmeNamespaceId = NvmeDevPath->NamespaceId;
144 Dev->DeviceType = OPAL_DEVICE_TYPE_NVME;
145 break;
146 }
147 TmpDevPath = NextDevicePathNode (TmpDevPath);
148 }
149
150 //
151 // Get bridge node info for the nvme device.
152 //
153 BusNum = 0;
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;
164 } else {
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));
168 }
169 }
170 }
171
172 TmpDevPath = NextDevicePathNode (TmpDevPath);
173 TmpDevPath2 = NextDevicePathNode (TmpDevPath2);
174 }
175 }
176
177 /**
178
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
182
183 @param[in] OpalDev Opal object to determine if locked
184
185 **/
186 BOOLEAN
187 IsOpalDeviceLocked(
188 OPAL_SMM_DEVICE *OpalDev
189 )
190 {
191 OPAL_SESSION Session;
192 OPAL_DISK_SUPPORT_ATTRIBUTE SupportedAttributes;
193 TCG_LOCKING_FEATURE_DESCRIPTOR LockingFeature;
194 UINT16 OpalBaseComId;
195 TCG_RESULT Ret;
196
197 Session.Sscp = &OpalDev->Sscp;
198 Session.MediaId = 0;
199
200 Ret = OpalGetSupportedAttributesInfo (&Session, &SupportedAttributes, &OpalBaseComId);
201 if (Ret != TcgResultSuccess) {
202 return FALSE;
203 }
204
205 OpalDev->OpalBaseComId = OpalBaseComId;
206 Session.OpalBaseComId = OpalBaseComId;
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
350 ZeroMem (StorePcieConfDataList, sizeof (StorePcieConfDataList));
351 Status = EFI_DEVICE_ERROR;
352
353 //
354 // try to unlock all locked hdd disks.
355 //
356 for (Entry = mSmmDeviceList.ForwardLink; Entry != &mSmmDeviceList; Entry = Entry->ForwardLink) {
357 OpalDev = BASE_CR(Entry, OPAL_SMM_DEVICE, Link);
358
359 RpBase = 0;
360 SataCmdSt = 0;
361
362 ///
363 /// Configure RootPort for PCIe AHCI/NVME devices.
364 ///
365 if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
366 ///
367 /// Save original RootPort configuration space to heap
368 ///
369 RpBase = SaveRestoreRootportConfSpace (
370 OpalDev,
371 TRUE,
372 StorePcieConfDataList
373 );
374 MemoryBase = mNvmeContext.Nbar;
375 MemoryLength = 0;
376 ConfigureRootPortForPcieNand (RpBase, OpalDev->BusNum, (UINT32) MemoryBase, (UINT32) MemoryLength);
377
378 ///
379 /// Enable PCIE decode for RootPort
380 ///
381 SataCmdSt = PciRead8 (RpBase + NVME_PCIE_PCICMD);
382 PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0x6);
383 } else {
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);
386 }
387
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;
393 break;
394 }
395
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));
402 goto done;
403 }
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));
408 goto done;
409 }
410 } else {
411 DEBUG ((DEBUG_ERROR, "SubClassCode not support for SATA device\n"));
412 }
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;
418 goto done;
419 }
420
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);
425 } else {
426 DEBUG ((DEBUG_ERROR, "SubClassCode not support for NVME device\n"));
427 }
428 } else {
429 DEBUG ((DEBUG_ERROR, "Invalid Devicetype\n"));
430 goto done;
431 }
432
433 Status = EFI_DEVICE_ERROR;
434 if (IsOpalDeviceLocked(OpalDev)) {
435 ZeroMem(&Session, sizeof(Session));
436 Session.Sscp = &OpalDev->Sscp;
437 Session.MediaId = 0;
438 Session.OpalBaseComId = OpalDev->OpalBaseComId;
439
440 if (mSendBlockSID) {
441 Result = OpalBlockSid (&Session, TRUE);
442 if (Result != TcgResultSuccess) {
443 break;
444 }
445 }
446
447 Result = OpalSupportUnlock (&Session, OpalDev->Password, OpalDev->PasswordLength, NULL);
448 if (Result == TcgResultSuccess) {
449 Status = EFI_SUCCESS;
450 }
451 }
452
453 if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
454 if (SubClassCode == PCI_CLASS_MASS_STORAGE_NVM) {
455 Status = NvmeControllerExit (&mNvmeContext);
456 }
457 }
458
459 done:
460 if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
461 ASSERT (RpBase != 0);
462 PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0);
463 RpBase = SaveRestoreRootportConfSpace (
464 OpalDev,
465 FALSE, // restore
466 StorePcieConfDataList
467 );
468 PciWrite8 (RpBase + NVME_PCIE_PCICMD, SataCmdSt);
469 } else {
470 PciWrite8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD), SataCmdSt);
471 }
472
473 if (EFI_ERROR (Status)) {
474 break;
475 }
476 }
477
478 return Status;
479 }
480
481
482 /**
483 Main entry point for an SMM handler dispatch or communicate-based callback.
484
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.
491
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
495 still be called.
496 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
497 be called.
498 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
499 **/
500 EFI_STATUS
501 EFIAPI
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
507 )
508 {
509 UINTN Bus;
510 UINTN Device;
511 UINTN Function;
512 UINTN Index;
513 EFI_STATUS Status;
514 LIST_ENTRY *Entry;
515 UINTN Offset;
516 UINT64 Address;
517 S3_BOOT_SCRIPT_LIB_WIDTH Width;
518 UINT32 Data;
519 OPAL_DISK_AND_PASSWORD_INFO *PciDev;
520 OPAL_HC_PCI_REGISTER_SAVE *HcRegisterSaveListPtr;
521 UINTN Count;
522 OPAL_SMM_DEVICE *SmmDev;
523
524 Data = 0;
525 Status = EFI_SUCCESS;
526
527 mOpalDeviceList = OpalSupportGetOpalDeviceList();
528
529 for (Entry = mOpalDeviceList->ForwardLink; Entry != mOpalDeviceList; Entry = Entry->ForwardLink) {
530 PciDev = BASE_CR (Entry, OPAL_DISK_AND_PASSWORD_INFO, Link);
531
532 SmmDev = AllocateZeroPool (sizeof (OPAL_SMM_DEVICE));
533 if (SmmDev == NULL) {
534 return EFI_OUT_OF_RESOURCES;
535 }
536 SmmDev->Signature = OPAL_SMM_DEVICE_SIGNATURE;
537
538 ExtractDeviceInfoFromDevicePath(&PciDev->OpalDevicePath, SmmDev);
539
540 SmmDev->PasswordLength = PciDev->PasswordLength;
541 CopyMem(&(SmmDev->Password), PciDev->Password, OPAL_PASSWORD_MAX_LENGTH);
542
543 SmmDev->Sscp.ReceiveData = SecurityReceiveData;
544 SmmDev->Sscp.SendData = SecuritySendData;
545
546 InsertHeadList (&mSmmDeviceList, &SmmDev->Link);
547
548 if (SmmDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
549 continue;
550 }
551
552 //
553 // Save register Data for S3. Sata controller only.
554 //
555 Bus = SmmDev->BusNum;
556 Device = SmmDev->DevNum;
557 Function = SmmDev->FuncNum;
558
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);
562
563 for (Index = 0; Index < Count; Index += 1) {
564 Offset = HcRegisterSaveListPtr[Index].Address;
565 Width = HcRegisterSaveListPtr[Index].Width;
566
567 switch (Width) {
568 case S3BootScriptWidthUint8:
569 Data = (UINT32)PciRead8 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));
570 break;
571 case S3BootScriptWidthUint16:
572 Data = (UINT32)PciRead16 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));
573 break;
574 case S3BootScriptWidthUint32:
575 Data = PciRead32 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));
576 break;
577 default:
578 ASSERT (FALSE);
579 break;
580 }
581
582 Address = S3_BOOT_SCRIPT_LIB_PCI_ADDRESS (Bus, Device, Function, Offset);
583 Status = S3BootScriptSavePciCfgWrite (Width, Address, 1, &Data);
584 if (EFI_ERROR (Status)) {
585 return Status;
586 }
587 }
588 }
589
590 if (!IsListEmpty (mOpalDeviceList)) {
591 Status = S3BootScriptSaveIoWrite (S3BootScriptWidthUint8, 0xB2, 1, &mSwSmiValue);
592 ASSERT_EFI_ERROR (Status);
593 }
594
595 return Status;
596 }
597
598 /**
599 OpalPassword Notification for SMM EndOfDxe protocol.
600
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.
604
605 @retval EFI_SUCCESS Notification runs successfully.
606 **/
607 EFI_STATUS
608 EFIAPI
609 OpalPasswordEndOfDxeNotification (
610 IN CONST EFI_GUID *Protocol,
611 IN VOID *Interface,
612 IN EFI_HANDLE Handle
613 )
614 {
615 UINTN NumberOfDescriptors;
616 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemSpaceMap;
617 EFI_STATUS Status;
618
619 Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemSpaceMap);
620 if (EFI_ERROR (Status)) {
621 return Status;
622 }
623
624 mGcdMemSpace = AllocateCopyPool (NumberOfDescriptors * sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR), MemSpaceMap);
625 if (EFI_ERROR (Status)) {
626 gBS->FreePool (MemSpaceMap);
627 return Status;
628 }
629
630 mNumberOfDescriptors = NumberOfDescriptors;
631 gBS->FreePool (MemSpaceMap);
632
633 return EFI_SUCCESS;
634 }
635
636 /**
637 Main entry for this driver.
638
639 @param ImageHandle Image handle this driver.
640 @param SystemTable Pointer to SystemTable.
641
642 @retval EFI_SUCESS This function always complete successfully.
643
644 **/
645 EFI_STATUS
646 EFIAPI
647 OpalPasswordSmmInit (
648 IN EFI_HANDLE ImageHandle,
649 IN EFI_SYSTEM_TABLE *SystemTable
650 )
651 {
652 EFI_STATUS Status;
653 EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
654 EFI_SMM_SX_DISPATCH2_PROTOCOL *SxDispatch;
655 EFI_HANDLE SwHandle;
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;
661 UINTN DataSize;
662 EFI_EVENT EndOfDxeEvent;
663 EFI_PHYSICAL_ADDRESS Address;
664
665 mBuffer = NULL;
666 SwHandle = NULL;
667 S3SleepEntryHandle = NULL;
668 ZeroMem (&mNvmeContext, sizeof (NVME_CONTEXT));
669
670 Status = gSmst->SmmLocateProtocol (
671 &gEfiSmmSwDispatch2ProtocolGuid,
672 NULL,
673 (VOID **)&SwDispatch
674 );
675 ASSERT_EFI_ERROR (Status);
676 if (EFI_ERROR (Status)) {
677 DEBUG((DEBUG_ERROR, " SmmLocateProtocol gEfiSmmSwDispatch2ProtocolGuid fail, Status: %r\n", Status));
678 return Status;
679 }
680
681 Status = gSmst->SmmLocateProtocol (
682 &gEfiSmmSxDispatch2ProtocolGuid,
683 NULL,
684 (VOID **)&SxDispatch
685 );
686 ASSERT_EFI_ERROR (Status);
687 if (EFI_ERROR (Status)) {
688 DEBUG((DEBUG_ERROR, " SmmLocateProtocol gEfiSmmSxDispatch2ProtocolGuid fail, Status: %r\n", Status));
689 return Status;
690 }
691
692 //
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.
696 //
697 Address = 0xFFFFFFFF;
698 Status = gBS->AllocatePages (
699 AllocateMaxAddress,
700 EfiACPIMemoryNVS,
701 EFI_SIZE_TO_PAGES (SMM_SIZE_ALLOC_BYTES),
702 &Address
703 );
704 if (EFI_ERROR (Status)) {
705 DEBUG((DEBUG_ERROR, " AllocatePages for SATA DAM fail, Status: %r\n", Status));
706 return EFI_OUT_OF_RESOURCES;
707 }
708
709 mBuffer = (VOID *)(UINTN)Address;
710 ZeroMem ((VOID *)(UINTN)mBuffer, SMM_SIZE_ALLOC_BYTES);
711
712 //
713 // Preallocate resource for AHCI transfer descriptor.
714 //
715 Status = AhciAllocateResource ();
716 if (EFI_ERROR (Status)) {
717 DEBUG((DEBUG_ERROR, " AhciAllocateResource fail, Status: %r\n", Status));
718 Status = EFI_OUT_OF_RESOURCES;
719 goto EXIT;
720 }
721
722 //
723 // Preallocate resource for NVMe configuration space.
724 //
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;
729 goto EXIT;
730 }
731
732 //
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.
736 //
737 EntryRegisterContext.Type = SxS3;
738 EntryRegisterContext.Phase = SxEntry;
739 Status = SxDispatch->Register (
740 SxDispatch,
741 S3SleepEntryCallBack,
742 &EntryRegisterContext,
743 &S3SleepEntryHandle
744 );
745 ASSERT_EFI_ERROR (Status);
746 if (EFI_ERROR (Status)) {
747 goto EXIT;
748 }
749
750 //
751 // Register Opal password smm unlock handler
752 //
753 Context.SwSmiInputValue = (UINTN) -1;
754 Status = SwDispatch->Register (
755 SwDispatch,
756 SmmUnlockOpalPassword,
757 &Context,
758 &SwHandle
759 );
760 ASSERT_EFI_ERROR (Status);
761 if (EFI_ERROR (Status)) {
762 DEBUG((DEBUG_ERROR, " SwDispatch->Register fail, Status: %r\n", Status));
763 goto EXIT;
764 }
765
766 //
767 // trigger smi to unlock hdd if it's locked.
768 //
769 mSwSmiValue = (UINT8) Context.SwSmiInputValue;
770
771 //
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.
774 //
775 Status = gSmst->SmmRegisterProtocolNotify (&gEfiSmmEndOfDxeProtocolGuid, OpalPasswordEndOfDxeNotification, &EndOfDxeEvent);
776 if (EFI_ERROR (Status)) {
777 DEBUG((DEBUG_ERROR, "OpalPasswordSmm: Register SmmEndOfDxe fail, Status: %r\n", Status));
778 goto EXIT;
779 }
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,
786 NULL,
787 &DataSize,
788 &OpalExtraInfo
789 );
790 if (!EFI_ERROR (Status)) {
791 mSendBlockSID = OpalExtraInfo.EnableBlockSid;
792 }
793 }
794
795 return EFI_SUCCESS;
796
797 EXIT:
798 if (S3SleepEntryHandle != NULL) {
799 SxDispatch->UnRegister (SxDispatch, S3SleepEntryHandle);
800 }
801
802 AhciFreeResource ();
803
804 NvmeFreeResource (&mNvmeContext);
805
806 if (mBuffer != NULL) {
807 gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN) mBuffer, EFI_SIZE_TO_PAGES (SMM_SIZE_ALLOC_BYTES));
808 }
809
810 return Status;
811 }
812
813 /**
814 Provide Io action support.
815
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
822
823 @retval TcgResultSuccess Perform the io action success.
824 @retval TcgResultFailure Perform the io action failed.
825
826 **/
827 EFI_STATUS
828 PerformTrustedIo (
829 OPAL_SMM_DEVICE *SmmDev,
830 OPAL_IO_TYPE IoType,
831 UINT8 SecurityProtocol,
832 UINT16 SpSpecific,
833 UINTN TransferLength,
834 VOID *Buffer
835 )
836 {
837 EFI_STATUS Status;
838 UINTN BufferSizeBlocks;
839 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
840
841 Status = EFI_DEVICE_ERROR;
842 if (SmmDev->DeviceType == OPAL_DEVICE_TYPE_SATA) {
843 BufferSizeBlocks = TransferLength / 512;
844
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;
853
854
855 ZeroMem( mBuffer, HDD_PAYLOAD );
856 ASSERT( TransferLength <= HDD_PAYLOAD );
857
858 if (IoType == OpalSend) {
859 CopyMem( mBuffer, Buffer, TransferLength );
860 }
861
862 Status = AhciPioTransfer(
863 &mAhciRegisters,
864 (UINT8) SmmDev->SataPort,
865 (UINT8) SmmDev->SataPortMultiplierPort,
866 NULL,
867 0,
868 ( IoType == OpalSend ) ? FALSE : TRUE, // i/o direction
869 &AtaCommandBlock,
870 NULL,
871 mBuffer,
872 (UINT32)TransferLength,
873 ATA_TIMEOUT
874 );
875
876 if (IoType == OpalRecv) {
877 CopyMem( Buffer, mBuffer, TransferLength );
878 }
879 } else if (SmmDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
880 Status = NvmeSecuritySendReceive (
881 &mNvmeContext,
882 IoType == OpalSend,
883 SecurityProtocol,
884 SwapBytes16(SpSpecific),
885 TransferLength,
886 Buffer
887 );
888 } else {
889 DEBUG((DEBUG_ERROR, "DeviceType(%x) not support.\n", SmmDev->DeviceType));
890 }
891
892 return Status;
893 }
894
895 /**
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.
898
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.
903
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.
906
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
909 is non-zero.
910
911 If the PayloadBufferSize is zero, the security protocol command is sent using the
912 Trusted Non-Data command defined in ATA8-ACS.
913
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.
917
918 If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
919 the function shall return EFI_INVALID_PARAMETER.
920
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.
925
926 If the security protocol fails to complete within the Timeout period, the function
927 shall return EFI_TIMEOUT.
928
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.
932
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.
953
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.
965
966 **/
967 EFI_STATUS
968 EFIAPI
969 SecurityReceiveData (
970 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
971 IN UINT32 MediaId,
972 IN UINT64 Timeout,
973 IN UINT8 SecurityProtocolId,
974 IN UINT16 SecurityProtocolSpecificData,
975 IN UINTN PayloadBufferSize,
976 OUT VOID *PayloadBuffer,
977 OUT UINTN *PayloadTransferSize
978 )
979 {
980 OPAL_SMM_DEVICE *SmmDev;
981
982 SmmDev = OPAL_SMM_DEVICE_FROM_THIS (This);
983 if (SmmDev == NULL) {
984 return EFI_DEVICE_ERROR;
985 }
986
987 return PerformTrustedIo (
988 SmmDev,
989 OpalRecv,
990 SecurityProtocolId,
991 SecurityProtocolSpecificData,
992 PayloadBufferSize,
993 PayloadBuffer
994 );
995 }
996
997 /**
998 Send a security protocol command to a device.
999
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.
1006
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.
1009
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.
1014
1015 If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
1016 return EFI_INVALID_PARAMETER.
1017
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.
1022
1023 If the security protocol fails to complete within the Timeout period, the function
1024 shall return EFI_TIMEOUT.
1025
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.
1029
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
1046 protocol command.
1047
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.
1056
1057 **/
1058 EFI_STATUS
1059 EFIAPI
1060 SecuritySendData (
1061 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
1062 IN UINT32 MediaId,
1063 IN UINT64 Timeout,
1064 IN UINT8 SecurityProtocolId,
1065 IN UINT16 SecurityProtocolSpecificData,
1066 IN UINTN PayloadBufferSize,
1067 IN VOID *PayloadBuffer
1068 )
1069 {
1070 OPAL_SMM_DEVICE *SmmDev;
1071
1072 SmmDev = OPAL_SMM_DEVICE_FROM_THIS (This);
1073 if (SmmDev == NULL) {
1074 return EFI_DEVICE_ERROR;
1075 }
1076
1077 return PerformTrustedIo (
1078 SmmDev,
1079 OpalSend,
1080 SecurityProtocolId,
1081 SecurityProtocolSpecificData,
1082 PayloadBufferSize,
1083 PayloadBuffer
1084 );
1085
1086 }
1087