Home | History | Annotate | Download | only in OpalPasswordSmm
      1 /** @file
      2   Opal password smm driver which is used to support Opal security feature at s3 path.
      3 
      4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "OpalPasswordSmm.h"
     16 
     17 #define SMM_SIZE_ALLOC_BYTES                      (512)
     18 #define RESPONSE_SIZE                             (200)
     19 
     20 #define PCI_CLASS_MASS_STORAGE_AHCI               (0x06)
     21 
     22 #define OPAL_PCIE_ROOTPORT_SAVESIZE               (0x40)
     23 #define STORE_INVALID_ROOTPORT_INDEX              ((UINT8) -1)
     24 #define OPAL_DEVICE_TYPE_SATA                     0x1
     25 #define OPAL_DEVICE_TYPE_NVME                     0x2
     26 #define OPAL_DEVICE_TYPE_UNKNOWN                  0xFF
     27 
     28 //
     29 // To unlock the Intel SATA controller at S3 Resume, restored the following registers.
     30 //
     31 const OPAL_HC_PCI_REGISTER_SAVE mSataHcRegisterSaveTemplate[] = {
     32   {0x9,  S3BootScriptWidthUint8},
     33   {0x10, S3BootScriptWidthUint32},
     34   {0x14, S3BootScriptWidthUint32},
     35   {0x18, S3BootScriptWidthUint32},
     36   {0x1C, S3BootScriptWidthUint32},
     37   {0x20, S3BootScriptWidthUint32},
     38   {0x24, S3BootScriptWidthUint32},
     39   {0x3c, S3BootScriptWidthUint8},
     40   {0x3d, S3BootScriptWidthUint8},
     41   {0x40, S3BootScriptWidthUint16},
     42   {0x42, S3BootScriptWidthUint16},
     43   {0x92, S3BootScriptWidthUint16},
     44   {0x94, S3BootScriptWidthUint32},
     45   {0x9C, S3BootScriptWidthUint32},
     46   {0x4,  S3BootScriptWidthUint16},
     47 };
     48 
     49 
     50 UINT8                mSwSmiValue;
     51 LIST_ENTRY           *mOpalDeviceList;
     52 LIST_ENTRY           mSmmDeviceList  = INITIALIZE_LIST_HEAD_VARIABLE (mSmmDeviceList);
     53 
     54 BOOLEAN              mSendBlockSID   = FALSE;
     55 
     56 // AHCI
     57 UINT32               mAhciBar = 0;
     58 EFI_AHCI_REGISTERS   mAhciRegisters;
     59 VOID                 *mBuffer = NULL; // DMA can not read/write Data to smram, so we pre-allocates Buffer from AcpiNVS.
     60 //
     61 // NVME
     62 NVME_CONTEXT         mNvmeContext;
     63 
     64 EFI_GCD_MEMORY_SPACE_DESCRIPTOR   *mGcdMemSpace        = NULL;
     65 UINTN                             mNumberOfDescriptors = 0;
     66 
     67 /**
     68   Add new bridge node or nvme device info to the device list.
     69 
     70   @param[in]       BusNum        The bus number.
     71   @param[in]       DevNum        The device number.
     72   @param[in]       FuncNum       The function number.
     73   @param[in]       Dev           The device which need to add device node info.
     74 
     75 **/
     76 VOID
     77 AddPciDeviceNode (
     78   UINT32                  BusNum,
     79   UINT32                  DevNum,
     80   UINT32                  FuncNum,
     81   OPAL_SMM_DEVICE         *Dev
     82   )
     83 {
     84   UINT8       *DevList;
     85   PCI_DEVICE  *DeviceNode;
     86 
     87   DevList = AllocateZeroPool (sizeof (PCI_DEVICE) + Dev->Length);
     88   ASSERT (DevList != NULL);
     89 
     90   if (Dev->Length != 0) {
     91     CopyMem (DevList, Dev->PciBridgeNode, Dev->Length);
     92     FreePool (Dev->PciBridgeNode);
     93   }
     94 
     95   DeviceNode = (PCI_DEVICE *) (DevList + Dev->Length);
     96 
     97   DeviceNode->BusNum  = BusNum;
     98   DeviceNode->DevNum  = DevNum;
     99   DeviceNode->FuncNum = FuncNum;
    100 
    101   Dev->Length += sizeof (PCI_DEVICE);
    102   Dev->PciBridgeNode = (PCI_DEVICE *)DevList;
    103 }
    104 
    105 /**
    106   Extract device info from the input device path.
    107 
    108   @param[in]       DevicePath        Device path info for the device.
    109   @param[in,out]   Dev               The device which new inputed.
    110 
    111 **/
    112 VOID
    113 ExtractDeviceInfoFromDevicePath (
    114   IN     EFI_DEVICE_PATH_PROTOCOL    *DevicePath,
    115   IN OUT OPAL_SMM_DEVICE             *Dev
    116   )
    117 {
    118   EFI_DEVICE_PATH_PROTOCOL      *TmpDevPath;
    119   EFI_DEVICE_PATH_PROTOCOL      *TmpDevPath2;
    120   PCI_DEVICE_PATH               *PciDevPath;
    121   SATA_DEVICE_PATH              *SataDevPath;
    122   NVME_NAMESPACE_DEVICE_PATH    *NvmeDevPath;
    123   UINTN                         BusNum;
    124 
    125   TmpDevPath = DevicePath;
    126   Dev->DeviceType = OPAL_DEVICE_TYPE_UNKNOWN;
    127 
    128   while (!IsDevicePathEnd(TmpDevPath)) {
    129     if (TmpDevPath->Type == MESSAGING_DEVICE_PATH && TmpDevPath->SubType == MSG_SATA_DP) {
    130       //
    131       // SATA
    132       //
    133       SataDevPath = ( SATA_DEVICE_PATH* )TmpDevPath;
    134       Dev->SataPort = SataDevPath->HBAPortNumber;
    135       Dev->SataPortMultiplierPort = SataDevPath->PortMultiplierPortNumber;
    136       Dev->DeviceType = OPAL_DEVICE_TYPE_SATA;
    137       break;
    138     } else if (TmpDevPath->Type == MESSAGING_DEVICE_PATH && TmpDevPath->SubType == MSG_NVME_NAMESPACE_DP) {
    139       //
    140       // NVMe
    141       //
    142       NvmeDevPath = ( NVME_NAMESPACE_DEVICE_PATH* )TmpDevPath;
    143       Dev->NvmeNamespaceId = NvmeDevPath->NamespaceId;
    144       Dev->DeviceType = OPAL_DEVICE_TYPE_NVME;
    145       break;
    146     }
    147     TmpDevPath = NextDevicePathNode (TmpDevPath);
    148   }
    149 
    150   //
    151   // Get bridge node info for the nvme device.
    152   //
    153   BusNum = 0;
    154   TmpDevPath = DevicePath;
    155   TmpDevPath2 = NextDevicePathNode (DevicePath);
    156   while (!IsDevicePathEnd(TmpDevPath2)) {
    157     if (TmpDevPath->Type == HARDWARE_DEVICE_PATH && TmpDevPath->SubType == HW_PCI_DP) {
    158       PciDevPath = (PCI_DEVICE_PATH *) TmpDevPath;
    159       if ((TmpDevPath2->Type == MESSAGING_DEVICE_PATH && TmpDevPath2->SubType == MSG_NVME_NAMESPACE_DP)||
    160           (TmpDevPath2->Type == MESSAGING_DEVICE_PATH && TmpDevPath2->SubType == MSG_SATA_DP)) {
    161         Dev->BusNum = (UINT32)BusNum;
    162         Dev->DevNum = PciDevPath->Device;
    163         Dev->FuncNum = PciDevPath->Function;
    164       } else {
    165         AddPciDeviceNode((UINT32)BusNum, PciDevPath->Device, PciDevPath->Function, Dev);
    166         if (TmpDevPath2->Type == HARDWARE_DEVICE_PATH && TmpDevPath2->SubType == HW_PCI_DP) {
    167           BusNum = PciRead8 (PCI_LIB_ADDRESS (BusNum, PciDevPath->Device, PciDevPath->Function, NVME_PCIE_SEC_BNUM));
    168         }
    169       }
    170     }
    171 
    172     TmpDevPath  = NextDevicePathNode (TmpDevPath);
    173     TmpDevPath2 = NextDevicePathNode (TmpDevPath2);
    174   }
    175 }
    176 
    177 /**
    178 
    179   The function returns whether or not the device is Opal Locked.
    180   TRUE means that the device is partially or fully locked.
    181   This will perform a Level 0 Discovery and parse the locking feature descriptor
    182 
    183   @param[in]      OpalDev             Opal object to determine if locked
    184   @param[out]     BlockSidSupported   Whether device support BlockSid feature.
    185 
    186 **/
    187 BOOLEAN
    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
    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
    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
    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
    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
    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
    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
    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
    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
   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
   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