• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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