From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- .../PlatformDriOverrideDxe/PlatDriOverrideDxe.c | 1744 ++++++++++++++++++++ 1 file changed, 1744 insertions(+) create mode 100644 roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideDxe.c (limited to 'roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideDxe.c') diff --git a/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideDxe.c b/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideDxe.c new file mode 100644 index 000000000..045c57415 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Universal/PlatformDriOverrideDxe/PlatDriOverrideDxe.c @@ -0,0 +1,1744 @@ +/** @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 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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; +UINTN mDriverImageHandleCount; +EFI_STRING_ID *mDriverImageToken; +EFI_DEVICE_PATH_PROTOCOL **mControllerDevicePathProtocol; +UINTN mSelectedDriverImageNum; +UINTN mLastSavedDriverImageNum; +UINT16 mCurrentPage; +EFI_CALLBACK_INFO *mCallbackInfo; +BOOLEAN *mDriSelection; +UINTN mMaxDeviceCount; + +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. + + @param DevPath Given device path instance + + @return Converted string from given device path. + @retval L"?" Converting failed. +**/ +CHAR16 * +DevicePathToStr ( + IN EFI_DEVICE_PATH_PROTOCOL *DevPath + ) +{ + CHAR16 *Text; + Text = ConvertDevicePathToText ( + DevPath, + FALSE, + TRUE + ); + if (Text == NULL) { + Text = AllocateCopyPool (sizeof (L"?"), L"?"); + ASSERT (Text != NULL); + } + + return Text; +} + +/** + 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. + // + GetEfiGlobalVariable2 (VariableName, (VOID**)&Language, NULL); + 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; + UINTN NewStrSize; + 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; + } + + mMaxDeviceCount = DevicePathHandleCount; + mControllerDevicePathProtocol = AllocateZeroPool (DevicePathHandleCount * sizeof (EFI_DEVICE_PATH_PROTOCOL *)); + ASSERT (mControllerDevicePathProtocol != NULL); + mControllerToken = AllocateZeroPool (DevicePathHandleCount * sizeof (EFI_STRING_ID)); + ASSERT (mControllerToken != NULL); + + 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); + NewStrSize = Len + StrSize (L"--"); + NewString = AllocateZeroPool (NewStrSize); + ASSERT (NewString != NULL); + if (EFI_ERROR (CheckMapping (ControllerDevicePath,NULL, &mMappingDataBase, NULL, NULL))) { + StrCatS (NewString, NewStrSize/sizeof(CHAR16), L"--"); + } else { + StrCatS (NewString, NewStrSize/sizeof(CHAR16), L"**"); + } + StrCatS (NewString, NewStrSize/sizeof(CHAR16), 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 parameter 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; + UINTN NewStrSize; + 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; + EFI_LOADED_IMAGE_PROTOCOL **DriverImageProtocol; + EFI_STRING_ID *DriverImageFilePathToken; + UINT8 CheckFlags; + + // + // 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; + } + + mDriverImageToken = AllocateZeroPool (DriverImageHandleCount * sizeof (EFI_STRING_ID)); + ASSERT (mDriverImageToken != NULL); + mDriSelection = AllocateZeroPool (DriverImageHandleCount * sizeof (BOOLEAN)); + ASSERT (mDriSelection != NULL); + + DriverImageProtocol = AllocateZeroPool (DriverImageHandleCount * sizeof (EFI_LOADED_IMAGE_PROTOCOL *)); + ASSERT (DriverImageProtocol != NULL); + DriverImageFilePathToken = AllocateZeroPool (DriverImageHandleCount * sizeof (EFI_STRING_ID)); + ASSERT (DriverImageFilePathToken != NULL); + + 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)) { + mDriSelection[Index] = FALSE; + continue; + } + DriverImageProtocol[Index] = LoadedImage; + // + // Find its related driver binding protocol + // + DriverBindingHandle = GetDriverBindingHandleFromImageHandle (mDriverImageHandleBuffer[Index]); + if (DriverBindingHandle == NULL) { + mDriSelection[Index] = FALSE; + continue; + } + + // + // Get the EFI Loaded Image Device Path Protocol + // + LoadedImageDevicePath = NULL; + Status = gBS->HandleProtocol ( + mDriverImageHandleBuffer[Index], + &gEfiLoadedImageDevicePathProtocolGuid, + (VOID **) &LoadedImageDevicePath + ); + if (LoadedImageDevicePath == NULL) { + mDriSelection[Index] = FALSE; + 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) { + mDriSelection[Index] = FALSE; + continue; + } + } else { + mDriSelection[Index] = FALSE; + 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 + // + NewStrSize = StrSize (DriverName); + NewString = AllocateZeroPool (NewStrSize); + ASSERT (NewString != NULL); + if (EFI_ERROR (CheckMapping (mControllerDevicePathProtocol[mSelectedCtrIndex], LoadedImageDevicePath, &mMappingDataBase, NULL, NULL))) { + mDriSelection[Index] = FALSE; + } else { + mDriSelection[Index] = TRUE; + mLastSavedDriverImageNum++; + } + StrCatS (NewString, NewStrSize/sizeof(CHAR16), 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); + + NewStrSize = StrSize (DriverName); + NewString = AllocateZeroPool (NewStrSize); + ASSERT (NewString != NULL); + StrCatS (NewString, NewStrSize/sizeof(CHAR16), DriverName); + NewStringHelpToken = HiiSetString (Private->RegisteredHandle, DriverImageFilePathToken[Index], NewString, NULL); + ASSERT (NewStringHelpToken != 0); + DriverImageFilePathToken[Index] = NewStringHelpToken; + FreePool (NewString); + FreePool (DriverName); + + CheckFlags = 0; + if (mDriSelection[Index]) { + CheckFlags |= EFI_IFR_CHECKBOX_DEFAULT; + } + + HiiCreateCheckBoxOpCode ( + StartOpCodeHandle, + (UINT16) (KEY_VALUE_DRIVER_OFFSET + Index), + 0, + 0, + NewStringToken, + NewStringHelpToken, + EFI_IFR_FLAG_CALLBACK, + CheckFlags, + NULL + ); + } + + // + // Update second page form + // + HiiUpdateForm ( + Private->RegisteredHandle, + &gPlatformOverridesManagerGuid, + FORM_ID_DRIVER, + StartOpCodeHandle, // Label FORM_ID_DRIVER + EndOpCodeHandle // LABEL_END + ); + + HiiFreeOpCodeHandle (StartOpCodeHandle); + HiiFreeOpCodeHandle (EndOpCodeHandle); + + if (DriverImageProtocol != NULL) { + FreePool (DriverImageProtocol); + } + + if (DriverImageFilePathToken != NULL) { + FreePool (DriverImageFilePathToken); + } + + 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 (mDriSelection[Index]) { + 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 (mDriSelection[Index]) { + // + // 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 +CommitChanges ( + 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 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 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 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 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 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; + EFI_STATUS Status; + + 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; + } + + Status = EFI_SUCCESS; + + if (mCurrentPage == FORM_ID_ORDER) { + KeyValue = KEY_VALUE_ORDER_SAVE_AND_EXIT; + Status = CommitChanges (Private, KeyValue, FakeNvData); + } + + return Status; +} + +/** + 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 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) && (Action != EFI_BROWSER_ACTION_CHANGED)) { + // + // All other action return unsupported. + // + return EFI_UNSUPPORTED; + } + + 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 (Action == EFI_BROWSER_ACTION_CHANGING) { + if (Value == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (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_OFFSET + mMaxDeviceCount)) || (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_DEVICE_CLEAR) { + // + // Deletes all environment variable(s) that contain the override mappings info + // + FreeMappingDatabase (&mMappingDataBase); + Status = SaveOverridesMapping (&mMappingDataBase); + UpdateDeviceSelectPage (Private, KeyValue, FakeNvData); + } + } else if (Action == EFI_BROWSER_ACTION_CHANGED) { + if ((KeyValue >= KEY_VALUE_DRIVER_OFFSET) && (KeyValue < KEY_VALUE_DRIVER_OFFSET + mDriverImageHandleCount)) { + mDriSelection[KeyValue - KEY_VALUE_DRIVER_OFFSET] = Value->b; + } else { + switch (KeyValue) { + case KEY_VALUE_DEVICE_REFRESH: + case KEY_VALUE_DEVICE_FILTER: + 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); + } + break; + + case KEY_VALUE_ORDER_SAVE_AND_EXIT: + Status = CommitChanges (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; + } + break; + + default: + break; + } + } + } + + // + // Pass changed uncommitted data back to Form Browser + // + HiiSetBrowserData (&gPlatformOverridesManagerGuid, mVariableName, sizeof (PLAT_OVER_MNGR_DATA), (UINT8 *) FakeNvData, NULL); + + return EFI_SUCCESS; +} + +/** + 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_INFO, "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 function 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; + + // + // Locate ConfigRouting protocol + // + Status = gBS->LocateProtocol ( + &gEfiHiiConfigRoutingProtocolGuid, + NULL, + (VOID **) &mCallbackInfo->HiiConfigRouting + ); + if (EFI_ERROR (Status)) { + goto Finish; + } + + // + // 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; + } + + // + // Clear all the globle variable + // + mDriverImageHandleCount = 0; + mCurrentPage = 0; + + 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); + + if (mControllerToken != NULL) { + FreePool (mControllerToken); + } + + if (mControllerDevicePathProtocol != NULL) { + FreePool (mControllerDevicePathProtocol); + } + + if (mDriverImageToken != NULL) { + FreePool (mDriverImageToken); + } + + return EFI_SUCCESS; +} -- cgit