mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-31 09:21:56 +00:00 
			
		
		
		
	 2573712e01
			
		
	
	
		2573712e01
		
	
	
	
	
		
			
			git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10069 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			2834 lines
		
	
	
		
			80 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2834 lines
		
	
	
		
			80 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| Entry and initialization module for the browser.
 | |
| 
 | |
| 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 "Setup.h"
 | |
| 
 | |
| SETUP_DRIVER_PRIVATE_DATA  mPrivateData = {
 | |
|   SETUP_DRIVER_SIGNATURE,
 | |
|   NULL,
 | |
|   {
 | |
|     SendForm,
 | |
|     BrowserCallback
 | |
|   }
 | |
| };
 | |
| 
 | |
| EFI_HII_DATABASE_PROTOCOL         *mHiiDatabase;
 | |
| EFI_HII_STRING_PROTOCOL           *mHiiString;
 | |
| EFI_HII_CONFIG_ROUTING_PROTOCOL   *mHiiConfigRouting;
 | |
| 
 | |
| UINTN           gBrowserContextCount = 0;
 | |
| LIST_ENTRY      gBrowserContextList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserContextList);
 | |
| 
 | |
| BANNER_DATA           *gBannerData;
 | |
| EFI_HII_HANDLE        gFrontPageHandle;
 | |
| UINTN                 gClassOfVfr;
 | |
| UINTN                 gFunctionKeySetting;
 | |
| BOOLEAN               gResetRequired;
 | |
| BOOLEAN               gNvUpdateRequired;
 | |
| EFI_HII_HANDLE        gHiiHandle;
 | |
| UINT16                gDirection;
 | |
| EFI_SCREEN_DESCRIPTOR gScreenDimensions;
 | |
| 
 | |
| //
 | |
| // Browser Global Strings
 | |
| //
 | |
| CHAR16            *gFunctionNineString;
 | |
| CHAR16            *gFunctionTenString;
 | |
| CHAR16            *gEnterString;
 | |
| CHAR16            *gEnterCommitString;
 | |
| CHAR16            *gEnterEscapeString;
 | |
| CHAR16            *gEscapeString;
 | |
| CHAR16            *gSaveFailed;
 | |
| CHAR16            *gMoveHighlight;
 | |
| CHAR16            *gMakeSelection;
 | |
| CHAR16            *gDecNumericInput;
 | |
| CHAR16            *gHexNumericInput;
 | |
| CHAR16            *gToggleCheckBox;
 | |
| CHAR16            *gPromptForData;
 | |
| CHAR16            *gPromptForPassword;
 | |
| CHAR16            *gPromptForNewPassword;
 | |
| CHAR16            *gConfirmPassword;
 | |
| CHAR16            *gConfirmError;
 | |
| CHAR16            *gPassowordInvalid;
 | |
| CHAR16            *gPressEnter;
 | |
| CHAR16            *gEmptyString;
 | |
| CHAR16            *gAreYouSure;
 | |
| CHAR16            *gYesResponse;
 | |
| CHAR16            *gNoResponse;
 | |
| CHAR16            *gMiniString;
 | |
| CHAR16            *gPlusString;
 | |
| CHAR16            *gMinusString;
 | |
| CHAR16            *gAdjustNumber;
 | |
| CHAR16            *gSaveChanges;
 | |
| CHAR16            *gOptionMismatch;
 | |
| CHAR16            *gFormSuppress;
 | |
| 
 | |
| CHAR16            *mUnknownString = L"!";
 | |
| 
 | |
| CHAR16            gPromptBlockWidth;
 | |
| CHAR16            gOptionBlockWidth;
 | |
| CHAR16            gHelpBlockWidth;
 | |
| 
 | |
| EFI_GUID  gZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
 | |
| EFI_GUID  gSetupBrowserGuid = {
 | |
|   0xab368524, 0xb60c, 0x495b, {0xa0, 0x9, 0x12, 0xe8, 0x5b, 0x1a, 0xea, 0x32}
 | |
| };
 | |
| 
 | |
| FORM_BROWSER_FORMSET  *gOldFormSet;
 | |
| 
 | |
| FUNCTIION_KEY_SETTING gFunctionKeySettingTable[] = {
 | |
|   //
 | |
|   // Boot Manager
 | |
|   //
 | |
|   {
 | |
|     {
 | |
|       0x847bc3fe,
 | |
|       0xb974,
 | |
|       0x446d,
 | |
|       {
 | |
|         0x94,
 | |
|         0x49,
 | |
|         0x5a,
 | |
|         0xd5,
 | |
|         0x41,
 | |
|         0x2e,
 | |
|         0x99,
 | |
|         0x3b
 | |
|       }
 | |
|     },
 | |
|     NONE_FUNCTION_KEY_SETTING
 | |
|   },
 | |
|   //
 | |
|   // Device Manager
 | |
|   //
 | |
|   {
 | |
|     {
 | |
|       0x3ebfa8e6,
 | |
|       0x511d,
 | |
|       0x4b5b,
 | |
|       {
 | |
|         0xa9,
 | |
|         0x5f,
 | |
|         0xfb,
 | |
|         0x38,
 | |
|         0x26,
 | |
|         0xf,
 | |
|         0x1c,
 | |
|         0x27
 | |
|       }
 | |
|     },
 | |
|     NONE_FUNCTION_KEY_SETTING
 | |
|   },
 | |
|   //
 | |
|   // BMM FormSet.
 | |
|   //
 | |
|   {
 | |
|     {
 | |
|       0x642237c7,
 | |
|       0x35d4,
 | |
|       0x472d,
 | |
|       {
 | |
|         0x83,
 | |
|         0x65,
 | |
|         0x12,
 | |
|         0xe0,
 | |
|         0xcc,
 | |
|         0xf2,
 | |
|         0x7a,
 | |
|         0x22
 | |
|       }
 | |
|     },
 | |
|     NONE_FUNCTION_KEY_SETTING
 | |
|   },
 | |
|   //
 | |
|   // BMM File Explorer FormSet.
 | |
|   //
 | |
|   {
 | |
|     {
 | |
|       0x1f2d63e1,
 | |
|       0xfebd,
 | |
|       0x4dc7,
 | |
|       {
 | |
|         0x9c,
 | |
|         0xc5,
 | |
|         0xba,
 | |
|         0x2b,
 | |
|         0x1c,
 | |
|         0xef,
 | |
|         0x9c,
 | |
|         0x5b
 | |
|       }
 | |
|     },
 | |
|     NONE_FUNCTION_KEY_SETTING
 | |
|   },
 | |
| };
 | |
| 
 | |
| /**
 | |
|   This is the routine which an external caller uses to direct the browser
 | |
|   where to obtain it's information.
 | |
| 
 | |
| 
 | |
|   @param This            The Form Browser protocol instanse.
 | |
|   @param Handles         A pointer to an array of Handles.  If HandleCount > 1 we
 | |
|                          display a list of the formsets for the handles specified.
 | |
|   @param HandleCount     The number of Handles specified in Handle.
 | |
|   @param FormSetGuid     This field points to the EFI_GUID which must match the Guid
 | |
|                          field in the EFI_IFR_FORM_SET op-code for the specified
 | |
|                          forms-based package. If FormSetGuid is NULL, then this
 | |
|                          function will display the first found forms package.
 | |
|   @param FormId          This field specifies which EFI_IFR_FORM to render as the first
 | |
|                          displayable page. If this field has a value of 0x0000, then
 | |
|                          the forms browser will render the specified forms in their encoded order.
 | |
|   @param ScreenDimensions Points to recommended form dimensions, including any non-content area, in
 | |
|                           characters.
 | |
|   @param ActionRequest   Points to the action recommended by the form.
 | |
| 
 | |
|   @retval  EFI_SUCCESS            The function completed successfully.
 | |
|   @retval  EFI_INVALID_PARAMETER  One of the parameters has an invalid value.
 | |
|   @retval  EFI_NOT_FOUND          No valid forms could be found to display.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| SendForm (
 | |
|   IN  CONST EFI_FORM_BROWSER2_PROTOCOL *This,
 | |
|   IN  EFI_HII_HANDLE                   *Handles,
 | |
|   IN  UINTN                            HandleCount,
 | |
|   IN  EFI_GUID                         *FormSetGuid, OPTIONAL
 | |
|   IN  UINT16                           FormId, OPTIONAL
 | |
|   IN  CONST EFI_SCREEN_DESCRIPTOR      *ScreenDimensions, OPTIONAL
 | |
|   OUT EFI_BROWSER_ACTION_REQUEST       *ActionRequest  OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                    Status;
 | |
|   UI_MENU_SELECTION             *Selection;
 | |
|   UINTN                         Index;
 | |
|   FORM_BROWSER_FORMSET          *FormSet;
 | |
| 
 | |
|   //
 | |
|   // Save globals used by SendForm()
 | |
|   //
 | |
|   SaveBrowserContext ();
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
|   ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
 | |
| 
 | |
|   //
 | |
|   // Seed the dimensions in the global
 | |
|   //
 | |
|   gST->ConOut->QueryMode (
 | |
|                  gST->ConOut,
 | |
|                  gST->ConOut->Mode->Mode,
 | |
|                  &gScreenDimensions.RightColumn,
 | |
|                  &gScreenDimensions.BottomRow
 | |
|                  );
 | |
| 
 | |
|   if (ScreenDimensions != NULL) {
 | |
|     //
 | |
|     // Check local dimension vs. global dimension.
 | |
|     //
 | |
|     if ((gScreenDimensions.RightColumn < ScreenDimensions->RightColumn) ||
 | |
|         (gScreenDimensions.BottomRow < ScreenDimensions->BottomRow)
 | |
|         ) {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto Done;
 | |
|     } else {
 | |
|       //
 | |
|       // Local dimension validation.
 | |
|       //
 | |
|       if ((ScreenDimensions->RightColumn > ScreenDimensions->LeftColumn) &&
 | |
|           (ScreenDimensions->BottomRow > ScreenDimensions->TopRow) &&
 | |
|           ((ScreenDimensions->RightColumn - ScreenDimensions->LeftColumn) > 2) &&
 | |
|           (
 | |
|             (ScreenDimensions->BottomRow - ScreenDimensions->TopRow) > STATUS_BAR_HEIGHT +
 | |
|             SCROLL_ARROW_HEIGHT *
 | |
|             2 +
 | |
|             FRONT_PAGE_HEADER_HEIGHT +
 | |
|             FOOTER_HEIGHT +
 | |
|             1
 | |
|           )
 | |
|         ) {
 | |
|         CopyMem (&gScreenDimensions, (VOID *) ScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
 | |
|       } else {
 | |
|         Status = EFI_INVALID_PARAMETER;
 | |
|         goto Done;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   gOptionBlockWidth = (CHAR16) ((gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3);
 | |
|   gHelpBlockWidth   = gOptionBlockWidth;
 | |
|   gPromptBlockWidth = gOptionBlockWidth;
 | |
| 
 | |
|   //
 | |
|   // Initialize the strings for the browser, upon exit of the browser, the strings will be freed
 | |
|   //
 | |
|   InitializeBrowserStrings ();
 | |
| 
 | |
|   gFunctionKeySetting = DEFAULT_FUNCTION_KEY_SETTING;
 | |
| 
 | |
|   //
 | |
|   // Ensure we are in Text mode
 | |
|   //
 | |
|   gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
 | |
| 
 | |
|   for (Index = 0; Index < HandleCount; Index++) {
 | |
|     Selection = AllocateZeroPool (sizeof (UI_MENU_SELECTION));
 | |
|     ASSERT (Selection != NULL);
 | |
| 
 | |
|     Selection->Handle = Handles[Index];
 | |
|     if (FormSetGuid != NULL) {
 | |
|       CopyMem (&Selection->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));
 | |
|       Selection->FormId = FormId;
 | |
|     }
 | |
| 
 | |
|     gOldFormSet = NULL;
 | |
|     gNvUpdateRequired = FALSE;
 | |
| 
 | |
|     do {
 | |
|       FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
 | |
|       ASSERT (FormSet != NULL);
 | |
| 
 | |
|       //
 | |
|       // Initialize internal data structures of FormSet
 | |
|       //
 | |
|       Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet);
 | |
|       if (EFI_ERROR (Status) || IsListEmpty (&FormSet->FormListHead)) {
 | |
|         DestroyFormSet (FormSet);
 | |
|         break;
 | |
|       }
 | |
|       Selection->FormSet = FormSet;
 | |
| 
 | |
|       //
 | |
|       // Display this formset
 | |
|       //
 | |
|       gCurrentSelection = Selection;
 | |
| 
 | |
|       Status = SetupBrowser (Selection);
 | |
| 
 | |
|       gCurrentSelection = NULL;
 | |
| 
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         break;
 | |
|       }
 | |
| 
 | |
|     } while (Selection->Action == UI_ACTION_REFRESH_FORMSET);
 | |
| 
 | |
|     if (gOldFormSet != NULL) {
 | |
|       DestroyFormSet (gOldFormSet);
 | |
|       gOldFormSet = NULL;
 | |
|     }
 | |
| 
 | |
|     FreePool (Selection);
 | |
|   }
 | |
| 
 | |
|   if (ActionRequest != NULL) {
 | |
|     *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
 | |
|     if (gResetRequired) {
 | |
|       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   FreeBrowserStrings ();
 | |
| 
 | |
|   gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
 | |
|   gST->ConOut->ClearScreen (gST->ConOut);
 | |
| 
 | |
| Done:
 | |
|   //
 | |
|   // Restore globals used by SendForm()
 | |
|   //
 | |
|   RestoreBrowserContext ();
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   This function is called by a callback handler to retrieve uncommitted state
 | |
|   data from the browser.
 | |
| 
 | |
|   @param  This                   A pointer to the EFI_FORM_BROWSER2_PROTOCOL
 | |
|                                  instance.
 | |
|   @param  ResultsDataSize        A pointer to the size of the buffer associated
 | |
|                                  with ResultsData.
 | |
|   @param  ResultsData            A string returned from an IFR browser or
 | |
|                                  equivalent. The results string will have no
 | |
|                                  routing information in them.
 | |
|   @param  RetrieveData           A BOOLEAN field which allows an agent to retrieve
 | |
|                                  (if RetrieveData = TRUE) data from the uncommitted
 | |
|                                  browser state information or set (if RetrieveData
 | |
|                                  = FALSE) data in the uncommitted browser state
 | |
|                                  information.
 | |
|   @param  VariableGuid           An optional field to indicate the target variable
 | |
|                                  GUID name to use.
 | |
|   @param  VariableName           An optional field to indicate the target
 | |
|                                  human-readable variable name.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The results have been distributed or are awaiting
 | |
|                                  distribution.
 | |
|   @retval EFI_BUFFER_TOO_SMALL   The ResultsDataSize specified was too small to
 | |
|                                  contain the results data.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| BrowserCallback (
 | |
|   IN CONST EFI_FORM_BROWSER2_PROTOCOL  *This,
 | |
|   IN OUT UINTN                         *ResultsDataSize,
 | |
|   IN OUT EFI_STRING                    ResultsData,
 | |
|   IN BOOLEAN                           RetrieveData,
 | |
|   IN CONST EFI_GUID                    *VariableGuid, OPTIONAL
 | |
|   IN CONST CHAR16                      *VariableName  OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS            Status;
 | |
|   LIST_ENTRY            *Link;
 | |
|   FORMSET_STORAGE       *Storage;
 | |
|   FORM_BROWSER_FORMSET  *FormSet;
 | |
|   BOOLEAN               Found;
 | |
|   CHAR16                *ConfigResp;
 | |
|   CHAR16                *StrPtr;
 | |
|   UINTN                 BufferSize;
 | |
|   UINTN                 TmpSize;
 | |
| 
 | |
|   if (ResultsDataSize == NULL || ResultsData == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (gCurrentSelection == NULL) {
 | |
|     return EFI_NOT_READY;
 | |
|   }
 | |
| 
 | |
|   Storage = NULL;
 | |
|   ConfigResp = NULL;
 | |
|   FormSet = gCurrentSelection->FormSet;
 | |
| 
 | |
|   //
 | |
|   // Find target storage
 | |
|   //
 | |
|   Link = GetFirstNode (&FormSet->StorageListHead);
 | |
|   if (IsNull (&FormSet->StorageListHead, Link)) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   if (VariableGuid != NULL) {
 | |
|     //
 | |
|     // Try to find target storage
 | |
|     //
 | |
|     Found = FALSE;
 | |
|     while (!IsNull (&FormSet->StorageListHead, Link)) {
 | |
|       Storage = FORMSET_STORAGE_FROM_LINK (Link);
 | |
|       Link = GetNextNode (&FormSet->StorageListHead, Link);
 | |
| 
 | |
|       if (CompareGuid (&Storage->Guid, (EFI_GUID *) VariableGuid)) {
 | |
|         if (Storage->Type == EFI_HII_VARSTORE_BUFFER) {
 | |
|           //
 | |
|           // Buffer storage require both GUID and Name
 | |
|           //
 | |
|           if (VariableName == NULL) {
 | |
|             return EFI_NOT_FOUND;
 | |
|           }
 | |
| 
 | |
|           if (StrCmp (Storage->Name, (CHAR16 *) VariableName) != 0) {
 | |
|             continue;
 | |
|           }
 | |
|         }
 | |
|         Found = TRUE;
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (!Found) {
 | |
|       return EFI_NOT_FOUND;
 | |
|     }
 | |
|   } else {
 | |
|     //
 | |
|     // GUID/Name is not specified, take the first storage in FormSet
 | |
|     //
 | |
|     Storage = FORMSET_STORAGE_FROM_LINK (Link);
 | |
|   }
 | |
| 
 | |
|   if (RetrieveData) {
 | |
|     //
 | |
|     // Skip if there is no RequestElement
 | |
|     //
 | |
|     if (Storage->ElementCount == 0) {
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Generate <ConfigResp>
 | |
|     //
 | |
|     Status = StorageToConfigResp (Storage, &ConfigResp);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Skip <ConfigHdr> and '&' to point to <ConfigBody>
 | |
|     //
 | |
|     StrPtr = ConfigResp + StrLen (Storage->ConfigHdr) + 1;
 | |
| 
 | |
|     BufferSize = StrSize (StrPtr);
 | |
|     if (*ResultsDataSize < BufferSize) {
 | |
|       *ResultsDataSize = BufferSize;
 | |
| 
 | |
|       FreePool (ConfigResp);
 | |
|       return EFI_BUFFER_TOO_SMALL;
 | |
|     }
 | |
| 
 | |
|     *ResultsDataSize = BufferSize;
 | |
|     CopyMem (ResultsData, StrPtr, BufferSize);
 | |
| 
 | |
|     FreePool (ConfigResp);
 | |
|   } else {
 | |
|     //
 | |
|     // Prepare <ConfigResp>
 | |
|     //
 | |
|     TmpSize = StrLen (ResultsData);
 | |
|     BufferSize = (TmpSize + StrLen (Storage->ConfigHdr) + 2) * sizeof (CHAR16);
 | |
|     ConfigResp = AllocateZeroPool (BufferSize);
 | |
|     ASSERT (ConfigResp != NULL);
 | |
| 
 | |
|     StrCpy (ConfigResp, Storage->ConfigHdr);
 | |
|     StrCat (ConfigResp, L"&");
 | |
|     StrCat (ConfigResp, ResultsData);
 | |
| 
 | |
|     //
 | |
|     // Update Browser uncommited data
 | |
|     //
 | |
|     Status = ConfigRespToStorage (Storage, ConfigResp);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Initialize Setup Browser driver.
 | |
| 
 | |
|   @param ImageHandle     The image handle.
 | |
|   @param SystemTable     The system table.
 | |
| 
 | |
|   @retval EFI_SUCCESS    The Setup Browser module is initialized correctly..
 | |
|   @return Other value if failed to initialize the Setup Browser module.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| InitializeSetup (
 | |
|   IN EFI_HANDLE           ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE     *SystemTable
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
| 
 | |
|   //
 | |
|   // Locate required Hii relative protocols
 | |
|   //
 | |
|   Status = gBS->LocateProtocol (
 | |
|                   &gEfiHiiDatabaseProtocolGuid,
 | |
|                   NULL,
 | |
|                   (VOID **) &mHiiDatabase
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   Status = gBS->LocateProtocol (
 | |
|                   &gEfiHiiStringProtocolGuid,
 | |
|                   NULL,
 | |
|                   (VOID **) &mHiiString
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   Status = gBS->LocateProtocol (
 | |
|                   &gEfiHiiConfigRoutingProtocolGuid,
 | |
|                   NULL,
 | |
|                   (VOID **) &mHiiConfigRouting
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // Publish our HII data
 | |
|   //
 | |
|   gHiiHandle = HiiAddPackages (
 | |
|                  &gSetupBrowserGuid,
 | |
|                  ImageHandle,
 | |
|                  SetupBrowserStrings,
 | |
|                  NULL
 | |
|                  );
 | |
|   ASSERT (gHiiHandle != NULL);
 | |
| 
 | |
|   //
 | |
|   // Initialize Driver private data
 | |
|   //
 | |
|   gBannerData = AllocateZeroPool (sizeof (BANNER_DATA));
 | |
|   ASSERT (gBannerData != NULL);
 | |
| 
 | |
|   //
 | |
|   // Install FormBrowser2 protocol
 | |
|   //
 | |
|   mPrivateData.Handle = NULL;
 | |
|   Status = gBS->InstallProtocolInterface (
 | |
|                   &mPrivateData.Handle,
 | |
|                   &gEfiFormBrowser2ProtocolGuid,
 | |
|                   EFI_NATIVE_INTERFACE,
 | |
|                   &mPrivateData.FormBrowser2
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Create a new string in HII Package List.
 | |
| 
 | |
|   @param  String                 The String to be added
 | |
|   @param  HiiHandle              The package list in the HII database to insert the
 | |
|                                  specified string.
 | |
| 
 | |
|   @return The output string.
 | |
| 
 | |
| **/
 | |
| EFI_STRING_ID
 | |
| NewString (
 | |
|   IN  CHAR16                   *String,
 | |
|   IN  EFI_HII_HANDLE           HiiHandle
 | |
|   )
 | |
| {
 | |
|   EFI_STRING_ID  StringId;
 | |
| 
 | |
|   StringId = HiiSetString (HiiHandle, 0, String, NULL);
 | |
|   ASSERT (StringId != 0);
 | |
| 
 | |
|   return StringId;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Delete a string from HII Package List.
 | |
| 
 | |
|   @param  StringId               Id of the string in HII database.
 | |
|   @param  HiiHandle              The HII package list handle.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The string was deleted successfully.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| DeleteString (
 | |
|   IN  EFI_STRING_ID            StringId,
 | |
|   IN  EFI_HII_HANDLE           HiiHandle
 | |
|   )
 | |
| {
 | |
|   CHAR16  NullChar;
 | |
| 
 | |
|   NullChar = CHAR_NULL;
 | |
|   HiiSetString (HiiHandle, StringId, &NullChar, NULL);
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Get the string based on the StringId and HII Package List Handle.
 | |
| 
 | |
|   @param  Token                  The String's ID.
 | |
|   @param  HiiHandle              The package list in the HII database to search for
 | |
|                                  the specified string.
 | |
| 
 | |
|   @return The output string.
 | |
| 
 | |
| **/
 | |
| CHAR16 *
 | |
| GetToken (
 | |
|   IN  EFI_STRING_ID                Token,
 | |
|   IN  EFI_HII_HANDLE               HiiHandle
 | |
|   )
 | |
| {
 | |
|   EFI_STRING  String;
 | |
| 
 | |
|   if (HiiHandle == NULL) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   String = HiiGetString (HiiHandle, Token, NULL);
 | |
|   if (String == NULL) {
 | |
|     String = AllocateCopyPool (sizeof (mUnknownString), mUnknownString);
 | |
|     ASSERT (String != NULL);
 | |
|   }
 | |
|   return (CHAR16 *) String;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Allocate new memory and then copy the Unicode string Source to Destination.
 | |
| 
 | |
|   @param  Dest                   Location to copy string
 | |
|   @param  Src                    String to copy
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| NewStringCpy (
 | |
|   IN OUT CHAR16       **Dest,
 | |
|   IN CHAR16           *Src
 | |
|   )
 | |
| {
 | |
|   if (*Dest != NULL) {
 | |
|     FreePool (*Dest);
 | |
|   }
 | |
|   *Dest = AllocateCopyPool (StrSize (Src), Src);
 | |
|   ASSERT (*Dest != NULL);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Allocate new memory and concatinate Source on the end of Destination.
 | |
| 
 | |
|   @param  Dest                   String to added to the end of.
 | |
|   @param  Src                    String to concatinate.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| NewStringCat (
 | |
|   IN OUT CHAR16       **Dest,
 | |
|   IN CHAR16           *Src
 | |
|   )
 | |
| {
 | |
|   CHAR16  *NewString;
 | |
|   UINTN   TmpSize;
 | |
| 
 | |
|   if (*Dest == NULL) {
 | |
|     NewStringCpy (Dest, Src);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   TmpSize = StrSize (*Dest);
 | |
|   NewString = AllocateZeroPool (TmpSize + StrSize (Src) - 1);
 | |
|   ASSERT (NewString != NULL);
 | |
| 
 | |
|   StrCpy (NewString, *Dest);
 | |
|   StrCat (NewString, Src);
 | |
| 
 | |
|   FreePool (*Dest);
 | |
|   *Dest = NewString;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Synchronize Storage's Edit copy to Shadow copy.
 | |
| 
 | |
|   @param  Storage                The Storage to be synchronized.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SynchronizeStorage (
 | |
|   IN FORMSET_STORAGE         *Storage
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY              *Link;
 | |
|   NAME_VALUE_NODE         *Node;
 | |
| 
 | |
|   switch (Storage->Type) {
 | |
|   case EFI_HII_VARSTORE_BUFFER:
 | |
|     CopyMem (Storage->Buffer, Storage->EditBuffer, Storage->Size);
 | |
|     break;
 | |
| 
 | |
|   case EFI_HII_VARSTORE_NAME_VALUE:
 | |
|     Link = GetFirstNode (&Storage->NameValueListHead);
 | |
|     while (!IsNull (&Storage->NameValueListHead, Link)) {
 | |
|       Node = NAME_VALUE_NODE_FROM_LINK (Link);
 | |
| 
 | |
|       NewStringCpy (&Node->Value, Node->EditValue);
 | |
| 
 | |
|       Link = GetNextNode (&Storage->NameValueListHead, Link);
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   case EFI_HII_VARSTORE_EFI_VARIABLE:
 | |
|   default:
 | |
|     break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Get Value for given Name from a NameValue Storage.
 | |
| 
 | |
|   @param  Storage                The NameValue Storage.
 | |
|   @param  Name                   The Name.
 | |
|   @param  Value                  The retured Value.
 | |
| 
 | |
|   @retval EFI_SUCCESS            Value found for given Name.
 | |
|   @retval EFI_NOT_FOUND          No such Name found in NameValue storage.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| GetValueByName (
 | |
|   IN FORMSET_STORAGE         *Storage,
 | |
|   IN CHAR16                  *Name,
 | |
|   IN OUT CHAR16              **Value
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY              *Link;
 | |
|   NAME_VALUE_NODE         *Node;
 | |
| 
 | |
|   *Value = NULL;
 | |
| 
 | |
|   Link = GetFirstNode (&Storage->NameValueListHead);
 | |
|   while (!IsNull (&Storage->NameValueListHead, Link)) {
 | |
|     Node = NAME_VALUE_NODE_FROM_LINK (Link);
 | |
| 
 | |
|     if (StrCmp (Name, Node->Name) == 0) {
 | |
|       NewStringCpy (Value, Node->EditValue);
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
| 
 | |
|     Link = GetNextNode (&Storage->NameValueListHead, Link);
 | |
|   }
 | |
| 
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Set Value of given Name in a NameValue Storage.
 | |
| 
 | |
|   @param  Storage                The NameValue Storage.
 | |
|   @param  Name                   The Name.
 | |
|   @param  Value                  The Value to set.
 | |
| 
 | |
|   @retval EFI_SUCCESS            Value found for given Name.
 | |
|   @retval EFI_NOT_FOUND          No such Name found in NameValue storage.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SetValueByName (
 | |
|   IN FORMSET_STORAGE         *Storage,
 | |
|   IN CHAR16                  *Name,
 | |
|   IN CHAR16                  *Value
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY              *Link;
 | |
|   NAME_VALUE_NODE         *Node;
 | |
| 
 | |
|   Link = GetFirstNode (&Storage->NameValueListHead);
 | |
|   while (!IsNull (&Storage->NameValueListHead, Link)) {
 | |
|     Node = NAME_VALUE_NODE_FROM_LINK (Link);
 | |
| 
 | |
|     if (StrCmp (Name, Node->Name) == 0) {
 | |
|       if (Node->EditValue != NULL) {
 | |
|         FreePool (Node->EditValue);
 | |
|       }
 | |
|       Node->EditValue = AllocateCopyPool (StrSize (Value), Value);
 | |
|       ASSERT (Node->EditValue != NULL);
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
| 
 | |
|     Link = GetNextNode (&Storage->NameValueListHead, Link);
 | |
|   }
 | |
| 
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Convert setting of Buffer Storage or NameValue Storage to <ConfigResp>.
 | |
| 
 | |
|   @param  Storage                The Storage to be conveted.
 | |
|   @param  ConfigResp             The returned <ConfigResp>.
 | |
| 
 | |
|   @retval EFI_SUCCESS            Convert success.
 | |
|   @retval EFI_INVALID_PARAMETER  Incorrect storage type.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| StorageToConfigResp (
 | |
|   IN FORMSET_STORAGE         *Storage,
 | |
|   IN CHAR16                  **ConfigResp
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   EFI_STRING  Progress;
 | |
|   LIST_ENTRY              *Link;
 | |
|   NAME_VALUE_NODE         *Node;
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
| 
 | |
|   switch (Storage->Type) {
 | |
|   case EFI_HII_VARSTORE_BUFFER:
 | |
|     Status = mHiiConfigRouting->BlockToConfig (
 | |
|                                   mHiiConfigRouting,
 | |
|                                   Storage->ConfigRequest,
 | |
|                                   Storage->EditBuffer,
 | |
|                                   Storage->Size,
 | |
|                                   ConfigResp,
 | |
|                                   &Progress
 | |
|                                   );
 | |
|     break;
 | |
| 
 | |
|   case EFI_HII_VARSTORE_NAME_VALUE:
 | |
|     *ConfigResp = NULL;
 | |
|     NewStringCat (ConfigResp, Storage->ConfigHdr);
 | |
| 
 | |
|     Link = GetFirstNode (&Storage->NameValueListHead);
 | |
|     while (!IsNull (&Storage->NameValueListHead, Link)) {
 | |
|       Node = NAME_VALUE_NODE_FROM_LINK (Link);
 | |
| 
 | |
|       NewStringCat (ConfigResp, L"&");
 | |
|       NewStringCat (ConfigResp, Node->Name);
 | |
|       NewStringCat (ConfigResp, L"=");
 | |
|       NewStringCat (ConfigResp, Node->EditValue);
 | |
| 
 | |
|       Link = GetNextNode (&Storage->NameValueListHead, Link);
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   case EFI_HII_VARSTORE_EFI_VARIABLE:
 | |
|   default:
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Convert <ConfigResp> to settings in Buffer Storage or NameValue Storage.
 | |
| 
 | |
|   @param  Storage                The Storage to receive the settings.
 | |
|   @param  ConfigResp             The <ConfigResp> to be converted.
 | |
| 
 | |
|   @retval EFI_SUCCESS            Convert success.
 | |
|   @retval EFI_INVALID_PARAMETER  Incorrect storage type.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ConfigRespToStorage (
 | |
|   IN FORMSET_STORAGE         *Storage,
 | |
|   IN CHAR16                  *ConfigResp
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   EFI_STRING  Progress;
 | |
|   UINTN       BufferSize;
 | |
|   CHAR16      *StrPtr;
 | |
|   CHAR16      *Name;
 | |
|   CHAR16      *Value;
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
| 
 | |
|   switch (Storage->Type) {
 | |
|   case EFI_HII_VARSTORE_BUFFER:
 | |
|     BufferSize = Storage->Size;
 | |
|     Status = mHiiConfigRouting->ConfigToBlock (
 | |
|                                   mHiiConfigRouting,
 | |
|                                   ConfigResp,
 | |
|                                   Storage->EditBuffer,
 | |
|                                   &BufferSize,
 | |
|                                   &Progress
 | |
|                                   );
 | |
|     break;
 | |
| 
 | |
|   case EFI_HII_VARSTORE_NAME_VALUE:
 | |
|     StrPtr = StrStr (ConfigResp, L"PATH");
 | |
|     if (StrPtr == NULL) {
 | |
|       break;
 | |
|     }
 | |
|     StrPtr = StrStr (ConfigResp, L"&");
 | |
|     while (StrPtr != NULL) {
 | |
|       //
 | |
|       // Skip '&'
 | |
|       //
 | |
|       StrPtr = StrPtr + 1;
 | |
|       Name = StrPtr;
 | |
|       StrPtr = StrStr (StrPtr, L"=");
 | |
|       if (StrPtr == NULL) {
 | |
|         break;
 | |
|       }
 | |
|       *StrPtr = 0;
 | |
| 
 | |
|       //
 | |
|       // Skip '='
 | |
|       //
 | |
|       StrPtr = StrPtr + 1;
 | |
|       Value = StrPtr;
 | |
|       StrPtr = StrStr (StrPtr, L"&");
 | |
|       if (StrPtr != NULL) {
 | |
|         *StrPtr = 0;
 | |
|       }
 | |
|       SetValueByName (Storage, Name, Value);
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   case EFI_HII_VARSTORE_EFI_VARIABLE:
 | |
|   default:
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Get Question's current Value.
 | |
| 
 | |
|   @param  FormSet                FormSet data structure.
 | |
|   @param  Form                   Form data structure.
 | |
|   @param  Question               Question to be initialized.
 | |
|   @param  Cached                 TRUE:  get from Edit copy FALSE: get from original
 | |
|                                  Storage
 | |
| 
 | |
|   @retval EFI_SUCCESS            The function completed successfully.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| GetQuestionValue (
 | |
|   IN FORM_BROWSER_FORMSET             *FormSet,
 | |
|   IN FORM_BROWSER_FORM                *Form,
 | |
|   IN OUT FORM_BROWSER_STATEMENT       *Question,
 | |
|   IN BOOLEAN                          Cached
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS          Status;
 | |
|   BOOLEAN             Enabled;
 | |
|   BOOLEAN             Pending;
 | |
|   UINT8               *Dst;
 | |
|   UINTN               StorageWidth;
 | |
|   EFI_TIME            EfiTime;
 | |
|   FORMSET_STORAGE     *Storage;
 | |
|   EFI_IFR_TYPE_VALUE  *QuestionValue;
 | |
|   CHAR16              *ConfigRequest;
 | |
|   CHAR16              *Progress;
 | |
|   CHAR16              *Result;
 | |
|   CHAR16              *Value;
 | |
|   CHAR16              *StringPtr;
 | |
|   UINTN               Length;
 | |
|   UINTN               Index;
 | |
|   UINTN               LengthStr;
 | |
|   BOOLEAN             IsBufferStorage;
 | |
|   BOOLEAN             IsString;
 | |
|   CHAR16              TemStr[5];
 | |
|   UINT8               DigitUint8;
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
| 
 | |
|   //
 | |
|   // Statement don't have storage, skip them
 | |
|   //
 | |
|   if (Question->QuestionId == 0) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Question value is provided by an Expression, evaluate it
 | |
|   //
 | |
|   if (Question->ValueExpression != NULL) {
 | |
|     Status = EvaluateExpression (FormSet, Form, Question->ValueExpression);
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       CopyMem (&Question->HiiValue, &Question->ValueExpression->Result, sizeof (EFI_HII_VALUE));
 | |
|     }
 | |
|     return Status;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Get question value by read expression.
 | |
|   //
 | |
|   if (Question->ReadExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {
 | |
|     Status = EvaluateExpression (FormSet, Form, Question->ReadExpression);
 | |
|     if (!EFI_ERROR (Status) && (Question->ReadExpression->Result.Type < EFI_IFR_TYPE_OTHER)) {
 | |
|       //
 | |
|       // Only update question value to the valid result.
 | |
|       //
 | |
|       CopyMem (&Question->HiiValue, &Question->ReadExpression->Result, sizeof (EFI_HII_VALUE));
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Question value is provided by RTC
 | |
|   //
 | |
|   Storage = Question->Storage;
 | |
|   QuestionValue = &Question->HiiValue.Value;
 | |
|   if (Storage == NULL) {
 | |
|     //
 | |
|     // It's a Question without storage, or RTC date/time
 | |
|     //
 | |
|     if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {
 | |
|       //
 | |
|       // Date and time define the same Flags bit
 | |
|       //
 | |
|       switch (Question->Flags & EFI_QF_DATE_STORAGE) {
 | |
|       case QF_DATE_STORAGE_TIME:
 | |
|         Status = gRT->GetTime (&EfiTime, NULL);
 | |
|         break;
 | |
| 
 | |
|       case QF_DATE_STORAGE_WAKEUP:
 | |
|         Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);
 | |
|         break;
 | |
| 
 | |
|       case QF_DATE_STORAGE_NORMAL:
 | |
|       default:
 | |
|         //
 | |
|         // For date/time without storage
 | |
|         //
 | |
|         return EFI_SUCCESS;
 | |
|       }
 | |
| 
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         return Status;
 | |
|       }
 | |
| 
 | |
|       if (Question->Operand == EFI_IFR_DATE_OP) {
 | |
|         QuestionValue->date.Year  = EfiTime.Year;
 | |
|         QuestionValue->date.Month = EfiTime.Month;
 | |
|         QuestionValue->date.Day   = EfiTime.Day;
 | |
|       } else {
 | |
|         QuestionValue->time.Hour   = EfiTime.Hour;
 | |
|         QuestionValue->time.Minute = EfiTime.Minute;
 | |
|         QuestionValue->time.Second = EfiTime.Second;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Question value is provided by EFI variable
 | |
|   //
 | |
|   StorageWidth = Question->StorageWidth;
 | |
|   if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
 | |
|     if (Question->BufferValue != NULL) {
 | |
|       Dst = Question->BufferValue;
 | |
|     } else {
 | |
|       Dst = (UINT8 *) QuestionValue;
 | |
|     }
 | |
| 
 | |
|     Status = gRT->GetVariable (
 | |
|                      Question->VariableName,
 | |
|                      &Storage->Guid,
 | |
|                      NULL,
 | |
|                      &StorageWidth,
 | |
|                      Dst
 | |
|                      );
 | |
|     //
 | |
|     // Always return success, even this EFI variable doesn't exist
 | |
|     //
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Question Value is provided by Buffer Storage or NameValue Storage
 | |
|   //
 | |
|   if (Question->BufferValue != NULL) {
 | |
|     //
 | |
|     // This Question is password or orderedlist
 | |
|     //
 | |
|     Dst = Question->BufferValue;
 | |
|   } else {
 | |
|     //
 | |
|     // Other type of Questions
 | |
|     //
 | |
|     Dst = (UINT8 *) &Question->HiiValue.Value;
 | |
|   }
 | |
| 
 | |
|   IsBufferStorage = (BOOLEAN) ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ? TRUE : FALSE);
 | |
|   IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ?  TRUE : FALSE);
 | |
|   if (Cached) {
 | |
|     if (IsBufferStorage) {
 | |
|       //
 | |
|       // Copy from storage Edit buffer
 | |
|       //
 | |
|       CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth);
 | |
|     } else {
 | |
|       Value = NULL;
 | |
|       Status = GetValueByName (Storage, Question->VariableName, &Value);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         return Status;
 | |
|       }
 | |
| 
 | |
|       ASSERT (Value != NULL);
 | |
|       LengthStr = StrLen (Value);
 | |
|       Status    = EFI_SUCCESS;
 | |
|       if (IsString) {
 | |
|         //
 | |
|         // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"
 | |
|         // Add string tail char L'\0' into Length
 | |
|         //
 | |
|         Length    = StorageWidth + sizeof (CHAR16);
 | |
|         if (Length < ((LengthStr / 4 + 1) * 2)) {
 | |
|           Status = EFI_BUFFER_TOO_SMALL;
 | |
|         } else {
 | |
|           StringPtr = (CHAR16 *) Dst;
 | |
|           ZeroMem (TemStr, sizeof (TemStr));
 | |
|           for (Index = 0; Index < LengthStr; Index += 4) {
 | |
|             StrnCpy (TemStr, Value + Index, 4);
 | |
|             StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
 | |
|           }
 | |
|           //
 | |
|           // Add tailing L'\0' character
 | |
|           //
 | |
|           StringPtr[Index/4] = L'\0';
 | |
|         }
 | |
|       } else {
 | |
|         if (StorageWidth < ((LengthStr + 1) / 2)) {
 | |
|           Status = EFI_BUFFER_TOO_SMALL;
 | |
|         } else {
 | |
|           ZeroMem (TemStr, sizeof (TemStr));
 | |
|           for (Index = 0; Index < LengthStr; Index ++) {
 | |
|             TemStr[0] = Value[LengthStr - Index - 1];
 | |
|             DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
 | |
|             if ((Index & 1) == 0) {
 | |
|               Dst [Index/2] = DigitUint8;
 | |
|             } else {
 | |
|               Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       FreePool (Value);
 | |
|     }
 | |
|   } else {
 | |
|     //
 | |
|     // Request current settings from Configuration Driver
 | |
|     //
 | |
|     if (FormSet->ConfigAccess == NULL) {
 | |
|       return EFI_NOT_FOUND;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // <ConfigRequest> ::= <ConfigHdr> + <BlockName> ||
 | |
|     //                   <ConfigHdr> + "&" + <VariableName>
 | |
|     //
 | |
|     if (IsBufferStorage) {
 | |
|       Length = StrLen (Storage->ConfigHdr);
 | |
|       Length += StrLen (Question->BlockName);
 | |
|     } else {
 | |
|       Length = StrLen (Storage->ConfigHdr);
 | |
|       Length += StrLen (Question->VariableName) + 1;
 | |
|     }
 | |
|     ConfigRequest = AllocateZeroPool ((Length + 1) * sizeof (CHAR16));
 | |
|     ASSERT (ConfigRequest != NULL);
 | |
| 
 | |
|     StrCpy (ConfigRequest, Storage->ConfigHdr);
 | |
|     if (IsBufferStorage) {
 | |
|       StrCat (ConfigRequest, Question->BlockName);
 | |
|     } else {
 | |
|       StrCat (ConfigRequest, L"&");
 | |
|       StrCat (ConfigRequest, Question->VariableName);
 | |
|     }
 | |
| 
 | |
|     Status = FormSet->ConfigAccess->ExtractConfig (
 | |
|                                       FormSet->ConfigAccess,
 | |
|                                       ConfigRequest,
 | |
|                                       &Progress,
 | |
|                                       &Result
 | |
|                                       );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Skip <ConfigRequest>
 | |
|     //
 | |
|     Value = Result + Length;
 | |
|     if (IsBufferStorage) {
 | |
|       //
 | |
|       // Skip "&VALUE"
 | |
|       //
 | |
|       Value = Value + 6;
 | |
|     }
 | |
|     if (*Value != '=') {
 | |
|       FreePool (Result);
 | |
|       return EFI_NOT_FOUND;
 | |
|     }
 | |
|     //
 | |
|     // Skip '=', point to value
 | |
|     //
 | |
|     Value = Value + 1;
 | |
| 
 | |
|     //
 | |
|     // Suppress <AltResp> if any
 | |
|     //
 | |
|     StringPtr = Value;
 | |
|     while (*StringPtr != L'\0' && *StringPtr != L'&') {
 | |
|       StringPtr++;
 | |
|     }
 | |
|     *StringPtr = L'\0';
 | |
| 
 | |
|     LengthStr = StrLen (Value);
 | |
|     Status    = EFI_SUCCESS;
 | |
|     if (!IsBufferStorage && IsString) {
 | |
|       //
 | |
|       // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD"
 | |
|       // Add string tail char L'\0' into Length
 | |
|       //
 | |
|       Length    = StorageWidth + sizeof (CHAR16);
 | |
|       if (Length < ((LengthStr / 4 + 1) * 2)) {
 | |
|         Status = EFI_BUFFER_TOO_SMALL;
 | |
|       } else {
 | |
|         StringPtr = (CHAR16 *) Dst;
 | |
|         ZeroMem (TemStr, sizeof (TemStr));
 | |
|         for (Index = 0; Index < LengthStr; Index += 4) {
 | |
|           StrnCpy (TemStr, Value + Index, 4);
 | |
|           StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
 | |
|         }
 | |
|         //
 | |
|         // Add tailing L'\0' character
 | |
|         //
 | |
|         StringPtr[Index/4] = L'\0';
 | |
|       }
 | |
|     } else {
 | |
|       if (StorageWidth < ((LengthStr + 1) / 2)) {
 | |
|         Status = EFI_BUFFER_TOO_SMALL;
 | |
|       } else {
 | |
|         ZeroMem (TemStr, sizeof (TemStr));
 | |
|         for (Index = 0; Index < LengthStr; Index ++) {
 | |
|           TemStr[0] = Value[LengthStr - Index - 1];
 | |
|           DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
 | |
|           if ((Index & 1) == 0) {
 | |
|             Dst [Index/2] = DigitUint8;
 | |
|           } else {
 | |
|             Dst [Index/2] = (UINT8) ((DigitUint8 << 4) + Dst [Index/2]);
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       FreePool (Result);
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Synchronize Edit Buffer
 | |
|     //
 | |
|     if (IsBufferStorage) {
 | |
|       CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth);
 | |
|     } else {
 | |
|       SetValueByName (Storage, Question->VariableName, Value);
 | |
|     }
 | |
| 
 | |
|     FreePool (Result);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Save Question Value to edit copy(cached) or Storage(uncached).
 | |
| 
 | |
|   @param  FormSet                FormSet data structure.
 | |
|   @param  Form                   Form data structure.
 | |
|   @param  Question               Pointer to the Question.
 | |
|   @param  Cached                 TRUE:  set to Edit copy FALSE: set to original
 | |
|                                  Storage
 | |
| 
 | |
|   @retval EFI_SUCCESS            The function completed successfully.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SetQuestionValue (
 | |
|   IN FORM_BROWSER_FORMSET             *FormSet,
 | |
|   IN FORM_BROWSER_FORM                *Form,
 | |
|   IN OUT FORM_BROWSER_STATEMENT       *Question,
 | |
|   IN BOOLEAN                          Cached
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS          Status;
 | |
|   BOOLEAN             Enabled;
 | |
|   BOOLEAN             Pending;
 | |
|   UINT8               *Src;
 | |
|   EFI_TIME            EfiTime;
 | |
|   UINTN               BufferLen;
 | |
|   UINTN               StorageWidth;
 | |
|   FORMSET_STORAGE     *Storage;
 | |
|   EFI_IFR_TYPE_VALUE  *QuestionValue;
 | |
|   CHAR16              *ConfigResp;
 | |
|   CHAR16              *Progress;
 | |
|   CHAR16              *Value;
 | |
|   UINTN               Length;
 | |
|   BOOLEAN             IsBufferStorage;
 | |
|   BOOLEAN             IsString;
 | |
|   UINT8               *TemBuffer;
 | |
|   CHAR16              *TemName;
 | |
|   CHAR16              *TemString;
 | |
|   UINTN               Index;
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
| 
 | |
|   //
 | |
|   // Statement don't have storage, skip them
 | |
|   //
 | |
|   if (Question->QuestionId == 0) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // If Question value is provided by an Expression, then it is read only
 | |
|   //
 | |
|   if (Question->ValueExpression != NULL) {
 | |
|     return Status;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Before set question value, evaluate its write expression.
 | |
|   //
 | |
|   if (Question->WriteExpression != NULL && Form->FormType == STANDARD_MAP_FORM_TYPE) {
 | |
|     Status = EvaluateExpression (FormSet, Form, Question->WriteExpression);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Question value is provided by RTC
 | |
|   //
 | |
|   Storage = Question->Storage;
 | |
|   QuestionValue = &Question->HiiValue.Value;
 | |
|   if (Storage == NULL) {
 | |
|     //
 | |
|     // It's a Question without storage, or RTC date/time
 | |
|     //
 | |
|     if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {
 | |
|       //
 | |
|       // Date and time define the same Flags bit
 | |
|       //
 | |
|       switch (Question->Flags & EFI_QF_DATE_STORAGE) {
 | |
|       case QF_DATE_STORAGE_TIME:
 | |
|         Status = gRT->GetTime (&EfiTime, NULL);
 | |
|         break;
 | |
| 
 | |
|       case QF_DATE_STORAGE_WAKEUP:
 | |
|         Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime);
 | |
|         break;
 | |
| 
 | |
|       case QF_DATE_STORAGE_NORMAL:
 | |
|       default:
 | |
|         //
 | |
|         // For date/time without storage
 | |
|         //
 | |
|         return EFI_SUCCESS;
 | |
|       }
 | |
| 
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         return Status;
 | |
|       }
 | |
| 
 | |
|       if (Question->Operand == EFI_IFR_DATE_OP) {
 | |
|         EfiTime.Year  = QuestionValue->date.Year;
 | |
|         EfiTime.Month = QuestionValue->date.Month;
 | |
|         EfiTime.Day   = QuestionValue->date.Day;
 | |
|       } else {
 | |
|         EfiTime.Hour   = QuestionValue->time.Hour;
 | |
|         EfiTime.Minute = QuestionValue->time.Minute;
 | |
|         EfiTime.Second = QuestionValue->time.Second;
 | |
|       }
 | |
| 
 | |
|       if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) {
 | |
|         Status = gRT->SetTime (&EfiTime);
 | |
|       } else {
 | |
|         Status = gRT->SetWakeupTime (TRUE, &EfiTime);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Question value is provided by EFI variable
 | |
|   //
 | |
|   StorageWidth = Question->StorageWidth;
 | |
|   if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
 | |
|     if (Question->BufferValue != NULL) {
 | |
|       Src = Question->BufferValue;
 | |
|     } else {
 | |
|       Src = (UINT8 *) QuestionValue;
 | |
|     }
 | |
| 
 | |
|     Status = gRT->SetVariable (
 | |
|                      Question->VariableName,
 | |
|                      &Storage->Guid,
 | |
|                      Storage->Attributes,
 | |
|                      StorageWidth,
 | |
|                      Src
 | |
|                      );
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Question Value is provided by Buffer Storage or NameValue Storage
 | |
|   //
 | |
|   if (Question->BufferValue != NULL) {
 | |
|     Src = Question->BufferValue;
 | |
|   } else {
 | |
|     Src = (UINT8 *) &Question->HiiValue.Value;
 | |
|   }
 | |
| 
 | |
|   IsBufferStorage = (BOOLEAN) ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ? TRUE : FALSE);
 | |
|   IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ?  TRUE : FALSE);
 | |
|   if (IsBufferStorage) {
 | |
|     //
 | |
|     // Copy to storage edit buffer
 | |
|     //
 | |
|     CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);
 | |
|   } else {
 | |
|     if (IsString) {
 | |
|       //
 | |
|       // Allocate enough string buffer.
 | |
|       //
 | |
|       Value = NULL;
 | |
|       BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16);
 | |
|       Value = AllocateZeroPool (BufferLen);
 | |
|       ASSERT (Value != NULL);
 | |
|       //
 | |
|       // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
 | |
|       //
 | |
|       TemName = (CHAR16 *) Src;
 | |
|       TemString = Value;
 | |
|       for (; *TemName != L'\0'; TemName++) {
 | |
|         TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);
 | |
|       }
 | |
|     } else {
 | |
|       BufferLen = StorageWidth * 2 + 1;
 | |
|       Value = AllocateZeroPool (BufferLen * sizeof (CHAR16));
 | |
|       ASSERT (Value != NULL);
 | |
|       //
 | |
|       // Convert Buffer to Hex String
 | |
|       //
 | |
|       TemBuffer = Src + StorageWidth - 1;
 | |
|       TemString = Value;
 | |
|       for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {
 | |
|         TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     Status = SetValueByName (Storage, Question->VariableName, Value);
 | |
|     FreePool (Value);
 | |
|   }
 | |
| 
 | |
|   if (!Cached) {
 | |
|     //
 | |
|     // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" ||
 | |
|     //                <ConfigHdr> + "&" + <VariableName> + "=" + "<string>"
 | |
|     //
 | |
|     if (IsBufferStorage) {
 | |
|       Length = StrLen (Question->BlockName) + 7;
 | |
|     } else {
 | |
|       Length = StrLen (Question->VariableName) + 2;
 | |
|     }
 | |
|     if (!IsBufferStorage && IsString) {
 | |
|       Length += (StrLen ((CHAR16 *) Src) * 4);
 | |
|     } else {
 | |
|       Length += (StorageWidth * 2);
 | |
|     }
 | |
|     ConfigResp = AllocateZeroPool ((StrLen (Storage->ConfigHdr) + Length + 1) * sizeof (CHAR16));
 | |
|     ASSERT (ConfigResp != NULL);
 | |
| 
 | |
|     StrCpy (ConfigResp, Storage->ConfigHdr);
 | |
|     if (IsBufferStorage) {
 | |
|       StrCat (ConfigResp, Question->BlockName);
 | |
|       StrCat (ConfigResp, L"&VALUE=");
 | |
|     } else {
 | |
|       StrCat (ConfigResp, L"&");
 | |
|       StrCat (ConfigResp, Question->VariableName);
 | |
|       StrCat (ConfigResp, L"=");
 | |
|     }
 | |
| 
 | |
|     Value = ConfigResp + StrLen (ConfigResp);
 | |
| 
 | |
|     if (!IsBufferStorage && IsString) {
 | |
|       //
 | |
|       // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
 | |
|       //
 | |
|       TemName = (CHAR16 *) Src;
 | |
|       TemString = Value;
 | |
|       for (; *TemName != L'\0'; TemName++) {
 | |
|         TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);
 | |
|       }
 | |
|     } else {
 | |
|       //
 | |
|       // Convert Buffer to Hex String
 | |
|       //
 | |
|       TemBuffer = Src + StorageWidth - 1;
 | |
|       TemString = Value;
 | |
|       for (Index = 0; Index < StorageWidth; Index ++, TemBuffer --) {
 | |
|         TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Convert to lower char.
 | |
|     //
 | |
|     for (TemString = Value; *Value != L'\0'; Value++) {
 | |
|       if (*Value >= L'A' && *Value <= L'Z') {
 | |
|         *Value = (CHAR16) (*Value - L'A' + L'a');
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Submit Question Value to Configuration Driver
 | |
|     //
 | |
|     if (FormSet->ConfigAccess != NULL) {
 | |
|       Status = FormSet->ConfigAccess->RouteConfig (
 | |
|                                         FormSet->ConfigAccess,
 | |
|                                         ConfigResp,
 | |
|                                         &Progress
 | |
|                                         );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         FreePool (ConfigResp);
 | |
|         return Status;
 | |
|       }
 | |
|     }
 | |
|     FreePool (ConfigResp);
 | |
| 
 | |
|     //
 | |
|     // Synchronize shadow Buffer
 | |
|     //
 | |
|     SynchronizeStorage (Storage);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Perform inconsistent check for a Form.
 | |
| 
 | |
|   @param  FormSet                FormSet data structure.
 | |
|   @param  Form                   Form data structure.
 | |
|   @param  Question               The Question to be validated.
 | |
|   @param  Type                   Validation type: InConsistent or NoSubmit
 | |
| 
 | |
|   @retval EFI_SUCCESS            Form validation pass.
 | |
|   @retval other                  Form validation failed.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ValidateQuestion (
 | |
|   IN  FORM_BROWSER_FORMSET            *FormSet,
 | |
|   IN  FORM_BROWSER_FORM               *Form,
 | |
|   IN  FORM_BROWSER_STATEMENT          *Question,
 | |
|   IN  UINTN                           Type
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   LIST_ENTRY              *Link;
 | |
|   LIST_ENTRY              *ListHead;
 | |
|   EFI_STRING              PopUp;
 | |
|   EFI_INPUT_KEY           Key;
 | |
|   FORM_EXPRESSION         *Expression;
 | |
| 
 | |
|   if (Type == EFI_HII_EXPRESSION_INCONSISTENT_IF) {
 | |
|     ListHead = &Question->InconsistentListHead;
 | |
|   } else if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) {
 | |
|     ListHead = &Question->NoSubmitListHead;
 | |
|   } else {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   Link = GetFirstNode (ListHead);
 | |
|   while (!IsNull (ListHead, Link)) {
 | |
|     Expression = FORM_EXPRESSION_FROM_LINK (Link);
 | |
| 
 | |
|     //
 | |
|     // Evaluate the expression
 | |
|     //
 | |
|     Status = EvaluateExpression (FormSet, Form, Expression);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     if (Expression->Result.Value.b) {
 | |
|       //
 | |
|       // Condition meet, show up error message
 | |
|       //
 | |
|       if (Expression->Error != 0) {
 | |
|         PopUp = GetToken (Expression->Error, FormSet->HiiHandle);
 | |
|         do {
 | |
|           CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, PopUp, gPressEnter, gEmptyString);
 | |
|         } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
 | |
|         FreePool (PopUp);
 | |
|       }
 | |
| 
 | |
|       return EFI_NOT_READY;
 | |
|     }
 | |
| 
 | |
|     Link = GetNextNode (ListHead, Link);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Perform NoSubmit check for a Form.
 | |
| 
 | |
|   @param  FormSet                FormSet data structure.
 | |
|   @param  Form                   Form data structure.
 | |
| 
 | |
|   @retval EFI_SUCCESS            Form validation pass.
 | |
|   @retval other                  Form validation failed.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| NoSubmitCheck (
 | |
|   IN  FORM_BROWSER_FORMSET            *FormSet,
 | |
|   IN  FORM_BROWSER_FORM               *Form
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   LIST_ENTRY              *Link;
 | |
|   FORM_BROWSER_STATEMENT  *Question;
 | |
| 
 | |
|   Link = GetFirstNode (&Form->StatementListHead);
 | |
|   while (!IsNull (&Form->StatementListHead, Link)) {
 | |
|     Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
 | |
| 
 | |
|     Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     Link = GetNextNode (&Form->StatementListHead, Link);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Submit a Form.
 | |
| 
 | |
|   @param  FormSet                FormSet data structure.
 | |
|   @param  Form                   Form data structure.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The function completed successfully.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SubmitForm (
 | |
|   IN FORM_BROWSER_FORMSET             *FormSet,
 | |
|   IN FORM_BROWSER_FORM                *Form
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   LIST_ENTRY              *Link;
 | |
|   EFI_STRING              ConfigResp;
 | |
|   EFI_STRING              Progress;
 | |
|   FORMSET_STORAGE         *Storage;
 | |
| 
 | |
|   //
 | |
|   // Validate the Form by NoSubmit check
 | |
|   //
 | |
|   Status = NoSubmitCheck (FormSet, Form);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Submit Buffer storage or Name/Value storage
 | |
|   //
 | |
|   Link = GetFirstNode (&FormSet->StorageListHead);
 | |
|   while (!IsNull (&FormSet->StorageListHead, Link)) {
 | |
|     Storage = FORMSET_STORAGE_FROM_LINK (Link);
 | |
|     Link = GetNextNode (&FormSet->StorageListHead, Link);
 | |
| 
 | |
|     if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Skip if there is no RequestElement
 | |
|     //
 | |
|     if (Storage->ElementCount == 0) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Prepare <ConfigResp>
 | |
|     //
 | |
|     Status = StorageToConfigResp (Storage, &ConfigResp);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Send <ConfigResp> to Configuration Driver
 | |
|     //
 | |
|     if (FormSet->ConfigAccess != NULL) {
 | |
|       Status = FormSet->ConfigAccess->RouteConfig (
 | |
|                                         FormSet->ConfigAccess,
 | |
|                                         ConfigResp,
 | |
|                                         &Progress
 | |
|                                         );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         FreePool (ConfigResp);
 | |
|         return Status;
 | |
|       }
 | |
|     }
 | |
|     FreePool (ConfigResp);
 | |
| 
 | |
|     //
 | |
|     // Config success, update storage shadow Buffer
 | |
|     //
 | |
|     SynchronizeStorage (Storage);
 | |
|   }
 | |
| 
 | |
|   gNvUpdateRequired = FALSE;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Reset Question to its default value.
 | |
| 
 | |
|   @param  FormSet                The form set.
 | |
|   @param  Form                   The form.
 | |
|   @param  Question               The question.
 | |
|   @param  DefaultId              The Class of the default.
 | |
| 
 | |
|   @retval EFI_SUCCESS            Question is reset to default value.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| GetQuestionDefault (
 | |
|   IN FORM_BROWSER_FORMSET             *FormSet,
 | |
|   IN FORM_BROWSER_FORM                *Form,
 | |
|   IN FORM_BROWSER_STATEMENT           *Question,
 | |
|   IN UINT16                           DefaultId
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   LIST_ENTRY              *Link;
 | |
|   QUESTION_DEFAULT        *Default;
 | |
|   QUESTION_OPTION         *Option;
 | |
|   EFI_HII_VALUE           *HiiValue;
 | |
|   UINT8                   Index;
 | |
|   EFI_STRING              StrValue;
 | |
| 
 | |
|   Status   = EFI_SUCCESS;
 | |
|   StrValue = NULL;
 | |
| 
 | |
|   //
 | |
|   // Statement don't have storage, skip them
 | |
|   //
 | |
|   if (Question->QuestionId == 0) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // There are three ways to specify default value for a Question:
 | |
|   //  1, use nested EFI_IFR_DEFAULT (highest priority)
 | |
|   //  2, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)
 | |
|   //  3, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)
 | |
|   //
 | |
|   HiiValue = &Question->HiiValue;
 | |
| 
 | |
|   //
 | |
|   // EFI_IFR_DEFAULT has highest priority
 | |
|   //
 | |
|   if (!IsListEmpty (&Question->DefaultListHead)) {
 | |
|     Link = GetFirstNode (&Question->DefaultListHead);
 | |
|     while (!IsNull (&Question->DefaultListHead, Link)) {
 | |
|       Default = QUESTION_DEFAULT_FROM_LINK (Link);
 | |
| 
 | |
|       if (Default->DefaultId == DefaultId) {
 | |
|         if (Default->ValueExpression != NULL) {
 | |
|           //
 | |
|           // Default is provided by an Expression, evaluate it
 | |
|           //
 | |
|           Status = EvaluateExpression (FormSet, Form, Default->ValueExpression);
 | |
|           if (EFI_ERROR (Status)) {
 | |
|             return Status;
 | |
|           }
 | |
| 
 | |
|           CopyMem (HiiValue, &Default->ValueExpression->Result, sizeof (EFI_HII_VALUE));
 | |
|         } else {
 | |
|           //
 | |
|           // Default value is embedded in EFI_IFR_DEFAULT
 | |
|           //
 | |
|           CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));
 | |
|         }
 | |
| 
 | |
|         if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
 | |
|           StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string, NULL);
 | |
|           if (StrValue == NULL) {
 | |
|             return EFI_NOT_FOUND;
 | |
|           }
 | |
|           Question->BufferValue = AllocateCopyPool (StrSize (StrValue), StrValue);
 | |
|         }
 | |
| 
 | |
|         return EFI_SUCCESS;
 | |
|       }
 | |
| 
 | |
|       Link = GetNextNode (&Question->DefaultListHead, Link);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // EFI_ONE_OF_OPTION
 | |
|   //
 | |
|   if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {
 | |
|     if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING)  {
 | |
|       //
 | |
|       // OneOfOption could only provide Standard and Manufacturing default
 | |
|       //
 | |
|       Link = GetFirstNode (&Question->OptionListHead);
 | |
|       while (!IsNull (&Question->OptionListHead, Link)) {
 | |
|         Option = QUESTION_OPTION_FROM_LINK (Link);
 | |
| 
 | |
|         if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||
 | |
|             ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))
 | |
|            ) {
 | |
|           CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
 | |
| 
 | |
|           return EFI_SUCCESS;
 | |
|         }
 | |
| 
 | |
|         Link = GetNextNode (&Question->OptionListHead, Link);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // EFI_IFR_CHECKBOX - lowest priority
 | |
|   //
 | |
|   if (Question->Operand == EFI_IFR_CHECKBOX_OP) {
 | |
|     if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING)  {
 | |
|       //
 | |
|       // Checkbox could only provide Standard and Manufacturing default
 | |
|       //
 | |
|       if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||
 | |
|           ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))
 | |
|          ) {
 | |
|         HiiValue->Value.b = TRUE;
 | |
|       } else {
 | |
|         HiiValue->Value.b = FALSE;
 | |
|       }
 | |
| 
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // For Questions without default
 | |
|   //
 | |
|   switch (Question->Operand) {
 | |
|   case EFI_IFR_ONE_OF_OP:
 | |
|     //
 | |
|     // Take first oneof option as oneof's default value
 | |
|     //
 | |
|     if (ValueToOption (Question, HiiValue) == NULL) {
 | |
|       Link = GetFirstNode (&Question->OptionListHead);
 | |
|       if (!IsNull (&Question->OptionListHead, Link)) {
 | |
|         Option = QUESTION_OPTION_FROM_LINK (Link);
 | |
|         CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
 | |
|       }
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   case EFI_IFR_ORDERED_LIST_OP:
 | |
|     //
 | |
|     // Take option sequence in IFR as ordered list's default value
 | |
|     //
 | |
|     Index = 0;
 | |
|     Link = GetFirstNode (&Question->OptionListHead);
 | |
|     while (!IsNull (&Question->OptionListHead, Link)) {
 | |
|       Option = QUESTION_OPTION_FROM_LINK (Link);
 | |
| 
 | |
|       SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);
 | |
| 
 | |
|       Index++;
 | |
|       if (Index >= Question->MaxContainers) {
 | |
|         break;
 | |
|       }
 | |
| 
 | |
|       Link = GetNextNode (&Question->OptionListHead, Link);
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     Status = EFI_NOT_FOUND;
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Reset Questions in a Form to their default value.
 | |
| 
 | |
|   @param  FormSet                FormSet data structure.
 | |
|   @param  Form                   The Form which to be reset.
 | |
|   @param  DefaultId              The Class of the default.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The function completed successfully.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ExtractFormDefault (
 | |
|   IN FORM_BROWSER_FORMSET             *FormSet,
 | |
|   IN FORM_BROWSER_FORM                *Form,
 | |
|   IN UINT16                           DefaultId
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   LIST_ENTRY              *Link;
 | |
|   FORM_BROWSER_STATEMENT  *Question;
 | |
| 
 | |
|   Link = GetFirstNode (&Form->StatementListHead);
 | |
|   while (!IsNull (&Form->StatementListHead, Link)) {
 | |
|     Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
 | |
|     Link = GetNextNode (&Form->StatementListHead, Link);
 | |
| 
 | |
|     //
 | |
|     // If Question is disabled, don't reset it to default
 | |
|     //
 | |
|     if (Question->DisableExpression != NULL) {
 | |
|       Status = EvaluateExpression (FormSet, Form, Question->DisableExpression);
 | |
|       if (!EFI_ERROR (Status) && Question->DisableExpression->Result.Value.b) {
 | |
|         continue;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Reset Question to its default value
 | |
|     //
 | |
|     Status = GetQuestionDefault (FormSet, Form, Question, DefaultId);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Synchronize Buffer storage's Edit buffer
 | |
|     //
 | |
|     if ((Question->Storage != NULL) &&
 | |
|         (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) {
 | |
|       SetQuestionValue (FormSet, Form, Question, TRUE);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Initialize Question's Edit copy from Storage.
 | |
| 
 | |
|   @param  Selection              Selection contains the information about 
 | |
|                                  the Selection, form and formset to be displayed.
 | |
|                                  Selection action may be updated in retrieve callback.
 | |
|   @param  FormSet                FormSet data structure.
 | |
|   @param  Form                   Form data structure.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The function completed successfully.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| LoadFormConfig (
 | |
|   IN OUT UI_MENU_SELECTION    *Selection,
 | |
|   IN FORM_BROWSER_FORMSET     *FormSet,
 | |
|   IN FORM_BROWSER_FORM        *Form
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   LIST_ENTRY                  *Link;
 | |
|   FORM_BROWSER_STATEMENT      *Question;
 | |
|   UINT8                       *BufferValue;
 | |
|   UINTN                       StorageWidth;
 | |
|   EFI_HII_VALUE               *HiiValue;
 | |
|   EFI_BROWSER_ACTION_REQUEST  ActionRequest;
 | |
|   
 | |
|   Link = GetFirstNode (&Form->StatementListHead);
 | |
|   while (!IsNull (&Form->StatementListHead, Link)) {
 | |
|     Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
 | |
| 
 | |
|     //
 | |
|     // Initialize local copy of Value for each Question
 | |
|     //
 | |
|     Status = GetQuestionValue (FormSet, Form, Question, TRUE);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|     
 | |
|     //
 | |
|     // Check whether EfiVarstore with CallBack can be got.
 | |
|     //
 | |
|     if ((Question->QuestionId != 0) && (Question->Storage != NULL) &&
 | |
|         (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) && 
 | |
|         ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK)) {
 | |
|       //
 | |
|       // ConfigAccess can't be NULL.
 | |
|       //
 | |
|       if (FormSet->ConfigAccess == NULL) {
 | |
|         return EFI_UNSUPPORTED;
 | |
|       }
 | |
|       //
 | |
|       // Check QuestionValue does exist.
 | |
|       //
 | |
|       StorageWidth = Question->StorageWidth;
 | |
|       if (Question->BufferValue != NULL) {
 | |
|         BufferValue  = Question->BufferValue;
 | |
|       } else {
 | |
|         BufferValue = (UINT8 *) &Question->HiiValue.Value;
 | |
|       }
 | |
|       Status = gRT->GetVariable (
 | |
|                        Question->VariableName,
 | |
|                        &Question->Storage->Guid,
 | |
|                        NULL,
 | |
|                        &StorageWidth,
 | |
|                        BufferValue
 | |
|                        );
 | |
| 
 | |
|       if (!EFI_ERROR (Status)) {
 | |
|         ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
 | |
|         HiiValue = &Question->HiiValue;
 | |
|         BufferValue = (UINT8 *) &Question->HiiValue.Value;
 | |
|         if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
 | |
|           //
 | |
|           // Create String in HII database for Configuration Driver to retrieve
 | |
|           //
 | |
|           HiiValue->Value.string = NewString ((CHAR16 *) Question->BufferValue, FormSet->HiiHandle);
 | |
|         } else if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
 | |
|           BufferValue = Question->BufferValue;
 | |
|         }
 | |
| 
 | |
|         Status = FormSet->ConfigAccess->Callback (
 | |
|                                  FormSet->ConfigAccess,
 | |
|                                  EFI_BROWSER_ACTION_RETRIEVE,
 | |
|                                  Question->QuestionId,
 | |
|                                  HiiValue->Type,
 | |
|                                  (EFI_IFR_TYPE_VALUE *) BufferValue,
 | |
|                                  &ActionRequest
 | |
|                                  );
 | |
| 
 | |
|         if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
 | |
|           //
 | |
|           // Clean the String in HII Database
 | |
|           //
 | |
|           DeleteString (HiiValue->Value.string, FormSet->HiiHandle);
 | |
|         }
 | |
| 
 | |
|         if (!EFI_ERROR (Status)) {
 | |
|           switch (ActionRequest) {
 | |
|           case EFI_BROWSER_ACTION_REQUEST_RESET:
 | |
|             gResetRequired = TRUE;
 | |
|             break;
 | |
| 
 | |
|           case EFI_BROWSER_ACTION_REQUEST_SUBMIT:
 | |
|             //
 | |
|             // Till now there is no uncommitted data, so ignore this request
 | |
|             //
 | |
|             break;
 | |
| 
 | |
|           case EFI_BROWSER_ACTION_REQUEST_EXIT:
 | |
|             Selection->Action = UI_ACTION_EXIT;
 | |
|             break;
 | |
| 
 | |
|           default:
 | |
|             break;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     Link = GetNextNode (&Form->StatementListHead, Link);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Initialize Question's Edit copy from Storage for the whole Formset.
 | |
| 
 | |
|   @param  Selection              Selection contains the information about 
 | |
|                                  the Selection, form and formset to be displayed.
 | |
|                                  Selection action may be updated in retrieve callback.
 | |
|   @param  FormSet                FormSet data structure.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The function completed successfully.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| LoadFormSetConfig (
 | |
|   IN OUT UI_MENU_SELECTION    *Selection,
 | |
|   IN     FORM_BROWSER_FORMSET *FormSet
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS            Status;
 | |
|   LIST_ENTRY            *Link;
 | |
|   FORM_BROWSER_FORM     *Form;
 | |
| 
 | |
|   Link = GetFirstNode (&FormSet->FormListHead);
 | |
|   while (!IsNull (&FormSet->FormListHead, Link)) {
 | |
|     Form = FORM_BROWSER_FORM_FROM_LINK (Link);
 | |
| 
 | |
|     //
 | |
|     // Initialize local copy of Value for each Form
 | |
|     //
 | |
|     Status = LoadFormConfig (Selection, FormSet, Form);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     Link = GetNextNode (&FormSet->FormListHead, Link);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Fill storage's edit copy with settings requested from Configuration Driver.
 | |
| 
 | |
|   @param  FormSet                FormSet data structure.
 | |
|   @param  Storage                Buffer Storage.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The function completed successfully.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| LoadStorage (
 | |
|   IN FORM_BROWSER_FORMSET    *FormSet,
 | |
|   IN FORMSET_STORAGE         *Storage
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   EFI_STRING  Progress;
 | |
|   EFI_STRING  Result;
 | |
|   CHAR16      *StrPtr;
 | |
| 
 | |
|   if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   if (FormSet->ConfigAccess == NULL) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   if (Storage->ElementCount == 0) {
 | |
|     //
 | |
|     // Skip if there is no RequestElement
 | |
|     //
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Request current settings from Configuration Driver
 | |
|   //
 | |
|   Status = FormSet->ConfigAccess->ExtractConfig (
 | |
|                                     FormSet->ConfigAccess,
 | |
|                                     Storage->ConfigRequest,
 | |
|                                     &Progress,
 | |
|                                     &Result
 | |
|                                     );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Convert Result from <ConfigAltResp> to <ConfigResp>
 | |
|   //
 | |
|   StrPtr = StrStr (Result, L"ALTCFG");
 | |
|   if (StrPtr != NULL) {
 | |
|     *StrPtr = L'\0';
 | |
|   }
 | |
| 
 | |
|   Status = ConfigRespToStorage (Storage, Result);
 | |
|   FreePool (Result);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Copy uncommitted data from source Storage to destination Storage.
 | |
| 
 | |
|   @param  Dst                    Target Storage for uncommitted data.
 | |
|   @param  Src                    Source Storage for uncommitted data.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The function completed successfully.
 | |
|   @retval EFI_INVALID_PARAMETER  Source and destination Storage is not the same type.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| CopyStorage (
 | |
|   IN OUT FORMSET_STORAGE     *Dst,
 | |
|   IN FORMSET_STORAGE         *Src
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY          *Link;
 | |
|   NAME_VALUE_NODE     *Node;
 | |
| 
 | |
|   if ((Dst->Type != Src->Type) || (Dst->Size != Src->Size)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   switch (Src->Type) {
 | |
|   case EFI_HII_VARSTORE_BUFFER:
 | |
|     CopyMem (Dst->EditBuffer, Src->EditBuffer, Src->Size);
 | |
|     break;
 | |
| 
 | |
|   case EFI_HII_VARSTORE_NAME_VALUE:
 | |
|     Link = GetFirstNode (&Src->NameValueListHead);
 | |
|     while (!IsNull (&Src->NameValueListHead, Link)) {
 | |
|       Node = NAME_VALUE_NODE_FROM_LINK (Link);
 | |
| 
 | |
|       SetValueByName (Dst, Node->Name, Node->EditValue);
 | |
| 
 | |
|       Link = GetNextNode (&Src->NameValueListHead, Link);
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   case EFI_HII_VARSTORE_EFI_VARIABLE:
 | |
|   default:
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Get current setting of Questions.
 | |
| 
 | |
|   @param  FormSet                FormSet data structure.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The function completed successfully.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| InitializeCurrentSetting (
 | |
|   IN OUT FORM_BROWSER_FORMSET             *FormSet
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY              *Link;
 | |
|   LIST_ENTRY              *Link2;
 | |
|   FORMSET_STORAGE         *Storage;
 | |
|   FORMSET_STORAGE         *StorageSrc;
 | |
|   FORMSET_STORAGE         *OldStorage;
 | |
|   FORM_BROWSER_FORM       *Form;
 | |
|   EFI_STATUS              Status;
 | |
| 
 | |
|   //
 | |
|   // Extract default from IFR binary
 | |
|   //
 | |
|   Link = GetFirstNode (&FormSet->FormListHead);
 | |
|   while (!IsNull (&FormSet->FormListHead, Link)) {
 | |
|     Form = FORM_BROWSER_FORM_FROM_LINK (Link);
 | |
| 
 | |
|     Status = ExtractFormDefault (FormSet, Form, EFI_HII_DEFAULT_CLASS_STANDARD);
 | |
| 
 | |
|     Link = GetNextNode (&FormSet->FormListHead, Link);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Request current settings from Configuration Driver
 | |
|   //
 | |
|   Link = GetFirstNode (&FormSet->StorageListHead);
 | |
|   while (!IsNull (&FormSet->StorageListHead, Link)) {
 | |
|     Storage = FORMSET_STORAGE_FROM_LINK (Link);
 | |
| 
 | |
|     OldStorage = NULL;
 | |
|     if (gOldFormSet != NULL) {
 | |
|       //
 | |
|       // Try to find the Storage in backup formset gOldFormSet
 | |
|       //
 | |
|       Link2 = GetFirstNode (&gOldFormSet->StorageListHead);
 | |
|       while (!IsNull (&gOldFormSet->StorageListHead, Link2)) {
 | |
|         StorageSrc = FORMSET_STORAGE_FROM_LINK (Link2);
 | |
| 
 | |
|         if (StorageSrc->VarStoreId == Storage->VarStoreId) {
 | |
|           OldStorage = StorageSrc;
 | |
|           break;
 | |
|         }
 | |
| 
 | |
|         Link2 = GetNextNode (&gOldFormSet->StorageListHead, Link2);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (OldStorage == NULL) {
 | |
|       //
 | |
|       // Storage is not found in backup formset, request it from ConfigDriver
 | |
|       //
 | |
|       Status = LoadStorage (FormSet, Storage);
 | |
|     } else {
 | |
|       //
 | |
|       // Storage found in backup formset, use it
 | |
|       //
 | |
|       Status = CopyStorage (Storage, OldStorage);
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Now Edit Buffer is filled with default values(lower priority) and current
 | |
|     // settings(higher priority), sychronize it to shadow Buffer
 | |
|     //
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       SynchronizeStorage (Storage);
 | |
|     }
 | |
| 
 | |
|     Link = GetNextNode (&FormSet->StorageListHead, Link);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Fetch the Ifr binary data of a FormSet.
 | |
| 
 | |
|   @param  Handle                 PackageList Handle
 | |
|   @param  FormSetGuid            On input, GUID or class GUID of a formset. If not
 | |
|                                  specified (NULL or zero GUID), take the first
 | |
|                                  FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
 | |
|                                  found in package list.
 | |
|                                  On output, GUID of the formset found(if not NULL).
 | |
|   @param  BinaryLength           The length of the FormSet IFR binary.
 | |
|   @param  BinaryData             The buffer designed to receive the FormSet.
 | |
| 
 | |
|   @retval EFI_SUCCESS            Buffer filled with the requested FormSet.
 | |
|                                  BufferLength was updated.
 | |
|   @retval EFI_INVALID_PARAMETER  The handle is unknown.
 | |
|   @retval EFI_NOT_FOUND          A form or FormSet on the requested handle cannot
 | |
|                                  be found with the requested FormId.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| GetIfrBinaryData (
 | |
|   IN  EFI_HII_HANDLE   Handle,
 | |
|   IN OUT EFI_GUID      *FormSetGuid,
 | |
|   OUT UINTN            *BinaryLength,
 | |
|   OUT UINT8            **BinaryData
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                   Status;
 | |
|   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
 | |
|   UINTN                        BufferSize;
 | |
|   UINT8                        *Package;
 | |
|   UINT8                        *OpCodeData;
 | |
|   UINT32                       Offset;
 | |
|   UINT32                       Offset2;
 | |
|   UINT32                       PackageListLength;
 | |
|   EFI_HII_PACKAGE_HEADER       PackageHeader;
 | |
|   UINT8                        Index;
 | |
|   UINT8                        NumberOfClassGuid;
 | |
|   BOOLEAN                      ClassGuidMatch;
 | |
|   EFI_GUID                     *ClassGuid;
 | |
|   EFI_GUID                     *ComparingGuid;
 | |
| 
 | |
|   OpCodeData = NULL;
 | |
|   Package = NULL;
 | |
|   ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
 | |
| 
 | |
|   //
 | |
|   // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list
 | |
|   //
 | |
|   if (FormSetGuid == NULL || CompareGuid (FormSetGuid, &gZeroGuid)) {
 | |
|     ComparingGuid = &gEfiHiiPlatformSetupFormsetGuid;
 | |
|   } else {
 | |
|     ComparingGuid = FormSetGuid;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get HII PackageList
 | |
|   //
 | |
|   BufferSize = 0;
 | |
|   HiiPackageList = NULL;
 | |
|   Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
 | |
|   if (Status == EFI_BUFFER_TOO_SMALL) {
 | |
|     HiiPackageList = AllocatePool (BufferSize);
 | |
|     ASSERT (HiiPackageList != NULL);
 | |
| 
 | |
|     Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
 | |
|   }
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   ASSERT (HiiPackageList != NULL);
 | |
| 
 | |
|   //
 | |
|   // Get Form package from this HII package List
 | |
|   //
 | |
|   Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
 | |
|   Offset2 = 0;
 | |
|   CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
 | |
| 
 | |
|   ClassGuidMatch = FALSE;
 | |
|   while (Offset < PackageListLength) {
 | |
|     Package = ((UINT8 *) HiiPackageList) + Offset;
 | |
|     CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
 | |
| 
 | |
|     if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
 | |
|       //
 | |
|       // Search FormSet in this Form Package
 | |
|       //
 | |
|       Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
 | |
|       while (Offset2 < PackageHeader.Length) {
 | |
|         OpCodeData = Package + Offset2;
 | |
| 
 | |
|         if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
 | |
|           //
 | |
|           // Try to compare against formset GUID
 | |
|           //
 | |
|           if (CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
 | |
|             break;
 | |
|           }
 | |
| 
 | |
|           if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
 | |
|             //
 | |
|             // Try to compare against formset class GUID
 | |
|             //
 | |
|             NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
 | |
|             ClassGuid         = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET));
 | |
|             for (Index = 0; Index < NumberOfClassGuid; Index++) {
 | |
|               if (CompareGuid (ComparingGuid, ClassGuid + Index)) {
 | |
|                 ClassGuidMatch = TRUE;
 | |
|                 break;
 | |
|               }
 | |
|             }
 | |
|             if (ClassGuidMatch) {
 | |
|               break;
 | |
|             }
 | |
|           } else if (ComparingGuid == &gEfiHiiPlatformSetupFormsetGuid) {
 | |
|             ClassGuidMatch = TRUE;
 | |
|             break;
 | |
|           }
 | |
|         }
 | |
| 
 | |
|         Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
 | |
|       }
 | |
| 
 | |
|       if (Offset2 < PackageHeader.Length) {
 | |
|         //
 | |
|         // Target formset found
 | |
|         //
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     Offset += PackageHeader.Length;
 | |
|   }
 | |
| 
 | |
|   if (Offset >= PackageListLength) {
 | |
|     //
 | |
|     // Form package not found in this Package List
 | |
|     //
 | |
|     FreePool (HiiPackageList);
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   if (ClassGuidMatch && (FormSetGuid != NULL)) {
 | |
|     //
 | |
|     // Return the FormSet GUID
 | |
|     //
 | |
|     CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes
 | |
|   // in this FormSet; So, here just simply copy the data from start of a FormSet to the end
 | |
|   // of the Form Package.
 | |
|   //
 | |
|   *BinaryLength = PackageHeader.Length - Offset2;
 | |
|   *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData);
 | |
| 
 | |
|   FreePool (HiiPackageList);
 | |
| 
 | |
|   if (*BinaryData == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Initialize the internal data structure of a FormSet.
 | |
| 
 | |
|   @param  Handle                 PackageList Handle
 | |
|   @param  FormSetGuid            On input, GUID or class GUID of a formset. If not
 | |
|                                  specified (NULL or zero GUID), take the first
 | |
|                                  FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID
 | |
|                                  found in package list.
 | |
|                                  On output, GUID of the formset found(if not NULL).
 | |
|   @param  FormSet                FormSet data structure.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The function completed successfully.
 | |
|   @retval EFI_NOT_FOUND          The specified FormSet could not be found.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| InitializeFormSet (
 | |
|   IN  EFI_HII_HANDLE                   Handle,
 | |
|   IN OUT EFI_GUID                      *FormSetGuid,
 | |
|   OUT FORM_BROWSER_FORMSET             *FormSet
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                Status;
 | |
|   EFI_HANDLE                DriverHandle;
 | |
|   UINT16                    Index;
 | |
| 
 | |
|   Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   FormSet->HiiHandle = Handle;
 | |
|   CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));
 | |
| 
 | |
|   //
 | |
|   // Retrieve ConfigAccess Protocol associated with this HiiPackageList
 | |
|   //
 | |
|   Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   FormSet->DriverHandle = DriverHandle;
 | |
|   Status = gBS->HandleProtocol (
 | |
|                   DriverHandle,
 | |
|                   &gEfiHiiConfigAccessProtocolGuid,
 | |
|                   (VOID **) &FormSet->ConfigAccess
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // Configuration Driver don't attach ConfigAccess protocol to its HII package
 | |
|     // list, then there will be no configuration action required
 | |
|     //
 | |
|     FormSet->ConfigAccess = NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Parse the IFR binary OpCodes
 | |
|   //
 | |
|   Status = ParseOpCodes (FormSet);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Set VFR type by FormSet SubClass field
 | |
|   //
 | |
|   gClassOfVfr = FORMSET_CLASS_PLATFORM_SETUP;
 | |
|   if (FormSet->SubClass == EFI_FRONT_PAGE_SUBCLASS) {
 | |
|     gClassOfVfr = FORMSET_CLASS_FRONT_PAGE;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Set VFR type by FormSet class guid
 | |
|   //
 | |
|   for (Index = 0; Index < 3; Index ++) {
 | |
|     if (CompareGuid (&FormSet->ClassGuid[Index], &gEfiHiiPlatformSetupFormsetGuid)) {
 | |
|       gClassOfVfr |= FORMSET_CLASS_PLATFORM_SETUP;
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) {
 | |
|     gFrontPageHandle = FormSet->HiiHandle;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Match GUID to find out the function key setting. If match fail, use the default setting.
 | |
|   //
 | |
|   for (Index = 0; Index < sizeof (gFunctionKeySettingTable) / sizeof (FUNCTIION_KEY_SETTING); Index++) {
 | |
|     if (CompareGuid (&FormSet->Guid, &(gFunctionKeySettingTable[Index].FormSetGuid))) {
 | |
|       //
 | |
|       // Update the function key setting.
 | |
|       //
 | |
|       gFunctionKeySetting = gFunctionKeySettingTable[Index].KeySetting;
 | |
|       //
 | |
|       // Function key prompt can not be displayed if the function key has been disabled.
 | |
|       //
 | |
|       if ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE) {
 | |
|         gFunctionNineString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
 | |
|       }
 | |
| 
 | |
|       if ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN) {
 | |
|         gFunctionTenString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Save globals used by previous call to SendForm(). SendForm() may be called from 
 | |
|   HiiConfigAccess.Callback(), this will cause SendForm() be reentried.
 | |
|   So, save globals of previous call to SendForm() and restore them upon exit.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SaveBrowserContext (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   BROWSER_CONTEXT  *Context;
 | |
| 
 | |
|   gBrowserContextCount++;
 | |
|   if (gBrowserContextCount == 1) {
 | |
|     //
 | |
|     // This is not reentry of SendForm(), no context to save
 | |
|     //
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   Context = AllocatePool (sizeof (BROWSER_CONTEXT));
 | |
|   ASSERT (Context != NULL);
 | |
| 
 | |
|   Context->Signature = BROWSER_CONTEXT_SIGNATURE;
 | |
| 
 | |
|   //
 | |
|   // Save FormBrowser context
 | |
|   //
 | |
|   Context->BannerData           = gBannerData;
 | |
|   Context->ClassOfVfr           = gClassOfVfr;
 | |
|   Context->FunctionKeySetting   = gFunctionKeySetting;
 | |
|   Context->ResetRequired        = gResetRequired;
 | |
|   Context->NvUpdateRequired     = gNvUpdateRequired;
 | |
|   Context->Direction            = gDirection;
 | |
|   Context->FunctionNineString   = gFunctionNineString;
 | |
|   Context->FunctionTenString    = gFunctionTenString;
 | |
|   Context->EnterString          = gEnterString;
 | |
|   Context->EnterCommitString    = gEnterCommitString;
 | |
|   Context->EnterEscapeString    = gEnterEscapeString;
 | |
|   Context->EscapeString         = gEscapeString;
 | |
|   Context->SaveFailed           = gSaveFailed;
 | |
|   Context->MoveHighlight        = gMoveHighlight;
 | |
|   Context->MakeSelection        = gMakeSelection;
 | |
|   Context->DecNumericInput      = gDecNumericInput;
 | |
|   Context->HexNumericInput      = gHexNumericInput;
 | |
|   Context->ToggleCheckBox       = gToggleCheckBox;
 | |
|   Context->PromptForData        = gPromptForData;
 | |
|   Context->PromptForPassword    = gPromptForPassword;
 | |
|   Context->PromptForNewPassword = gPromptForNewPassword;
 | |
|   Context->ConfirmPassword      = gConfirmPassword;
 | |
|   Context->ConfirmError         = gConfirmError;
 | |
|   Context->PassowordInvalid     = gPassowordInvalid;
 | |
|   Context->PressEnter           = gPressEnter;
 | |
|   Context->EmptyString          = gEmptyString;
 | |
|   Context->AreYouSure           = gAreYouSure;
 | |
|   Context->YesResponse          = gYesResponse;
 | |
|   Context->NoResponse           = gNoResponse;
 | |
|   Context->MiniString           = gMiniString;
 | |
|   Context->PlusString           = gPlusString;
 | |
|   Context->MinusString          = gMinusString;
 | |
|   Context->AdjustNumber         = gAdjustNumber;
 | |
|   Context->SaveChanges          = gSaveChanges;
 | |
|   Context->OptionMismatch       = gOptionMismatch;
 | |
|   Context->FormSuppress         = gFormSuppress;
 | |
|   Context->PromptBlockWidth     = gPromptBlockWidth;
 | |
|   Context->OptionBlockWidth     = gOptionBlockWidth;
 | |
|   Context->HelpBlockWidth       = gHelpBlockWidth;
 | |
|   Context->OldFormSet           = gOldFormSet;
 | |
|   Context->MenuRefreshHead      = gMenuRefreshHead;
 | |
| 
 | |
|   CopyMem (&Context->ScreenDimensions, &gScreenDimensions, sizeof (gScreenDimensions));
 | |
|   CopyMem (&Context->MenuOption, &gMenuOption, sizeof (gMenuOption));
 | |
| 
 | |
|   //
 | |
|   // Insert to FormBrowser context list
 | |
|   //
 | |
|   InsertHeadList (&gBrowserContextList, &Context->Link);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Restore globals used by previous call to SendForm().
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| RestoreBrowserContext (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY       *Link;
 | |
|   BROWSER_CONTEXT  *Context;
 | |
| 
 | |
|   ASSERT (gBrowserContextCount != 0);
 | |
|   gBrowserContextCount--;
 | |
|   if (gBrowserContextCount == 0) {
 | |
|     //
 | |
|     // This is not reentry of SendForm(), no context to restore
 | |
|     //
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   ASSERT (!IsListEmpty (&gBrowserContextList));
 | |
| 
 | |
|   Link = GetFirstNode (&gBrowserContextList);
 | |
|   Context = BROWSER_CONTEXT_FROM_LINK (Link);
 | |
| 
 | |
|   //
 | |
|   // Restore FormBrowser context
 | |
|   //
 | |
|   gBannerData           = Context->BannerData;
 | |
|   gClassOfVfr           = Context->ClassOfVfr;
 | |
|   gFunctionKeySetting   = Context->FunctionKeySetting;
 | |
|   gResetRequired        = Context->ResetRequired;
 | |
|   gNvUpdateRequired     = Context->NvUpdateRequired;
 | |
|   gDirection            = Context->Direction;
 | |
|   gFunctionNineString   = Context->FunctionNineString;
 | |
|   gFunctionTenString    = Context->FunctionTenString;
 | |
|   gEnterString          = Context->EnterString;
 | |
|   gEnterCommitString    = Context->EnterCommitString;
 | |
|   gEnterEscapeString    = Context->EnterEscapeString;
 | |
|   gEscapeString         = Context->EscapeString;
 | |
|   gSaveFailed           = Context->SaveFailed;
 | |
|   gMoveHighlight        = Context->MoveHighlight;
 | |
|   gMakeSelection        = Context->MakeSelection;
 | |
|   gDecNumericInput      = Context->DecNumericInput;
 | |
|   gHexNumericInput      = Context->HexNumericInput;
 | |
|   gToggleCheckBox       = Context->ToggleCheckBox;
 | |
|   gPromptForData        = Context->PromptForData;
 | |
|   gPromptForPassword    = Context->PromptForPassword;
 | |
|   gPromptForNewPassword = Context->PromptForNewPassword;
 | |
|   gConfirmPassword      = Context->ConfirmPassword;
 | |
|   gConfirmError         = Context->ConfirmError;
 | |
|   gPassowordInvalid     = Context->PassowordInvalid;
 | |
|   gPressEnter           = Context->PressEnter;
 | |
|   gEmptyString          = Context->EmptyString;
 | |
|   gAreYouSure           = Context->AreYouSure;
 | |
|   gYesResponse          = Context->YesResponse;
 | |
|   gNoResponse           = Context->NoResponse;
 | |
|   gMiniString           = Context->MiniString;
 | |
|   gPlusString           = Context->PlusString;
 | |
|   gMinusString          = Context->MinusString;
 | |
|   gAdjustNumber         = Context->AdjustNumber;
 | |
|   gSaveChanges          = Context->SaveChanges;
 | |
|   gOptionMismatch       = Context->OptionMismatch;
 | |
|   gFormSuppress         = Context->FormSuppress;
 | |
|   gPromptBlockWidth     = Context->PromptBlockWidth;
 | |
|   gOptionBlockWidth     = Context->OptionBlockWidth;
 | |
|   gHelpBlockWidth       = Context->HelpBlockWidth;
 | |
|   gOldFormSet           = Context->OldFormSet;
 | |
|   gMenuRefreshHead      = Context->MenuRefreshHead;
 | |
| 
 | |
|   CopyMem (&gScreenDimensions, &Context->ScreenDimensions, sizeof (gScreenDimensions));
 | |
|   CopyMem (&gMenuOption, &Context->MenuOption, sizeof (gMenuOption));
 | |
| 
 | |
|   //
 | |
|   // Remove from FormBrowser context list
 | |
|   //
 | |
|   RemoveEntryList (&Context->Link);
 | |
|   gBS->FreePool (Context);
 | |
| }
 |