processoptions.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,634 行 · 第 1/5 页

C
1,634
字号
/*++

Copyright (c) 2004 - 2005, 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.             

Module Name:

  ProcessOptions.c

Abstract:
  
  Implementation for handling the User Interface option processing.

Revision History

--*/

#include "Ui.h"
#include "Setup.h"

EFI_STATUS
ExtractRequestedNvMap (
  IN  EFI_FILE_FORM_TAGS          *FileFormTags,
  IN  UINT16                      VariableId,
  OUT EFI_VARIABLE_DEFINITION     **VariableDefinition
  )
{
  *VariableDefinition = FileFormTags->VariableDefinitions;

  //
  // Extract the data from the NV variable - consumer will free the buffer.
  //
  for (; *VariableDefinition != NULL; *VariableDefinition = (*VariableDefinition)->Next) {
    //
    // If there is a variable with this ID return with EFI_SUCCESS
    //
    if (!EfiCompareMem (&(*VariableDefinition)->VariableId, &VariableId, sizeof (UINT16))) {
      return EFI_SUCCESS;
    }
  }

  return EFI_NOT_FOUND;
}

EFI_STATUS
ExtractNvValue (
  IN  EFI_FILE_FORM_TAGS          *FileFormTags,
  IN  UINT16                      VariableId,
  IN  UINT16                      VariableSize,
  IN  UINT16                      OffsetValue,
  OUT VOID                        **Buffer
  )
{
  EFI_STATUS              Status;
  EFI_VARIABLE_DEFINITION *VariableDefinition;

  Status = ExtractRequestedNvMap (FileFormTags, VariableId, &VariableDefinition);

  if (!EFI_ERROR (Status)) {
    //
    // Allocate sufficient space for the data and copy it into the outgoing buffer
    //
    *Buffer = EfiLibAllocateZeroPool (VariableSize);
    ASSERT (*Buffer != NULL);
    EfiCopyMem (*Buffer, &VariableDefinition->NvRamMap[OffsetValue], VariableSize);
    return EFI_SUCCESS;
  }

  return Status;
}

VOID
AdjustNvMap (
  IN  EFI_FILE_FORM_TAGS          *FileFormTags,
  IN  UI_MENU_OPTION              *MenuOption
  )
{
  CHAR8                   *NvRamMap;
  UINTN                   SizeRequired;
  UINTN                   Index;
  UINTN                   CachedStart;
  EFI_VARIABLE_DEFINITION *VariableDefinition;

  CachedStart   = 0;

  SizeRequired  = MenuOption->ThisTag->StorageStart + MenuOption->ThisTag->StorageWidth;

  ExtractRequestedNvMap (FileFormTags, MenuOption->Tags->VariableNumber, &VariableDefinition);

  //
  // We arrived here because the current NvRamMap is too small for the new op-code to store things and
  // we need to adjust the buffer to support this.
  //
  NvRamMap = EfiLibAllocateZeroPool (SizeRequired + 1);
  ASSERT (NvRamMap != NULL);

  //
  // Copy current NvRamMap to the new NvRamMap
  //
  EfiCopyMem (NvRamMap, VariableDefinition->NvRamMap, VariableDefinition->VariableFakeSize);

  //
  // Remember, the only time we come here is because we are in the NVPlus section of the NvRamMap
  //
  for (Index = MenuOption->TagIndex;
       (MenuOption->Tags[Index].Operand != EFI_IFR_END_FORM_OP) && (MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP);
       Index++
      ) {

    switch (MenuOption->Tags[Index].Operand) {
    case EFI_IFR_ORDERED_LIST_OP:
    case EFI_IFR_ONE_OF_OP:
      CachedStart = MenuOption->Tags[Index].StorageStart;
      break;

    case EFI_IFR_ONE_OF_OPTION_OP:
      if (MenuOption->Tags[Index].Flags & EFI_IFR_FLAG_DEFAULT) {
        EfiCopyMem (&NvRamMap[CachedStart], &MenuOption->Tags[Index].Value, 2);
      }
      break;

    case EFI_IFR_CHECKBOX_OP:
      EfiCopyMem (&NvRamMap[MenuOption->Tags[Index].StorageStart], &MenuOption->Tags[Index].Flags, 1);
      break;

    case EFI_IFR_NUMERIC_OP:
    case EFI_IFR_DATE_OP:
    case EFI_IFR_TIME_OP:
    case EFI_IFR_STRING_OP:
    case EFI_IFR_PASSWORD_OP:
      EfiCopyMem (
        &NvRamMap[MenuOption->Tags[Index].StorageStart],
        &MenuOption->Tags[Index].Value,
        MenuOption->Tags[Index].StorageWidth
        );
      break;

    }
  }

  gBS->FreePool (VariableDefinition->NvRamMap);
  VariableDefinition->NvRamMap          = NvRamMap;
  VariableDefinition->VariableFakeSize  = (UINT16) SizeRequired;
}

EFI_STATUS
ProcessOptions (
  IN  UI_MENU_OPTION              *MenuOption,
  IN  BOOLEAN                     Selected,
  IN  EFI_FILE_FORM_TAGS          *FileFormTagsHead,
  IN  EFI_IFR_DATA_ARRAY          *PageData,
  OUT CHAR16                      **OptionString
  )
{
  EFI_STATUS                  Status;
  CHAR16                      *StringPtr;
  UINTN                       Index;
  UINTN                       CachedIndex;
  EFI_FILE_FORM_TAGS          *FileFormTags;
  EFI_TAG                     *Tag;
  CHAR16                      FormattedNumber[6];
  UINT16                      Number;
  UINT16                      Value;
  UINT16                      *ValueArray;
  UINT16                      *NvRamMap;
  CHAR8                       *TmpNvRamMap;
  UINTN                       Default;
  UINTN                       StringCount;
  CHAR16                      Character[2];
  UINTN                       Count;
  EFI_TIME                    Time;
  EFI_FORM_CALLBACK_PROTOCOL  *FormCallback;
  STRING_REF                  PopUp;
  CHAR16                      NullCharacter;
  EFI_INPUT_KEY               Key;
  EFI_VARIABLE_DEFINITION     *VariableDefinition;
  BOOLEAN                     OrderedList;
  BOOLEAN                     Initialized;
  UINT16                      KeyValue;
  BOOLEAN                     Skip;

  FileFormTags = FileFormTagsHead;

  for (Index = 0; Index < MenuOption->IfrNumber; Index++) {
    FileFormTags = FileFormTags->NextFile;
  }

  OrderedList         = FALSE;
  Initialized         = FALSE;
  ValueArray          = NULL;
  VariableDefinition  = NULL;
  Skip                = FALSE;

  EfiZeroMem (&Time, sizeof (EFI_TIME));

  StringPtr = L"\0";
  Tag       = MenuOption->ThisTag;
  ExtractRequestedNvMap (FileFormTags, Tag->VariableNumber, &VariableDefinition);

  if (Tag->StorageStart > VariableDefinition->VariableSize) {
    NvRamMap = (UINT16 *) &VariableDefinition->FakeNvRamMap[Tag->StorageStart];
  } else {
    NvRamMap = (UINT16 *) &VariableDefinition->NvRamMap[Tag->StorageStart];
  }

  StringCount   = 0;
  Character[1]  = 0;
  Count         = 0;
  Default       = 0;
  NullCharacter = CHAR_NULL;
  FormCallback  = NULL;

  if (MenuOption->ThisTag->Operand == EFI_IFR_ORDERED_LIST_OP) {
    OrderedList = TRUE;
    if (((UINT8 *) NvRamMap)[0] != 0x00) {
      Initialized = TRUE;
    }
  }

  EfiZeroMem (FormattedNumber, 12);

  Status = gBS->HandleProtocol (
                  (VOID *) (UINTN) FileFormTags->FormTags.Tags[0].CallbackHandle,
                  &gEfiFormCallbackProtocolGuid,
                  &FormCallback
                  );

  if (*OptionString != NULL) {
    gBS->FreePool (*OptionString);
    *OptionString = NULL;
  }

  switch (Tag->Operand) {

  case EFI_IFR_ORDERED_LIST_OP:
  case EFI_IFR_ONE_OF_OP:
    //
    // If the op-code we are looking at is larger than the latest created NvMap - we likely encountered a dynamically
    // created entry which has an expanded NvMap requirement.  We won't save this information - but we need to adjust
    // the NvMap so that we can properly display the information
    //
    if ((UINTN) (Tag->StorageStart + Tag->StorageWidth) > VariableDefinition->VariableFakeSize) {
      AdjustNvMap (FileFormTags, MenuOption);
      NvRamMap = (UINT16 *) &VariableDefinition->NvRamMap[Tag->StorageStart];
    }

    CachedIndex = MenuOption->TagIndex;

    //
    // search for EFI_IFR_ONE_OF_OPTION_OP until you hit the EFI_IFR_END_ONE_OF_OP,
    // each of the .Text in the options are going to be what gets displayed.  Break each into 26 char chunks
    // when hit right/left arrow allows for selection - then repopulate Tag[TagIndex] with the choice
    //
    for (Index = MenuOption->TagIndex; MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP; Index++) {
      //
      // We found an option - which assumedly has a string.  We will eventually have to support
      // wrapping of strings.  For now, let's pretend they don't wrap and code that up.
      //
      // Count how many strings there are
      //
      if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) {
        //
        // If one of the options for the one-of has an interactive flag, back-define the oneof to have one too
        //
        if (MenuOption->Tags[Index].Flags & EFI_IFR_FLAG_INTERACTIVE) {
          MenuOption->Tags[CachedIndex].Flags = (UINT8) (MenuOption->Tags[CachedIndex].Flags | EFI_IFR_FLAG_INTERACTIVE);
        }

        StringCount++;
      }
    }
    //
    // We now know how many strings we will have, so we can allocate the
    // space required for the array or strings.
    //
    *OptionString = EfiLibAllocateZeroPool (StringCount * (gOptionBlockWidth + 1) * 2 * gScreenDimensions.BottomRow);
    ASSERT (*OptionString);

    //
    // Add left delimeter to string
    //
    *OptionString[0] = LEFT_ONEOF_DELIMITER;

    //
    // Retrieve the current OneOf value
    //
    if (Selected) {
      //
      // Auto selection from list
      //
      Value = 0;
      //
      // Copy current setting to the seed Value
      //
      if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) {
        ValueArray = EfiLibAllocateZeroPool (MenuOption->ThisTag->StorageWidth);
        ASSERT (ValueArray != NULL);
        EfiCopyMem (ValueArray, NvRamMap, MenuOption->ThisTag->StorageWidth);
      } else {
        EfiCopyMem (&Value, NvRamMap, MenuOption->ThisTag->StorageWidth);
        EfiCopyMem (gPreviousValue, NvRamMap, MenuOption->ThisTag->StorageWidth);
      }

      Number = Value;
      if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) {
        Status = GetSelectionInputPopUp (MenuOption, Tag, MenuOption->ThisTag->StorageWidth, ValueArray, &KeyValue);
      } else {
        Status = GetSelectionInputPopUp (MenuOption, Tag, 1, &Value, &KeyValue);
      }

      if (!EFI_ERROR (Status)) {
        if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) {
          EfiCopyMem (NvRamMap, ValueArray, MenuOption->ThisTag->StorageWidth);
          gBS->FreePool (ValueArray);
        } else {
          //
          // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth
          //
          EfiCopyMem (NvRamMap, &Value, Tag->StorageWidth);
          MenuOption->ThisTag->Key = KeyValue;
        }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?