mirror of https://github.com/acidanthera/audk.git
1703 lines
58 KiB
C
1703 lines
58 KiB
C
/** @file
|
|
This file also installs UEFI PLATFORM_DRIVER_OVERRIDE_PROTOCOL.
|
|
|
|
The main code offers a UI interface in device manager to let user configure
|
|
platform override protocol to override the default algorithm for matching
|
|
drivers to controllers.
|
|
|
|
The main flow:
|
|
1. It dynamicly locate all controller device path.
|
|
2. It dynamicly locate all drivers which support binding protocol.
|
|
3. It export and dynamicly update two menu to let user select the
|
|
mapping between drivers to controllers.
|
|
4. It save all the mapping info in NV variables which will be consumed
|
|
by platform override protocol driver to publish the platform override protocol.
|
|
|
|
Copyright (c) 2007 - 2011, 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.
|
|
|
|
**/
|
|
|
|
#include "InternalPlatDriOverrideDxe.h"
|
|
#include "PlatOverMngr.h"
|
|
|
|
#define EFI_CALLBACK_INFO_SIGNATURE SIGNATURE_32 ('C', 'l', 'b', 'k')
|
|
#define EFI_CALLBACK_INFO_FROM_THIS(a) CR (a, EFI_CALLBACK_INFO, ConfigAccess, EFI_CALLBACK_INFO_SIGNATURE)
|
|
|
|
typedef struct {
|
|
UINTN Signature;
|
|
EFI_HANDLE DriverHandle;
|
|
EFI_HII_HANDLE RegisteredHandle;
|
|
PLAT_OVER_MNGR_DATA FakeNvData;
|
|
EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
|
|
EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
|
|
EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL PlatformDriverOverride;
|
|
} EFI_CALLBACK_INFO;
|
|
|
|
#pragma pack(1)
|
|
|
|
///
|
|
/// HII specific Vendor Device Path definition.
|
|
///
|
|
typedef struct {
|
|
VENDOR_DEVICE_PATH VendorDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL End;
|
|
} HII_VENDOR_DEVICE_PATH;
|
|
|
|
#pragma pack()
|
|
|
|
//
|
|
// uni string and Vfr Binary data.
|
|
//
|
|
extern UINT8 VfrBin[];
|
|
extern UINT8 PlatDriOverrideDxeStrings[];
|
|
|
|
//
|
|
// module global data
|
|
//
|
|
CHAR16 mVariableName[] = L"Data";
|
|
LIST_ENTRY mMappingDataBase = INITIALIZE_LIST_HEAD_VARIABLE (mMappingDataBase);
|
|
BOOLEAN mEnvironmentVariableRead = FALSE;
|
|
EFI_HANDLE mCallerImageHandle = NULL;
|
|
|
|
EFI_HANDLE *mDevicePathHandleBuffer;
|
|
EFI_HANDLE *mDriverImageHandleBuffer;
|
|
|
|
INTN mSelectedCtrIndex;
|
|
EFI_STRING_ID mControllerToken[MAX_CHOICE_NUM];
|
|
UINTN mDriverImageHandleCount;
|
|
EFI_STRING_ID mDriverImageToken[MAX_CHOICE_NUM];
|
|
EFI_STRING_ID mDriverImageFilePathToken[MAX_CHOICE_NUM];
|
|
EFI_LOADED_IMAGE_PROTOCOL *mDriverImageProtocol[MAX_CHOICE_NUM];
|
|
EFI_DEVICE_PATH_PROTOCOL *mControllerDevicePathProtocol[MAX_CHOICE_NUM];
|
|
UINTN mSelectedDriverImageNum;
|
|
UINTN mLastSavedDriverImageNum;
|
|
UINT16 mCurrentPage;
|
|
EFI_CALLBACK_INFO *mCallbackInfo;
|
|
|
|
HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath = {
|
|
{
|
|
{
|
|
HARDWARE_DEVICE_PATH,
|
|
HW_VENDOR_DP,
|
|
{
|
|
(UINT8) (sizeof (VENDOR_DEVICE_PATH)),
|
|
(UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
|
|
}
|
|
},
|
|
PLAT_OVER_MNGR_GUID
|
|
},
|
|
{
|
|
END_DEVICE_PATH_TYPE,
|
|
END_ENTIRE_DEVICE_PATH_SUBTYPE,
|
|
{
|
|
(UINT8) (END_DEVICE_PATH_LENGTH),
|
|
(UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
Converting a given device to an unicode string.
|
|
|
|
This function will dependent on gEfiDevicePathToTextProtocolGuid, if protocol
|
|
does not installed, then return unknown device path L"?" directly.
|
|
|
|
@param DevPath Given device path instance
|
|
|
|
@return Converted string from given device path.
|
|
@retval L"?" Can not locate gEfiDevicePathToTextProtocolGuid protocol for converting.
|
|
**/
|
|
CHAR16 *
|
|
DevicePathToStr (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevPath
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText;
|
|
CHAR16 *ToText;
|
|
|
|
if (DevPath == NULL) {
|
|
return L"";
|
|
}
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiDevicePathToTextProtocolGuid,
|
|
NULL,
|
|
(VOID **) &DevPathToText
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
ToText = DevPathToText->ConvertDevicePathToText (
|
|
DevPath,
|
|
FALSE,
|
|
TRUE
|
|
);
|
|
ASSERT (ToText != NULL);
|
|
return ToText;
|
|
}
|
|
|
|
return L"?";
|
|
}
|
|
|
|
/**
|
|
Worker function to get the driver name by ComponentName or ComponentName2 protocol
|
|
according to the driver binding handle.
|
|
|
|
@param DriverBindingHandle The Handle of DriverBinding.
|
|
@param ProtocolGuid The pointer to Component Name (2) protocol GUID.
|
|
@param VariableName The name of the RFC 4646 or ISO 639-2 language variable.
|
|
|
|
@retval !NULL Pointer into the image name if the image name is found,
|
|
@retval NULL Pointer to NULL if the image name is not found.
|
|
|
|
**/
|
|
CHAR16 *
|
|
GetComponentNameWorker (
|
|
IN EFI_HANDLE DriverBindingHandle,
|
|
IN EFI_GUID *ProtocolGuid,
|
|
IN CONST CHAR16 *VariableName
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_COMPONENT_NAME_PROTOCOL *ComponentName;
|
|
CHAR16 *DriverName;
|
|
CHAR8 *Language;
|
|
CHAR8 *BestLanguage;
|
|
|
|
Status = gBS->OpenProtocol (
|
|
DriverBindingHandle,
|
|
ProtocolGuid,
|
|
(VOID *) &ComponentName,
|
|
NULL,
|
|
NULL,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Find the best matching language.
|
|
//
|
|
Language = GetEfiGlobalVariable (VariableName);
|
|
BestLanguage = GetBestLanguage (
|
|
ComponentName->SupportedLanguages,
|
|
(BOOLEAN) (ProtocolGuid == &gEfiComponentNameProtocolGuid),
|
|
Language,
|
|
NULL
|
|
);
|
|
|
|
DriverName = NULL;
|
|
if (BestLanguage != NULL) {
|
|
ComponentName->GetDriverName (
|
|
ComponentName,
|
|
BestLanguage,
|
|
&DriverName
|
|
);
|
|
FreePool (BestLanguage);
|
|
}
|
|
|
|
if (Language != NULL) {
|
|
FreePool (Language);
|
|
}
|
|
|
|
return DriverName;
|
|
}
|
|
|
|
|
|
/**
|
|
Get the driver name by ComponentName or ComponentName2 protocol
|
|
according to the driver binding handle
|
|
|
|
@param DriverBindingHandle The Handle of DriverBinding.
|
|
|
|
@retval !NULL Pointer into the image name if the image name is found,
|
|
@retval NULL Pointer to NULL if the image name is not found.
|
|
|
|
**/
|
|
CHAR16 *
|
|
GetComponentName (
|
|
IN EFI_HANDLE DriverBindingHandle
|
|
)
|
|
{
|
|
CHAR16 *DriverName;
|
|
|
|
//
|
|
// Try RFC 4646 Component Name 2 protocol first.
|
|
//
|
|
DriverName = GetComponentNameWorker (DriverBindingHandle, &gEfiComponentName2ProtocolGuid, L"PlatformLang");
|
|
if (DriverName == NULL) {
|
|
//
|
|
// If we can not get driver name from Component Name 2 protocol, we can try ISO 639-2 Component Name protocol.
|
|
//
|
|
DriverName = GetComponentNameWorker (DriverBindingHandle, &gEfiComponentNameProtocolGuid, L"Lang");
|
|
}
|
|
|
|
return DriverName;
|
|
}
|
|
|
|
/**
|
|
Get the image name from EFI UI section.
|
|
Get FV protocol by its loaded image protocol to abstract EFI UI section.
|
|
|
|
@param Image Pointer to the loaded image protocol
|
|
|
|
@retval !NULL Pointer to the image name if the image name is found,
|
|
@retval NULL NULL if the image name is not found.
|
|
|
|
**/
|
|
CHAR16 *
|
|
GetImageName (
|
|
IN EFI_LOADED_IMAGE_PROTOCOL *Image
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
|
|
EFI_DEVICE_PATH_PROTOCOL *AlignedDevPathNode;
|
|
MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath;
|
|
VOID *Buffer;
|
|
UINTN BufferSize;
|
|
UINT32 AuthenticationStatus;
|
|
EFI_GUID *NameGuid;
|
|
EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv2;
|
|
|
|
Fv2 = NULL;
|
|
Buffer = NULL;
|
|
BufferSize = 0;
|
|
|
|
if (Image->FilePath == NULL) {
|
|
return NULL;
|
|
}
|
|
DevPathNode = Image->FilePath;
|
|
|
|
while (!IsDevicePathEnd (DevPathNode)) {
|
|
//
|
|
// Make sure device path node is aligned when accessing it's FV Name Guid field.
|
|
//
|
|
AlignedDevPathNode = AllocateCopyPool (DevicePathNodeLength(DevPathNode), DevPathNode);
|
|
|
|
//
|
|
// Find the Fv File path
|
|
//
|
|
NameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)AlignedDevPathNode);
|
|
if (NameGuid != NULL) {
|
|
FvFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) AlignedDevPathNode;
|
|
Status = gBS->HandleProtocol (
|
|
Image->DeviceHandle,
|
|
&gEfiFirmwareVolume2ProtocolGuid,
|
|
(VOID **) &Fv2
|
|
);
|
|
//
|
|
// Locate Image EFI UI section to get the image name.
|
|
//
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = Fv2->ReadSection (
|
|
Fv2,
|
|
&FvFilePath->FvFileName,
|
|
EFI_SECTION_USER_INTERFACE,
|
|
0,
|
|
&Buffer,
|
|
&BufferSize,
|
|
&AuthenticationStatus
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
FreePool (AlignedDevPathNode);
|
|
break;
|
|
}
|
|
Buffer = NULL;
|
|
}
|
|
}
|
|
|
|
FreePool (AlignedDevPathNode);
|
|
|
|
//
|
|
// Next device path node
|
|
//
|
|
DevPathNode = NextDevicePathNode (DevPathNode);
|
|
}
|
|
|
|
return Buffer;
|
|
}
|
|
|
|
/**
|
|
Prepare the first page to let user select the device controller which need to
|
|
add mapping drivers if user select 'Refresh' in first page.
|
|
During first page, user will see all currnet controller device path in system,
|
|
select any device path will go to second page to select its overrides drivers.
|
|
|
|
@param Private Pointer to EFI_CALLBACK_INFO.
|
|
@param KeyValue The callback key value of device controller item in first page.
|
|
@param FakeNvData Pointer to PLAT_OVER_MNGR_DATA.
|
|
|
|
@retval EFI_SUCCESS Always returned.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UpdateDeviceSelectPage (
|
|
IN EFI_CALLBACK_INFO *Private,
|
|
IN UINT16 KeyValue,
|
|
IN PLAT_OVER_MNGR_DATA *FakeNvData
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
UINTN DevicePathHandleCount;
|
|
CHAR16 *NewString;
|
|
EFI_STRING_ID NewStringToken;
|
|
CHAR16 *ControllerName;
|
|
EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *BusSpecificDriverOverride;
|
|
UINTN Len;
|
|
VOID *StartOpCodeHandle;
|
|
VOID *EndOpCodeHandle;
|
|
EFI_IFR_GUID_LABEL *StartLabel;
|
|
EFI_IFR_GUID_LABEL *EndLabel;
|
|
|
|
//
|
|
// Set current page form ID.
|
|
//
|
|
mCurrentPage = FORM_ID_DEVICE;
|
|
|
|
//
|
|
// Initial the mapping database in memory
|
|
//
|
|
FreeMappingDatabase (&mMappingDataBase);
|
|
InitOverridesMapping (&mMappingDataBase);
|
|
|
|
//
|
|
// Init OpCode Handle
|
|
//
|
|
StartOpCodeHandle = HiiAllocateOpCodeHandle ();
|
|
ASSERT (StartOpCodeHandle != NULL);
|
|
|
|
EndOpCodeHandle = HiiAllocateOpCodeHandle ();
|
|
ASSERT (EndOpCodeHandle != NULL);
|
|
|
|
//
|
|
// Create Hii Extend Label OpCode as the start opcode
|
|
//
|
|
StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
|
|
StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
|
|
StartLabel->Number = FORM_ID_DEVICE;
|
|
|
|
//
|
|
// Create Hii Extend Label OpCode as the end opcode
|
|
//
|
|
EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
|
|
EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
|
|
EndLabel->Number = LABEL_END;
|
|
|
|
//
|
|
// Clear first page form
|
|
//
|
|
HiiUpdateForm (
|
|
Private->RegisteredHandle,
|
|
&gPlatformOverridesManagerGuid,
|
|
FORM_ID_DEVICE,
|
|
StartOpCodeHandle, // Label FORM_ID_DEVICE
|
|
EndOpCodeHandle // LABEL_END
|
|
);
|
|
|
|
//
|
|
// When user enter the page at first time, the 'first refresh' string is given to notify user to refresh all the drivers,
|
|
// then the 'first refresh' string will be replaced by the 'refresh' string, and the two strings content are same after the replacement
|
|
//
|
|
NewStringToken = STRING_TOKEN (STR_FIRST_REFRESH);
|
|
NewString = HiiGetString (Private->RegisteredHandle, STRING_TOKEN (STR_REFRESH), NULL);
|
|
ASSERT (NewString != NULL);
|
|
if (HiiSetString (Private->RegisteredHandle, NewStringToken, NewString, NULL) == 0) {
|
|
ASSERT (FALSE);
|
|
}
|
|
FreePool (NewString);
|
|
|
|
NewStringToken = STRING_TOKEN (STR_FIRST_REFRESH_HELP);
|
|
NewString = HiiGetString (Private->RegisteredHandle, STRING_TOKEN (STR_REFRESH_HELP), NULL);
|
|
ASSERT (NewString != NULL);
|
|
if (HiiSetString (Private->RegisteredHandle, NewStringToken, NewString, NULL) == 0) {
|
|
ASSERT (FALSE);
|
|
}
|
|
FreePool (NewString);
|
|
|
|
//
|
|
// created needed controller device item in first page
|
|
//
|
|
DevicePathHandleCount = 0;
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiDevicePathProtocolGuid,
|
|
NULL,
|
|
&DevicePathHandleCount,
|
|
&mDevicePathHandleBuffer
|
|
);
|
|
if (EFI_ERROR (Status) || (DevicePathHandleCount == 0)) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
for (Index = 0; Index < DevicePathHandleCount; Index++) {
|
|
if (FakeNvData->PciDeviceFilter == 0x01) {
|
|
//
|
|
// Only care PCI device which contain efi driver in its option rom.
|
|
//
|
|
|
|
//
|
|
// Check whether it is a pci device
|
|
//
|
|
ControllerDevicePath = NULL;
|
|
Status = gBS->OpenProtocol (
|
|
mDevicePathHandleBuffer[Index],
|
|
&gEfiPciIoProtocolGuid,
|
|
(VOID **) &PciIo,
|
|
NULL,
|
|
NULL,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
//
|
|
// Check whether it contain efi driver in its option rom
|
|
//
|
|
Status = gBS->HandleProtocol(
|
|
mDevicePathHandleBuffer[Index],
|
|
&gEfiBusSpecificDriverOverrideProtocolGuid,
|
|
(VOID **) &BusSpecificDriverOverride
|
|
);
|
|
if (EFI_ERROR (Status) || BusSpecificDriverOverride == NULL) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
ControllerDevicePath = NULL;
|
|
Status = gBS->OpenProtocol (
|
|
mDevicePathHandleBuffer[Index],
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID **) &ControllerDevicePath,
|
|
NULL,
|
|
NULL,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
//
|
|
// Save the device path protocol interface
|
|
//
|
|
mControllerDevicePathProtocol[Index] = ControllerDevicePath;
|
|
|
|
//
|
|
// Get the driver name
|
|
//
|
|
ControllerName = DevicePathToStr (ControllerDevicePath);
|
|
|
|
//
|
|
// Export the driver name string and create item in set options page
|
|
//
|
|
Len = StrSize (ControllerName);
|
|
NewString = AllocateZeroPool (Len + StrSize (L"--"));
|
|
ASSERT (NewString != NULL);
|
|
if (EFI_ERROR (CheckMapping (ControllerDevicePath,NULL, &mMappingDataBase, NULL, NULL))) {
|
|
StrCat (NewString, L"--");
|
|
} else {
|
|
StrCat (NewString, L"**");
|
|
}
|
|
StrCat (NewString, ControllerName);
|
|
|
|
NewStringToken = HiiSetString (Private->RegisteredHandle, mControllerToken[Index], NewString, NULL);
|
|
ASSERT (NewStringToken != 0);
|
|
FreePool (NewString);
|
|
//
|
|
// Save the device path string toke for next access use
|
|
//
|
|
mControllerToken[Index] = NewStringToken;
|
|
|
|
HiiCreateGotoOpCode (
|
|
StartOpCodeHandle,
|
|
FORM_ID_DRIVER,
|
|
NewStringToken,
|
|
STRING_TOKEN (STR_GOTO_HELP_DRIVER),
|
|
EFI_IFR_FLAG_CALLBACK,
|
|
(UINT16) (Index + KEY_VALUE_DEVICE_OFFSET)
|
|
);
|
|
}
|
|
|
|
//
|
|
// Update first page form
|
|
//
|
|
HiiUpdateForm (
|
|
Private->RegisteredHandle,
|
|
&gPlatformOverridesManagerGuid,
|
|
FORM_ID_DEVICE,
|
|
StartOpCodeHandle, // Label FORM_ID_DEVICE
|
|
EndOpCodeHandle // LABEL_END
|
|
);
|
|
|
|
HiiFreeOpCodeHandle (StartOpCodeHandle);
|
|
HiiFreeOpCodeHandle (EndOpCodeHandle);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get the first Driver Binding handle which has the specific image handle.
|
|
|
|
@param ImageHandle The Image handle
|
|
|
|
@return Handle to Driver binding
|
|
@retval NULL The paramter is not valid or the driver binding handle is not found.
|
|
|
|
**/
|
|
EFI_HANDLE
|
|
GetDriverBindingHandleFromImageHandle (
|
|
IN EFI_HANDLE ImageHandle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
UINTN DriverBindingHandleCount;
|
|
EFI_HANDLE *DriverBindingHandleBuffer;
|
|
EFI_DRIVER_BINDING_PROTOCOL *DriverBindingInterface;
|
|
EFI_HANDLE DriverBindingHandle;
|
|
|
|
DriverBindingHandle = NULL;
|
|
|
|
if (ImageHandle == NULL) {
|
|
return NULL;
|
|
}
|
|
//
|
|
// Get all drivers which support driver binding protocol
|
|
//
|
|
DriverBindingHandleCount = 0;
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiDriverBindingProtocolGuid,
|
|
NULL,
|
|
&DriverBindingHandleCount,
|
|
&DriverBindingHandleBuffer
|
|
);
|
|
if (EFI_ERROR (Status) || (DriverBindingHandleCount == 0)) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Get the first Driver Binding handle which has the specific image handle.
|
|
//
|
|
for (Index = 0; Index < DriverBindingHandleCount; Index++) {
|
|
DriverBindingInterface = NULL;
|
|
Status = gBS->OpenProtocol (
|
|
DriverBindingHandleBuffer[Index],
|
|
&gEfiDriverBindingProtocolGuid,
|
|
(VOID **) &DriverBindingInterface,
|
|
NULL,
|
|
NULL,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
if (DriverBindingInterface->ImageHandle == ImageHandle) {
|
|
DriverBindingHandle = DriverBindingHandleBuffer[Index];
|
|
break;
|
|
}
|
|
}
|
|
|
|
FreePool (DriverBindingHandleBuffer);
|
|
return DriverBindingHandle;
|
|
}
|
|
|
|
/**
|
|
Prepare to let user select the drivers which need mapping with the device controller
|
|
selected in first page.
|
|
|
|
@param Private Pointer to EFI_CALLBACK_INFO.
|
|
@param KeyValue The callback key value of device controller item in first page.
|
|
KeyValue is larger than or equal to KEY_VALUE_DEVICE_OFFSET.
|
|
@param FakeNvData Pointer to PLAT_OVER_MNGR_DATA.
|
|
|
|
@retval EFI_SUCCESS Always returned.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UpdateBindingDriverSelectPage (
|
|
IN EFI_CALLBACK_INFO *Private,
|
|
IN UINT16 KeyValue,
|
|
IN PLAT_OVER_MNGR_DATA *FakeNvData
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
CHAR16 *NewString;
|
|
EFI_STRING_ID NewStringToken;
|
|
EFI_STRING_ID NewStringHelpToken;
|
|
UINTN DriverImageHandleCount;
|
|
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
|
|
CHAR16 *DriverName;
|
|
BOOLEAN FreeDriverName;
|
|
EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;
|
|
EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *BusSpecificDriverOverride;
|
|
EFI_HANDLE DriverBindingHandle;
|
|
VOID *StartOpCodeHandle;
|
|
VOID *EndOpCodeHandle;
|
|
EFI_IFR_GUID_LABEL *StartLabel;
|
|
EFI_IFR_GUID_LABEL *EndLabel;
|
|
|
|
//
|
|
// If user select a controller item in the first page the following code will be run.
|
|
// During second page, user will see all currnet driver bind protocol driver, the driver name and its device path will be shown
|
|
//
|
|
//First acquire the list of Loaded Image Protocols, and then when want the name of the driver, look up all the Driver Binding Protocols
|
|
// and find the first one whose ImageHandle field matches the image handle of the Loaded Image Protocol.
|
|
// then use the Component Name Protocol on the same handle as the first matching Driver Binding Protocol to look up the name of the driver.
|
|
//
|
|
|
|
mCurrentPage = FORM_ID_DRIVER;
|
|
//
|
|
// Switch the item callback key value to its NO. in mDevicePathHandleBuffer
|
|
//
|
|
mSelectedCtrIndex = KeyValue - KEY_VALUE_DEVICE_OFFSET;
|
|
ASSERT (mSelectedCtrIndex >= 0 && mSelectedCtrIndex < MAX_CHOICE_NUM);
|
|
|
|
mLastSavedDriverImageNum = 0;
|
|
|
|
//
|
|
// Init OpCode Handle
|
|
//
|
|
StartOpCodeHandle = HiiAllocateOpCodeHandle ();
|
|
ASSERT (StartOpCodeHandle != NULL);
|
|
|
|
EndOpCodeHandle = HiiAllocateOpCodeHandle ();
|
|
ASSERT (EndOpCodeHandle != NULL);
|
|
|
|
//
|
|
// Create Hii Extend Label OpCode as the start opcode
|
|
//
|
|
StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
|
|
StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
|
|
StartLabel->Number = FORM_ID_DRIVER;
|
|
|
|
//
|
|
// Create Hii Extend Label OpCode as the end opcode
|
|
//
|
|
EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
|
|
EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
|
|
EndLabel->Number = LABEL_END;
|
|
|
|
//
|
|
// Clear second page form
|
|
//
|
|
HiiUpdateForm (
|
|
Private->RegisteredHandle,
|
|
&gPlatformOverridesManagerGuid,
|
|
FORM_ID_DRIVER,
|
|
StartOpCodeHandle,
|
|
EndOpCodeHandle
|
|
);
|
|
|
|
//
|
|
// Show all driver which support loaded image protocol in second page
|
|
//
|
|
DriverImageHandleCount = 0;
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiLoadedImageProtocolGuid,
|
|
NULL,
|
|
&DriverImageHandleCount,
|
|
&mDriverImageHandleBuffer
|
|
);
|
|
if (EFI_ERROR (Status) || (DriverImageHandleCount == 0)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
mDriverImageHandleCount = DriverImageHandleCount;
|
|
for (Index = 0; Index < DriverImageHandleCount; Index++) {
|
|
//
|
|
// Step1: Get the driver image total file path for help string and the driver name.
|
|
//
|
|
|
|
//
|
|
// Find driver's Loaded Image protocol
|
|
//
|
|
LoadedImage =NULL;
|
|
|
|
Status = gBS->OpenProtocol (
|
|
mDriverImageHandleBuffer[Index],
|
|
&gEfiLoadedImageProtocolGuid,
|
|
(VOID **) &LoadedImage,
|
|
NULL,
|
|
NULL,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
FakeNvData->DriSelection[Index] = 0x00;
|
|
continue;
|
|
}
|
|
mDriverImageProtocol[Index] = LoadedImage;
|
|
//
|
|
// Find its related driver binding protocol
|
|
//
|
|
DriverBindingHandle = GetDriverBindingHandleFromImageHandle (mDriverImageHandleBuffer[Index]);
|
|
if (DriverBindingHandle == NULL) {
|
|
FakeNvData->DriSelection[Index] = 0x00;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Get the EFI Loaded Image Device Path Protocol
|
|
//
|
|
LoadedImageDevicePath = NULL;
|
|
Status = gBS->HandleProtocol (
|
|
mDriverImageHandleBuffer[Index],
|
|
&gEfiLoadedImageDevicePathProtocolGuid,
|
|
(VOID **) &LoadedImageDevicePath
|
|
);
|
|
if (LoadedImageDevicePath == NULL) {
|
|
FakeNvData->DriSelection[Index] = 0x00;
|
|
continue;
|
|
}
|
|
|
|
if (FakeNvData->PciDeviceFilter == 0x01) {
|
|
//
|
|
// only care the driver which is in a Pci device option rom,
|
|
// and the driver's LoadedImage->DeviceHandle must point to a pci device which has efi option rom
|
|
//
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = gBS->HandleProtocol(
|
|
LoadedImage->DeviceHandle,
|
|
&gEfiBusSpecificDriverOverrideProtocolGuid,
|
|
(VOID **) &BusSpecificDriverOverride
|
|
);
|
|
if (EFI_ERROR (Status) || BusSpecificDriverOverride == NULL) {
|
|
FakeNvData->DriSelection[Index] = 0x00;
|
|
continue;
|
|
}
|
|
} else {
|
|
FakeNvData->DriSelection[Index] = 0x00;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// For driver name, try to get its component name, if fail, get its image name,
|
|
// if also fail, give a default name.
|
|
//
|
|
FreeDriverName = FALSE;
|
|
DriverName = GetComponentName (DriverBindingHandle);
|
|
if (DriverName == NULL) {
|
|
//
|
|
// get its image name
|
|
//
|
|
DriverName = GetImageName (LoadedImage);
|
|
}
|
|
if (DriverName == NULL) {
|
|
//
|
|
// give a default name
|
|
//
|
|
DriverName = HiiGetString (Private->RegisteredHandle, STRING_TOKEN (STR_DRIVER_DEFAULT_NAME), NULL);
|
|
ASSERT (DriverName != NULL);
|
|
FreeDriverName = TRUE; // the DriverName string need to free pool
|
|
}
|
|
|
|
|
|
//
|
|
// Step2 Export the driver name string and create check box item in second page
|
|
//
|
|
|
|
//
|
|
// First create the driver image name
|
|
//
|
|
NewString = AllocateZeroPool (StrSize (DriverName));
|
|
ASSERT (NewString != NULL);
|
|
if (EFI_ERROR (CheckMapping (mControllerDevicePathProtocol[mSelectedCtrIndex], LoadedImageDevicePath, &mMappingDataBase, NULL, NULL))) {
|
|
FakeNvData->DriSelection[Index] = 0x00;
|
|
} else {
|
|
FakeNvData->DriSelection[Index] = 0x01;
|
|
mLastSavedDriverImageNum++;
|
|
}
|
|
StrCat (NewString, DriverName);
|
|
NewStringToken = HiiSetString (Private->RegisteredHandle, mDriverImageToken[Index], NewString, NULL);
|
|
ASSERT (NewStringToken != 0);
|
|
mDriverImageToken[Index] = NewStringToken;
|
|
FreePool (NewString);
|
|
if (FreeDriverName) {
|
|
FreePool (DriverName);
|
|
}
|
|
|
|
//
|
|
// Second create the driver image device path as item help string
|
|
//
|
|
DriverName = DevicePathToStr (LoadedImageDevicePath);
|
|
|
|
NewString = AllocateZeroPool (StrSize (DriverName));
|
|
ASSERT (NewString != NULL);
|
|
StrCat (NewString, DriverName);
|
|
NewStringHelpToken = HiiSetString (Private->RegisteredHandle, mDriverImageFilePathToken[Index], NewString, NULL);
|
|
ASSERT (NewStringHelpToken != 0);
|
|
mDriverImageFilePathToken[Index] = NewStringHelpToken;
|
|
FreePool (NewString);
|
|
FreePool (DriverName);
|
|
|
|
HiiCreateCheckBoxOpCode (
|
|
StartOpCodeHandle,
|
|
(UINT16) (DRIVER_SELECTION_QUESTION_ID + Index),
|
|
VARSTORE_ID_PLAT_OVER_MNGR,
|
|
(UINT16) (DRIVER_SELECTION_VAR_OFFSET + Index),
|
|
NewStringToken,
|
|
NewStringHelpToken,
|
|
0,
|
|
0,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
//
|
|
// Update second page form
|
|
//
|
|
HiiUpdateForm (
|
|
Private->RegisteredHandle,
|
|
&gPlatformOverridesManagerGuid,
|
|
FORM_ID_DRIVER,
|
|
StartOpCodeHandle, // Label FORM_ID_DRIVER
|
|
EndOpCodeHandle // LABEL_END
|
|
);
|
|
|
|
HiiFreeOpCodeHandle (StartOpCodeHandle);
|
|
HiiFreeOpCodeHandle (EndOpCodeHandle);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Prepare to let user select the priority order of the drivers which are
|
|
selected in second page.
|
|
|
|
@param Private Pointer to EFI_CALLBACK_INFO.
|
|
@param KeyValue The callback key value of device controller item in first page.
|
|
@param FakeNvData Pointer to PLAT_OVER_MNGR_DATA.
|
|
|
|
@retval EFI_SUCCESS Always returned.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UpdatePrioritySelectPage (
|
|
IN EFI_CALLBACK_INFO *Private,
|
|
IN UINT16 KeyValue,
|
|
IN PLAT_OVER_MNGR_DATA *FakeNvData
|
|
)
|
|
{
|
|
UINTN Index;
|
|
EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;
|
|
UINTN SelectedDriverImageNum;
|
|
UINT32 DriverImageNO;
|
|
UINTN MinNO;
|
|
UINTN Index1;
|
|
UINTN TempNO[100];
|
|
UINTN OrderNO[100];
|
|
VOID *StartOpCodeHandle;
|
|
VOID *EndOpCodeHandle;
|
|
VOID *OptionsOpCodeHandle;
|
|
EFI_IFR_GUID_LABEL *StartLabel;
|
|
EFI_IFR_GUID_LABEL *EndLabel;
|
|
|
|
//
|
|
// Following code will be run if user select 'order ... priority' item in second page
|
|
// Prepare third page. In third page, user will order the drivers priority which are selected in second page
|
|
//
|
|
mCurrentPage = FORM_ID_ORDER;
|
|
|
|
//
|
|
// Init OpCode Handle
|
|
//
|
|
StartOpCodeHandle = HiiAllocateOpCodeHandle ();
|
|
ASSERT (StartOpCodeHandle != NULL);
|
|
|
|
EndOpCodeHandle = HiiAllocateOpCodeHandle ();
|
|
ASSERT (EndOpCodeHandle != NULL);
|
|
|
|
//
|
|
// Create Hii Extend Label OpCode as the start opcode
|
|
//
|
|
StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
|
|
StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
|
|
StartLabel->Number = FORM_ID_ORDER;
|
|
|
|
//
|
|
// Create Hii Extend Label OpCode as the end opcode
|
|
//
|
|
EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
|
|
EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
|
|
EndLabel->Number = LABEL_END;
|
|
|
|
//
|
|
// Clear third page form
|
|
//
|
|
HiiUpdateForm (
|
|
Private->RegisteredHandle,
|
|
&gPlatformOverridesManagerGuid,
|
|
FORM_ID_ORDER,
|
|
StartOpCodeHandle,
|
|
EndOpCodeHandle
|
|
);
|
|
|
|
//
|
|
// Check how many drivers have been selected
|
|
//
|
|
SelectedDriverImageNum = 0;
|
|
for (Index = 0; Index < mDriverImageHandleCount; Index++) {
|
|
if (FakeNvData->DriSelection[Index] != 0) {
|
|
SelectedDriverImageNum ++;
|
|
}
|
|
}
|
|
|
|
mSelectedDriverImageNum = SelectedDriverImageNum;
|
|
if (SelectedDriverImageNum == 0) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
|
|
ASSERT (OptionsOpCodeHandle != NULL);
|
|
|
|
//
|
|
// Create order list for those selected drivers
|
|
//
|
|
SelectedDriverImageNum = 0;
|
|
for (Index = 0; Index < mDriverImageHandleCount; Index++) {
|
|
if (FakeNvData->DriSelection[Index] != 0) {
|
|
//
|
|
// Use the NO. in driver binding buffer as value, will use it later
|
|
//
|
|
HiiCreateOneOfOptionOpCode (
|
|
OptionsOpCodeHandle,
|
|
mDriverImageToken[Index],
|
|
0,
|
|
EFI_IFR_NUMERIC_SIZE_1,
|
|
Index + 1
|
|
);
|
|
|
|
//
|
|
// Get the EFI Loaded Image Device Path Protocol
|
|
//
|
|
LoadedImageDevicePath = NULL;
|
|
gBS->HandleProtocol (
|
|
mDriverImageHandleBuffer[Index],
|
|
&gEfiLoadedImageDevicePathProtocolGuid,
|
|
(VOID **) &LoadedImageDevicePath
|
|
);
|
|
ASSERT (LoadedImageDevicePath != NULL);
|
|
|
|
//
|
|
// Check the driver DriverImage's order number in mapping database
|
|
//
|
|
DriverImageNO = 0;
|
|
CheckMapping (
|
|
mControllerDevicePathProtocol[mSelectedCtrIndex],
|
|
LoadedImageDevicePath,
|
|
&mMappingDataBase,
|
|
NULL,
|
|
&DriverImageNO
|
|
);
|
|
if (DriverImageNO == 0) {
|
|
DriverImageNO = (UINT32) mLastSavedDriverImageNum + 1;
|
|
mLastSavedDriverImageNum++;
|
|
}
|
|
TempNO[SelectedDriverImageNum] = DriverImageNO;
|
|
OrderNO[SelectedDriverImageNum] = Index + 1;
|
|
SelectedDriverImageNum ++;
|
|
}
|
|
}
|
|
|
|
ASSERT (SelectedDriverImageNum == mSelectedDriverImageNum);
|
|
//
|
|
// NvRamMap Must be clear firstly
|
|
//
|
|
ZeroMem (FakeNvData->DriOrder, sizeof (FakeNvData->DriOrder));
|
|
|
|
//
|
|
// Order the selected drivers according to the info already in mapping database
|
|
// the less order number in mapping database the less order number in NvRamMap
|
|
//
|
|
for (Index=0; Index < SelectedDriverImageNum; Index++) {
|
|
//
|
|
// Find the minimal order number in TempNO array, its index in TempNO is same as IfrOptionList array
|
|
//
|
|
MinNO = 0;
|
|
for (Index1=0; Index1 < SelectedDriverImageNum; Index1++) {
|
|
if (TempNO[Index1] < TempNO[MinNO]) {
|
|
MinNO = Index1;
|
|
}
|
|
}
|
|
//
|
|
// the IfrOptionList[MinNO].Value = the driver NO. in driver binding buffer
|
|
//
|
|
FakeNvData->DriOrder[Index] = (UINT8) OrderNO[MinNO];
|
|
TempNO[MinNO] = MAX_CHOICE_NUM + 1;
|
|
}
|
|
|
|
//
|
|
// Create Order List OpCode
|
|
//
|
|
HiiCreateOrderedListOpCode (
|
|
StartOpCodeHandle,
|
|
(UINT16) DRIVER_ORDER_QUESTION_ID,
|
|
VARSTORE_ID_PLAT_OVER_MNGR,
|
|
(UINT16) DRIVER_ORDER_VAR_OFFSET,
|
|
mControllerToken[mSelectedCtrIndex],
|
|
mControllerToken[mSelectedCtrIndex],
|
|
EFI_IFR_FLAG_RESET_REQUIRED,
|
|
0,
|
|
EFI_IFR_NUMERIC_SIZE_1,
|
|
(UINT8) MAX_CHOICE_NUM,
|
|
OptionsOpCodeHandle,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Update third page form
|
|
//
|
|
HiiUpdateForm (
|
|
Private->RegisteredHandle,
|
|
&gPlatformOverridesManagerGuid,
|
|
FORM_ID_ORDER,
|
|
StartOpCodeHandle, // Label FORM_ID_ORDER
|
|
EndOpCodeHandle // LABEL_END
|
|
);
|
|
|
|
HiiFreeOpCodeHandle (StartOpCodeHandle);
|
|
HiiFreeOpCodeHandle (EndOpCodeHandle);
|
|
HiiFreeOpCodeHandle (OptionsOpCodeHandle);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Save the save the mapping database to NV variable.
|
|
|
|
@param Private Pointer to EFI_CALLBACK_INFO.
|
|
@param KeyValue The callback key value of device controller item in first page.
|
|
@param FakeNvData Pointer to PLAT_OVER_MNGR_DATA.
|
|
|
|
@retval EFI_SUCCESS Always returned.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
CommintChanges (
|
|
IN EFI_CALLBACK_INFO *Private,
|
|
IN UINT16 KeyValue,
|
|
IN PLAT_OVER_MNGR_DATA *FakeNvData
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
UINTN SelectedDriverImageNum;
|
|
EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;
|
|
//
|
|
// Following code will be run if user select 'commint changes' in third page
|
|
// user enter 'Commit Changes' to save the mapping database
|
|
//
|
|
DeleteDriverImage (mControllerDevicePathProtocol[mSelectedCtrIndex], NULL, &mMappingDataBase);
|
|
for (SelectedDriverImageNum = 0; SelectedDriverImageNum < mSelectedDriverImageNum; SelectedDriverImageNum++) {
|
|
//
|
|
// DriOrder[SelectedDriverImageNum] = the driver NO. in driver binding buffer
|
|
//
|
|
Index = FakeNvData->DriOrder[SelectedDriverImageNum] - 1;
|
|
|
|
//
|
|
// Get the EFI Loaded Image Device Path Protocol
|
|
//
|
|
LoadedImageDevicePath = NULL;
|
|
Status = gBS->HandleProtocol (
|
|
mDriverImageHandleBuffer[Index],
|
|
&gEfiLoadedImageDevicePathProtocolGuid,
|
|
(VOID **) &LoadedImageDevicePath
|
|
);
|
|
ASSERT (LoadedImageDevicePath != NULL);
|
|
|
|
InsertDriverImage (
|
|
mControllerDevicePathProtocol[mSelectedCtrIndex],
|
|
LoadedImageDevicePath,
|
|
&mMappingDataBase,
|
|
(UINT32)SelectedDriverImageNum + 1
|
|
);
|
|
}
|
|
Status = SaveOverridesMapping (&mMappingDataBase);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
This function allows a caller to extract the current configuration for one
|
|
or more named elements from the target driver.
|
|
|
|
@param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
|
|
@param Request A null-terminated Unicode string in <ConfigRequest> format.
|
|
@param Progress On return, points to a character in the Request string.
|
|
Points to the string's null terminator if request was successful.
|
|
Points to the most recent '&' before the first failing name/value
|
|
pair (or the beginning of the string if the failure is in the
|
|
first name/value pair) if the request was not successful.
|
|
@param Results A null-terminated Unicode string in <ConfigAltResp> format which
|
|
has all values filled in for the names in the Request string.
|
|
String to be allocated by the called function.
|
|
|
|
@retval EFI_SUCCESS The Results is filled with the requested values.
|
|
@retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
|
|
@retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
|
|
@retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PlatOverMngrExtractConfig (
|
|
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
|
|
IN CONST EFI_STRING Request,
|
|
OUT EFI_STRING *Progress,
|
|
OUT EFI_STRING *Results
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_CALLBACK_INFO *Private;
|
|
EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
|
|
EFI_STRING ConfigRequestHdr;
|
|
EFI_STRING ConfigRequest;
|
|
BOOLEAN AllocatedRequest;
|
|
UINTN Size;
|
|
UINTN BufferSize;
|
|
|
|
if (Progress == NULL || Results == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
*Progress = Request;
|
|
if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gPlatformOverridesManagerGuid, mVariableName)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
ConfigRequestHdr = NULL;
|
|
ConfigRequest = NULL;
|
|
Size = 0;
|
|
AllocatedRequest = FALSE;
|
|
|
|
Private = EFI_CALLBACK_INFO_FROM_THIS (This);
|
|
HiiConfigRouting = Private->HiiConfigRouting;
|
|
ConfigRequest = Request;
|
|
if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
|
|
//
|
|
// Request has no request element, construct full request string.
|
|
// Allocate and fill a buffer large enough to hold the <ConfigHdr> template
|
|
// followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
|
|
//
|
|
ConfigRequestHdr = HiiConstructConfigHdr (&gPlatformOverridesManagerGuid, mVariableName, Private->DriverHandle);
|
|
Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
|
|
ConfigRequest = AllocateZeroPool (Size);
|
|
ASSERT (ConfigRequest != NULL);
|
|
AllocatedRequest = TRUE;
|
|
BufferSize = sizeof (PLAT_OVER_MNGR_DATA);
|
|
UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
|
|
FreePool (ConfigRequestHdr);
|
|
}
|
|
|
|
//
|
|
// Convert buffer data to <ConfigResp> by helper function BlockToConfig()
|
|
//
|
|
Status = HiiConfigRouting->BlockToConfig (
|
|
HiiConfigRouting,
|
|
ConfigRequest,
|
|
(UINT8 *) &Private->FakeNvData,
|
|
sizeof (PLAT_OVER_MNGR_DATA),
|
|
Results,
|
|
Progress
|
|
);
|
|
|
|
//
|
|
// Free the allocated config request string.
|
|
//
|
|
if (AllocatedRequest) {
|
|
FreePool (ConfigRequest);
|
|
ConfigRequest = NULL;
|
|
}
|
|
//
|
|
// Set Progress string to the original request string.
|
|
//
|
|
if (Request == NULL) {
|
|
*Progress = NULL;
|
|
} else if (StrStr (Request, L"OFFSET") == NULL) {
|
|
*Progress = Request + StrLen (Request);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
This function processes the results of changes in configuration.
|
|
|
|
@param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
|
|
@param Configuration A null-terminated Unicode string in <ConfigRequest> format.
|
|
@param Progress A pointer to a string filled in with the offset of the most
|
|
recent '&' before the first failing name/value pair (or the
|
|
beginning of the string if the failure is in the first
|
|
name/value pair) or the terminating NULL if all was successful.
|
|
|
|
@retval EFI_SUCCESS The Results is processed successfully.
|
|
@retval EFI_INVALID_PARAMETER Configuration is NULL.
|
|
@retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PlatOverMngrRouteConfig (
|
|
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
|
|
IN CONST EFI_STRING Configuration,
|
|
OUT EFI_STRING *Progress
|
|
)
|
|
{
|
|
EFI_CALLBACK_INFO *Private;
|
|
UINT16 KeyValue;
|
|
PLAT_OVER_MNGR_DATA *FakeNvData;
|
|
|
|
if (Configuration == NULL || Progress == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
*Progress = Configuration;
|
|
|
|
if (!HiiIsConfigHdrMatch (Configuration, &gPlatformOverridesManagerGuid, mVariableName)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
*Progress = Configuration + StrLen (Configuration);
|
|
Private = EFI_CALLBACK_INFO_FROM_THIS (This);
|
|
FakeNvData = &Private->FakeNvData;
|
|
if (!HiiGetBrowserData (&gPlatformOverridesManagerGuid, mVariableName, sizeof (PLAT_OVER_MNGR_DATA), (UINT8 *) FakeNvData)) {
|
|
//
|
|
// FakeNvData can't be got from SetupBrowser, which doesn't need to be set.
|
|
//
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (mCurrentPage == FORM_ID_DRIVER) {
|
|
KeyValue = KEY_VALUE_DRIVER_GOTO_ORDER;
|
|
UpdatePrioritySelectPage (Private, KeyValue, FakeNvData);
|
|
KeyValue = KEY_VALUE_ORDER_SAVE_AND_EXIT;
|
|
CommintChanges (Private, KeyValue, FakeNvData);
|
|
//
|
|
// Since UpdatePrioritySelectPage will change mCurrentPage,
|
|
// should ensure the mCurrentPage still indicate the second page here
|
|
//
|
|
mCurrentPage = FORM_ID_DRIVER;
|
|
}
|
|
|
|
if (mCurrentPage == FORM_ID_ORDER) {
|
|
KeyValue = KEY_VALUE_ORDER_SAVE_AND_EXIT;
|
|
CommintChanges (Private, KeyValue, FakeNvData);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This is the function that is called to provide results data to the driver. This data
|
|
consists of a unique key which is used to identify what data is either being passed back
|
|
or being asked for.
|
|
|
|
@param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
|
|
@param Action A null-terminated Unicode string in <ConfigRequest> format.
|
|
@param KeyValue A unique Goto OpCode callback value which record user's selection.
|
|
0x100 <= KeyValue <0x500 : user select a controller item in the first page;
|
|
KeyValue == 0x1234 : user select 'Refresh' in first page, or user select 'Go to Previous Menu' in second page
|
|
KeyValue == 0x1235 : user select 'Pci device filter' in first page
|
|
KeyValue == 0x1500 : user select 'order ... priority' item in second page
|
|
KeyValue == 0x1800 : user select 'commint changes' in third page
|
|
KeyValue == 0x2000 : user select 'Go to Previous Menu' in third page
|
|
@param Type The type of value for the question.
|
|
@param Value A pointer to the data being sent to the original exporting driver.
|
|
@param ActionRequest On return, points to the action requested by the callback function.
|
|
|
|
@retval EFI_SUCCESS Always returned.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PlatOverMngrCallback (
|
|
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
|
|
IN EFI_BROWSER_ACTION Action,
|
|
IN EFI_QUESTION_ID KeyValue,
|
|
IN UINT8 Type,
|
|
IN EFI_IFR_TYPE_VALUE *Value,
|
|
OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
|
|
)
|
|
{
|
|
EFI_CALLBACK_INFO *Private;
|
|
EFI_STATUS Status;
|
|
EFI_STRING_ID NewStringToken;
|
|
EFI_INPUT_KEY Key;
|
|
PLAT_OVER_MNGR_DATA *FakeNvData;
|
|
|
|
if (Action == EFI_BROWSER_ACTION_CHANGING) {
|
|
Private = EFI_CALLBACK_INFO_FROM_THIS (This);
|
|
FakeNvData = &Private->FakeNvData;
|
|
if (!HiiGetBrowserData (&gPlatformOverridesManagerGuid, mVariableName, sizeof (PLAT_OVER_MNGR_DATA), (UINT8 *) FakeNvData)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
if (KeyValue == KEY_VALUE_DEVICE_REFRESH ||
|
|
KeyValue == KEY_VALUE_DEVICE_FILTER ||
|
|
KeyValue == KEY_VALUE_DRIVER_GOTO_PREVIOUS
|
|
) {
|
|
UpdateDeviceSelectPage (Private, KeyValue, FakeNvData);
|
|
//
|
|
// Update page title string
|
|
//
|
|
NewStringToken = STRING_TOKEN (STR_TITLE);
|
|
if (HiiSetString (Private->RegisteredHandle, NewStringToken, L"First, Select the controller by device path", NULL) == 0) {
|
|
ASSERT (FALSE);
|
|
}
|
|
}
|
|
|
|
if (((KeyValue >= KEY_VALUE_DEVICE_OFFSET) && (KeyValue < KEY_VALUE_DEVICE_MAX)) || (KeyValue == KEY_VALUE_ORDER_GOTO_PREVIOUS)) {
|
|
if (KeyValue == KEY_VALUE_ORDER_GOTO_PREVIOUS) {
|
|
KeyValue = (EFI_QUESTION_ID) (mSelectedCtrIndex + KEY_VALUE_DEVICE_OFFSET);
|
|
}
|
|
UpdateBindingDriverSelectPage (Private, KeyValue, FakeNvData);
|
|
//
|
|
// Update page title string
|
|
//
|
|
NewStringToken = STRING_TOKEN (STR_TITLE);
|
|
if (HiiSetString (Private->RegisteredHandle, NewStringToken, L"Second, Select drivers for the previous selected controller", NULL) == 0) {
|
|
ASSERT (FALSE);
|
|
}
|
|
}
|
|
|
|
if (KeyValue == KEY_VALUE_DRIVER_GOTO_ORDER) {
|
|
UpdatePrioritySelectPage (Private, KeyValue, FakeNvData);
|
|
//
|
|
// Update page title string
|
|
//
|
|
NewStringToken = STRING_TOKEN (STR_TITLE);
|
|
if (HiiSetString (Private->RegisteredHandle, NewStringToken, L"Finally, Set the priority order for the drivers and save them", NULL) == 0) {
|
|
ASSERT (FALSE);
|
|
}
|
|
}
|
|
|
|
if (KeyValue == KEY_VALUE_ORDER_SAVE_AND_EXIT) {
|
|
Status = CommintChanges (Private, KeyValue, FakeNvData);
|
|
*ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
|
|
if (EFI_ERROR (Status)) {
|
|
CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Single Override Info too large, Saving Error!", NULL);
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
}
|
|
|
|
if (KeyValue == KEY_VALUE_DEVICE_CLEAR) {
|
|
//
|
|
// Deletes all environment variable(s) that contain the override mappings info
|
|
//
|
|
FreeMappingDatabase (&mMappingDataBase);
|
|
Status = SaveOverridesMapping (&mMappingDataBase);
|
|
UpdateDeviceSelectPage (Private, KeyValue, FakeNvData);
|
|
}
|
|
//
|
|
// Pass changed uncommitted data back to Form Browser
|
|
//
|
|
HiiSetBrowserData (&gPlatformOverridesManagerGuid, mVariableName, sizeof (PLAT_OVER_MNGR_DATA), (UINT8 *) FakeNvData, NULL);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// All other action return unsupported.
|
|
//
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
/**
|
|
Retrieves the image handle of the platform override driver for a controller in the system.
|
|
|
|
@param This A pointer to the
|
|
EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL instance.
|
|
@param ControllerHandle The device handle of the controller to check if a
|
|
driver override exists.
|
|
@param DriverImageHandle On input, a pointer to the previous driver image
|
|
handle returned by GetDriver(). On output, a
|
|
pointer to the next driver image handle. Passing
|
|
in a NULL, will return the first driver image
|
|
handle for ControllerHandle.
|
|
|
|
@retval EFI_SUCCESS The driver override for ControllerHandle was
|
|
returned in DriverImageHandle.
|
|
@retval EFI_NOT_FOUND A driver override for ControllerHandle was not
|
|
found.
|
|
@retval EFI_INVALID_PARAMETER The handle specified by ControllerHandle is NULL.
|
|
DriverImageHandle is not a handle that was returned
|
|
on a previous call to GetDriver().
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
GetDriver (
|
|
IN EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *This,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN OUT EFI_HANDLE *DriverImageHandle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
//
|
|
// Check that ControllerHandle is a valid handle
|
|
//
|
|
if (ControllerHandle == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Read the environment variable(s) that contain the override mappings from Controller Device Path to
|
|
// a set of Driver Device Paths, and initialize in memory database of the overrides that map Controller
|
|
// Device Paths to an ordered set of Driver Device Paths and Driver Handles. This action is only performed
|
|
// once and finished in first call.
|
|
//
|
|
if (!mEnvironmentVariableRead) {
|
|
mEnvironmentVariableRead = TRUE;
|
|
|
|
Status = InitOverridesMapping (&mMappingDataBase);
|
|
if (EFI_ERROR (Status)){
|
|
DEBUG ((DEBUG_ERROR, "The status to Get Platform Driver Override Variable is %r\n", Status));
|
|
InitializeListHead (&mMappingDataBase);
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
//
|
|
// if the environment variable does not exist, just return not found
|
|
//
|
|
if (IsListEmpty (&mMappingDataBase)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
return GetDriverFromMapping (
|
|
ControllerHandle,
|
|
DriverImageHandle,
|
|
&mMappingDataBase,
|
|
mCallerImageHandle
|
|
);
|
|
}
|
|
|
|
/**
|
|
Retrieves the device path of the platform override driver for a controller in the system.
|
|
This driver doesn't support this API.
|
|
|
|
@param This A pointer to the EFI_PLATFORM_DRIVER_OVERRIDE_
|
|
PROTOCOL instance.
|
|
@param ControllerHandle The device handle of the controller to check if a driver override
|
|
exists.
|
|
@param DriverImagePath On input, a pointer to the previous driver device path returned by
|
|
GetDriverPath(). On output, a pointer to the next driver
|
|
device path. Passing in a pointer to NULL, will return the first
|
|
driver device path for ControllerHandle.
|
|
|
|
@retval EFI_UNSUPPORTED
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
GetDriverPath (
|
|
IN EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *This,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN OUT EFI_DEVICE_PATH_PROTOCOL **DriverImagePath
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
|
|
/**
|
|
Used to associate a driver image handle with a device path that was returned on a prior call to the
|
|
GetDriverPath() service. This driver image handle will then be available through the
|
|
GetDriver() service. This driver doesn't support this API.
|
|
|
|
@param This A pointer to the EFI_PLATFORM_DRIVER_OVERRIDE_
|
|
PROTOCOL instance.
|
|
@param ControllerHandle The device handle of the controller.
|
|
@param DriverImagePath A pointer to the driver device path that was returned in a prior
|
|
call to GetDriverPath().
|
|
@param DriverImageHandle The driver image handle that was returned by LoadImage()
|
|
when the driver specified by DriverImagePath was loaded
|
|
into memory.
|
|
|
|
@retval EFI_UNSUPPORTED
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DriverLoaded (
|
|
IN EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *This,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DriverImagePath,
|
|
IN EFI_HANDLE DriverImageHandle
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
/**
|
|
The driver Entry Point. The funciton will export a disk device class formset and
|
|
its callback function to hii database.
|
|
|
|
@param ImageHandle The firmware allocated handle for the EFI image.
|
|
@param SystemTable A pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS The entry point is executed successfully.
|
|
@retval other Some error occurs when executing this entry point.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PlatDriOverrideDxeInit (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
|
|
VOID *Instance;
|
|
|
|
//
|
|
// There should only be one Form Configuration protocol
|
|
//
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiFormBrowser2ProtocolGuid,
|
|
NULL,
|
|
(VOID **) &FormBrowser2
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// According to UEFI spec, there can be at most a single instance
|
|
// in the system of the EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL.
|
|
// So here we check the existence.
|
|
//
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiPlatformDriverOverrideProtocolGuid,
|
|
NULL,
|
|
&Instance
|
|
);
|
|
//
|
|
// If there was no error, assume there is an installation and return error
|
|
//
|
|
if (!EFI_ERROR (Status)) {
|
|
return EFI_ALREADY_STARTED;
|
|
}
|
|
|
|
mCallerImageHandle = ImageHandle;
|
|
mCallbackInfo = AllocateZeroPool (sizeof (EFI_CALLBACK_INFO));
|
|
if (mCallbackInfo == NULL) {
|
|
return EFI_BAD_BUFFER_SIZE;
|
|
}
|
|
|
|
mCallbackInfo->Signature = EFI_CALLBACK_INFO_SIGNATURE;
|
|
mCallbackInfo->ConfigAccess.ExtractConfig = PlatOverMngrExtractConfig;
|
|
mCallbackInfo->ConfigAccess.RouteConfig = PlatOverMngrRouteConfig;
|
|
mCallbackInfo->ConfigAccess.Callback = PlatOverMngrCallback;
|
|
mCallbackInfo->PlatformDriverOverride.GetDriver = GetDriver;
|
|
mCallbackInfo->PlatformDriverOverride.GetDriverPath = GetDriverPath;
|
|
mCallbackInfo->PlatformDriverOverride.DriverLoaded = DriverLoaded;
|
|
//
|
|
// Install Device Path Protocol and Config Access protocol to driver handle
|
|
// Install Platform Driver Override Protocol to driver handle
|
|
//
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&mCallbackInfo->DriverHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
&mHiiVendorDevicePath,
|
|
&gEfiHiiConfigAccessProtocolGuid,
|
|
&mCallbackInfo->ConfigAccess,
|
|
&gEfiPlatformDriverOverrideProtocolGuid,
|
|
&mCallbackInfo->PlatformDriverOverride,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Finish;
|
|
}
|
|
|
|
//
|
|
// Publish our HII data
|
|
//
|
|
mCallbackInfo->RegisteredHandle = HiiAddPackages (
|
|
&gPlatformOverridesManagerGuid,
|
|
mCallbackInfo->DriverHandle,
|
|
VfrBin,
|
|
PlatDriOverrideDxeStrings,
|
|
NULL
|
|
);
|
|
if (mCallbackInfo->RegisteredHandle == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Finish;
|
|
}
|
|
|
|
//
|
|
// Locate ConfigRouting protocol
|
|
//
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiHiiConfigRoutingProtocolGuid,
|
|
NULL,
|
|
(VOID **) &mCallbackInfo->HiiConfigRouting
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Finish;
|
|
}
|
|
|
|
//
|
|
// Clear all the globle variable
|
|
//
|
|
mDriverImageHandleCount = 0;
|
|
mCurrentPage = 0;
|
|
ZeroMem (mDriverImageToken, MAX_CHOICE_NUM * sizeof (EFI_STRING_ID));
|
|
ZeroMem (mDriverImageFilePathToken, MAX_CHOICE_NUM * sizeof (EFI_STRING_ID));
|
|
ZeroMem (mControllerToken, MAX_CHOICE_NUM * sizeof (EFI_STRING_ID));
|
|
ZeroMem (mDriverImageProtocol, MAX_CHOICE_NUM * sizeof (EFI_LOADED_IMAGE_PROTOCOL *));
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
Finish:
|
|
PlatDriOverrideDxeUnload (ImageHandle);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Unload its installed protocol.
|
|
|
|
@param[in] ImageHandle Handle that identifies the image to be unloaded.
|
|
|
|
@retval EFI_SUCCESS The image has been unloaded.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PlatDriOverrideDxeUnload (
|
|
IN EFI_HANDLE ImageHandle
|
|
)
|
|
{
|
|
ASSERT (mCallbackInfo != NULL);
|
|
|
|
if (mCallbackInfo->DriverHandle != NULL) {
|
|
gBS->UninstallMultipleProtocolInterfaces (
|
|
mCallbackInfo->DriverHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
&mHiiVendorDevicePath,
|
|
&gEfiHiiConfigAccessProtocolGuid,
|
|
&mCallbackInfo->ConfigAccess,
|
|
&gEfiPlatformDriverOverrideProtocolGuid,
|
|
&mCallbackInfo->PlatformDriverOverride,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
if (mCallbackInfo->RegisteredHandle != NULL) {
|
|
HiiRemovePackages (mCallbackInfo->RegisteredHandle);
|
|
}
|
|
|
|
FreePool (mCallbackInfo);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|