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