mirror of https://github.com/acidanthera/audk.git
1104 lines
30 KiB
C
1104 lines
30 KiB
C
/** @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);
|
|
|
|
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 hanlder private Data
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
ReadyToBootCallback (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
OPAL_DRIVER_DEVICE* Itr;
|
|
TCG_RESULT Result;
|
|
OPAL_EXTRA_INFO_VAR OpalExtraInfo;
|
|
UINTN DataSize;
|
|
OPAL_SESSION Session;
|
|
|
|
gBS->CloseEvent (Event);
|
|
|
|
DataSize = sizeof (OPAL_EXTRA_INFO_VAR);
|
|
Status = gRT->GetVariable (
|
|
OPAL_EXTRA_INFO_VAR_NAME,
|
|
&gOpalExtraInfoVariableGuid,
|
|
NULL,
|
|
&DataSize,
|
|
&OpalExtraInfo
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
|
|
if (OpalExtraInfo.EnableBlockSid == TRUE) {
|
|
//
|
|
// 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;
|
|
}
|
|
|