Home | History | Annotate | Download | only in OpalPasswordDxe
      1 /** @file
      2   Entrypoint of Opal UEFI Driver and contains all the logic to
      3   register for new Opal device instances.
      4 
      5 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 // This UEFI driver consumes EFI_STORAGE_SECURITY_PROTOCOL instances and installs an
     17 // HII GUI to manage Opal features if the device is Opal capable
     18 // If the Opal device is being managed by the UEFI Driver, it shall provide a popup
     19 // window during boot requesting a user password
     20 
     21 #include "OpalDriver.h"
     22 #include "OpalDriverPrivate.h"
     23 #include "OpalHii.h"
     24 
     25 OPAL_DRIVER mOpalDriver;
     26 
     27 #define MAX_PASSWORD_SIZE        32
     28 #define MAX_PASSWORD_TRY_COUNT   5
     29 
     30 //
     31 // Globals
     32 //
     33 EFI_DRIVER_BINDING_PROTOCOL gOpalDriverBinding = {
     34   OpalEfiDriverBindingSupported,
     35   OpalEfiDriverBindingStart,
     36   OpalEfiDriverBindingStop,
     37   0x1b,
     38   NULL,
     39   NULL
     40 };
     41 
     42 
     43 /**
     44   Add new device to the global device list.
     45 
     46   @param Dev             New create device.
     47 
     48 **/
     49 VOID
     50 AddDeviceToTail(
     51   IN OPAL_DRIVER_DEVICE    *Dev
     52   )
     53 {
     54   OPAL_DRIVER_DEVICE                *TmpDev;
     55 
     56   if (mOpalDriver.DeviceList == NULL) {
     57     mOpalDriver.DeviceList = Dev;
     58   } else {
     59     TmpDev = mOpalDriver.DeviceList;
     60     while (TmpDev->Next != NULL) {
     61       TmpDev = TmpDev->Next;
     62     }
     63 
     64     TmpDev->Next = Dev;
     65   }
     66 }
     67 
     68 /**
     69   Remove one device in the global device list.
     70 
     71   @param Dev             The device need to be removed.
     72 
     73 **/
     74 VOID
     75 RemoveDevice (
     76   IN OPAL_DRIVER_DEVICE    *Dev
     77   )
     78 {
     79   OPAL_DRIVER_DEVICE                *TmpDev;
     80 
     81   if (mOpalDriver.DeviceList == NULL) {
     82     return;
     83   }
     84 
     85   if (mOpalDriver.DeviceList == Dev) {
     86     mOpalDriver.DeviceList = NULL;
     87     return;
     88   }
     89 
     90   TmpDev = mOpalDriver.DeviceList;
     91   while (TmpDev->Next != NULL) {
     92     if (TmpDev->Next == Dev) {
     93       TmpDev->Next = Dev->Next;
     94       break;
     95     }
     96   }
     97 }
     98 
     99 /**
    100   Get current device count.
    101 
    102   @retval  return the current created device count.
    103 
    104 **/
    105 UINT8
    106 GetDeviceCount (
    107   VOID
    108   )
    109 {
    110   UINT8                Count;
    111   OPAL_DRIVER_DEVICE   *TmpDev;
    112 
    113   Count = 0;
    114   TmpDev = mOpalDriver.DeviceList;
    115 
    116   while (TmpDev != NULL) {
    117     Count++;
    118     TmpDev = TmpDev->Next;
    119   }
    120 
    121   return Count;
    122 }
    123 
    124 /**
    125   Get password input from the popup windows, and unlock the device.
    126 
    127   @param[in]       Dev          The device which need to be unlock.
    128   @param[out]      PressEsc     Whether user escape function through Press ESC.
    129 
    130   @retval   Password string if success. NULL if failed.
    131 
    132 **/
    133 CHAR8 *
    134 OpalDriverPopUpHddPassword (
    135   IN  OPAL_DRIVER_DEVICE         *Dev,
    136   OUT BOOLEAN                    *PressEsc
    137   )
    138 {
    139   EFI_INPUT_KEY                InputKey;
    140   UINTN                        InputLength;
    141   CHAR16                       Mask[MAX_PASSWORD_SIZE + 1];
    142   CHAR16                       Unicode[MAX_PASSWORD_SIZE + 1];
    143   CHAR8                        *Ascii;
    144   CHAR16                       *PopUpString;
    145   UINTN                        StrLength;
    146 
    147   ZeroMem(Unicode, sizeof(Unicode));
    148   ZeroMem(Mask, sizeof(Mask));
    149 
    150   StrLength = StrLen(Dev->Name16);
    151   PopUpString = (CHAR16*) AllocateZeroPool ((8 + StrLength) * 2);
    152   *PressEsc = FALSE;
    153 
    154   if (Dev->Name16 == NULL) {
    155     UnicodeSPrint(PopUpString, StrLen(L"Unlock Disk") + 1, L"Unlock Disk");
    156   } else {
    157     UnicodeSPrint(PopUpString, StrLen(L"Unlock ") + StrLength + 1, L"Unlock %s", Dev->Name16);
    158   }
    159 
    160   gST->ConOut->ClearScreen(gST->ConOut);
    161 
    162   InputLength = 0;
    163   while (TRUE) {
    164     Mask[InputLength] = L'_';
    165     CreatePopUp(
    166         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
    167         &InputKey,
    168         PopUpString,
    169         L"---------------------",
    170         Mask,
    171         NULL
    172     );
    173 
    174     //
    175     // Check key.
    176     //
    177     if (InputKey.ScanCode == SCAN_NULL) {
    178       //
    179       // password finished
    180       //
    181       if (InputKey.UnicodeChar == CHAR_CARRIAGE_RETURN) {
    182         //
    183         // Add the null terminator.
    184         //
    185         Unicode[InputLength] = 0;
    186         InputLength++;
    187         break;
    188       } else if ((InputKey.UnicodeChar == CHAR_NULL) ||
    189                  (InputKey.UnicodeChar == CHAR_TAB) ||
    190                  (InputKey.UnicodeChar == CHAR_LINEFEED)
    191                 ) {
    192         continue;
    193       } else {
    194         //
    195         // delete last key entered
    196         //
    197         if (InputKey.UnicodeChar == CHAR_BACKSPACE) {
    198           if (InputLength > 0) {
    199             Unicode[InputLength] = 0;
    200             Mask[InputLength] = 0;
    201             InputLength--;
    202           }
    203         } else {
    204           //
    205           // add Next key entry
    206           //
    207           Unicode[InputLength] = InputKey.UnicodeChar;
    208           Mask[InputLength] = L'*';
    209           InputLength++;
    210           if (InputLength == MAX_PASSWORD_SIZE) {
    211             //
    212             // Add the null terminator.
    213             //
    214             Unicode[InputLength] = 0;
    215             Mask[InputLength] = 0;
    216             break;
    217           }
    218         }
    219       }
    220     }
    221 
    222     //
    223     // exit on ESC
    224     //
    225     if (InputKey.ScanCode == SCAN_ESC) {
    226       *PressEsc = TRUE;
    227       break;
    228     }
    229   }
    230 
    231   gST->ConOut->ClearScreen(gST->ConOut);
    232 
    233   if (InputLength == 0 || InputKey.ScanCode == SCAN_ESC) {
    234     return NULL;
    235   }
    236 
    237   Ascii = AllocateZeroPool (MAX_PASSWORD_SIZE + 1);
    238   if (Ascii == NULL) {
    239     return NULL;
    240   }
    241 
    242   UnicodeStrToAsciiStrS (Unicode, Ascii, MAX_PASSWORD_SIZE + 1);
    243   ZeroMem (Unicode, sizeof (Unicode));
    244 
    245   return Ascii;
    246 }
    247 
    248 /**
    249   Check if disk is locked, show popup window and ask for password if it is
    250 
    251   @param[in]       Dev          The device which need to be unlock.
    252 
    253 **/
    254 VOID
    255 OpalDriverRequestPassword (
    256   OPAL_DRIVER_DEVICE       *Dev
    257   )
    258 {
    259   UINT8               Count;
    260   BOOLEAN             IsEnabled;
    261   CHAR8               *Password;
    262   UINT32              PasswordLen;
    263   TCG_RESULT          Ret;
    264   EFI_INPUT_KEY       Key;
    265   OPAL_SESSION        Session;
    266   BOOLEAN             PressEsc;
    267   BOOLEAN             Locked;
    268 
    269   if (Dev == NULL) {
    270     return;
    271   }
    272 
    273   Count = 0;
    274 
    275   IsEnabled = OpalFeatureEnabled (&Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.LockingFeature);
    276   if (IsEnabled) {
    277     ZeroMem(&Session, sizeof(Session));
    278     Session.Sscp = Dev->OpalDisk.Sscp;
    279     Session.MediaId = Dev->OpalDisk.MediaId;
    280     Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;
    281 
    282     Locked = OpalDeviceLocked (&Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.LockingFeature);
    283 
    284     while (Count < MAX_PASSWORD_TRY_COUNT) {
    285       Password = OpalDriverPopUpHddPassword (Dev, &PressEsc);
    286       if (PressEsc) {
    287         if (Locked) {
    288           //
    289           // Current device in the lock status and
    290           // User not input password and press ESC,
    291           // keep device in lock status and continue boot.
    292           //
    293           do {
    294             CreatePopUp (
    295                     EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
    296                     &Key,
    297                     L"Press ENTER to skip password, Press ESC to input password",
    298                     NULL
    299                     );
    300           } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));
    301 
    302           if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
    303             gST->ConOut->ClearScreen(gST->ConOut);
    304             //
    305             // Keep lock and continue boot.
    306             //
    307             return;
    308           } else {
    309             //
    310             // Let user input password again.
    311             //
    312             continue;
    313           }
    314         } else {
    315           //
    316           // Current device in the unlock status and
    317           // User not input password and press ESC,
    318           // Shutdown the device.
    319           //
    320           do {
    321             CreatePopUp (
    322                     EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
    323                     &Key,
    324                     L"Press ENTER to shutdown, Press ESC to input password",
    325                     NULL
    326                     );
    327           } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));
    328 
    329           if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
    330             gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);
    331           } else {
    332             //
    333             // Let user input password again.
    334             //
    335             continue;
    336           }
    337         }
    338       }
    339 
    340       if (Password == NULL) {
    341         Count ++;
    342         continue;
    343       }
    344       PasswordLen = (UINT32) AsciiStrLen(Password);
    345 
    346       if (Locked) {
    347         Ret = OpalSupportUnlock(&Session, Password, PasswordLen, Dev->OpalDevicePath);
    348       } else {
    349         Ret = OpalSupportLock(&Session, Password, PasswordLen, Dev->OpalDevicePath);
    350         if (Ret == TcgResultSuccess) {
    351           Ret = OpalSupportUnlock(&Session, Password, PasswordLen, Dev->OpalDevicePath);
    352         }
    353       }
    354 
    355       if (Password != NULL) {
    356         ZeroMem (Password, PasswordLen);
    357         FreePool (Password);
    358       }
    359 
    360       if (Ret == TcgResultSuccess) {
    361         break;
    362       }
    363 
    364       Count++;
    365 
    366       do {
    367         CreatePopUp (
    368                   EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
    369                   &Key,
    370                   L"Invalid password.",
    371                   L"Press ENTER to retry",
    372                   NULL
    373                   );
    374       } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
    375     }
    376 
    377     if (Count >= MAX_PASSWORD_TRY_COUNT) {
    378       do {
    379         CreatePopUp (
    380                 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
    381                 &Key,
    382                 L"Opal password retry count exceeds the limit. Must shutdown!",
    383                 L"Press ENTER to shutdown",
    384                 NULL
    385                 );
    386       } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
    387 
    388       gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);
    389     }
    390   }
    391 }
    392 
    393 /**
    394   Get devcie list info.
    395 
    396   @retval     return the device list pointer.
    397 **/
    398 OPAL_DRIVER_DEVICE*
    399 OpalDriverGetDeviceList(
    400   VOID
    401   )
    402 {
    403   return mOpalDriver.DeviceList;
    404 }
    405 
    406 /**
    407   ReadyToBoot callback to send BlockSid command.
    408 
    409   @param  Event   Pointer to this event
    410   @param  Context Event handler private Data
    411 
    412 **/
    413 VOID
    414 EFIAPI
    415 ReadyToBootCallback (
    416   IN EFI_EVENT        Event,
    417   IN VOID             *Context
    418   )
    419 {
    420   OPAL_DRIVER_DEVICE                         *Itr;
    421   TCG_RESULT                                 Result;
    422   OPAL_SESSION                               Session;
    423   UINT32                                     PpStorageFlag;
    424 
    425   gBS->CloseEvent (Event);
    426 
    427   PpStorageFlag = Tcg2PhysicalPresenceLibGetManagementFlags ();
    428   if ((PpStorageFlag & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID) != 0) {
    429     //
    430     // Send BlockSID command to each Opal disk
    431     //
    432     Itr = mOpalDriver.DeviceList;
    433     while (Itr != NULL) {
    434       if (Itr->OpalDisk.SupportedAttributes.BlockSid) {
    435         ZeroMem(&Session, sizeof(Session));
    436         Session.Sscp = Itr->OpalDisk.Sscp;
    437         Session.MediaId = Itr->OpalDisk.MediaId;
    438         Session.OpalBaseComId = Itr->OpalDisk.OpalBaseComId;
    439 
    440         Result = OpalBlockSid (&Session, TRUE);  // HardwareReset must always be TRUE
    441         if (Result != TcgResultSuccess) {
    442           DEBUG ((DEBUG_ERROR, "OpalBlockSid fail\n"));
    443           break;
    444         }
    445       }
    446 
    447       Itr = Itr->Next;
    448     }
    449   }
    450 }
    451 
    452 /**
    453   Stop this Controller.
    454 
    455   @param  Dev               The device need to be stopped.
    456 
    457 **/
    458 VOID
    459 OpalDriverStopDevice (
    460   OPAL_DRIVER_DEVICE     *Dev
    461   )
    462 {
    463   //
    464   // free each name
    465   //
    466   FreePool(Dev->Name16);
    467 
    468   //
    469   // remove OPAL_DRIVER_DEVICE from the list
    470   // it updates the controllerList pointer
    471   //
    472   RemoveDevice(Dev);
    473 
    474   //
    475   // close protocols that were opened
    476   //
    477   gBS->CloseProtocol(
    478     Dev->Handle,
    479     &gEfiStorageSecurityCommandProtocolGuid,
    480     gOpalDriverBinding.DriverBindingHandle,
    481     Dev->Handle
    482     );
    483 
    484   gBS->CloseProtocol(
    485     Dev->Handle,
    486     &gEfiBlockIoProtocolGuid,
    487     gOpalDriverBinding.DriverBindingHandle,
    488     Dev->Handle
    489     );
    490 
    491   FreePool(Dev);
    492 }
    493 
    494 /**
    495   Get devcie name through the component name protocol.
    496 
    497   @param[in]       AllHandlesBuffer   The handle buffer for current system.
    498   @param[in]       NumAllHandles      The number of handles for the handle buffer.
    499   @param[in]       Dev                The device which need to get name.
    500   @param[in]       UseComp1           Whether use component name or name2 protocol.
    501 
    502   @retval     TRUE        Find the name for this device.
    503   @retval     FALSE       Not found the name for this device.
    504 **/
    505 BOOLEAN
    506 OpalDriverGetDeviceNameByProtocol(
    507   EFI_HANDLE             *AllHandlesBuffer,
    508   UINTN                  NumAllHandles,
    509   OPAL_DRIVER_DEVICE     *Dev,
    510   BOOLEAN                UseComp1
    511   )
    512 {
    513   EFI_HANDLE*                   ProtocolHandlesBuffer;
    514   UINTN                         NumProtocolHandles;
    515   EFI_STATUS                    Status;
    516   EFI_COMPONENT_NAME2_PROTOCOL* Cnp1_2; // efi component name and componentName2 have same layout
    517   EFI_GUID                      Protocol;
    518   UINTN                         StrLength;
    519   EFI_DEVICE_PATH_PROTOCOL*     TmpDevPath;
    520   UINTN                         Index1;
    521   UINTN                         Index2;
    522   EFI_HANDLE                    TmpHandle;
    523   CHAR16                        *DevName;
    524 
    525   if (Dev == NULL || AllHandlesBuffer == NULL || NumAllHandles == 0) {
    526     return FALSE;
    527   }
    528 
    529   Protocol = UseComp1 ? gEfiComponentNameProtocolGuid : gEfiComponentName2ProtocolGuid;
    530 
    531   //
    532   // Find all EFI_HANDLES with protocol
    533   //
    534   Status = gBS->LocateHandleBuffer(
    535                ByProtocol,
    536                &Protocol,
    537                NULL,
    538                &NumProtocolHandles,
    539                &ProtocolHandlesBuffer
    540                );
    541   if (EFI_ERROR(Status)) {
    542     return FALSE;
    543   }
    544 
    545 
    546   //
    547   // Exit early if no supported devices
    548   //
    549   if (NumProtocolHandles == 0) {
    550     return FALSE;
    551   }
    552 
    553   //
    554   // Get printable name by iterating through all protocols
    555   // using the handle as the child, and iterate through all handles for the controller
    556   // exit loop early once found, if not found, then delete device
    557   // storage security protocol instances already exist, add them to internal list
    558   //
    559   Status = EFI_DEVICE_ERROR;
    560   for (Index1 = 0; Index1 < NumProtocolHandles; Index1++) {
    561     DevName = NULL;
    562 
    563     if (Dev->Name16 != NULL) {
    564       return TRUE;
    565     }
    566 
    567     TmpHandle = ProtocolHandlesBuffer[Index1];
    568 
    569     Status = gBS->OpenProtocol(
    570                  TmpHandle,
    571                  &Protocol,
    572                  (VOID**)&Cnp1_2,
    573                  gImageHandle,
    574                  NULL,
    575                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
    576                  );
    577     if (EFI_ERROR(Status) || Cnp1_2 == NULL) {
    578       continue;
    579     }
    580 
    581     //
    582     // Use all handles array as controller handle
    583     //
    584     for (Index2 = 0; Index2 < NumAllHandles; Index2++) {
    585       Status = Cnp1_2->GetControllerName(
    586                    Cnp1_2,
    587                    AllHandlesBuffer[Index2],
    588                    Dev->Handle,
    589                    LANGUAGE_ISO_639_2_ENGLISH,
    590                    &DevName
    591                    );
    592       if (EFI_ERROR(Status)) {
    593         Status = Cnp1_2->GetControllerName(
    594                      Cnp1_2,
    595                      AllHandlesBuffer[Index2],
    596                      Dev->Handle,
    597                      LANGUAGE_RFC_3066_ENGLISH,
    598                      &DevName
    599                      );
    600       }
    601       if (!EFI_ERROR(Status) && DevName != NULL) {
    602         StrLength = StrLen(DevName) + 1;        // Add one for NULL terminator
    603         Dev->Name16 = AllocateZeroPool(StrLength * sizeof (CHAR16));
    604         ASSERT (Dev->Name16 != NULL);
    605         StrCpyS (Dev->Name16, StrLength, DevName);
    606         Dev->NameZ = (CHAR8*)AllocateZeroPool(StrLength);
    607         UnicodeStrToAsciiStrS (DevName, Dev->NameZ, StrLength);
    608 
    609         //
    610         // Retrieve bridge BDF info and port number or namespace depending on type
    611         //
    612         TmpDevPath = NULL;
    613         Status = gBS->OpenProtocol(
    614             Dev->Handle,
    615             &gEfiDevicePathProtocolGuid,
    616             (VOID**)&TmpDevPath,
    617             gImageHandle,
    618             NULL,
    619             EFI_OPEN_PROTOCOL_GET_PROTOCOL
    620             );
    621         if (!EFI_ERROR(Status)) {
    622           Dev->OpalDevicePath = DuplicateDevicePath (TmpDevPath);
    623           return TRUE;
    624         }
    625 
    626         if (Dev->Name16 != NULL) {
    627           FreePool(Dev->Name16);
    628           Dev->Name16 = NULL;
    629         }
    630         if (Dev->NameZ != NULL) {
    631           FreePool(Dev->NameZ);
    632           Dev->NameZ = NULL;
    633         }
    634       }
    635     }
    636   }
    637 
    638   return FALSE;
    639 }
    640 
    641 /**
    642   Get devcie name through the component name protocol.
    643 
    644   @param[in]       Dev                The device which need to get name.
    645 
    646   @retval     TRUE        Find the name for this device.
    647   @retval     FALSE       Not found the name for this device.
    648 **/
    649 BOOLEAN
    650 OpalDriverGetDriverDeviceName(
    651   OPAL_DRIVER_DEVICE          *Dev
    652   )
    653 {
    654   EFI_HANDLE*                  AllHandlesBuffer;
    655   UINTN                        NumAllHandles;
    656   EFI_STATUS                   Status;
    657 
    658   if (Dev == NULL) {
    659     DEBUG((DEBUG_ERROR | DEBUG_INIT, "OpalDriverGetDriverDeviceName Exiting, Dev=NULL\n"));
    660     return FALSE;
    661   }
    662 
    663   //
    664   // Iterate through ComponentName2 handles to get name, if fails, try ComponentName
    665   //
    666   if (Dev->Name16 == NULL) {
    667     DEBUG((DEBUG_ERROR | DEBUG_INIT, "Name is null, update it\n"));
    668     //
    669     // Find all EFI_HANDLES
    670     //
    671     Status = gBS->LocateHandleBuffer(
    672                  AllHandles,
    673                  NULL,
    674                  NULL,
    675                  &NumAllHandles,
    676                  &AllHandlesBuffer
    677                  );
    678     if (EFI_ERROR(Status)) {
    679       DEBUG ((DEBUG_INFO, "LocateHandleBuffer for AllHandles failed %r\n", Status ));
    680       return FALSE;
    681     }
    682 
    683     //
    684     // Try component Name2
    685     //
    686     if (!OpalDriverGetDeviceNameByProtocol(AllHandlesBuffer, NumAllHandles, Dev, FALSE)) {
    687       DEBUG((DEBUG_ERROR | DEBUG_INIT, "ComponentName2 failed to get device name, try ComponentName\n"));
    688       if (!OpalDriverGetDeviceNameByProtocol(AllHandlesBuffer, NumAllHandles, Dev, TRUE)) {
    689         DEBUG((DEBUG_ERROR | DEBUG_INIT, "ComponentName failed to get device name, skip device\n"));
    690         return FALSE;
    691       }
    692     }
    693   }
    694 
    695   return TRUE;
    696 }
    697 
    698 /**
    699   Main entry for this driver.
    700 
    701   @param ImageHandle     Image Handle this driver.
    702   @param SystemTable     Pointer to SystemTable.
    703 
    704   @retval EFI_SUCESS     This function always complete successfully.
    705 **/
    706 EFI_STATUS
    707 EFIAPI
    708 EfiDriverEntryPoint(
    709   IN EFI_HANDLE         ImageHandle,
    710   IN EFI_SYSTEM_TABLE*  SystemTable
    711   )
    712 {
    713   EFI_STATUS                     Status;
    714   EFI_EVENT                      ReadyToBootEvent;
    715 
    716   Status = EfiLibInstallDriverBindingComponentName2 (
    717              ImageHandle,
    718              SystemTable,
    719              &gOpalDriverBinding,
    720              ImageHandle,
    721              &gOpalComponentName,
    722              &gOpalComponentName2
    723              );
    724 
    725   if (EFI_ERROR(Status)) {
    726     DEBUG((DEBUG_ERROR, "Install protocols to Opal driver Handle failed\n"));
    727     return Status ;
    728   }
    729 
    730   //
    731   // Initialize Driver object
    732   //
    733   ZeroMem(&mOpalDriver, sizeof(mOpalDriver));
    734   mOpalDriver.Handle = ImageHandle;
    735 
    736   //
    737   // register a ReadyToBoot event callback for sending BlockSid command
    738   //
    739   Status = EfiCreateEventReadyToBootEx (
    740                   TPL_CALLBACK,
    741                   ReadyToBootCallback,
    742                   (VOID *) &ImageHandle,
    743                   &ReadyToBootEvent
    744                   );
    745 
    746   //
    747   // Install Hii packages.
    748   //
    749   HiiInstall();
    750 
    751   return Status;
    752 }
    753 
    754 /**
    755   Tests to see if this driver supports a given controller.
    756 
    757   This function checks to see if the controller contains an instance of the
    758   EFI_STORAGE_SECURITY_COMMAND_PROTOCOL and the EFI_BLOCK_IO_PROTOCL
    759   and returns EFI_SUCCESS if it does.
    760 
    761   @param[in]  This                  A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    762   @param[in]  ControllerHandle      The Handle of the controller to test. This Handle
    763                                     must support a protocol interface that supplies
    764                                     an I/O abstraction to the driver.
    765   @param[in]  RemainingDevicePath  This parameter is ignored.
    766 
    767   @retval EFI_SUCCESS               The device contains required protocols
    768   @retval EFI_ALREADY_STARTED       The device specified by ControllerHandle and
    769                                     RemainingDevicePath is already being managed by the driver
    770                                     specified by This.
    771   @retval EFI_ACCESS_DENIED         The device specified by ControllerHandle and
    772                                     RemainingDevicePath is already being managed by a different
    773                                     driver or an application that requires exclusive access.
    774                                     Currently not implemented.
    775   @retval EFI_UNSUPPORTED           The device does not contain requires protocols
    776 
    777 **/
    778 EFI_STATUS
    779 EFIAPI
    780 OpalEfiDriverBindingSupported(
    781   IN EFI_DRIVER_BINDING_PROTOCOL* This,
    782   IN EFI_HANDLE                   Controller,
    783   IN EFI_DEVICE_PATH_PROTOCOL*    RemainingDevicePath
    784   )
    785 {
    786   EFI_STATUS                              Status;
    787   EFI_STORAGE_SECURITY_COMMAND_PROTOCOL*  SecurityCommand;
    788   EFI_BLOCK_IO_PROTOCOL*                  BlkIo;
    789 
    790   //
    791   // Test EFI_STORAGE_SECURITY_COMMAND_PROTOCOL on controller Handle.
    792   //
    793   Status = gBS->OpenProtocol(
    794     Controller,
    795     &gEfiStorageSecurityCommandProtocolGuid,
    796     ( VOID ** )&SecurityCommand,
    797     This->DriverBindingHandle,
    798     Controller,
    799     EFI_OPEN_PROTOCOL_BY_DRIVER
    800     );
    801 
    802   if (Status == EFI_ALREADY_STARTED) {
    803     return EFI_SUCCESS;
    804   }
    805 
    806   if (EFI_ERROR(Status)) {
    807     return Status;
    808   }
    809 
    810   //
    811   // Close protocol and reopen in Start call
    812   //
    813   gBS->CloseProtocol(
    814       Controller,
    815       &gEfiStorageSecurityCommandProtocolGuid,
    816       This->DriverBindingHandle,
    817       Controller
    818       );
    819 
    820   //
    821   // Test EFI_BLOCK_IO_PROTOCOL on controller Handle, required by EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
    822   // function APIs
    823   //
    824   Status = gBS->OpenProtocol(
    825     Controller,
    826     &gEfiBlockIoProtocolGuid,
    827     (VOID **)&BlkIo,
    828     This->DriverBindingHandle,
    829     Controller,
    830     EFI_OPEN_PROTOCOL_BY_DRIVER
    831     );
    832 
    833   if (EFI_ERROR(Status)) {
    834     DEBUG((DEBUG_INFO, "No EFI_BLOCK_IO_PROTOCOL on controller\n"));
    835     return Status;
    836   }
    837 
    838   //
    839   // Close protocol and reopen in Start call
    840   //
    841   gBS->CloseProtocol(
    842     Controller,
    843     &gEfiBlockIoProtocolGuid,
    844     This->DriverBindingHandle,
    845     Controller
    846     );
    847 
    848   return EFI_SUCCESS;
    849 }
    850 
    851 /**
    852   Enables Opal Management on a supported device if available.
    853 
    854   The start function is designed to be called after the Opal UEFI Driver has confirmed the
    855   "controller", which is a child Handle, contains the EF_STORAGE_SECURITY_COMMAND protocols.
    856   This function will complete the other necessary checks, such as verifying the device supports
    857   the correct version of Opal.  Upon verification, it will add the device to the
    858   Opal HII list in order to expose Opal managmeent options.
    859 
    860   @param[in]  This                  A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    861   @param[in]  ControllerHandle      The Handle of the controller to start. This Handle
    862                                     must support a protocol interface that supplies
    863                                     an I/O abstraction to the driver.
    864   @param[in]  RemainingDevicePath   A pointer to the remaining portion of a device path.  This
    865                                     parameter is ignored by device drivers, and is optional for bus
    866                                     drivers. For a bus driver, if this parameter is NULL, then handles
    867                                     for all the children of Controller are created by this driver.
    868                                     If this parameter is not NULL and the first Device Path Node is
    869                                     not the End of Device Path Node, then only the Handle for the
    870                                     child device specified by the first Device Path Node of
    871                                     RemainingDevicePath is created by this driver.
    872                                     If the first Device Path Node of RemainingDevicePath is
    873                                     the End of Device Path Node, no child Handle is created by this
    874                                     driver.
    875 
    876   @retval EFI_SUCCESS               Opal management was enabled.
    877   @retval EFI_DEVICE_ERROR          The device could not be started due to a device error.Currently not implemented.
    878   @retval EFI_OUT_OF_RESOURCES      The request could not be completed due to a lack of resources.
    879   @retval Others                    The driver failed to start the device.
    880 
    881 **/
    882 EFI_STATUS
    883 EFIAPI
    884 OpalEfiDriverBindingStart(
    885   IN EFI_DRIVER_BINDING_PROTOCOL* This,
    886   IN EFI_HANDLE                   Controller,
    887   IN EFI_DEVICE_PATH_PROTOCOL*    RemainingDevicePath
    888   )
    889 {
    890   EFI_STATUS                  Status;
    891   EFI_BLOCK_IO_PROTOCOL       *BlkIo;
    892   OPAL_DRIVER_DEVICE          *Dev;
    893   OPAL_DRIVER_DEVICE          *Itr;
    894   BOOLEAN                     Result;
    895 
    896   Itr = mOpalDriver.DeviceList;
    897   while (Itr != NULL) {
    898     if (Controller == Itr->Handle) {
    899       return EFI_SUCCESS;
    900     }
    901     Itr = Itr->Next;
    902   }
    903 
    904   //
    905   // Create internal device for tracking.  This allows all disks to be tracked
    906   // by same HII form
    907   //
    908   Dev = (OPAL_DRIVER_DEVICE*)AllocateZeroPool(sizeof(OPAL_DRIVER_DEVICE));
    909   if (Dev == NULL) {
    910     return EFI_OUT_OF_RESOURCES;
    911   }
    912   Dev->Handle = Controller;
    913 
    914   //
    915   // Open EFI_STORAGE_SECURITY_COMMAND_PROTOCOL to perform Opal supported checks
    916   //
    917   Status = gBS->OpenProtocol(
    918     Controller,
    919     &gEfiStorageSecurityCommandProtocolGuid,
    920     (VOID **)&Dev->Sscp,
    921     This->DriverBindingHandle,
    922     Controller,
    923     EFI_OPEN_PROTOCOL_BY_DRIVER
    924     );
    925   if (EFI_ERROR(Status)) {
    926     FreePool(Dev);
    927     return Status;
    928   }
    929 
    930   //
    931   // Open EFI_BLOCK_IO_PROTOCOL on controller Handle, required by EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
    932   // function APIs
    933   //
    934   Status = gBS->OpenProtocol(
    935     Controller,
    936     &gEfiBlockIoProtocolGuid,
    937     (VOID **)&BlkIo,
    938     This->DriverBindingHandle,
    939     Controller,
    940     EFI_OPEN_PROTOCOL_BY_DRIVER
    941     );
    942   if (EFI_ERROR(Status)) {
    943     //
    944     // Close storage security that was opened
    945     //
    946     gBS->CloseProtocol(
    947         Controller,
    948         &gEfiStorageSecurityCommandProtocolGuid,
    949         This->DriverBindingHandle,
    950         Controller
    951         );
    952 
    953     FreePool(Dev);
    954     return Status;
    955   }
    956 
    957   //
    958   // Save mediaId
    959   //
    960   Dev->MediaId = BlkIo->Media->MediaId;
    961 
    962   gBS->CloseProtocol(
    963     Controller,
    964     &gEfiBlockIoProtocolGuid,
    965     This->DriverBindingHandle,
    966     Controller
    967     );
    968 
    969   //
    970   // Acquire Ascii printable name of child, if not found, then ignore device
    971   //
    972   Result = OpalDriverGetDriverDeviceName (Dev);
    973   if (!Result) {
    974     goto Done;
    975   }
    976 
    977   Status = OpalDiskInitialize (Dev);
    978   if (EFI_ERROR (Status)) {
    979     goto Done;
    980   }
    981 
    982   AddDeviceToTail(Dev);
    983 
    984   //
    985   // check if device is locked and prompt for password
    986   //
    987   OpalDriverRequestPassword (Dev);
    988 
    989   return EFI_SUCCESS;
    990 
    991 Done:
    992   //
    993   // free device, close protocols and exit
    994   //
    995   gBS->CloseProtocol(
    996       Controller,
    997       &gEfiStorageSecurityCommandProtocolGuid,
    998       This->DriverBindingHandle,
    999       Controller
   1000       );
   1001 
   1002   FreePool(Dev);
   1003 
   1004   return EFI_DEVICE_ERROR;
   1005 }
   1006 
   1007 /**
   1008   Stop this driver on Controller.
   1009 
   1010   @param  This              Protocol instance pointer.
   1011   @param  Controller        Handle of device to stop driver on
   1012   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
   1013                             children is zero stop the entire bus driver.
   1014   @param  ChildHandleBuffer List of Child Handles to Stop.
   1015 
   1016   @retval EFI_SUCCESS       This driver is removed Controller.
   1017   @retval other             This driver could not be removed from this device.
   1018 
   1019 **/
   1020 EFI_STATUS
   1021 EFIAPI
   1022 OpalEfiDriverBindingStop(
   1023   EFI_DRIVER_BINDING_PROTOCOL*    This,
   1024   EFI_HANDLE                      Controller,
   1025   UINTN                           NumberOfChildren,
   1026   EFI_HANDLE*                     ChildHandleBuffer
   1027   )
   1028 {
   1029   OPAL_DRIVER_DEVICE*   Itr;
   1030 
   1031   Itr = mOpalDriver.DeviceList;
   1032 
   1033   //
   1034   // does Controller match any of the devices we are managing for Opal
   1035   //
   1036   while (Itr != NULL) {
   1037     if (Itr->Handle == Controller) {
   1038       OpalDriverStopDevice (Itr);
   1039       return EFI_SUCCESS;
   1040     }
   1041 
   1042     Itr = Itr->Next;
   1043   }
   1044 
   1045   return EFI_NOT_FOUND;
   1046 }
   1047 
   1048 
   1049 /**
   1050   Unloads UEFI Driver.  Very useful for debugging and testing.
   1051 
   1052   @param ImageHandle            Image Handle this driver.
   1053 
   1054   @retval EFI_SUCCESS           This function always complete successfully.
   1055   @retval EFI_INVALID_PARAMETER The input ImageHandle is not valid.
   1056 **/
   1057 EFI_STATUS
   1058 EFIAPI
   1059 OpalEfiDriverUnload (
   1060   IN EFI_HANDLE ImageHandle
   1061   )
   1062 {
   1063   EFI_STATUS                     Status;
   1064   OPAL_DRIVER_DEVICE                   *Itr;
   1065 
   1066   Status = EFI_SUCCESS;
   1067 
   1068   if (ImageHandle != gImageHandle) {
   1069     return (EFI_INVALID_PARAMETER);
   1070   }
   1071 
   1072   //
   1073   // Uninstall any interface added to each device by us
   1074   //
   1075   while (mOpalDriver.DeviceList) {
   1076     Itr = mOpalDriver.DeviceList;
   1077     //
   1078     // Remove OPAL_DRIVER_DEVICE from the list
   1079     // it updates the controllerList pointer
   1080     //
   1081     OpalDriverStopDevice(Itr);
   1082   }
   1083 
   1084   //
   1085   // Uninstall the HII capability
   1086   //
   1087   Status = HiiUninstall();
   1088 
   1089   return Status;
   1090 }
   1091 
   1092