| /** @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 - 2010, Intel Corporation | |
| All rights reserved. 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 | |
| // | |
| EFI_GUID mPlatformOverridesManagerGuid = PLAT_OVER_MNGR_GUID; | |
| 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) | |
| } | |
| }, | |
| EFI_CALLER_ID_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, | |
| &mPlatformOverridesManagerGuid, | |
| 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, | |
| &mPlatformOverridesManagerGuid, | |
| 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, | |
| &mPlatformOverridesManagerGuid, | |
| 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, | |
| &mPlatformOverridesManagerGuid, | |
| 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, | |
| &mPlatformOverridesManagerGuid, | |
| 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, | |
| &mPlatformOverridesManagerGuid, | |
| 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 NULL, 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, &mPlatformOverridesManagerGuid, 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 (&mPlatformOverridesManagerGuid, 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, &mPlatformOverridesManagerGuid, mVariableName)) { | |
| return EFI_NOT_FOUND; | |
| } | |
| *Progress = Configuration + StrLen (Configuration); | |
| Private = EFI_CALLBACK_INFO_FROM_THIS (This); | |
| FakeNvData = &Private->FakeNvData; | |
| if (!HiiGetBrowserData (&mPlatformOverridesManagerGuid, 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_FORM_OPEN) || (Action == EFI_BROWSER_ACTION_FORM_CLOSE)) { | |
| // | |
| // Do nothing for UEFI OPEN/CLOSE Action | |
| // | |
| return EFI_SUCCESS; | |
| } | |
| Private = EFI_CALLBACK_INFO_FROM_THIS (This); | |
| FakeNvData = &Private->FakeNvData; | |
| if (!HiiGetBrowserData (&mPlatformOverridesManagerGuid, 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 (&mPlatformOverridesManagerGuid, 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 not a | |
| valid handle. 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 ( | |
| &mPlatformOverridesManagerGuid, | |
| 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; | |
| } |