summaryrefslogtreecommitdiff
path: root/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.c
diff options
context:
space:
mode:
Diffstat (limited to 'Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.c')
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.c1091
1 files changed, 1091 insertions, 0 deletions
diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.c b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.c
new file mode 100644
index 0000000000..cd0c5a4096
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.c
@@ -0,0 +1,1091 @@
+/** @file
+ Entrypoint of Opal UEFI Driver and contains all the logic to
+ register for new Opal device instances.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+// This UEFI driver consumes EFI_STORAGE_SECURITY_PROTOCOL instances and installs an
+// HII GUI to manage Opal features if the device is Opal capable
+// If the Opal device is being managed by the UEFI Driver, it shall provide a popup
+// window during boot requesting a user password
+
+#include "OpalDriver.h"
+#include "OpalDriverPrivate.h"
+#include "OpalHii.h"
+
+OPAL_DRIVER mOpalDriver;
+
+#define MAX_PASSWORD_SIZE 32
+#define MAX_PASSWORD_TRY_COUNT 5
+
+//
+// Globals
+//
+EFI_DRIVER_BINDING_PROTOCOL gOpalDriverBinding = {
+ OpalEfiDriverBindingSupported,
+ OpalEfiDriverBindingStart,
+ OpalEfiDriverBindingStop,
+ 0x1b,
+ NULL,
+ NULL
+};
+
+
+/**
+ Add new device to the global device list.
+
+ @param Dev New create device.
+
+**/
+VOID
+AddDeviceToTail(
+ IN OPAL_DRIVER_DEVICE *Dev
+ )
+{
+ OPAL_DRIVER_DEVICE *TmpDev;
+
+ if (mOpalDriver.DeviceList == NULL) {
+ mOpalDriver.DeviceList = Dev;
+ } else {
+ TmpDev = mOpalDriver.DeviceList;
+ while (TmpDev->Next != NULL) {
+ TmpDev = TmpDev->Next;
+ }
+
+ TmpDev->Next = Dev;
+ }
+}
+
+/**
+ Remove one device in the global device list.
+
+ @param Dev The device need to be removed.
+
+**/
+VOID
+RemoveDevice (
+ IN OPAL_DRIVER_DEVICE *Dev
+ )
+{
+ OPAL_DRIVER_DEVICE *TmpDev;
+
+ if (mOpalDriver.DeviceList == NULL) {
+ return;
+ }
+
+ if (mOpalDriver.DeviceList == Dev) {
+ mOpalDriver.DeviceList = NULL;
+ return;
+ }
+
+ TmpDev = mOpalDriver.DeviceList;
+ while (TmpDev->Next != NULL) {
+ if (TmpDev->Next == Dev) {
+ TmpDev->Next = Dev->Next;
+ break;
+ }
+ }
+}
+
+/**
+ Get current device count.
+
+ @retval return the current created device count.
+
+**/
+UINT8
+GetDeviceCount (
+ VOID
+ )
+{
+ UINT8 Count;
+ OPAL_DRIVER_DEVICE *TmpDev;
+
+ Count = 0;
+ TmpDev = mOpalDriver.DeviceList;
+
+ while (TmpDev != NULL) {
+ Count++;
+ TmpDev = TmpDev->Next;
+ }
+
+ return Count;
+}
+
+/**
+ Get password input from the popup windows, and unlock the device.
+
+ @param[in] Dev The device which need to be unlock.
+ @param[out] PressEsc Whether user escape function through Press ESC.
+
+ @retval Password string if success. NULL if failed.
+
+**/
+CHAR8 *
+OpalDriverPopUpHddPassword (
+ IN OPAL_DRIVER_DEVICE *Dev,
+ OUT BOOLEAN *PressEsc
+ )
+{
+ EFI_INPUT_KEY InputKey;
+ UINTN InputLength;
+ CHAR16 Mask[MAX_PASSWORD_SIZE + 1];
+ CHAR16 Unicode[MAX_PASSWORD_SIZE + 1];
+ CHAR8 *Ascii;
+ CHAR16 *PopUpString;
+ UINTN StrLength;
+
+ ZeroMem(Unicode, sizeof(Unicode));
+ ZeroMem(Mask, sizeof(Mask));
+
+ StrLength = StrLen(Dev->Name16);
+ PopUpString = (CHAR16*) AllocateZeroPool ((8 + StrLength) * 2);
+ *PressEsc = FALSE;
+
+ if (Dev->Name16 == NULL) {
+ UnicodeSPrint(PopUpString, StrLen(L"Unlock Disk") + 1, L"Unlock Disk");
+ } else {
+ UnicodeSPrint(PopUpString, StrLen(L"Unlock ") + StrLength + 1, L"Unlock %s", Dev->Name16);
+ }
+
+ gST->ConOut->ClearScreen(gST->ConOut);
+
+ InputLength = 0;
+ while (TRUE) {
+ Mask[InputLength] = L'_';
+ CreatePopUp(
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &InputKey,
+ PopUpString,
+ L"---------------------",
+ Mask,
+ NULL
+ );
+
+ //
+ // Check key.
+ //
+ if (InputKey.ScanCode == SCAN_NULL) {
+ //
+ // password finished
+ //
+ if (InputKey.UnicodeChar == CHAR_CARRIAGE_RETURN) {
+ //
+ // Add the null terminator.
+ //
+ Unicode[InputLength] = 0;
+ InputLength++;
+ break;
+ } else if ((InputKey.UnicodeChar == CHAR_NULL) ||
+ (InputKey.UnicodeChar == CHAR_TAB) ||
+ (InputKey.UnicodeChar == CHAR_LINEFEED)
+ ) {
+ continue;
+ } else {
+ //
+ // delete last key entered
+ //
+ if (InputKey.UnicodeChar == CHAR_BACKSPACE) {
+ if (InputLength > 0) {
+ Unicode[InputLength] = 0;
+ Mask[InputLength] = 0;
+ InputLength--;
+ }
+ } else {
+ //
+ // add Next key entry
+ //
+ Unicode[InputLength] = InputKey.UnicodeChar;
+ Mask[InputLength] = L'*';
+ InputLength++;
+ if (InputLength == MAX_PASSWORD_SIZE) {
+ //
+ // Add the null terminator.
+ //
+ Unicode[InputLength] = 0;
+ Mask[InputLength] = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // exit on ESC
+ //
+ if (InputKey.ScanCode == SCAN_ESC) {
+ *PressEsc = TRUE;
+ break;
+ }
+ }
+
+ gST->ConOut->ClearScreen(gST->ConOut);
+
+ if (InputLength == 0 || InputKey.ScanCode == SCAN_ESC) {
+ return NULL;
+ }
+
+ Ascii = AllocateZeroPool (MAX_PASSWORD_SIZE + 1);
+ if (Ascii == NULL) {
+ return NULL;
+ }
+
+ UnicodeStrToAsciiStrS (Unicode, Ascii, MAX_PASSWORD_SIZE + 1);
+ ZeroMem (Unicode, sizeof (Unicode));
+
+ return Ascii;
+}
+
+/**
+ Check if disk is locked, show popup window and ask for password if it is
+
+ @param[in] Dev The device which need to be unlock.
+
+**/
+VOID
+OpalDriverRequestPassword (
+ OPAL_DRIVER_DEVICE *Dev
+ )
+{
+ UINT8 Count;
+ BOOLEAN IsEnabled;
+ CHAR8 *Password;
+ UINT32 PasswordLen;
+ TCG_RESULT Ret;
+ EFI_INPUT_KEY Key;
+ OPAL_SESSION Session;
+ BOOLEAN PressEsc;
+ BOOLEAN Locked;
+
+ if (Dev == NULL) {
+ return;
+ }
+
+ Count = 0;
+
+ IsEnabled = OpalFeatureEnabled (&Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.LockingFeature);
+ if (IsEnabled) {
+ ZeroMem(&Session, sizeof(Session));
+ Session.Sscp = Dev->OpalDisk.Sscp;
+ Session.MediaId = Dev->OpalDisk.MediaId;
+ Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;
+
+ Locked = OpalDeviceLocked (&Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.LockingFeature);
+
+ while (Count < MAX_PASSWORD_TRY_COUNT) {
+ Password = OpalDriverPopUpHddPassword (Dev, &PressEsc);
+ if (PressEsc) {
+ if (Locked) {
+ //
+ // Current device in the lock status and
+ // User not input password and press ESC,
+ // keep device in lock status and continue boot.
+ //
+ do {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"Press ENTER to skip password, Press ESC to input password",
+ NULL
+ );
+ } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));
+
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
+ gST->ConOut->ClearScreen(gST->ConOut);
+ //
+ // Keep lock and continue boot.
+ //
+ return;
+ } else {
+ //
+ // Let user input password again.
+ //
+ continue;
+ }
+ } else {
+ //
+ // Current device in the unlock status and
+ // User not input password and press ESC,
+ // Shutdown the device.
+ //
+ do {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"Press ENTER to shutdown, Press ESC to input password",
+ NULL
+ );
+ } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));
+
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
+ gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);
+ } else {
+ //
+ // Let user input password again.
+ //
+ continue;
+ }
+ }
+ }
+
+ if (Password == NULL) {
+ Count ++;
+ continue;
+ }
+ PasswordLen = (UINT32) AsciiStrLen(Password);
+
+ if (Locked) {
+ Ret = OpalSupportUnlock(&Session, Password, PasswordLen, Dev->OpalDevicePath);
+ } else {
+ Ret = OpalSupportLock(&Session, Password, PasswordLen, Dev->OpalDevicePath);
+ if (Ret == TcgResultSuccess) {
+ Ret = OpalSupportUnlock(&Session, Password, PasswordLen, Dev->OpalDevicePath);
+ }
+ }
+
+ if (Password != NULL) {
+ ZeroMem (Password, PasswordLen);
+ FreePool (Password);
+ }
+
+ if (Ret == TcgResultSuccess) {
+ break;
+ }
+
+ Count++;
+
+ do {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"Invalid password.",
+ L"Press ENTER to retry",
+ NULL
+ );
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+ }
+
+ if (Count >= MAX_PASSWORD_TRY_COUNT) {
+ do {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"Opal password retry count exceeds the limit. Must shutdown!",
+ L"Press ENTER to shutdown",
+ NULL
+ );
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+
+ gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);
+ }
+ }
+}
+
+/**
+ Get devcie list info.
+
+ @retval return the device list pointer.
+**/
+OPAL_DRIVER_DEVICE*
+OpalDriverGetDeviceList(
+ VOID
+ )
+{
+ return mOpalDriver.DeviceList;
+}
+
+/**
+ ReadyToBoot callback to send BlockSid command.
+
+ @param Event Pointer to this event
+ @param Context Event handler private Data
+
+**/
+VOID
+EFIAPI
+ReadyToBootCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ OPAL_DRIVER_DEVICE *Itr;
+ TCG_RESULT Result;
+ OPAL_SESSION Session;
+ UINT32 PpStorageFlag;
+
+ gBS->CloseEvent (Event);
+
+ PpStorageFlag = Tcg2PhysicalPresenceLibGetManagementFlags ();
+ if ((PpStorageFlag & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID) != 0) {
+ //
+ // Send BlockSID command to each Opal disk
+ //
+ Itr = mOpalDriver.DeviceList;
+ while (Itr != NULL) {
+ if (Itr->OpalDisk.SupportedAttributes.BlockSid) {
+ ZeroMem(&Session, sizeof(Session));
+ Session.Sscp = Itr->OpalDisk.Sscp;
+ Session.MediaId = Itr->OpalDisk.MediaId;
+ Session.OpalBaseComId = Itr->OpalDisk.OpalBaseComId;
+
+ Result = OpalBlockSid (&Session, TRUE); // HardwareReset must always be TRUE
+ if (Result != TcgResultSuccess) {
+ DEBUG ((DEBUG_ERROR, "OpalBlockSid fail\n"));
+ break;
+ }
+ }
+
+ Itr = Itr->Next;
+ }
+ }
+}
+
+/**
+ Stop this Controller.
+
+ @param Dev The device need to be stopped.
+
+**/
+VOID
+OpalDriverStopDevice (
+ OPAL_DRIVER_DEVICE *Dev
+ )
+{
+ //
+ // free each name
+ //
+ FreePool(Dev->Name16);
+
+ //
+ // remove OPAL_DRIVER_DEVICE from the list
+ // it updates the controllerList pointer
+ //
+ RemoveDevice(Dev);
+
+ //
+ // close protocols that were opened
+ //
+ gBS->CloseProtocol(
+ Dev->Handle,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ gOpalDriverBinding.DriverBindingHandle,
+ Dev->Handle
+ );
+
+ gBS->CloseProtocol(
+ Dev->Handle,
+ &gEfiBlockIoProtocolGuid,
+ gOpalDriverBinding.DriverBindingHandle,
+ Dev->Handle
+ );
+
+ FreePool(Dev);
+}
+
+/**
+ Get devcie name through the component name protocol.
+
+ @param[in] AllHandlesBuffer The handle buffer for current system.
+ @param[in] NumAllHandles The number of handles for the handle buffer.
+ @param[in] Dev The device which need to get name.
+ @param[in] UseComp1 Whether use component name or name2 protocol.
+
+ @retval TRUE Find the name for this device.
+ @retval FALSE Not found the name for this device.
+**/
+BOOLEAN
+OpalDriverGetDeviceNameByProtocol(
+ EFI_HANDLE *AllHandlesBuffer,
+ UINTN NumAllHandles,
+ OPAL_DRIVER_DEVICE *Dev,
+ BOOLEAN UseComp1
+ )
+{
+ EFI_HANDLE* ProtocolHandlesBuffer;
+ UINTN NumProtocolHandles;
+ EFI_STATUS Status;
+ EFI_COMPONENT_NAME2_PROTOCOL* Cnp1_2; // efi component name and componentName2 have same layout
+ EFI_GUID Protocol;
+ UINTN StrLength;
+ EFI_DEVICE_PATH_PROTOCOL* TmpDevPath;
+ UINTN Index1;
+ UINTN Index2;
+ EFI_HANDLE TmpHandle;
+ CHAR16 *DevName;
+
+ if (Dev == NULL || AllHandlesBuffer == NULL || NumAllHandles == 0) {
+ return FALSE;
+ }
+
+ Protocol = UseComp1 ? gEfiComponentNameProtocolGuid : gEfiComponentName2ProtocolGuid;
+
+ //
+ // Find all EFI_HANDLES with protocol
+ //
+ Status = gBS->LocateHandleBuffer(
+ ByProtocol,
+ &Protocol,
+ NULL,
+ &NumProtocolHandles,
+ &ProtocolHandlesBuffer
+ );
+ if (EFI_ERROR(Status)) {
+ return FALSE;
+ }
+
+
+ //
+ // Exit early if no supported devices
+ //
+ if (NumProtocolHandles == 0) {
+ return FALSE;
+ }
+
+ //
+ // Get printable name by iterating through all protocols
+ // using the handle as the child, and iterate through all handles for the controller
+ // exit loop early once found, if not found, then delete device
+ // storage security protocol instances already exist, add them to internal list
+ //
+ Status = EFI_DEVICE_ERROR;
+ for (Index1 = 0; Index1 < NumProtocolHandles; Index1++) {
+ DevName = NULL;
+
+ if (Dev->Name16 != NULL) {
+ return TRUE;
+ }
+
+ TmpHandle = ProtocolHandlesBuffer[Index1];
+
+ Status = gBS->OpenProtocol(
+ TmpHandle,
+ &Protocol,
+ (VOID**)&Cnp1_2,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR(Status) || Cnp1_2 == NULL) {
+ continue;
+ }
+
+ //
+ // Use all handles array as controller handle
+ //
+ for (Index2 = 0; Index2 < NumAllHandles; Index2++) {
+ Status = Cnp1_2->GetControllerName(
+ Cnp1_2,
+ AllHandlesBuffer[Index2],
+ Dev->Handle,
+ LANGUAGE_ISO_639_2_ENGLISH,
+ &DevName
+ );
+ if (EFI_ERROR(Status)) {
+ Status = Cnp1_2->GetControllerName(
+ Cnp1_2,
+ AllHandlesBuffer[Index2],
+ Dev->Handle,
+ LANGUAGE_RFC_3066_ENGLISH,
+ &DevName
+ );
+ }
+ if (!EFI_ERROR(Status) && DevName != NULL) {
+ StrLength = StrLen(DevName) + 1; // Add one for NULL terminator
+ Dev->Name16 = AllocateZeroPool(StrLength * sizeof (CHAR16));
+ ASSERT (Dev->Name16 != NULL);
+ StrCpyS (Dev->Name16, StrLength, DevName);
+ Dev->NameZ = (CHAR8*)AllocateZeroPool(StrLength);
+ UnicodeStrToAsciiStrS (DevName, Dev->NameZ, StrLength);
+
+ //
+ // Retrieve bridge BDF info and port number or namespace depending on type
+ //
+ TmpDevPath = NULL;
+ Status = gBS->OpenProtocol(
+ Dev->Handle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID**)&TmpDevPath,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR(Status)) {
+ Dev->OpalDevicePath = DuplicateDevicePath (TmpDevPath);
+ return TRUE;
+ }
+
+ if (Dev->Name16 != NULL) {
+ FreePool(Dev->Name16);
+ Dev->Name16 = NULL;
+ }
+ if (Dev->NameZ != NULL) {
+ FreePool(Dev->NameZ);
+ Dev->NameZ = NULL;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Get devcie name through the component name protocol.
+
+ @param[in] Dev The device which need to get name.
+
+ @retval TRUE Find the name for this device.
+ @retval FALSE Not found the name for this device.
+**/
+BOOLEAN
+OpalDriverGetDriverDeviceName(
+ OPAL_DRIVER_DEVICE *Dev
+ )
+{
+ EFI_HANDLE* AllHandlesBuffer;
+ UINTN NumAllHandles;
+ EFI_STATUS Status;
+
+ if (Dev == NULL) {
+ DEBUG((DEBUG_ERROR | DEBUG_INIT, "OpalDriverGetDriverDeviceName Exiting, Dev=NULL\n"));
+ return FALSE;
+ }
+
+ //
+ // Iterate through ComponentName2 handles to get name, if fails, try ComponentName
+ //
+ if (Dev->Name16 == NULL) {
+ DEBUG((DEBUG_ERROR | DEBUG_INIT, "Name is null, update it\n"));
+ //
+ // Find all EFI_HANDLES
+ //
+ Status = gBS->LocateHandleBuffer(
+ AllHandles,
+ NULL,
+ NULL,
+ &NumAllHandles,
+ &AllHandlesBuffer
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_INFO, "LocateHandleBuffer for AllHandles failed %r\n", Status ));
+ return FALSE;
+ }
+
+ //
+ // Try component Name2
+ //
+ if (!OpalDriverGetDeviceNameByProtocol(AllHandlesBuffer, NumAllHandles, Dev, FALSE)) {
+ DEBUG((DEBUG_ERROR | DEBUG_INIT, "ComponentName2 failed to get device name, try ComponentName\n"));
+ if (!OpalDriverGetDeviceNameByProtocol(AllHandlesBuffer, NumAllHandles, Dev, TRUE)) {
+ DEBUG((DEBUG_ERROR | DEBUG_INIT, "ComponentName failed to get device name, skip device\n"));
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ Main entry for this driver.
+
+ @param ImageHandle Image Handle this driver.
+ @param SystemTable Pointer to SystemTable.
+
+ @retval EFI_SUCESS This function always complete successfully.
+**/
+EFI_STATUS
+EFIAPI
+EfiDriverEntryPoint(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE* SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT ReadyToBootEvent;
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gOpalDriverBinding,
+ ImageHandle,
+ &gOpalComponentName,
+ &gOpalComponentName2
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "Install protocols to Opal driver Handle failed\n"));
+ return Status ;
+ }
+
+ //
+ // Initialize Driver object
+ //
+ ZeroMem(&mOpalDriver, sizeof(mOpalDriver));
+ mOpalDriver.Handle = ImageHandle;
+
+ //
+ // register a ReadyToBoot event callback for sending BlockSid command
+ //
+ Status = EfiCreateEventReadyToBootEx (
+ TPL_CALLBACK,
+ ReadyToBootCallback,
+ (VOID *) &ImageHandle,
+ &ReadyToBootEvent
+ );
+
+ //
+ // Install Hii packages.
+ //
+ HiiInstall();
+
+ return Status;
+}
+
+/**
+ Tests to see if this driver supports a given controller.
+
+ This function checks to see if the controller contains an instance of the
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL and the EFI_BLOCK_IO_PROTOCL
+ and returns EFI_SUCCESS if it does.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The Handle of the controller to test. This Handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath This parameter is ignored.
+
+ @retval EFI_SUCCESS The device contains required protocols
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device does not contain requires protocols
+
+**/
+EFI_STATUS
+EFIAPI
+OpalEfiDriverBindingSupported(
+ IN EFI_DRIVER_BINDING_PROTOCOL* This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL* RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL* SecurityCommand;
+ EFI_BLOCK_IO_PROTOCOL* BlkIo;
+
+ //
+ // Test EFI_STORAGE_SECURITY_COMMAND_PROTOCOL on controller Handle.
+ //
+ Status = gBS->OpenProtocol(
+ Controller,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ ( VOID ** )&SecurityCommand,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // Close protocol and reopen in Start call
+ //
+ gBS->CloseProtocol(
+ Controller,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Test EFI_BLOCK_IO_PROTOCOL on controller Handle, required by EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
+ // function APIs
+ //
+ Status = gBS->OpenProtocol(
+ Controller,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **)&BlkIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_INFO, "No EFI_BLOCK_IO_PROTOCOL on controller\n"));
+ return Status;
+ }
+
+ //
+ // Close protocol and reopen in Start call
+ //
+ gBS->CloseProtocol(
+ Controller,
+ &gEfiBlockIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Enables Opal Management on a supported device if available.
+
+ The start function is designed to be called after the Opal UEFI Driver has confirmed the
+ "controller", which is a child Handle, contains the EF_STORAGE_SECURITY_COMMAND protocols.
+ This function will complete the other necessary checks, such as verifying the device supports
+ the correct version of Opal. Upon verification, it will add the device to the
+ Opal HII list in order to expose Opal managmeent options.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The Handle of the controller to start. This Handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
+ parameter is ignored by device drivers, and is optional for bus
+ drivers. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the Handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child Handle is created by this
+ driver.
+
+ @retval EFI_SUCCESS Opal management was enabled.
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval Others The driver failed to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+OpalEfiDriverBindingStart(
+ IN EFI_DRIVER_BINDING_PROTOCOL* This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL* RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+ OPAL_DRIVER_DEVICE *Dev;
+ OPAL_DRIVER_DEVICE *Itr;
+ BOOLEAN Result;
+
+ Itr = mOpalDriver.DeviceList;
+ while (Itr != NULL) {
+ if (Controller == Itr->Handle) {
+ return EFI_SUCCESS;
+ }
+ Itr = Itr->Next;
+ }
+
+ //
+ // Create internal device for tracking. This allows all disks to be tracked
+ // by same HII form
+ //
+ Dev = (OPAL_DRIVER_DEVICE*)AllocateZeroPool(sizeof(OPAL_DRIVER_DEVICE));
+ if (Dev == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Dev->Handle = Controller;
+
+ //
+ // Open EFI_STORAGE_SECURITY_COMMAND_PROTOCOL to perform Opal supported checks
+ //
+ Status = gBS->OpenProtocol(
+ Controller,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ (VOID **)&Dev->Sscp,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR(Status)) {
+ FreePool(Dev);
+ return Status;
+ }
+
+ //
+ // Open EFI_BLOCK_IO_PROTOCOL on controller Handle, required by EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
+ // function APIs
+ //
+ Status = gBS->OpenProtocol(
+ Controller,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **)&BlkIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR(Status)) {
+ //
+ // Close storage security that was opened
+ //
+ gBS->CloseProtocol(
+ Controller,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ FreePool(Dev);
+ return Status;
+ }
+
+ //
+ // Save mediaId
+ //
+ Dev->MediaId = BlkIo->Media->MediaId;
+
+ gBS->CloseProtocol(
+ Controller,
+ &gEfiBlockIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Acquire Ascii printable name of child, if not found, then ignore device
+ //
+ Result = OpalDriverGetDriverDeviceName (Dev);
+ if (!Result) {
+ goto Done;
+ }
+
+ Status = OpalDiskInitialize (Dev);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ AddDeviceToTail(Dev);
+
+ //
+ // check if device is locked and prompt for password
+ //
+ OpalDriverRequestPassword (Dev);
+
+ return EFI_SUCCESS;
+
+Done:
+ //
+ // free device, close protocols and exit
+ //
+ gBS->CloseProtocol(
+ Controller,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ FreePool(Dev);
+
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Stop this driver on Controller.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed Controller.
+ @retval other This driver could not be removed from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+OpalEfiDriverBindingStop(
+ EFI_DRIVER_BINDING_PROTOCOL* This,
+ EFI_HANDLE Controller,
+ UINTN NumberOfChildren,
+ EFI_HANDLE* ChildHandleBuffer
+ )
+{
+ OPAL_DRIVER_DEVICE* Itr;
+
+ Itr = mOpalDriver.DeviceList;
+
+ //
+ // does Controller match any of the devices we are managing for Opal
+ //
+ while (Itr != NULL) {
+ if (Itr->Handle == Controller) {
+ OpalDriverStopDevice (Itr);
+ return EFI_SUCCESS;
+ }
+
+ Itr = Itr->Next;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Unloads UEFI Driver. Very useful for debugging and testing.
+
+ @param ImageHandle Image Handle this driver.
+
+ @retval EFI_SUCCESS This function always complete successfully.
+ @retval EFI_INVALID_PARAMETER The input ImageHandle is not valid.
+**/
+EFI_STATUS
+EFIAPI
+OpalEfiDriverUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ OPAL_DRIVER_DEVICE *Itr;
+
+ Status = EFI_SUCCESS;
+
+ if (ImageHandle != gImageHandle) {
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ //
+ // Uninstall any interface added to each device by us
+ //
+ while (mOpalDriver.DeviceList) {
+ Itr = mOpalDriver.DeviceList;
+ //
+ // Remove OPAL_DRIVER_DEVICE from the list
+ // it updates the controllerList pointer
+ //
+ OpalDriverStopDevice(Itr);
+ }
+
+ //
+ // Uninstall the HII capability
+ //
+ Status = HiiUninstall();
+
+ return Status;
+}
+