]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.c
SecurityPkg OpalPassword: Add solution without SMM device code
[mirror_edk2.git] / SecurityPkg / Tcg / Opal / OpalPasswordSmm / OpalPasswordSmm.c
CommitLineData
cb274a27
ED
1/** @file\r
2 Opal password smm driver which is used to support Opal security feature at s3 path.\r
3\r
4Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "OpalPasswordSmm.h"\r
16\r
17#define SMM_SIZE_ALLOC_BYTES (512)\r
18#define RESPONSE_SIZE (200)\r
19\r
20#define PCI_CLASS_MASS_STORAGE_AHCI (0x06)\r
21\r
22#define OPAL_PCIE_ROOTPORT_SAVESIZE (0x40)\r
23#define STORE_INVALID_ROOTPORT_INDEX ((UINT8) -1)\r
24#define OPAL_DEVICE_TYPE_SATA 0x1\r
25#define OPAL_DEVICE_TYPE_NVME 0x2\r
26#define OPAL_DEVICE_TYPE_UNKNOWN 0xFF\r
27\r
28//\r
29// To unlock the Intel SATA controller at S3 Resume, restored the following registers.\r
30//\r
31const OPAL_HC_PCI_REGISTER_SAVE mSataHcRegisterSaveTemplate[] = {\r
32 {0x9, S3BootScriptWidthUint8},\r
33 {0x10, S3BootScriptWidthUint32},\r
34 {0x14, S3BootScriptWidthUint32},\r
35 {0x18, S3BootScriptWidthUint32},\r
36 {0x1C, S3BootScriptWidthUint32},\r
37 {0x20, S3BootScriptWidthUint32},\r
38 {0x24, S3BootScriptWidthUint32},\r
39 {0x3c, S3BootScriptWidthUint8},\r
40 {0x3d, S3BootScriptWidthUint8},\r
41 {0x40, S3BootScriptWidthUint16},\r
42 {0x42, S3BootScriptWidthUint16},\r
43 {0x92, S3BootScriptWidthUint16},\r
44 {0x94, S3BootScriptWidthUint32},\r
45 {0x9C, S3BootScriptWidthUint32},\r
46 {0x4, S3BootScriptWidthUint16},\r
47};\r
48\r
49\r
50UINT8 mSwSmiValue;\r
51LIST_ENTRY *mOpalDeviceList;\r
52LIST_ENTRY mSmmDeviceList = INITIALIZE_LIST_HEAD_VARIABLE (mSmmDeviceList);\r
53\r
54BOOLEAN mSendBlockSID = FALSE;\r
55\r
56// AHCI\r
57UINT32 mAhciBar = 0;\r
58EFI_AHCI_REGISTERS mAhciRegisters;\r
59VOID *mBuffer = NULL; // DMA can not read/write Data to smram, so we pre-allocates Buffer from AcpiNVS.\r
60//\r
61// NVME\r
62NVME_CONTEXT mNvmeContext;\r
63\r
64/**\r
65 Add new bridge node or nvme device info to the device list.\r
66\r
67 @param[in] BusNum The bus number.\r
68 @param[in] DevNum The device number.\r
69 @param[in] FuncNum The function number.\r
70 @param[in] Dev The device which need to add device node info.\r
71\r
72**/\r
73VOID\r
74AddPciDeviceNode (\r
75 UINT32 BusNum,\r
76 UINT32 DevNum,\r
77 UINT32 FuncNum,\r
78 OPAL_SMM_DEVICE *Dev\r
79 )\r
80{\r
81 UINT8 *DevList;\r
82 PCI_DEVICE *DeviceNode;\r
83\r
84 DevList = AllocateZeroPool (sizeof (PCI_DEVICE) + Dev->Length);\r
85 ASSERT (DevList != NULL);\r
86\r
87 if (Dev->Length != 0) {\r
88 CopyMem (DevList, Dev->PciBridgeNode, Dev->Length);\r
89 FreePool (Dev->PciBridgeNode);\r
90 }\r
91\r
92 DeviceNode = (PCI_DEVICE *) (DevList + Dev->Length);\r
93\r
94 DeviceNode->BusNum = BusNum;\r
95 DeviceNode->DevNum = DevNum;\r
96 DeviceNode->FuncNum = FuncNum;\r
97\r
98 Dev->Length += sizeof (PCI_DEVICE);\r
99 Dev->PciBridgeNode = (PCI_DEVICE *)DevList;\r
100}\r
101\r
102/**\r
103 Extract device info from the input device path.\r
104\r
105 @param[in] DevicePath Device path info for the device.\r
106 @param[in,out] Dev The device which new inputed.\r
107\r
108**/\r
109VOID\r
110ExtractDeviceInfoFromDevicePath (\r
111 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
112 IN OUT OPAL_SMM_DEVICE *Dev\r
113 )\r
114{\r
115 EFI_DEVICE_PATH_PROTOCOL *TmpDevPath;\r
116 EFI_DEVICE_PATH_PROTOCOL *TmpDevPath2;\r
117 PCI_DEVICE_PATH *PciDevPath;\r
118 SATA_DEVICE_PATH *SataDevPath;\r
119 NVME_NAMESPACE_DEVICE_PATH *NvmeDevPath;\r
120 UINTN BusNum;\r
121\r
122 TmpDevPath = DevicePath;\r
123 Dev->DeviceType = OPAL_DEVICE_TYPE_UNKNOWN;\r
124\r
125 while (!IsDevicePathEnd(TmpDevPath)) {\r
126 if (TmpDevPath->Type == MESSAGING_DEVICE_PATH && TmpDevPath->SubType == MSG_SATA_DP) {\r
127 //\r
128 // SATA\r
129 //\r
130 SataDevPath = ( SATA_DEVICE_PATH* )TmpDevPath;\r
131 Dev->SataPort = SataDevPath->HBAPortNumber;\r
132 Dev->SataPortMultiplierPort = SataDevPath->PortMultiplierPortNumber;\r
133 Dev->DeviceType = OPAL_DEVICE_TYPE_SATA;\r
134 break;\r
135 } else if (TmpDevPath->Type == MESSAGING_DEVICE_PATH && TmpDevPath->SubType == MSG_NVME_NAMESPACE_DP) {\r
136 //\r
137 // NVMe\r
138 //\r
139 NvmeDevPath = ( NVME_NAMESPACE_DEVICE_PATH* )TmpDevPath;\r
140 Dev->NvmeNamespaceId = NvmeDevPath->NamespaceId;\r
141 Dev->DeviceType = OPAL_DEVICE_TYPE_NVME;\r
142 break;\r
143 }\r
144 TmpDevPath = NextDevicePathNode (TmpDevPath);\r
145 }\r
146\r
147 //\r
148 // Get bridge node info for the nvme device.\r
149 //\r
150 BusNum = 0;\r
151 TmpDevPath = DevicePath;\r
152 TmpDevPath2 = NextDevicePathNode (DevicePath);\r
153 while (!IsDevicePathEnd(TmpDevPath2)) {\r
154 if (TmpDevPath->Type == HARDWARE_DEVICE_PATH && TmpDevPath->SubType == HW_PCI_DP) {\r
155 PciDevPath = (PCI_DEVICE_PATH *) TmpDevPath;\r
156 if ((TmpDevPath2->Type == MESSAGING_DEVICE_PATH && TmpDevPath2->SubType == MSG_NVME_NAMESPACE_DP)||\r
157 (TmpDevPath2->Type == MESSAGING_DEVICE_PATH && TmpDevPath2->SubType == MSG_SATA_DP)) {\r
158 Dev->BusNum = (UINT32)BusNum;\r
159 Dev->DevNum = PciDevPath->Device;\r
160 Dev->FuncNum = PciDevPath->Function;\r
161 } else {\r
162 AddPciDeviceNode((UINT32)BusNum, PciDevPath->Device, PciDevPath->Function, Dev);\r
163 if (TmpDevPath2->Type == HARDWARE_DEVICE_PATH && TmpDevPath2->SubType == HW_PCI_DP) {\r
164 BusNum = PciRead8 (PCI_LIB_ADDRESS (BusNum, PciDevPath->Device, PciDevPath->Function, NVME_PCIE_SEC_BNUM));\r
165 }\r
166 }\r
167 }\r
168\r
169 TmpDevPath = NextDevicePathNode (TmpDevPath);\r
170 TmpDevPath2 = NextDevicePathNode (TmpDevPath2);\r
171 }\r
172}\r
173\r
174/**\r
175\r
176 The function returns whether or not the device is Opal Locked.\r
177 TRUE means that the device is partially or fully locked.\r
178 This will perform a Level 0 Discovery and parse the locking feature descriptor\r
179\r
69cd1294
ED
180 @param[in] OpalDev Opal object to determine if locked\r
181 @param[out] BlockSidSupported Whether device support BlockSid feature.\r
cb274a27
ED
182\r
183**/\r
184BOOLEAN\r
185IsOpalDeviceLocked(\r
69cd1294
ED
186 OPAL_SMM_DEVICE *OpalDev,\r
187 BOOLEAN *BlockSidSupported\r
cb274a27
ED
188 )\r
189{\r
190 OPAL_SESSION Session;\r
191 OPAL_DISK_SUPPORT_ATTRIBUTE SupportedAttributes;\r
192 TCG_LOCKING_FEATURE_DESCRIPTOR LockingFeature;\r
193 UINT16 OpalBaseComId;\r
194 TCG_RESULT Ret;\r
195\r
196 Session.Sscp = &OpalDev->Sscp;\r
197 Session.MediaId = 0;\r
198\r
199 Ret = OpalGetSupportedAttributesInfo (&Session, &SupportedAttributes, &OpalBaseComId);\r
200 if (Ret != TcgResultSuccess) {\r
201 return FALSE;\r
202 }\r
203\r
204 OpalDev->OpalBaseComId = OpalBaseComId;\r
69cd1294
ED
205 Session.OpalBaseComId = OpalBaseComId;\r
206 *BlockSidSupported = SupportedAttributes.BlockSid == 1 ? TRUE : FALSE;\r
cb274a27
ED
207\r
208 Ret = OpalGetLockingInfo(&Session, &LockingFeature);\r
209 if (Ret != TcgResultSuccess) {\r
210 return FALSE;\r
211 }\r
212\r
213 return OpalDeviceLocked (&SupportedAttributes, &LockingFeature);\r
214}\r
215\r
216/**\r
217 Save/Restore RootPort configuration space.\r
218\r
219 @param[in] DeviceNode - The device node.\r
220 @param[in] SaveAction - TRUE: Save, FALSE: Restore\r
221 @param[in,out] PcieConfBufferList - Configuration space data buffer for save/restore\r
222\r
223 @retval - PCIE base address of this RootPort\r
224**/\r
225UINTN\r
226SaveRestoreRootportConfSpace (\r
227 IN OPAL_SMM_DEVICE *DeviceNode,\r
228 IN BOOLEAN SaveAction,\r
229 IN OUT UINT8 **PcieConfBufferList\r
230 )\r
231{\r
232 UINTN RpBase;\r
233 UINTN Length;\r
234 PCI_DEVICE *DevNode;\r
235 UINT8 *StorePcieConfData;\r
236 UINTN Index;\r
237\r
238 Length = 0;\r
239 Index = 0;\r
240 RpBase = 0;\r
241\r
242 while (Length < DeviceNode->Length) {\r
243 DevNode = (PCI_DEVICE *)((UINT8*)DeviceNode->PciBridgeNode + Length);\r
244 RpBase = PCI_LIB_ADDRESS (DevNode->BusNum, DevNode->DevNum, DevNode->FuncNum, 0x0);\r
245\r
246 if (PcieConfBufferList != NULL) {\r
247 if (SaveAction) {\r
248 StorePcieConfData = (UINT8 *) AllocateZeroPool (OPAL_PCIE_ROOTPORT_SAVESIZE);\r
249 ASSERT (StorePcieConfData != NULL);\r
250 OpalPciRead (StorePcieConfData, RpBase, OPAL_PCIE_ROOTPORT_SAVESIZE);\r
251 PcieConfBufferList[Index] = StorePcieConfData;\r
252 } else {\r
253 // Skip PCIe Command & Status registers\r
254 StorePcieConfData = PcieConfBufferList[Index];\r
255 OpalPciWrite (RpBase, StorePcieConfData, 4);\r
256 OpalPciWrite (RpBase + 8, StorePcieConfData + 8, OPAL_PCIE_ROOTPORT_SAVESIZE - 8);\r
257\r
258 FreePool (StorePcieConfData);\r
259 }\r
260 }\r
261\r
262 Length += sizeof (PCI_DEVICE);\r
263 Index ++;\r
264 }\r
265\r
266 return RpBase;\r
267}\r
268\r
269/**\r
270 Configure RootPort for downstream PCIe NAND devices.\r
271\r
272 @param[in] RpBase - PCIe configuration space address of this RootPort\r
273 @param[in] BusNumber - Bus number\r
274 @param[in] MemoryBase - Memory base address\r
275 @param[in] MemoryLength - Memory size\r
276\r
277**/\r
278VOID\r
279ConfigureRootPortForPcieNand (\r
280 IN UINTN RpBase,\r
281 IN UINTN BusNumber,\r
282 IN UINT32 MemoryBase,\r
283 IN UINT32 MemoryLength\r
284 )\r
285{\r
286 UINT32 MemoryLimit;\r
287\r
288 DEBUG ((DEBUG_INFO, "ConfigureRootPortForPcieNand, BusNumber: %x, MemoryBase: %x, MemoryLength: %x\n",\r
289 BusNumber, MemoryBase, MemoryLength));\r
290\r
291 if (MemoryLength == 0) {\r
292 MemoryLimit = MemoryBase;\r
293 } else {\r
294 MemoryLimit = MemoryBase + MemoryLength + 0xFFFFF; // 1M\r
295 }\r
296\r
297 ///\r
298 /// Configue PCIE configuration space for RootPort\r
299 ///\r
300 PciWrite8 (RpBase + NVME_PCIE_BNUM + 1, (UINT8) BusNumber); // Secondary Bus Number registers\r
301 PciWrite8 (RpBase + NVME_PCIE_BNUM + 2, (UINT8) BusNumber); // Subordinate Bus Number registers\r
302 PciWrite8 (RpBase + NVME_PCIE_IOBL, 0xFF); // I/O Base registers\r
303 PciWrite8 (RpBase + NVME_PCIE_IOBL + 1, 0x00); // I/O Limit registers\r
304 PciWrite16 (RpBase + NVME_PCIE_MBL, (UINT16) RShiftU64 ((UINTN)MemoryBase, 16)); // Memory Base register\r
305 PciWrite16 (RpBase + NVME_PCIE_MBL + 2, (UINT16) RShiftU64 ((UINTN)MemoryLimit, 16)); // Memory Limit register\r
306 PciWrite16 (RpBase + NVME_PCIE_PMBL, 0xFFFF); // Prefetchable Memory Base registers\r
307 PciWrite16 (RpBase + NVME_PCIE_PMBL + 2, 0x0000); // Prefetchable Memory Limit registers\r
308 PciWrite32 (RpBase + NVME_PCIE_PMBU32, 0xFFFFFFFF); // Prefetchable Memory Upper Base registers\r
309 PciWrite32 (RpBase + NVME_PCIE_PMLU32, 0x00000000); // Prefetchable Memory Upper Limit registers\r
310}\r
311\r
312\r
313/**\r
314 Dispatch function for a Software SMI handler.\r
315\r
316 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
317 @param[in] RegisterContext Points to an optional handler context which was specified when the\r
318 handler was registered.\r
319 @param[in, out] CommBuffer A pointer to a collection of Data in memory that will\r
320 be conveyed from a non-SMM environment into an SMM environment.\r
321 @param[in, out] CommBufferSize The Size of the CommBuffer.\r
322\r
323 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers\r
324 should still be called.\r
325 @retval Others Other execution results.\r
326**/\r
327EFI_STATUS\r
328EFIAPI\r
329SmmUnlockOpalPassword (\r
330 IN EFI_HANDLE DispatchHandle,\r
331 IN CONST VOID *RegisterContext,\r
332 IN OUT VOID *CommBuffer,\r
333 IN OUT UINTN *CommBufferSize\r
334 )\r
335{\r
336 EFI_STATUS Status;\r
337 OPAL_SMM_DEVICE *OpalDev;\r
338 LIST_ENTRY *Entry;\r
339 UINT8 BaseClassCode;\r
340 UINT8 SubClassCode;\r
341 UINT8 ProgInt;\r
342 TCG_RESULT Result;\r
343 UINT8 SataCmdSt;\r
344 UINT8 *StorePcieConfDataList[16];\r
345 UINTN RpBase;\r
346 UINTN MemoryBase;\r
347 UINTN MemoryLength;\r
348 OPAL_SESSION Session;\r
69cd1294 349 BOOLEAN BlockSidSupport;\r
cb274a27
ED
350\r
351 ZeroMem (StorePcieConfDataList, sizeof (StorePcieConfDataList));\r
352 Status = EFI_DEVICE_ERROR;\r
353\r
354 //\r
355 // try to unlock all locked hdd disks.\r
356 //\r
357 for (Entry = mSmmDeviceList.ForwardLink; Entry != &mSmmDeviceList; Entry = Entry->ForwardLink) {\r
358 OpalDev = BASE_CR(Entry, OPAL_SMM_DEVICE, Link);\r
359\r
360 RpBase = 0;\r
361 SataCmdSt = 0;\r
362\r
363 ///\r
364 /// Configure RootPort for PCIe AHCI/NVME devices.\r
365 ///\r
366 if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {\r
367 ///\r
368 /// Save original RootPort configuration space to heap\r
369 ///\r
370 RpBase = SaveRestoreRootportConfSpace (\r
371 OpalDev,\r
372 TRUE,\r
373 StorePcieConfDataList\r
374 );\r
375 MemoryBase = mNvmeContext.Nbar;\r
376 MemoryLength = 0;\r
377 ConfigureRootPortForPcieNand (RpBase, OpalDev->BusNum, (UINT32) MemoryBase, (UINT32) MemoryLength);\r
378\r
379 ///\r
380 /// Enable PCIE decode for RootPort\r
381 ///\r
382 SataCmdSt = PciRead8 (RpBase + NVME_PCIE_PCICMD);\r
383 PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0x6);\r
384 } else {\r
385 SataCmdSt = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD));\r
386 PciWrite8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD), 0x6);\r
387 }\r
388\r
389 BaseClassCode = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0B));\r
390 SubClassCode = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0A));\r
391 ProgInt = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x09));\r
392 if (BaseClassCode != PCI_CLASS_MASS_STORAGE) {\r
393 Status = EFI_INVALID_PARAMETER;\r
394 break;\r
395 }\r
396\r
397 Status = EFI_DEVICE_ERROR;\r
398 if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_SATA) {\r
399 if ((SubClassCode == PCI_CLASS_MASS_STORAGE_AHCI) || (SubClassCode == PCI_CLASS_MASS_STORAGE_RAID)) {\r
400 Status = GetAhciBaseAddress (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum);\r
401 if (EFI_ERROR (Status)) {\r
402 DEBUG ((DEBUG_ERROR, "GetAhciBaseAddress error, Status: %r\n", Status));\r
403 goto done;\r
404 }\r
405 Status = AhciModeInitialize ((UINT8)OpalDev->SataPort);\r
406 ASSERT_EFI_ERROR (Status);\r
407 if (EFI_ERROR (Status)) {\r
408 DEBUG ((DEBUG_ERROR, "AhciModeInitialize error, Status: %r\n", Status));\r
409 goto done;\r
410 }\r
411 } else {\r
412 DEBUG ((DEBUG_ERROR, "SubClassCode not support for SATA device\n"));\r
413 }\r
414 } else if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {\r
415 if (SubClassCode == PCI_CLASS_MASS_STORAGE_NVM) {\r
416 if (ProgInt != PCI_IF_NVMHCI) {\r
417 DEBUG ((DEBUG_ERROR, "PI not support, skipped\n"));\r
418 Status = EFI_NOT_FOUND;\r
419 goto done;\r
420 }\r
421\r
422 mNvmeContext.PciBase = PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0);\r
423 mNvmeContext.NvmeInitWaitTime = 0;\r
424 mNvmeContext.Nsid = OpalDev->NvmeNamespaceId;\r
425 Status = NvmeControllerInit (&mNvmeContext);\r
426 } else {\r
427 DEBUG ((DEBUG_ERROR, "SubClassCode not support for NVME device\n"));\r
428 }\r
429 } else {\r
430 DEBUG ((DEBUG_ERROR, "Invalid Devicetype\n"));\r
431 goto done;\r
432 }\r
433\r
434 Status = EFI_DEVICE_ERROR;\r
69cd1294
ED
435 BlockSidSupport = FALSE;\r
436 if (IsOpalDeviceLocked (OpalDev, &BlockSidSupport)) {\r
cb274a27
ED
437 ZeroMem(&Session, sizeof(Session));\r
438 Session.Sscp = &OpalDev->Sscp;\r
439 Session.MediaId = 0;\r
440 Session.OpalBaseComId = OpalDev->OpalBaseComId;\r
441\r
cb274a27
ED
442 Result = OpalSupportUnlock (&Session, OpalDev->Password, OpalDev->PasswordLength, NULL);\r
443 if (Result == TcgResultSuccess) {\r
444 Status = EFI_SUCCESS;\r
445 }\r
446 }\r
447\r
3f250a94
ED
448 if (mSendBlockSID && BlockSidSupport) {\r
449 Result = OpalBlockSid (&Session, TRUE);\r
450 if (Result != TcgResultSuccess) {\r
451 break;\r
452 }\r
453 }\r
454\r
cb274a27
ED
455 if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {\r
456 if (SubClassCode == PCI_CLASS_MASS_STORAGE_NVM) {\r
457 Status = NvmeControllerExit (&mNvmeContext);\r
458 }\r
459 }\r
460\r
461done:\r
462 if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {\r
463 ASSERT (RpBase != 0);\r
464 PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0);\r
465 RpBase = SaveRestoreRootportConfSpace (\r
466 OpalDev,\r
467 FALSE, // restore\r
468 StorePcieConfDataList\r
469 );\r
470 PciWrite8 (RpBase + NVME_PCIE_PCICMD, SataCmdSt);\r
471 } else {\r
472 PciWrite8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD), SataCmdSt);\r
473 }\r
474\r
475 if (EFI_ERROR (Status)) {\r
476 break;\r
477 }\r
478 }\r
479\r
480 return Status;\r
481}\r
482\r
0acd8df4
ED
483/**\r
484 The function extracts device information from OpalDeviceList and creat SmmDeviceList used for S3.\r
485\r
486 @param[in] OpalDeviceList Opal device list created at POST which contains the information of OPAL_DISK_AND_PASSWORD_INFO\r
487 @param[in,out] SmmDeviceList Opal Smm device list to be created and used for unlocking devices at S3 resume.\r
488\r
489 @retval EFI_SUCCESS Create SmmDeviceList successfully.\r
490 @retval Others Other execution results.\r
491**/\r
492EFI_STATUS\r
493CreateSmmDeviceList (\r
494 IN LIST_ENTRY *OpalDeviceList,\r
495 IN OUT LIST_ENTRY *SmmDeviceList\r
496 )\r
497{\r
498 LIST_ENTRY *Entry;\r
499 OPAL_DISK_AND_PASSWORD_INFO *PciDev;\r
500 OPAL_SMM_DEVICE *SmmDev;\r
501\r
502 for (Entry = OpalDeviceList->ForwardLink; Entry != OpalDeviceList; Entry = Entry->ForwardLink) {\r
503 PciDev = BASE_CR (Entry, OPAL_DISK_AND_PASSWORD_INFO, Link);\r
504\r
505 SmmDev = AllocateZeroPool (sizeof (OPAL_SMM_DEVICE));\r
506 if (SmmDev == NULL) {\r
507 return EFI_OUT_OF_RESOURCES;\r
508 }\r
509 SmmDev->Signature = OPAL_SMM_DEVICE_SIGNATURE;\r
510\r
511 ExtractDeviceInfoFromDevicePath(&PciDev->OpalDevicePath, SmmDev);\r
512\r
513 SmmDev->PasswordLength = PciDev->PasswordLength;\r
514 CopyMem(&(SmmDev->Password), PciDev->Password, OPAL_PASSWORD_MAX_LENGTH);\r
515\r
516 SmmDev->Sscp.ReceiveData = SecurityReceiveData;\r
517 SmmDev->Sscp.SendData = SecuritySendData;\r
518\r
519 DEBUG ((DEBUG_INFO, "Opal SMM: Insert device node to SmmDeviceList:\n"));\r
520 DEBUG ((DEBUG_INFO, "DeviceType:%x, Bus:%d, Dev:%d, Fun:%d\n", \\r
521 SmmDev->DeviceType, SmmDev->BusNum, SmmDev->DevNum, SmmDev->FuncNum));\r
522 DEBUG ((DEBUG_INFO, "SataPort:%x, MultiplierPort:%x, NvmeNamespaceId:%x\n", \\r
523 SmmDev->SataPort, SmmDev->SataPortMultiplierPort, SmmDev->NvmeNamespaceId));\r
524\r
525 InsertHeadList (SmmDeviceList, &SmmDev->Link);\r
526 }\r
527\r
528 return EFI_SUCCESS;\r
529}\r
cb274a27
ED
530\r
531/**\r
532 Main entry point for an SMM handler dispatch or communicate-based callback.\r
533\r
534 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
535 @param[in] Context Points to an optional handler context which was specified when the\r
536 handler was registered.\r
537 @param[in,out] CommBuffer A pointer to a collection of Data in memory that will\r
538 be conveyed from a non-SMM environment into an SMM environment.\r
539 @param[in,out] CommBufferSize The Size of the CommBuffer.\r
540\r
541 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers\r
542 should still be called.\r
543 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should\r
544 still be called.\r
545 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still\r
546 be called.\r
547 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.\r
548**/\r
549EFI_STATUS\r
550EFIAPI\r
551S3SleepEntryCallBack (\r
552 IN EFI_HANDLE DispatchHandle,\r
553 IN CONST VOID *Context OPTIONAL,\r
554 IN OUT VOID *CommBuffer OPTIONAL,\r
555 IN OUT UINTN *CommBufferSize OPTIONAL\r
556 )\r
557{\r
558 UINTN Bus;\r
559 UINTN Device;\r
560 UINTN Function;\r
561 UINTN Index;\r
562 EFI_STATUS Status;\r
563 LIST_ENTRY *Entry;\r
564 UINTN Offset;\r
565 UINT64 Address;\r
566 S3_BOOT_SCRIPT_LIB_WIDTH Width;\r
567 UINT32 Data;\r
cb274a27
ED
568 OPAL_HC_PCI_REGISTER_SAVE *HcRegisterSaveListPtr;\r
569 UINTN Count;\r
570 OPAL_SMM_DEVICE *SmmDev;\r
571\r
572 Data = 0;\r
573 Status = EFI_SUCCESS;\r
574\r
575 mOpalDeviceList = OpalSupportGetOpalDeviceList();\r
0acd8df4
ED
576 if (IsListEmpty (mOpalDeviceList)) {\r
577 //\r
578 // No Opal enabled device. Do nothing.\r
579 //\r
580 return EFI_SUCCESS;\r
581 }\r
cb274a27 582\r
0acd8df4
ED
583 if (IsListEmpty (&mSmmDeviceList)) {\r
584 //\r
585 // mSmmDeviceList for S3 is empty, creat it by mOpalDeviceList.\r
586 //\r
587 Status = CreateSmmDeviceList (mOpalDeviceList, &mSmmDeviceList);\r
588 if (EFI_ERROR (Status)) {\r
589 return Status;\r
cb274a27 590 }\r
0acd8df4 591 }\r
cb274a27 592\r
0acd8df4
ED
593 //\r
594 // Go through SmmDeviceList to save register data for S3\r
595 //\r
596 for (Entry = mSmmDeviceList.ForwardLink; Entry != &mSmmDeviceList; Entry = Entry->ForwardLink) {\r
597 SmmDev = BASE_CR (Entry, OPAL_SMM_DEVICE, Link);\r
cb274a27
ED
598\r
599 if (SmmDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {\r
600 continue;\r
601 }\r
602\r
603 //\r
604 // Save register Data for S3. Sata controller only.\r
605 //\r
606 Bus = SmmDev->BusNum;\r
607 Device = SmmDev->DevNum;\r
608 Function = SmmDev->FuncNum;\r
609\r
610 ASSERT (SmmDev->DeviceType == OPAL_DEVICE_TYPE_SATA);\r
611 HcRegisterSaveListPtr = (OPAL_HC_PCI_REGISTER_SAVE *) mSataHcRegisterSaveTemplate;\r
612 Count = sizeof (mSataHcRegisterSaveTemplate) / sizeof (OPAL_HC_PCI_REGISTER_SAVE);\r
613\r
614 for (Index = 0; Index < Count; Index += 1) {\r
615 Offset = HcRegisterSaveListPtr[Index].Address;\r
616 Width = HcRegisterSaveListPtr[Index].Width;\r
617\r
618 switch (Width) {\r
619 case S3BootScriptWidthUint8:\r
620 Data = (UINT32)PciRead8 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));\r
621 break;\r
622 case S3BootScriptWidthUint16:\r
623 Data = (UINT32)PciRead16 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));\r
624 break;\r
625 case S3BootScriptWidthUint32:\r
626 Data = PciRead32 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));\r
627 break;\r
628 default:\r
629 ASSERT (FALSE);\r
630 break;\r
631 }\r
632\r
633 Address = S3_BOOT_SCRIPT_LIB_PCI_ADDRESS (Bus, Device, Function, Offset);\r
634 Status = S3BootScriptSavePciCfgWrite (Width, Address, 1, &Data);\r
635 if (EFI_ERROR (Status)) {\r
636 return Status;\r
637 }\r
638 }\r
639 }\r
640\r
0acd8df4
ED
641 Status = S3BootScriptSaveIoWrite (S3BootScriptWidthUint8, 0xB2, 1, &mSwSmiValue);\r
642 ASSERT_EFI_ERROR (Status);\r
cb274a27
ED
643\r
644 return Status;\r
645}\r
646\r
647/**\r
648 Main entry for this driver.\r
649\r
650 @param ImageHandle Image handle this driver.\r
651 @param SystemTable Pointer to SystemTable.\r
652\r
653 @retval EFI_SUCESS This function always complete successfully.\r
654\r
655**/\r
656EFI_STATUS\r
657EFIAPI\r
658OpalPasswordSmmInit (\r
659 IN EFI_HANDLE ImageHandle,\r
660 IN EFI_SYSTEM_TABLE *SystemTable\r
661 )\r
662{\r
663 EFI_STATUS Status;\r
664 EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;\r
665 EFI_SMM_SX_DISPATCH2_PROTOCOL *SxDispatch;\r
666 EFI_HANDLE SwHandle;\r
667 EFI_SMM_SW_REGISTER_CONTEXT Context;\r
668 EFI_HANDLE S3SleepEntryHandle;\r
669 EFI_SMM_SX_REGISTER_CONTEXT EntryRegisterContext;\r
670 EFI_SMM_VARIABLE_PROTOCOL *SmmVariable;\r
671 OPAL_EXTRA_INFO_VAR OpalExtraInfo;\r
672 UINTN DataSize;\r
673 EFI_PHYSICAL_ADDRESS Address;\r
674\r
675 mBuffer = NULL;\r
676 SwHandle = NULL;\r
677 S3SleepEntryHandle = NULL;\r
678 ZeroMem (&mNvmeContext, sizeof (NVME_CONTEXT));\r
679\r
680 Status = gSmst->SmmLocateProtocol (\r
681 &gEfiSmmSwDispatch2ProtocolGuid,\r
682 NULL,\r
683 (VOID **)&SwDispatch\r
684 );\r
685 ASSERT_EFI_ERROR (Status);\r
686 if (EFI_ERROR (Status)) {\r
687 DEBUG((DEBUG_ERROR, " SmmLocateProtocol gEfiSmmSwDispatch2ProtocolGuid fail, Status: %r\n", Status));\r
688 return Status;\r
689 }\r
690\r
691 Status = gSmst->SmmLocateProtocol (\r
692 &gEfiSmmSxDispatch2ProtocolGuid,\r
693 NULL,\r
694 (VOID **)&SxDispatch\r
695 );\r
696 ASSERT_EFI_ERROR (Status);\r
697 if (EFI_ERROR (Status)) {\r
698 DEBUG((DEBUG_ERROR, " SmmLocateProtocol gEfiSmmSxDispatch2ProtocolGuid fail, Status: %r\n", Status));\r
699 return Status;\r
700 }\r
701\r
702 //\r
703 // Preallocate a 512 bytes Buffer to perform trusted I/O.\r
704 // Assume this is big enough for unlock commands\r
705 // It's because DMA can not access smmram stack at the cmd execution.\r
706 //\r
707 Address = 0xFFFFFFFF;\r
708 Status = gBS->AllocatePages (\r
709 AllocateMaxAddress,\r
710 EfiACPIMemoryNVS,\r
711 EFI_SIZE_TO_PAGES (SMM_SIZE_ALLOC_BYTES),\r
712 &Address\r
713 );\r
714 if (EFI_ERROR (Status)) {\r
715 DEBUG((DEBUG_ERROR, " AllocatePages for SATA DAM fail, Status: %r\n", Status));\r
716 return EFI_OUT_OF_RESOURCES;\r
717 }\r
718\r
719 mBuffer = (VOID *)(UINTN)Address;\r
720 ZeroMem ((VOID *)(UINTN)mBuffer, SMM_SIZE_ALLOC_BYTES);\r
721\r
722 //\r
723 // Preallocate resource for AHCI transfer descriptor.\r
724 //\r
725 Status = AhciAllocateResource ();\r
726 if (EFI_ERROR (Status)) {\r
727 DEBUG((DEBUG_ERROR, " AhciAllocateResource fail, Status: %r\n", Status));\r
728 Status = EFI_OUT_OF_RESOURCES;\r
729 goto EXIT;\r
730 }\r
731\r
732 //\r
733 // Preallocate resource for NVMe configuration space.\r
734 //\r
735 Status = NvmeAllocateResource (ImageHandle, &mNvmeContext);\r
736 if (EFI_ERROR (Status)) {\r
737 DEBUG((DEBUG_ERROR, " NvmeAllocateResource fail, Status: %r\n", Status));\r
738 Status = EFI_OUT_OF_RESOURCES;\r
739 goto EXIT;\r
740 }\r
741\r
742 //\r
743 // Register a S3 entry callback function to store ATA host controller context to boot script.\r
744 // These boot scripts would be invoked at S3 path to recovery ATA host controller h/w context\r
745 // for executing HDD unlock cmd.\r
746 //\r
747 EntryRegisterContext.Type = SxS3;\r
748 EntryRegisterContext.Phase = SxEntry;\r
749 Status = SxDispatch->Register (\r
750 SxDispatch,\r
751 S3SleepEntryCallBack,\r
752 &EntryRegisterContext,\r
753 &S3SleepEntryHandle\r
754 );\r
755 ASSERT_EFI_ERROR (Status);\r
756 if (EFI_ERROR (Status)) {\r
757 goto EXIT;\r
758 }\r
759\r
760 //\r
761 // Register Opal password smm unlock handler\r
762 //\r
763 Context.SwSmiInputValue = (UINTN) -1;\r
764 Status = SwDispatch->Register (\r
765 SwDispatch,\r
766 SmmUnlockOpalPassword,\r
767 &Context,\r
768 &SwHandle\r
769 );\r
770 ASSERT_EFI_ERROR (Status);\r
771 if (EFI_ERROR (Status)) {\r
772 DEBUG((DEBUG_ERROR, " SwDispatch->Register fail, Status: %r\n", Status));\r
773 goto EXIT;\r
774 }\r
775\r
776 //\r
777 // trigger smi to unlock hdd if it's locked.\r
778 //\r
779 mSwSmiValue = (UINT8) Context.SwSmiInputValue;\r
780\r
781 Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&SmmVariable);\r
782 if (!EFI_ERROR (Status)) {\r
783 DataSize = sizeof (OPAL_EXTRA_INFO_VAR);\r
784 Status = SmmVariable->SmmGetVariable (\r
785 OPAL_EXTRA_INFO_VAR_NAME,\r
786 &gOpalExtraInfoVariableGuid,\r
787 NULL,\r
788 &DataSize,\r
789 &OpalExtraInfo\r
790 );\r
791 if (!EFI_ERROR (Status)) {\r
792 mSendBlockSID = OpalExtraInfo.EnableBlockSid;\r
793 }\r
794 }\r
795\r
796 return EFI_SUCCESS;\r
797\r
798EXIT:\r
799 if (S3SleepEntryHandle != NULL) {\r
800 SxDispatch->UnRegister (SxDispatch, S3SleepEntryHandle);\r
801 }\r
802\r
803 AhciFreeResource ();\r
804\r
805 NvmeFreeResource (&mNvmeContext);\r
806\r
807 if (mBuffer != NULL) {\r
808 gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN) mBuffer, EFI_SIZE_TO_PAGES (SMM_SIZE_ALLOC_BYTES));\r
809 }\r
810\r
811 return Status;\r
812}\r
813\r
814/**\r
815 Provide Io action support.\r
816\r
817 @param[in] SmmDev the opal device need to perform trust io.\r
818 @param[in] IoType OPAL_IO_TYPE indicating whether to perform a Trusted Send or Trusted Receive.\r
819 @param[in] SecurityProtocol Security Protocol\r
820 @param[in] SpSpecific Security Protocol Specific\r
821 @param[in] TransferLength Transfer Length of Buffer (in bytes) - always a multiple of 512\r
822 @param[in] Buffer Address of Data to transfer\r
823\r
824 @retval TcgResultSuccess Perform the io action success.\r
825 @retval TcgResultFailure Perform the io action failed.\r
826\r
827**/\r
828EFI_STATUS\r
829PerformTrustedIo (\r
830 OPAL_SMM_DEVICE *SmmDev,\r
831 OPAL_IO_TYPE IoType,\r
832 UINT8 SecurityProtocol,\r
833 UINT16 SpSpecific,\r
834 UINTN TransferLength,\r
835 VOID *Buffer\r
836 )\r
837{\r
838 EFI_STATUS Status;\r
839 UINTN BufferSizeBlocks;\r
840 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
841\r
842 Status = EFI_DEVICE_ERROR;\r
843 if (SmmDev->DeviceType == OPAL_DEVICE_TYPE_SATA) {\r
844 BufferSizeBlocks = TransferLength / 512;\r
845\r
846 ZeroMem( &AtaCommandBlock, sizeof( EFI_ATA_COMMAND_BLOCK ) );\r
847 AtaCommandBlock.AtaCommand = ( IoType == OpalSend ) ? ATA_COMMAND_TRUSTED_SEND : ATA_COMMAND_TRUSTED_RECEIVE;\r
848 AtaCommandBlock.AtaSectorCount = ( UINT8 )BufferSizeBlocks;\r
849 AtaCommandBlock.AtaSectorNumber = ( UINT8 )( BufferSizeBlocks >> 8 );\r
850 AtaCommandBlock.AtaFeatures = SecurityProtocol;\r
851 AtaCommandBlock.AtaCylinderLow = ( UINT8 )( SpSpecific >> 8 );\r
852 AtaCommandBlock.AtaCylinderHigh = ( UINT8 )( SpSpecific );\r
853 AtaCommandBlock.AtaDeviceHead = ATA_DEVICE_LBA;\r
854\r
855\r
856 ZeroMem( mBuffer, HDD_PAYLOAD );\r
857 ASSERT( TransferLength <= HDD_PAYLOAD );\r
858\r
859 if (IoType == OpalSend) {\r
860 CopyMem( mBuffer, Buffer, TransferLength );\r
861 }\r
862\r
863 Status = AhciPioTransfer(\r
864 &mAhciRegisters,\r
865 (UINT8) SmmDev->SataPort,\r
866 (UINT8) SmmDev->SataPortMultiplierPort,\r
867 NULL,\r
868 0,\r
869 ( IoType == OpalSend ) ? FALSE : TRUE, // i/o direction\r
870 &AtaCommandBlock,\r
871 NULL,\r
872 mBuffer,\r
873 (UINT32)TransferLength,\r
874 ATA_TIMEOUT\r
875 );\r
876\r
877 if (IoType == OpalRecv) {\r
878 CopyMem( Buffer, mBuffer, TransferLength );\r
879 }\r
880 } else if (SmmDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {\r
881 Status = NvmeSecuritySendReceive (\r
882 &mNvmeContext,\r
883 IoType == OpalSend,\r
884 SecurityProtocol,\r
885 SwapBytes16(SpSpecific),\r
886 TransferLength,\r
887 Buffer\r
888 );\r
889 } else {\r
890 DEBUG((DEBUG_ERROR, "DeviceType(%x) not support.\n", SmmDev->DeviceType));\r
891 }\r
892\r
893 return Status;\r
894}\r
895\r
896/**\r
897 Send a security protocol command to a device that receives data and/or the result\r
898 of one or more commands sent by SendData.\r
899\r
900 The ReceiveData function sends a security protocol command to the given MediaId.\r
901 The security protocol command sent is defined by SecurityProtocolId and contains\r
902 the security protocol specific data SecurityProtocolSpecificData. The function\r
903 returns the data from the security protocol command in PayloadBuffer.\r
904\r
905 For devices supporting the SCSI command set, the security protocol command is sent\r
906 using the SECURITY PROTOCOL IN command defined in SPC-4.\r
907\r
908 For devices supporting the ATA command set, the security protocol command is sent\r
909 using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize\r
910 is non-zero.\r
911\r
912 If the PayloadBufferSize is zero, the security protocol command is sent using the\r
913 Trusted Non-Data command defined in ATA8-ACS.\r
914\r
915 If PayloadBufferSize is too small to store the available data from the security\r
916 protocol command, the function shall copy PayloadBufferSize bytes into the\r
917 PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.\r
918\r
919 If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,\r
920 the function shall return EFI_INVALID_PARAMETER.\r
921\r
922 If the given MediaId does not support security protocol commands, the function shall\r
923 return EFI_UNSUPPORTED. If there is no media in the device, the function returns\r
924 EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,\r
925 the function returns EFI_MEDIA_CHANGED.\r
926\r
927 If the security protocol fails to complete within the Timeout period, the function\r
928 shall return EFI_TIMEOUT.\r
929\r
930 If the security protocol command completes without an error, the function shall\r
931 return EFI_SUCCESS. If the security protocol command completes with an error, the\r
932 function shall return EFI_DEVICE_ERROR.\r
933\r
934 @param This Indicates a pointer to the calling context.\r
935 @param MediaId ID of the medium to receive data from.\r
936 @param Timeout The timeout, in 100ns units, to use for the execution\r
937 of the security protocol command. A Timeout value of 0\r
938 means that this function will wait indefinitely for the\r
939 security protocol command to execute. If Timeout is greater\r
940 than zero, then this function will return EFI_TIMEOUT\r
941 if the time required to execute the receive data command\r
942 is greater than Timeout.\r
943 @param SecurityProtocolId The value of the "Security Protocol" parameter of\r
944 the security protocol command to be sent.\r
945 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
946 of the security protocol command to be sent.\r
947 @param PayloadBufferSize Size in bytes of the payload data buffer.\r
948 @param PayloadBuffer A pointer to a destination buffer to store the security\r
949 protocol command specific payload data for the security\r
950 protocol command. The caller is responsible for having\r
951 either implicit or explicit ownership of the buffer.\r
952 @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the\r
953 data written to the payload data buffer.\r
954\r
955 @retval EFI_SUCCESS The security protocol command completed successfully.\r
956 @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available\r
957 data from the device. The PayloadBuffer contains the truncated data.\r
958 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.\r
959 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.\r
960 @retval EFI_NO_MEDIA There is no media in the device.\r
961 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
962 @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and\r
963 PayloadBufferSize is non-zero.\r
964 @retval EFI_TIMEOUT A timeout occurred while waiting for the security\r
965 protocol command to execute.\r
966\r
967**/\r
968EFI_STATUS\r
969EFIAPI\r
970SecurityReceiveData (\r
971 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,\r
972 IN UINT32 MediaId,\r
973 IN UINT64 Timeout,\r
974 IN UINT8 SecurityProtocolId,\r
975 IN UINT16 SecurityProtocolSpecificData,\r
976 IN UINTN PayloadBufferSize,\r
977 OUT VOID *PayloadBuffer,\r
978 OUT UINTN *PayloadTransferSize\r
979 )\r
980{\r
981 OPAL_SMM_DEVICE *SmmDev;\r
982\r
983 SmmDev = OPAL_SMM_DEVICE_FROM_THIS (This);\r
984 if (SmmDev == NULL) {\r
985 return EFI_DEVICE_ERROR;\r
986 }\r
987\r
988 return PerformTrustedIo (\r
989 SmmDev,\r
990 OpalRecv,\r
991 SecurityProtocolId,\r
992 SecurityProtocolSpecificData,\r
993 PayloadBufferSize,\r
994 PayloadBuffer\r
995 );\r
996}\r
997\r
998/**\r
999 Send a security protocol command to a device.\r
1000\r
1001 The SendData function sends a security protocol command containing the payload\r
1002 PayloadBuffer to the given MediaId. The security protocol command sent is\r
1003 defined by SecurityProtocolId and contains the security protocol specific data\r
1004 SecurityProtocolSpecificData. If the underlying protocol command requires a\r
1005 specific padding for the command payload, the SendData function shall add padding\r
1006 bytes to the command payload to satisfy the padding requirements.\r
1007\r
1008 For devices supporting the SCSI command set, the security protocol command is sent\r
1009 using the SECURITY PROTOCOL OUT command defined in SPC-4.\r
1010\r
1011 For devices supporting the ATA command set, the security protocol command is sent\r
1012 using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize\r
1013 is non-zero. If the PayloadBufferSize is zero, the security protocol command is\r
1014 sent using the Trusted Non-Data command defined in ATA8-ACS.\r
1015\r
1016 If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall\r
1017 return EFI_INVALID_PARAMETER.\r
1018\r
1019 If the given MediaId does not support security protocol commands, the function\r
1020 shall return EFI_UNSUPPORTED. If there is no media in the device, the function\r
1021 returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the\r
1022 device, the function returns EFI_MEDIA_CHANGED.\r
1023\r
1024 If the security protocol fails to complete within the Timeout period, the function\r
1025 shall return EFI_TIMEOUT.\r
1026\r
1027 If the security protocol command completes without an error, the function shall return\r
1028 EFI_SUCCESS. If the security protocol command completes with an error, the function\r
1029 shall return EFI_DEVICE_ERROR.\r
1030\r
1031 @param This Indicates a pointer to the calling context.\r
1032 @param MediaId ID of the medium to receive data from.\r
1033 @param Timeout The timeout, in 100ns units, to use for the execution\r
1034 of the security protocol command. A Timeout value of 0\r
1035 means that this function will wait indefinitely for the\r
1036 security protocol command to execute. If Timeout is greater\r
1037 than zero, then this function will return EFI_TIMEOUT\r
1038 if the time required to execute the send data command\r
1039 is greater than Timeout.\r
1040 @param SecurityProtocolId The value of the "Security Protocol" parameter of\r
1041 the security protocol command to be sent.\r
1042 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
1043 of the security protocol command to be sent.\r
1044 @param PayloadBufferSize Size in bytes of the payload data buffer.\r
1045 @param PayloadBuffer A pointer to a destination buffer to store the security\r
1046 protocol command specific payload data for the security\r
1047 protocol command.\r
1048\r
1049 @retval EFI_SUCCESS The security protocol command completed successfully.\r
1050 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.\r
1051 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.\r
1052 @retval EFI_NO_MEDIA There is no media in the device.\r
1053 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
1054 @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.\r
1055 @retval EFI_TIMEOUT A timeout occurred while waiting for the security\r
1056 protocol command to execute.\r
1057\r
1058**/\r
1059EFI_STATUS\r
1060EFIAPI\r
1061SecuritySendData (\r
1062 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,\r
1063 IN UINT32 MediaId,\r
1064 IN UINT64 Timeout,\r
1065 IN UINT8 SecurityProtocolId,\r
1066 IN UINT16 SecurityProtocolSpecificData,\r
1067 IN UINTN PayloadBufferSize,\r
1068 IN VOID *PayloadBuffer\r
1069 )\r
1070{\r
1071 OPAL_SMM_DEVICE *SmmDev;\r
1072\r
1073 SmmDev = OPAL_SMM_DEVICE_FROM_THIS (This);\r
1074 if (SmmDev == NULL) {\r
1075 return EFI_DEVICE_ERROR;\r
1076 }\r
1077\r
1078 return PerformTrustedIo (\r
1079 SmmDev,\r
1080 OpalSend,\r
1081 SecurityProtocolId,\r
1082 SecurityProtocolSpecificData,\r
1083 PayloadBufferSize,\r
1084 PayloadBuffer\r
1085 );\r
1086\r
1087}\r
1088\r