mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-31 22:30:33 +00:00 
			
		
		
		
	 4a4297160f
			
		
	
	
		4a4297160f
		
	
	
	
	
		
			
			Contributed-under: TianoCore Contribution Agreement 1.0 Reviewed-by: Liming Gao <liming.gao@intel.com> Cc: Eric Dong <eric.dong@intel.com> Cc: Dandan Bi <dandan.bi@intel.com> Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
		
			
				
	
	
		
			3312 lines
		
	
	
		
			101 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			3312 lines
		
	
	
		
			101 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| Implementation of interfaces function for EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL.
 | |
| 
 | |
| Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
 | |
| This program and the accompanying materials
 | |
| are licensed and made available under the terms and conditions of the BSD License
 | |
| which accompanies this distribution.  The full text of the license may be found at
 | |
| http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| 
 | |
| #include "HiiDatabase.h"
 | |
| 
 | |
| extern HII_DATABASE_PRIVATE_DATA mPrivate;
 | |
| 
 | |
| /**
 | |
|   Convert the hex UNICODE %02x encoding of a UEFI device path to binary
 | |
|   from <PathHdr> of <MultiKeywordRequest>.
 | |
| 
 | |
|   This is a internal function.
 | |
| 
 | |
|   @param  String                 MultiKeywordRequest string.
 | |
|   @param  DevicePathData         Binary of a UEFI device path.
 | |
|   @param  NextString             string follow the possible PathHdr string.
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER  The device path is not valid or the incoming parameter is invalid.
 | |
|   @retval EFI_OUT_OF_RESOURCES   Lake of resources to store necessary structures.
 | |
|   @retval EFI_SUCCESS            The device path is retrieved and translated to binary format.
 | |
|                                  The Input string not include PathHdr section.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ExtractDevicePath (
 | |
|   IN  EFI_STRING                   String,
 | |
|   OUT UINT8                        **DevicePathData,
 | |
|   OUT EFI_STRING                   *NextString
 | |
|   )
 | |
| {
 | |
|   UINTN                    Length;
 | |
|   EFI_STRING               PathHdr;
 | |
|   UINT8                    *DevicePathBuffer;
 | |
|   CHAR16                   TemStr[2];
 | |
|   UINTN                    Index;
 | |
|   UINT8                    DigitUint8;
 | |
|   EFI_DEVICE_PATH_PROTOCOL *DevicePath;
 | |
| 
 | |
|   ASSERT (NextString != NULL && DevicePathData != NULL);
 | |
| 
 | |
|   //
 | |
|   // KeywordRequest == NULL case.
 | |
|   //
 | |
|   if (String == NULL) {
 | |
|     *DevicePathData = NULL;
 | |
|     *NextString = NULL;
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Skip '&' if exist.
 | |
|   //
 | |
|   if (*String == L'&') {
 | |
|     String ++;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Find the 'PATH=' of <PathHdr>.
 | |
|   //
 | |
|   if (StrnCmp (String, L"PATH=", StrLen (L"PATH=")) != 0) {
 | |
|     if (StrnCmp (String, L"KEYWORD=", StrLen (L"KEYWORD=")) != 0) {
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     } else {
 | |
|       //
 | |
|       // Not include PathHdr, return success and DevicePath = NULL.
 | |
|       //
 | |
|       *DevicePathData = NULL;
 | |
|       *NextString = String;
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check whether path data does exist.
 | |
|   //
 | |
|   String += StrLen (L"PATH=");
 | |
|   if (*String == 0) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   PathHdr = String;
 | |
| 
 | |
|   //
 | |
|   // The content between 'PATH=' of <ConfigHdr> and '&' of next element
 | |
|   // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding
 | |
|   // of UEFI device path.
 | |
|   //
 | |
|   for (Length = 0; *String != 0 && *String != L'&'; String++, Length++);
 | |
| 
 | |
|   //
 | |
|   // Save the return next keyword string value.
 | |
|   //
 | |
|   *NextString = String;
 | |
| 
 | |
|   //
 | |
|   // Check DevicePath Length
 | |
|   //
 | |
|   if (((Length + 1) / 2) < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // The data in <PathHdr> is encoded as hex UNICODE %02x bytes in the same order
 | |
|   // as the device path resides in RAM memory.
 | |
|   // Translate the data into binary.
 | |
|   //
 | |
|   DevicePathBuffer = (UINT8 *) AllocateZeroPool ((Length + 1) / 2);
 | |
|   if (DevicePathBuffer == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Convert DevicePath
 | |
|   //
 | |
|   ZeroMem (TemStr, sizeof (TemStr));
 | |
|   for (Index = 0; Index < Length; Index ++) {
 | |
|     TemStr[0] = PathHdr[Index];
 | |
|     DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
 | |
|     if ((Index & 1) == 0) {
 | |
|       DevicePathBuffer [Index/2] = DigitUint8;
 | |
|     } else {
 | |
|       DevicePathBuffer [Index/2] = (UINT8) ((DevicePathBuffer [Index/2] << 4) + DigitUint8);
 | |
|     }
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Validate DevicePath
 | |
|   //
 | |
|   DevicePath  = (EFI_DEVICE_PATH_PROTOCOL *) DevicePathBuffer;
 | |
|   while (!IsDevicePathEnd (DevicePath)) {
 | |
|     if ((DevicePath->Type == 0) || (DevicePath->SubType == 0) || (DevicePathNodeLength (DevicePath) < sizeof (EFI_DEVICE_PATH_PROTOCOL))) {
 | |
|       //
 | |
|       // Invalid device path
 | |
|       //
 | |
|       FreePool (DevicePathBuffer);
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
|     DevicePath = NextDevicePathNode (DevicePath);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // return the device path
 | |
|   //
 | |
|   *DevicePathData = DevicePathBuffer;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get NameSpace from the input NameSpaceId string.
 | |
| 
 | |
|   This is a internal function.
 | |
| 
 | |
|   @param  String                 <NameSpaceId> format string.
 | |
|   @param  NameSpace              Return the name space string.
 | |
|   @param  NextString             Return the next string follow namespace.
 | |
| 
 | |
|   @retval   EFI_SUCCESS             Get the namespace string success.
 | |
|   @retval   EFI_INVALID_PARAMETER   The NameSpaceId string not follow spec definition.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ExtractNameSpace (
 | |
|   IN  EFI_STRING                   String,
 | |
|   OUT CHAR8                        **NameSpace,
 | |
|   OUT EFI_STRING                   *NextString
 | |
|   )
 | |
| {
 | |
|   CHAR16    *TmpPtr;
 | |
|   UINTN     NameSpaceSize;
 | |
| 
 | |
|   ASSERT (NameSpace != NULL);
 | |
| 
 | |
|   TmpPtr = NULL;
 | |
| 
 | |
|   //
 | |
|   // Input NameSpaceId == NULL
 | |
|   //
 | |
|   if (String == NULL) {
 | |
|     *NameSpace = NULL;
 | |
|     if (NextString != NULL) {
 | |
|       *NextString = NULL;
 | |
|     }
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Skip '&' if exist.
 | |
|   //
 | |
|   if (*String == L'&') {
 | |
|     String++;
 | |
|   }
 | |
| 
 | |
|   if (StrnCmp (String, L"NAMESPACE=", StrLen (L"NAMESPACE=")) != 0) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   String += StrLen (L"NAMESPACE=");
 | |
| 
 | |
|   TmpPtr = StrStr (String, L"&");
 | |
|   if (TmpPtr != NULL) {
 | |
|     *TmpPtr = 0; 
 | |
|   }
 | |
|   if (NextString != NULL) {
 | |
|     *NextString = String + StrLen (String);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Input NameSpace is unicode string. The language in String package is ascii string.
 | |
|   // Here will convert the unicode string to ascii and save it.
 | |
|   //
 | |
|   NameSpaceSize = StrLen (String) + 1;
 | |
|   *NameSpace = AllocatePool (NameSpaceSize);
 | |
|   if (*NameSpace == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   UnicodeStrToAsciiStrS (String, *NameSpace, NameSpaceSize);
 | |
| 
 | |
|   if (TmpPtr != NULL) {
 | |
|     *TmpPtr = L'&'; 
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get Keyword from the input KeywordRequest string.
 | |
| 
 | |
|   This is a internal function.
 | |
| 
 | |
|   @param  String                 KeywordRequestformat string.
 | |
|   @param  Keyword                return the extract keyword string.
 | |
|   @param  NextString             return the next string follow this keyword section.
 | |
| 
 | |
|   @retval EFI_SUCCESS            Success to get the keyword string.
 | |
|   @retval EFI_INVALID_PARAMETER  Parse the input string return error.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ExtractKeyword (
 | |
|   IN  EFI_STRING                   String,
 | |
|   OUT EFI_STRING                   *Keyword,
 | |
|   OUT EFI_STRING                   *NextString
 | |
|   )
 | |
| {
 | |
|   EFI_STRING  TmpPtr;
 | |
| 
 | |
|   ASSERT ((Keyword != NULL) && (NextString != NULL));
 | |
|   
 | |
|   TmpPtr = NULL;
 | |
| 
 | |
|   //
 | |
|   // KeywordRequest == NULL case.
 | |
|   //
 | |
|   if (String == NULL) {
 | |
|     *Keyword = NULL;
 | |
|     *NextString = NULL;
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Skip '&' if exist.
 | |
|   //
 | |
|   if (*String == L'&') {
 | |
|     String++;
 | |
|   }
 | |
| 
 | |
|   if (StrnCmp (String, L"KEYWORD=", StrLen (L"KEYWORD=")) != 0) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   String += StrLen (L"KEYWORD=");
 | |
|   
 | |
|   TmpPtr = StrStr (String, L"&");
 | |
|   if (TmpPtr != NULL) {
 | |
|     *TmpPtr = 0; 
 | |
|   }
 | |
|   *NextString = String + StrLen (String);
 | |
| 
 | |
|   *Keyword = AllocateCopyPool (StrSize (String), String);
 | |
|   if (*Keyword == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   if (TmpPtr != NULL) {
 | |
|     *TmpPtr = L'&';
 | |
|   }
 | |
|   
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get value from the input KeywordRequest string.
 | |
| 
 | |
|   This is a internal function.
 | |
| 
 | |
|   @param  String                 KeywordRequestformat string.
 | |
|   @param  Value                  return the extract value string.
 | |
|   @param  NextString             return the next string follow this keyword section.
 | |
| 
 | |
|   @retval EFI_SUCCESS            Success to get the keyword string.
 | |
|   @retval EFI_INVALID_PARAMETER  Parse the input string return error.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ExtractValue (
 | |
|   IN  EFI_STRING                   String,
 | |
|   OUT EFI_STRING                   *Value,
 | |
|   OUT EFI_STRING                   *NextString
 | |
|   )
 | |
| {
 | |
|   EFI_STRING  TmpPtr;
 | |
| 
 | |
|   ASSERT ((Value != NULL) && (NextString != NULL) && (String != NULL));
 | |
| 
 | |
|   //
 | |
|   // Skip '&' if exist.
 | |
|   //
 | |
|   if (*String == L'&') {
 | |
|     String++;
 | |
|   }
 | |
| 
 | |
|   if (StrnCmp (String, L"VALUE=", StrLen (L"VALUE=")) != 0) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   String += StrLen (L"VALUE=");
 | |
|   
 | |
|   TmpPtr = StrStr (String, L"&");
 | |
|   if (TmpPtr != NULL) {
 | |
|     *TmpPtr = 0; 
 | |
|   }
 | |
|   *NextString = String + StrLen (String);
 | |
| 
 | |
|   *Value = AllocateCopyPool (StrSize (String), String);
 | |
|   if (*Value == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   if (TmpPtr != NULL) {
 | |
|     *TmpPtr = L'&';
 | |
|   }
 | |
|   
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get filter from the input KeywordRequest string.
 | |
| 
 | |
|   This is a internal function.
 | |
| 
 | |
|   @param  String                 KeywordRequestformat string.
 | |
|   @param  FilterFlags            return the filter condition.
 | |
|   @param  NextString             return the next string follow this keyword section.
 | |
| 
 | |
|   @retval EFI_SUCCESS            Success to get the keyword string.
 | |
|   @retval EFI_INVALID_PARAMETER  Parse the input string return error.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| ExtractFilter (
 | |
|   IN  EFI_STRING                   String,
 | |
|   OUT UINT8                        *FilterFlags,
 | |
|   OUT EFI_STRING                   *NextString
 | |
|   )
 | |
| {
 | |
|   CHAR16      *PathPtr;
 | |
|   CHAR16      *KeywordPtr;
 | |
|   BOOLEAN     RetVal; 
 | |
| 
 | |
|   ASSERT ((FilterFlags != NULL) && (NextString != NULL));
 | |
| 
 | |
|   //
 | |
|   // String end, no filter section.
 | |
|   //
 | |
|   if (String == NULL) {
 | |
|     *NextString = NULL;
 | |
|     return FALSE;
 | |
|   }
 | |
|   
 | |
|   *FilterFlags = 0;
 | |
|   RetVal = TRUE;
 | |
| 
 | |
|   //
 | |
|   // Skip '&' if exist.
 | |
|   //
 | |
|   if (*String == L'&') {
 | |
|     String++;
 | |
|   }
 | |
| 
 | |
|   if (StrnCmp (String, L"ReadOnly", StrLen (L"ReadOnly")) == 0) {
 | |
|     //
 | |
|     // Find ReadOnly filter.
 | |
|     //
 | |
|     *FilterFlags |= EFI_KEYWORD_FILTER_READONY;
 | |
|     String += StrLen (L"ReadOnly");
 | |
|   } else if (StrnCmp (String, L"ReadWrite", StrLen (L"ReadWrite")) == 0) {
 | |
|     //
 | |
|     // Find ReadWrite filter.
 | |
|     //
 | |
|     *FilterFlags |= EFI_KEYWORD_FILTER_REAWRITE;
 | |
|     String += StrLen (L"ReadWrite");
 | |
|   } else if (StrnCmp (String, L"Buffer", StrLen (L"Buffer")) == 0) {
 | |
|     //
 | |
|     // Find Buffer Filter.
 | |
|     //
 | |
|     *FilterFlags |= EFI_KEYWORD_FILTER_BUFFER;
 | |
|     String += StrLen (L"Buffer");
 | |
|   } else if (StrnCmp (String, L"Numeric", StrLen (L"Numeric")) == 0) {
 | |
|     //
 | |
|     // Find Numeric Filter
 | |
|     //
 | |
|     String += StrLen (L"Numeric");
 | |
|     if (*String != L':') {
 | |
|       *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC;
 | |
|     } else {
 | |
|       String++;
 | |
|       switch (*String) {
 | |
|       case L'1':
 | |
|         *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_1;
 | |
|         break;
 | |
|       case L'2':
 | |
|         *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_2;
 | |
|         break;
 | |
|       case L'4':
 | |
|         *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_4;
 | |
|         break;
 | |
|       case L'8':
 | |
|         *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_8;
 | |
|         break;
 | |
|       default:
 | |
|         ASSERT (FALSE);
 | |
|         break;
 | |
|       }
 | |
|       String++;
 | |
|     }
 | |
|   } else {
 | |
|     //
 | |
|     // Check whether other filter item defined by Platform.
 | |
|     //
 | |
|     if ((StrnCmp (String, L"&PATH", StrLen (L"&PATH")) == 0) ||
 | |
|         (StrnCmp (String, L"&KEYWORD", StrLen (L"&KEYWORD")) == 0)) {
 | |
|       //
 | |
|       // New KeywordRequest start, no platform defined filter.
 | |
|       //
 | |
|     } else {
 | |
|       //
 | |
|       // Platform defined filter rule.
 | |
|       // Just skip platform defined filter rule, return success.
 | |
|       //
 | |
|       PathPtr = StrStr(String, L"&PATH");
 | |
|       KeywordPtr = StrStr(String, L"&KEYWORD");
 | |
|       if (PathPtr != NULL && KeywordPtr != NULL) {
 | |
|         //
 | |
|         // If both sections exist, return the first follow string.
 | |
|         //
 | |
|         String = KeywordPtr > PathPtr ? PathPtr : KeywordPtr;
 | |
|       } else if (PathPtr != NULL) {
 | |
|         //
 | |
|         // Should not exist PathPtr != NULL && KeywordPtr == NULL case.
 | |
|         //
 | |
|         ASSERT (FALSE);
 | |
|       } else if (KeywordPtr != NULL) {
 | |
|         //
 | |
|         // Just to the next keyword section.
 | |
|         //
 | |
|         String = KeywordPtr;
 | |
|       } else {
 | |
|         //
 | |
|         // Only has platform defined filter section, just skip it.
 | |
|         //
 | |
|         String += StrLen (String);
 | |
|       }
 | |
|     }
 | |
|     RetVal = FALSE;
 | |
|   }
 | |
| 
 | |
|   *NextString = String;
 | |
| 
 | |
|   return RetVal;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Extract Readonly flag from opcode.
 | |
| 
 | |
|   This is a internal function.
 | |
| 
 | |
|   @param  OpCodeData             Input opcode for this question.
 | |
| 
 | |
|   @retval TRUE                   This question is readonly.
 | |
|   @retval FALSE                  This question is not readonly.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| ExtractReadOnlyFromOpCode (
 | |
|   IN  UINT8         *OpCodeData
 | |
|   )
 | |
| {
 | |
|   EFI_IFR_QUESTION_HEADER   *QuestionHdr;
 | |
| 
 | |
|   ASSERT (OpCodeData != NULL);
 | |
| 
 | |
|   QuestionHdr = (EFI_IFR_QUESTION_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
 | |
| 
 | |
|   return (QuestionHdr->Flags & EFI_IFR_FLAG_READ_ONLY) != 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create a circuit to check the filter section.
 | |
| 
 | |
|   This is a internal function.
 | |
| 
 | |
|   @param  OpCodeData             The question binary ifr data.
 | |
|   @param  KeywordRequest         KeywordRequestformat string.
 | |
|   @param  NextString             return the next string follow this keyword section.
 | |
|   @param  ReadOnly               Return whether this question is read only.
 | |
| 
 | |
|   @retval KEYWORD_HANDLER_NO_ERROR                     Success validate.
 | |
|   @retval KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED  Validate fail.
 | |
| 
 | |
| **/
 | |
| UINT32
 | |
| ValidateFilter (
 | |
|   IN  UINT8         *OpCodeData,
 | |
|   IN  CHAR16        *KeywordRequest,
 | |
|   OUT CHAR16        **NextString,
 | |
|   OUT BOOLEAN       *ReadOnly
 | |
|   )
 | |
| {
 | |
|   CHAR16                    *NextFilter;
 | |
|   CHAR16                    *StringPtr;
 | |
|   UINT8                     FilterFlags;
 | |
|   EFI_IFR_QUESTION_HEADER   *QuestionHdr;
 | |
|   EFI_IFR_OP_HEADER         *OpCodeHdr;
 | |
|   UINT8                     Flags;
 | |
|   UINT32                    RetVal;
 | |
| 
 | |
|   RetVal = KEYWORD_HANDLER_NO_ERROR;
 | |
|   StringPtr = KeywordRequest;
 | |
| 
 | |
|   OpCodeHdr = (EFI_IFR_OP_HEADER *) OpCodeData;
 | |
|   QuestionHdr = (EFI_IFR_QUESTION_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
 | |
|   if (OpCodeHdr->OpCode == EFI_IFR_ONE_OF_OP || OpCodeHdr->OpCode == EFI_IFR_NUMERIC_OP) {
 | |
|     Flags = *(OpCodeData + sizeof (EFI_IFR_OP_HEADER) + sizeof (EFI_IFR_QUESTION_HEADER));
 | |
|   } else {
 | |
|     Flags = 0;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get ReadOnly flag from Question.
 | |
|   // 
 | |
|   *ReadOnly = ExtractReadOnlyFromOpCode(OpCodeData);
 | |
| 
 | |
|   while (ExtractFilter (StringPtr, &FilterFlags, &NextFilter)) {
 | |
|     switch (FilterFlags) {
 | |
|     case EFI_KEYWORD_FILTER_READONY:
 | |
|       if ((QuestionHdr->Flags & EFI_IFR_FLAG_READ_ONLY) == 0) {
 | |
|         RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
 | |
|         goto Done;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case EFI_KEYWORD_FILTER_REAWRITE:
 | |
|       if ((QuestionHdr->Flags & EFI_IFR_FLAG_READ_ONLY) != 0) {
 | |
|         RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
 | |
|         goto Done;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case EFI_KEYWORD_FILTER_BUFFER:
 | |
|       //
 | |
|       // Only these three opcode use numeric value type.
 | |
|       //
 | |
|       if (OpCodeHdr->OpCode == EFI_IFR_ONE_OF_OP || OpCodeHdr->OpCode == EFI_IFR_NUMERIC_OP || OpCodeHdr->OpCode == EFI_IFR_CHECKBOX_OP) {
 | |
|         RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
 | |
|         goto Done;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case EFI_KEYWORD_FILTER_NUMERIC:
 | |
|       if (OpCodeHdr->OpCode != EFI_IFR_ONE_OF_OP && OpCodeHdr->OpCode != EFI_IFR_NUMERIC_OP && OpCodeHdr->OpCode != EFI_IFR_CHECKBOX_OP) {
 | |
|         RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
 | |
|         goto Done;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case EFI_KEYWORD_FILTER_NUMERIC_1:
 | |
|     case EFI_KEYWORD_FILTER_NUMERIC_2:
 | |
|     case EFI_KEYWORD_FILTER_NUMERIC_4:
 | |
|     case EFI_KEYWORD_FILTER_NUMERIC_8:
 | |
|       if (OpCodeHdr->OpCode != EFI_IFR_ONE_OF_OP && OpCodeHdr->OpCode != EFI_IFR_NUMERIC_OP && OpCodeHdr->OpCode != EFI_IFR_CHECKBOX_OP) {
 | |
|         RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // For numeric and oneof, it has flags field to specify the detail numeric type.
 | |
|       //
 | |
|       if (OpCodeHdr->OpCode == EFI_IFR_ONE_OF_OP || OpCodeHdr->OpCode == EFI_IFR_NUMERIC_OP) {
 | |
|         switch (Flags & EFI_IFR_NUMERIC_SIZE) {
 | |
|         case EFI_IFR_NUMERIC_SIZE_1:
 | |
|           if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_1) {
 | |
|             RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
 | |
|             goto Done;
 | |
|           }
 | |
|           break;
 | |
| 
 | |
|         case EFI_IFR_NUMERIC_SIZE_2:
 | |
|           if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_2) {
 | |
|             RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
 | |
|             goto Done;
 | |
|           }
 | |
|           break;
 | |
| 
 | |
|         case EFI_IFR_NUMERIC_SIZE_4:
 | |
|           if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_4) {
 | |
|             RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
 | |
|             goto Done;
 | |
|           }
 | |
|           break;
 | |
| 
 | |
|         case EFI_IFR_NUMERIC_SIZE_8:
 | |
|           if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_8) {
 | |
|             RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
 | |
|             goto Done;
 | |
|           }
 | |
|           break;
 | |
| 
 | |
|         default:
 | |
|           ASSERT (FALSE);
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       ASSERT (FALSE);
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Jump to the next filter.
 | |
|     //
 | |
|     StringPtr = NextFilter;
 | |
|   }
 | |
|   
 | |
| Done:
 | |
|   //
 | |
|   // The current filter which is processing.
 | |
|   //
 | |
|   *NextString = StringPtr;
 | |
| 
 | |
|   return RetVal;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get HII_DATABASE_RECORD from the input device path info.
 | |
| 
 | |
|   This is a internal function.
 | |
| 
 | |
|   @param  DevicePath             UEFI device path protocol.
 | |
| 
 | |
|   @retval Internal data base record.
 | |
| 
 | |
| **/
 | |
| HII_DATABASE_RECORD *
 | |
| GetRecordFromDevicePath (
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL   *DevicePath
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY             *Link;
 | |
|   UINT8                  *DevicePathPkg;
 | |
|   UINT8                  *CurrentDevicePath;
 | |
|   UINTN                  DevicePathSize;
 | |
|   HII_DATABASE_RECORD    *TempDatabase;
 | |
| 
 | |
|   ASSERT (DevicePath != NULL);
 | |
| 
 | |
|   for (Link = mPrivate.DatabaseList.ForwardLink; Link != &mPrivate.DatabaseList; Link = Link->ForwardLink) {
 | |
|     TempDatabase = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
 | |
|     DevicePathPkg = TempDatabase->PackageList->DevicePathPkg;
 | |
|     if (DevicePathPkg != NULL) {
 | |
|       CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
 | |
|       DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath);
 | |
|       if ((CompareMem (DevicePath, CurrentDevicePath, DevicePathSize) == 0)) {
 | |
|         return TempDatabase;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Calculate the size of StringSrc and output it. Also copy string text from src 
 | |
|   to dest.
 | |
| 
 | |
|   This is a internal function.
 | |
| 
 | |
|   @param  StringSrc              Points to current null-terminated string.
 | |
|   @param  BufferSize             Length of the buffer.
 | |
|   @param  StringDest             Buffer to store the string text. 
 | |
| 
 | |
|   @retval EFI_SUCCESS            The string text was outputted successfully.
 | |
|   @retval EFI_OUT_OF_RESOURCES   Out of resource.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| GetUnicodeStringTextAndSize (
 | |
|   IN  UINT8            *StringSrc,
 | |
|   OUT UINTN            *BufferSize,
 | |
|   OUT EFI_STRING       *StringDest
 | |
|   )
 | |
| {
 | |
|   UINTN  StringSize;
 | |
|   UINT8  *StringPtr;
 | |
| 
 | |
|   ASSERT (StringSrc != NULL && BufferSize != NULL && StringDest != NULL);
 | |
| 
 | |
|   StringSize = sizeof (CHAR16);
 | |
|   StringPtr  = StringSrc;
 | |
|   while (ReadUnaligned16 ((UINT16 *) StringPtr) != 0) {
 | |
|     StringSize += sizeof (CHAR16);
 | |
|     StringPtr += sizeof (CHAR16);
 | |
|   }
 | |
| 
 | |
|   *StringDest = AllocatePool (StringSize);
 | |
|   if (*StringDest == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   
 | |
|   CopyMem (*StringDest, StringSrc, StringSize);
 | |
| 
 | |
|   *BufferSize = StringSize;
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Find the string id for the input keyword.
 | |
| 
 | |
|   @param  StringPackage           Hii string package instance.
 | |
|   @param  KeywordValue            Input keyword value.
 | |
|   @param  StringId                The string's id, which is unique within PackageList.
 | |
| 
 | |
| 
 | |
|   @retval EFI_SUCCESS             The string text and font is retrieved
 | |
|                                   successfully.
 | |
|   @retval EFI_NOT_FOUND           The specified text or font info can not be found
 | |
|                                   out.
 | |
|   @retval EFI_OUT_OF_RESOURCES    The system is out of resources to accomplish the
 | |
|                                   task.
 | |
| **/
 | |
| EFI_STATUS
 | |
| GetStringIdFromString (
 | |
|   IN HII_STRING_PACKAGE_INSTANCE      *StringPackage,
 | |
|   IN CHAR16                           *KeywordValue,
 | |
|   OUT EFI_STRING_ID                   *StringId
 | |
|   )
 | |
| {
 | |
|   UINT8                                *BlockHdr;
 | |
|   EFI_STRING_ID                        CurrentStringId;
 | |
|   UINTN                                BlockSize;
 | |
|   UINTN                                Index;
 | |
|   UINT8                                *StringTextPtr;
 | |
|   UINTN                                Offset;
 | |
|   UINT16                               StringCount;
 | |
|   UINT16                               SkipCount;
 | |
|   UINT8                                Length8;
 | |
|   EFI_HII_SIBT_EXT2_BLOCK              Ext2;
 | |
|   UINT32                               Length32;
 | |
|   UINTN                                StringSize;
 | |
|   CHAR16                               *String;
 | |
|   CHAR8                                *AsciiKeywordValue;
 | |
|   UINTN                                KeywordValueSize;
 | |
|   EFI_STATUS                           Status;
 | |
| 
 | |
|   ASSERT (StringPackage != NULL && KeywordValue != NULL && StringId != NULL);
 | |
|   ASSERT (StringPackage->Signature == HII_STRING_PACKAGE_SIGNATURE);
 | |
| 
 | |
|   CurrentStringId = 1;
 | |
|   Status = EFI_SUCCESS;
 | |
|   String = NULL;
 | |
|   BlockHdr = StringPackage->StringBlock;
 | |
|   BlockSize = 0;
 | |
|   Offset = 0;
 | |
| 
 | |
|   //
 | |
|   // Make a ascii keyword value for later use.
 | |
|   //
 | |
|   KeywordValueSize = StrLen (KeywordValue) + 1;
 | |
|   AsciiKeywordValue = AllocatePool (KeywordValueSize);
 | |
|   if (AsciiKeywordValue == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   UnicodeStrToAsciiStrS (KeywordValue, AsciiKeywordValue, KeywordValueSize);
 | |
| 
 | |
|   while (*BlockHdr != EFI_HII_SIBT_END) {
 | |
|     switch (*BlockHdr) {
 | |
|     case EFI_HII_SIBT_STRING_SCSU:
 | |
|       Offset = sizeof (EFI_HII_STRING_BLOCK);
 | |
|       StringTextPtr = BlockHdr + Offset;
 | |
|       BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr);
 | |
|       if (AsciiStrCmp(AsciiKeywordValue, (CHAR8 *) StringTextPtr) == 0) {
 | |
|         *StringId = CurrentStringId;
 | |
|         goto Done;
 | |
|       }
 | |
|       CurrentStringId++;
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_STRING_SCSU_FONT:
 | |
|       Offset = sizeof (EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK) - sizeof (UINT8);
 | |
|       StringTextPtr = BlockHdr + Offset;
 | |
|       if (AsciiStrCmp(AsciiKeywordValue, (CHAR8 *) StringTextPtr) == 0) {
 | |
|         *StringId = CurrentStringId;
 | |
|         goto Done;
 | |
|       }
 | |
|       BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr);
 | |
|       CurrentStringId++;
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_STRINGS_SCSU:
 | |
|       CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
 | |
|       StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_BLOCK) - sizeof (UINT8));
 | |
|       BlockSize += StringTextPtr - BlockHdr;
 | |
| 
 | |
|       for (Index = 0; Index < StringCount; Index++) {
 | |
|         BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr);
 | |
|         if (AsciiStrCmp(AsciiKeywordValue, (CHAR8 *) StringTextPtr) == 0) {
 | |
|           *StringId = CurrentStringId;
 | |
|           goto Done;
 | |
|         }
 | |
|         StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr);
 | |
|         CurrentStringId++;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_STRINGS_SCSU_FONT:
 | |
|       CopyMem (
 | |
|         &StringCount,
 | |
|         (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
 | |
|         sizeof (UINT16)
 | |
|         );
 | |
|       StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK) - sizeof (UINT8));
 | |
|       BlockSize += StringTextPtr - BlockHdr;
 | |
| 
 | |
|       for (Index = 0; Index < StringCount; Index++) {
 | |
|         BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr);
 | |
|         if (AsciiStrCmp(AsciiKeywordValue, (CHAR8 *) StringTextPtr) == 0) {
 | |
|           *StringId = CurrentStringId;
 | |
|           goto Done;
 | |
|         }
 | |
|         StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr);
 | |
|         CurrentStringId++;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_STRING_UCS2:
 | |
|       Offset        = sizeof (EFI_HII_STRING_BLOCK);
 | |
|       StringTextPtr = BlockHdr + Offset;
 | |
|       //
 | |
|       // Use StringSize to store the size of the specified string, including the NULL
 | |
|       // terminator.
 | |
|       //
 | |
|       Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         goto Done;
 | |
|       }
 | |
|       ASSERT (String != NULL);
 | |
|       if (StrCmp(KeywordValue, String) == 0) {
 | |
|         *StringId = CurrentStringId;
 | |
|         goto Done;
 | |
|       }
 | |
|       BlockSize += Offset + StringSize;
 | |
|       CurrentStringId++;
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_STRING_UCS2_FONT:
 | |
|       Offset = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK)  - sizeof (CHAR16);
 | |
|       StringTextPtr = BlockHdr + Offset;
 | |
|       //
 | |
|       // Use StringSize to store the size of the specified string, including the NULL
 | |
|       // terminator.
 | |
|       //
 | |
|       Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         goto Done;
 | |
|       }
 | |
|       ASSERT (String != NULL);
 | |
|       if (StrCmp(KeywordValue, String) == 0) {
 | |
|         *StringId = CurrentStringId;
 | |
|         goto Done;
 | |
|       }
 | |
|       BlockSize += Offset + StringSize;
 | |
|       CurrentStringId++;
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_STRINGS_UCS2:
 | |
|       Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_BLOCK) - sizeof (CHAR16);
 | |
|       StringTextPtr = BlockHdr + Offset;
 | |
|       BlockSize += Offset;
 | |
|       CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
 | |
|       for (Index = 0; Index < StringCount; Index++) {
 | |
|         Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           goto Done;
 | |
|         }
 | |
|         ASSERT (String != NULL);
 | |
|         BlockSize += StringSize;
 | |
|         if (StrCmp(KeywordValue, String) == 0) {
 | |
|           *StringId = CurrentStringId;
 | |
|           goto Done;
 | |
|         }
 | |
|         StringTextPtr = StringTextPtr + StringSize;
 | |
|         CurrentStringId++;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_STRINGS_UCS2_FONT:
 | |
|       Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK) - sizeof (CHAR16);
 | |
|       StringTextPtr = BlockHdr + Offset;
 | |
|       BlockSize += Offset;
 | |
|       CopyMem (
 | |
|         &StringCount,
 | |
|         (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
 | |
|         sizeof (UINT16)
 | |
|         );
 | |
|       for (Index = 0; Index < StringCount; Index++) {
 | |
|         Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           goto Done;
 | |
|         }
 | |
|         ASSERT (String != NULL);
 | |
|         BlockSize += StringSize;
 | |
|         if (StrCmp(KeywordValue, String) == 0) {
 | |
|           *StringId = CurrentStringId;
 | |
|           goto Done;
 | |
|         }
 | |
|         StringTextPtr = StringTextPtr + StringSize;
 | |
|         CurrentStringId++;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_DUPLICATE:
 | |
|       BlockSize       += sizeof (EFI_HII_SIBT_DUPLICATE_BLOCK);
 | |
|       CurrentStringId++;
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_SKIP1:
 | |
|       SkipCount = (UINT16) (*(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK)));
 | |
|       CurrentStringId = (UINT16) (CurrentStringId + SkipCount);
 | |
|       BlockSize       +=  sizeof (EFI_HII_SIBT_SKIP1_BLOCK);
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_SKIP2:
 | |
|       CopyMem (&SkipCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
 | |
|       CurrentStringId = (UINT16) (CurrentStringId + SkipCount);
 | |
|       BlockSize       +=  sizeof (EFI_HII_SIBT_SKIP2_BLOCK);
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_EXT1:
 | |
|       CopyMem (
 | |
|         &Length8,
 | |
|         (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
 | |
|         sizeof (UINT8)
 | |
|         );
 | |
|       BlockSize += Length8;
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_EXT2:
 | |
|       CopyMem (&Ext2, BlockHdr, sizeof (EFI_HII_SIBT_EXT2_BLOCK));
 | |
|       BlockSize += Ext2.Length;
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_EXT4:
 | |
|       CopyMem (
 | |
|         &Length32,
 | |
|         (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
 | |
|         sizeof (UINT32)
 | |
|         );
 | |
| 
 | |
|       BlockSize += Length32;
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     if (String != NULL) {
 | |
|       FreePool (String);
 | |
|       String = NULL;
 | |
|     }
 | |
| 
 | |
|     BlockHdr  = StringPackage->StringBlock + BlockSize;
 | |
|   }
 | |
| 
 | |
|   Status = EFI_NOT_FOUND;
 | |
| 
 | |
| Done:
 | |
|   if (AsciiKeywordValue != NULL) {
 | |
|     FreePool (AsciiKeywordValue);
 | |
|   }
 | |
|   if (String != NULL) {
 | |
|     FreePool (String);
 | |
|   }
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Find the next valid string id for the input string id.
 | |
| 
 | |
|   @param  StringPackage           Hii string package instance.
 | |
|   @param  StringId                The current string id which is already got.
 | |
|                                   1 means just begin to get the string id.
 | |
|   @param  KeywordValue            Return the string for the next string id.
 | |
| 
 | |
| 
 | |
|   @retval EFI_STRING_ID           Not 0 means a valid stringid found.
 | |
|                                   0 means not found a valid string id.
 | |
| **/
 | |
| EFI_STRING_ID
 | |
| GetNextStringId (
 | |
|   IN  HII_STRING_PACKAGE_INSTANCE      *StringPackage,
 | |
|   IN  EFI_STRING_ID                    StringId,
 | |
|   OUT EFI_STRING                       *KeywordValue
 | |
|   )
 | |
| {
 | |
|   UINT8                                *BlockHdr;
 | |
|   EFI_STRING_ID                        CurrentStringId;
 | |
|   UINTN                                BlockSize;
 | |
|   UINTN                                Index;
 | |
|   UINT8                                *StringTextPtr;
 | |
|   UINTN                                Offset;
 | |
|   UINT16                               StringCount;
 | |
|   UINT16                               SkipCount;
 | |
|   UINT8                                Length8;
 | |
|   EFI_HII_SIBT_EXT2_BLOCK              Ext2;
 | |
|   UINT32                               Length32;
 | |
|   BOOLEAN                              FindString;
 | |
|   UINTN                                StringSize;
 | |
|   CHAR16                               *String;
 | |
| 
 | |
|   ASSERT (StringPackage != NULL);
 | |
|   ASSERT (StringPackage->Signature == HII_STRING_PACKAGE_SIGNATURE);
 | |
| 
 | |
|   CurrentStringId = 1;
 | |
|   FindString = FALSE;
 | |
|   String = NULL;
 | |
| 
 | |
|   //
 | |
|   // Parse the string blocks to get the string text and font.
 | |
|   //
 | |
|   BlockHdr  = StringPackage->StringBlock;
 | |
|   BlockSize = 0;
 | |
|   Offset    = 0;
 | |
|   while (*BlockHdr != EFI_HII_SIBT_END) {
 | |
|     switch (*BlockHdr) {
 | |
|     case EFI_HII_SIBT_STRING_SCSU:
 | |
|       Offset = sizeof (EFI_HII_STRING_BLOCK);
 | |
|       StringTextPtr = BlockHdr + Offset;
 | |
|       
 | |
|       if (FindString) {
 | |
|         StringSize = AsciiStrSize ((CHAR8 *) StringTextPtr);
 | |
|         *KeywordValue = AllocatePool (StringSize * sizeof (CHAR16));
 | |
|         if (*KeywordValue == NULL) {
 | |
|           return 0;
 | |
|         }
 | |
|         AsciiStrToUnicodeStrS ((CHAR8 *) StringTextPtr, *KeywordValue, StringSize);
 | |
|         return CurrentStringId;
 | |
|       } else if (CurrentStringId == StringId) {
 | |
|         FindString = TRUE;
 | |
|       }
 | |
| 
 | |
|       BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr);
 | |
|       CurrentStringId++;
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_STRING_SCSU_FONT:
 | |
|       Offset = sizeof (EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK) - sizeof (UINT8);
 | |
|       StringTextPtr = BlockHdr + Offset;
 | |
|       
 | |
|       if (FindString) {
 | |
|         StringSize = AsciiStrSize ((CHAR8 *) StringTextPtr);
 | |
|         *KeywordValue = AllocatePool (StringSize * sizeof (CHAR16));
 | |
|         if (*KeywordValue == NULL) {
 | |
|           return 0;
 | |
|         }
 | |
|         AsciiStrToUnicodeStrS ((CHAR8 *) StringTextPtr, *KeywordValue, StringSize);
 | |
|         return CurrentStringId;
 | |
|       } else if (CurrentStringId == StringId) {
 | |
|         FindString = TRUE;
 | |
|       }
 | |
| 
 | |
|       BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr);
 | |
|       CurrentStringId++;
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_STRINGS_SCSU:
 | |
|       CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
 | |
|       StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_BLOCK) - sizeof (UINT8));
 | |
|       BlockSize += StringTextPtr - BlockHdr;
 | |
| 
 | |
|       for (Index = 0; Index < StringCount; Index++) {
 | |
|         if (FindString) {
 | |
|           StringSize = AsciiStrSize ((CHAR8 *) StringTextPtr);
 | |
|           *KeywordValue = AllocatePool (StringSize * sizeof (CHAR16));
 | |
|           if (*KeywordValue == NULL) {
 | |
|             return 0;
 | |
|           }
 | |
|           AsciiStrToUnicodeStrS ((CHAR8 *) StringTextPtr, *KeywordValue, StringSize);
 | |
|           return CurrentStringId;
 | |
|         } else if (CurrentStringId == StringId) {
 | |
|           FindString = TRUE;
 | |
|         }
 | |
| 
 | |
|         BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr);
 | |
|         StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr);
 | |
|         CurrentStringId++;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_STRINGS_SCSU_FONT:
 | |
|       CopyMem (
 | |
|         &StringCount,
 | |
|         (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
 | |
|         sizeof (UINT16)
 | |
|         );
 | |
|       StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK) - sizeof (UINT8));
 | |
|       BlockSize += StringTextPtr - BlockHdr;
 | |
| 
 | |
|       for (Index = 0; Index < StringCount; Index++) {
 | |
|         if (FindString) {
 | |
|           StringSize = AsciiStrSize ((CHAR8 *) StringTextPtr);
 | |
|           *KeywordValue = AllocatePool (StringSize * sizeof (CHAR16));
 | |
|           if (*KeywordValue == NULL) {
 | |
|             return 0;
 | |
|           }
 | |
|           AsciiStrToUnicodeStrS ((CHAR8 *) StringTextPtr, *KeywordValue, StringSize);
 | |
|           return CurrentStringId;
 | |
|         } else if (CurrentStringId == StringId) {
 | |
|           FindString = TRUE;
 | |
|         }
 | |
| 
 | |
|         BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr);
 | |
|         StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr);
 | |
|         CurrentStringId++;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_STRING_UCS2:
 | |
|       Offset        = sizeof (EFI_HII_STRING_BLOCK);
 | |
|       StringTextPtr = BlockHdr + Offset;
 | |
|       //
 | |
|       // Use StringSize to store the size of the specified string, including the NULL
 | |
|       // terminator.
 | |
|       //
 | |
|       GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
 | |
|       if (FindString && (String != NULL) && (*String != L'\0')) {
 | |
|         //
 | |
|         // String protocol use this type for the string id which has value for other package.
 | |
|         // It will allocate an empty string block for this string id. so here we also check
 | |
|         // *String != L'\0' to prohibit this case.
 | |
|         //
 | |
|         *KeywordValue = String;
 | |
|         return CurrentStringId;
 | |
|       } else if (CurrentStringId == StringId) {
 | |
|         FindString = TRUE;
 | |
|       }
 | |
| 
 | |
|       BlockSize += Offset + StringSize;
 | |
|       CurrentStringId++;
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_STRING_UCS2_FONT:
 | |
|       Offset = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK)  - sizeof (CHAR16);
 | |
|       StringTextPtr = BlockHdr + Offset;
 | |
|       //
 | |
|       // Use StringSize to store the size of the specified string, including the NULL
 | |
|       // terminator.
 | |
|       //
 | |
|       GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
 | |
|       if (FindString) {
 | |
|         *KeywordValue = String;
 | |
|         return CurrentStringId;
 | |
|       } else if (CurrentStringId == StringId) {
 | |
|         FindString = TRUE;
 | |
|       }
 | |
| 
 | |
|       BlockSize += Offset + StringSize;
 | |
|       CurrentStringId++;
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_STRINGS_UCS2:
 | |
|       Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_BLOCK) - sizeof (CHAR16);
 | |
|       StringTextPtr = BlockHdr + Offset;
 | |
|       BlockSize += Offset;
 | |
|       CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
 | |
|       for (Index = 0; Index < StringCount; Index++) {
 | |
|         GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);        
 | |
| 
 | |
|         if (FindString) {
 | |
|           *KeywordValue = String;
 | |
|           return CurrentStringId;
 | |
|         } else if (CurrentStringId == StringId) {
 | |
|           FindString = TRUE;
 | |
|         }
 | |
| 
 | |
|         BlockSize += StringSize;
 | |
|         StringTextPtr = StringTextPtr + StringSize;
 | |
|         CurrentStringId++;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_STRINGS_UCS2_FONT:
 | |
|       Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK) - sizeof (CHAR16);
 | |
|       StringTextPtr = BlockHdr + Offset;
 | |
|       BlockSize += Offset;
 | |
|       CopyMem (
 | |
|         &StringCount,
 | |
|         (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
 | |
|         sizeof (UINT16)
 | |
|         );
 | |
|       for (Index = 0; Index < StringCount; Index++) {
 | |
|         GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
 | |
|         if (FindString) {
 | |
|           *KeywordValue = String;
 | |
|           return CurrentStringId;
 | |
|         } else if (CurrentStringId == StringId) {
 | |
|           FindString = TRUE;
 | |
|         }
 | |
| 
 | |
|         BlockSize += StringSize;
 | |
|         StringTextPtr = StringTextPtr + StringSize;
 | |
|         CurrentStringId++;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_DUPLICATE:
 | |
|       BlockSize       += sizeof (EFI_HII_SIBT_DUPLICATE_BLOCK);
 | |
|       CurrentStringId++;
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_SKIP1:
 | |
|       SkipCount = (UINT16) (*(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK)));
 | |
|       CurrentStringId = (UINT16) (CurrentStringId + SkipCount);
 | |
|       BlockSize       +=  sizeof (EFI_HII_SIBT_SKIP1_BLOCK);
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_SKIP2:
 | |
|       CopyMem (&SkipCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
 | |
|       CurrentStringId = (UINT16) (CurrentStringId + SkipCount);
 | |
|       BlockSize       +=  sizeof (EFI_HII_SIBT_SKIP2_BLOCK);
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_EXT1:
 | |
|       CopyMem (
 | |
|         &Length8,
 | |
|         (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
 | |
|         sizeof (UINT8)
 | |
|         );
 | |
|       BlockSize += Length8;
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_EXT2:
 | |
|       CopyMem (&Ext2, BlockHdr, sizeof (EFI_HII_SIBT_EXT2_BLOCK));
 | |
|       BlockSize += Ext2.Length;
 | |
|       break;
 | |
| 
 | |
|     case EFI_HII_SIBT_EXT4:
 | |
|       CopyMem (
 | |
|         &Length32,
 | |
|         (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
 | |
|         sizeof (UINT32)
 | |
|         );
 | |
| 
 | |
|       BlockSize += Length32;
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     if (String != NULL) {
 | |
|       FreePool (String);
 | |
|       String = NULL;
 | |
|     }
 | |
| 
 | |
|     BlockHdr  = StringPackage->StringBlock + BlockSize;
 | |
|   }
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get string package from the input NameSpace string.
 | |
| 
 | |
|   This is a internal function.
 | |
| 
 | |
|   @param  DatabaseRecord                 HII_DATABASE_RECORD format string.
 | |
|   @param  NameSpace                      NameSpace format string.
 | |
|   @param  KeywordValue                   Keyword value.
 | |
|   @param  StringId                       String Id for this keyword.
 | |
| 
 | |
|   @retval KEYWORD_HANDLER_NO_ERROR                     Get String id successfully.
 | |
|   @retval KEYWORD_HANDLER_KEYWORD_NOT_FOUND            Not found the string id in the string package.
 | |
|   @retval KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND       Not found the string package for this namespace.
 | |
|   @retval KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR   Out of resource error.
 | |
| 
 | |
| **/
 | |
| UINT32
 | |
| GetStringIdFromRecord (
 | |
|   IN HII_DATABASE_RECORD   *DatabaseRecord,
 | |
|   IN CHAR8                 **NameSpace,
 | |
|   IN CHAR16                *KeywordValue,
 | |
|   OUT EFI_STRING_ID        *StringId
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY                          *Link;
 | |
|   HII_DATABASE_PACKAGE_LIST_INSTANCE  *PackageListNode;
 | |
|   HII_STRING_PACKAGE_INSTANCE         *StringPackage;
 | |
|   EFI_STATUS                          Status;
 | |
|   CHAR8                               *Name;
 | |
|   UINT32                              RetVal;
 | |
| 
 | |
|   ASSERT (DatabaseRecord != NULL && NameSpace != NULL && KeywordValue != NULL);
 | |
| 
 | |
|   PackageListNode = DatabaseRecord->PackageList;
 | |
|   RetVal = KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND;
 | |
| 
 | |
|   if (*NameSpace != NULL) {
 | |
|     Name = *NameSpace;
 | |
|   } else {
 | |
|     Name = UEFI_CONFIG_LANG;
 | |
|   }
 | |
| 
 | |
|   for (Link = PackageListNode->StringPkgHdr.ForwardLink; Link != &PackageListNode->StringPkgHdr; Link = Link->ForwardLink) {
 | |
|     StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
 | |
| 
 | |
|     if (AsciiStrnCmp(Name, StringPackage->StringPkgHdr->Language, AsciiStrLen (Name)) == 0) {
 | |
|       Status = GetStringIdFromString (StringPackage, KeywordValue, StringId); 
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         return KEYWORD_HANDLER_KEYWORD_NOT_FOUND;
 | |
|       } else {
 | |
|         if (*NameSpace == NULL) {
 | |
|           *NameSpace = AllocateCopyPool (AsciiStrSize (StringPackage->StringPkgHdr->Language), StringPackage->StringPkgHdr->Language);
 | |
|           if (*NameSpace == NULL) {
 | |
|             return KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR;
 | |
|           }
 | |
|         }
 | |
|         return KEYWORD_HANDLER_NO_ERROR;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return RetVal;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Tell whether this Operand is an Statement OpCode.
 | |
| 
 | |
|   @param  Operand                Operand of an IFR OpCode.
 | |
| 
 | |
|   @retval TRUE                   This is an Statement OpCode.
 | |
|   @retval FALSE                  Not an Statement OpCode.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| IsStatementOpCode (
 | |
|   IN UINT8              Operand
 | |
|   )
 | |
| {
 | |
|   if ((Operand == EFI_IFR_SUBTITLE_OP) ||
 | |
|       (Operand == EFI_IFR_TEXT_OP) ||
 | |
|       (Operand == EFI_IFR_RESET_BUTTON_OP) ||
 | |
|       (Operand == EFI_IFR_REF_OP) ||
 | |
|       (Operand == EFI_IFR_ACTION_OP) ||
 | |
|       (Operand == EFI_IFR_NUMERIC_OP) ||
 | |
|       (Operand == EFI_IFR_ORDERED_LIST_OP) ||
 | |
|       (Operand == EFI_IFR_CHECKBOX_OP) ||
 | |
|       (Operand == EFI_IFR_STRING_OP) ||
 | |
|       (Operand == EFI_IFR_PASSWORD_OP) ||
 | |
|       (Operand == EFI_IFR_DATE_OP) ||
 | |
|       (Operand == EFI_IFR_TIME_OP) ||
 | |
|       (Operand == EFI_IFR_GUID_OP) ||
 | |
|       (Operand == EFI_IFR_ONE_OF_OP)) {
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Tell whether this Operand is an Statement OpCode.
 | |
| 
 | |
|   @param  Operand                Operand of an IFR OpCode.
 | |
| 
 | |
|   @retval TRUE                   This is an Statement OpCode.
 | |
|   @retval FALSE                  Not an Statement OpCode.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| IsStorageOpCode (
 | |
|   IN UINT8              Operand
 | |
|   )
 | |
| {
 | |
|   if ((Operand == EFI_IFR_VARSTORE_OP) ||
 | |
|       (Operand == EFI_IFR_VARSTORE_NAME_VALUE_OP) ||
 | |
|       (Operand == EFI_IFR_VARSTORE_EFI_OP)) {
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Base on the prompt string id to find the question.
 | |
| 
 | |
|   @param  FormPackage            The input form package.
 | |
|   @param  KeywordStrId           The input prompt string id for one question.
 | |
| 
 | |
|   @retval  the opcode for the question.
 | |
| 
 | |
| **/
 | |
| UINT8 * 
 | |
| FindQuestionFromStringId (
 | |
|   IN HII_IFR_PACKAGE_INSTANCE      *FormPackage,
 | |
|   IN EFI_STRING_ID                 KeywordStrId 
 | |
|   )
 | |
| {
 | |
|   UINT8                        *OpCodeData;
 | |
|   UINT32                       Offset;
 | |
|   EFI_IFR_STATEMENT_HEADER     *StatementHeader;
 | |
|   EFI_IFR_OP_HEADER            *OpCodeHeader;
 | |
|   UINT32                       FormDataLen;
 | |
| 
 | |
|   ASSERT (FormPackage != NULL);
 | |
| 
 | |
|   FormDataLen = FormPackage->FormPkgHdr.Length - sizeof (EFI_HII_PACKAGE_HEADER);
 | |
|   Offset = 0;
 | |
|   while (Offset < FormDataLen) {
 | |
|     OpCodeData = FormPackage->IfrData + Offset;
 | |
|     OpCodeHeader = (EFI_IFR_OP_HEADER *) OpCodeData;
 | |
| 
 | |
|     if (IsStatementOpCode(OpCodeHeader->OpCode)) {
 | |
|       StatementHeader = (EFI_IFR_STATEMENT_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
 | |
|       if (StatementHeader->Prompt == KeywordStrId) {
 | |
|         return OpCodeData;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     Offset += OpCodeHeader->Length;
 | |
|   }
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Base on the varstore id to find the storage info.
 | |
| 
 | |
|   @param  FormPackage            The input form package.
 | |
|   @param  VarStoreId             The input storage id.
 | |
| 
 | |
|   @retval  the opcode for the storage.
 | |
| 
 | |
| **/
 | |
| UINT8 *
 | |
| FindStorageFromVarId (
 | |
|   IN HII_IFR_PACKAGE_INSTANCE      *FormPackage,
 | |
|   IN EFI_VARSTORE_ID               VarStoreId
 | |
|   )
 | |
| {
 | |
|   UINT8                        *OpCodeData;
 | |
|   UINT32                       Offset;
 | |
|   EFI_IFR_OP_HEADER            *OpCodeHeader;
 | |
|   UINT32                       FormDataLen;
 | |
| 
 | |
|   ASSERT (FormPackage != NULL);
 | |
| 
 | |
|   FormDataLen = FormPackage->FormPkgHdr.Length - sizeof (EFI_HII_PACKAGE_HEADER);
 | |
|   Offset = 0;
 | |
|   while (Offset < FormDataLen) {
 | |
|     OpCodeData = FormPackage->IfrData + Offset;
 | |
|     OpCodeHeader = (EFI_IFR_OP_HEADER *) OpCodeData;
 | |
| 
 | |
|     if (IsStorageOpCode(OpCodeHeader->OpCode)) {
 | |
|       switch (OpCodeHeader->OpCode) {
 | |
|       case EFI_IFR_VARSTORE_OP:
 | |
|         if (VarStoreId == ((EFI_IFR_VARSTORE *) OpCodeData)->VarStoreId) {
 | |
|           return OpCodeData;
 | |
|         }
 | |
|         break;
 | |
| 
 | |
|       case EFI_IFR_VARSTORE_NAME_VALUE_OP:
 | |
|         if (VarStoreId == ((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->VarStoreId) {
 | |
|           return OpCodeData;
 | |
|         }
 | |
|         break;
 | |
| 
 | |
|       case EFI_IFR_VARSTORE_EFI_OP:
 | |
|         if (VarStoreId == ((EFI_IFR_VARSTORE_EFI *) OpCodeData)->VarStoreId) {
 | |
|           return OpCodeData;
 | |
|         }
 | |
|         break;
 | |
| 
 | |
|       default:
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     Offset += OpCodeHeader->Length;
 | |
|   }
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get width info for one question.
 | |
| 
 | |
|   @param  OpCodeData            The input opcode for one question.
 | |
| 
 | |
|   @retval  the width info for one question.
 | |
| 
 | |
| **/
 | |
| UINT16 
 | |
| GetWidth (
 | |
|   IN UINT8        *OpCodeData
 | |
|   )
 | |
| {
 | |
|   UINT8      *NextOpCodeData;
 | |
| 
 | |
|   ASSERT (OpCodeData != NULL);
 | |
| 
 | |
|   switch (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode) {
 | |
|   case EFI_IFR_REF_OP:
 | |
|     return (UINT16) sizeof (EFI_HII_REF);
 | |
| 
 | |
|   case EFI_IFR_ONE_OF_OP:
 | |
|   case EFI_IFR_NUMERIC_OP:
 | |
|     switch (((EFI_IFR_ONE_OF *) OpCodeData)->Flags & EFI_IFR_NUMERIC_SIZE) {
 | |
|     case EFI_IFR_NUMERIC_SIZE_1:
 | |
|       return (UINT16) sizeof (UINT8);
 | |
|     
 | |
|     case EFI_IFR_NUMERIC_SIZE_2:
 | |
|       return  (UINT16) sizeof (UINT16);
 | |
|     
 | |
|     case EFI_IFR_NUMERIC_SIZE_4:
 | |
|       return (UINT16) sizeof (UINT32);
 | |
|     
 | |
|     case EFI_IFR_NUMERIC_SIZE_8:
 | |
|       return (UINT16) sizeof (UINT64);
 | |
|     
 | |
|     default:
 | |
|       ASSERT (FALSE);
 | |
|       return 0;
 | |
|     }
 | |
| 
 | |
|   case EFI_IFR_ORDERED_LIST_OP:
 | |
|     NextOpCodeData = OpCodeData + ((EFI_IFR_ORDERED_LIST *) OpCodeData)->Header.Length;
 | |
|     //
 | |
|     // OneOfOption must follow the orderedlist opcode.
 | |
|     //
 | |
|     ASSERT (((EFI_IFR_OP_HEADER *) NextOpCodeData)->OpCode == EFI_IFR_ONE_OF_OPTION_OP);
 | |
|     switch (((EFI_IFR_ONE_OF_OPTION *) NextOpCodeData)->Type) {
 | |
|     case EFI_IFR_TYPE_NUM_SIZE_8:
 | |
|       return (UINT16) sizeof (UINT8) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers;
 | |
|     
 | |
|     case EFI_IFR_TYPE_NUM_SIZE_16:
 | |
|       return (UINT16) sizeof (UINT16) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers ;
 | |
|     
 | |
|     case EFI_IFR_TYPE_NUM_SIZE_32:
 | |
|       return (UINT16) sizeof (UINT32) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers;
 | |
|     
 | |
|     case EFI_IFR_TYPE_NUM_SIZE_64:
 | |
|       return (UINT16) sizeof (UINT64) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers;
 | |
|     
 | |
|     default:
 | |
|       ASSERT (FALSE);
 | |
|       return 0;
 | |
|     }
 | |
| 
 | |
|   case EFI_IFR_CHECKBOX_OP:
 | |
|     return (UINT16) sizeof (BOOLEAN);
 | |
|     
 | |
|   case EFI_IFR_PASSWORD_OP:
 | |
|     return (UINT16)((UINTN) ((EFI_IFR_PASSWORD *) OpCodeData)->MaxSize * sizeof (CHAR16));
 | |
| 
 | |
|   case EFI_IFR_STRING_OP:
 | |
|     return (UINT16)((UINTN) ((EFI_IFR_STRING *) OpCodeData)->MaxSize * sizeof (CHAR16));
 | |
| 
 | |
|   case EFI_IFR_DATE_OP:
 | |
|     return (UINT16) sizeof (EFI_HII_DATE);
 | |
| 
 | |
|   case EFI_IFR_TIME_OP:
 | |
|     return (UINT16) sizeof (EFI_HII_TIME);
 | |
| 
 | |
|   default:
 | |
|     ASSERT (FALSE);
 | |
|     return 0;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Converts all hex string characters in range ['A'..'F'] to ['a'..'f'] for
 | |
|   hex digits that appear between a '=' and a '&' in a config string.
 | |
| 
 | |
|   If ConfigString is NULL, then ASSERT().
 | |
| 
 | |
|   @param[in] ConfigString  Pointer to a Null-terminated Unicode string.
 | |
| 
 | |
|   @return  Pointer to the Null-terminated Unicode result string.
 | |
| 
 | |
| **/
 | |
| EFI_STRING
 | |
| EFIAPI
 | |
| InternalLowerConfigString (
 | |
|   IN EFI_STRING  ConfigString
 | |
|   )
 | |
| {
 | |
|   EFI_STRING  String;
 | |
|   BOOLEAN     Lower;
 | |
| 
 | |
|   ASSERT (ConfigString != NULL);
 | |
| 
 | |
|   //
 | |
|   // Convert all hex digits in range [A-F] in the configuration header to [a-f]
 | |
|   //
 | |
|   for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {
 | |
|     if (*String == L'=') {
 | |
|       Lower = TRUE;
 | |
|     } else if (*String == L'&') {
 | |
|       Lower = FALSE;
 | |
|     } else if (Lower && *String >= L'A' && *String <= L'F') {
 | |
|       *String = (CHAR16) (*String - L'A' + L'a');
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return ConfigString;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Allocates and returns a Null-terminated Unicode <ConfigHdr> string.
 | |
|   
 | |
|   The format of a <ConfigHdr> is as follows:
 | |
| 
 | |
|     GUID=<HexCh>32&NAME=<Char>NameLength&PATH=<HexChar>DevicePathSize<Null>
 | |
| 
 | |
|   @param[in]  OpCodeData    The opcode for the storage.                  
 | |
|   @param[in]  DriverHandle  The driver handle which supports a Device Path Protocol
 | |
|                             that is the routing information PATH.  Each byte of
 | |
|                             the Device Path associated with DriverHandle is converted
 | |
|                             to a 2 Unicode character hexadecimal string.
 | |
| 
 | |
|   @retval NULL   DriverHandle does not support the Device Path Protocol.
 | |
|   @retval Other  A pointer to the Null-terminate Unicode <ConfigHdr> string
 | |
| 
 | |
| **/
 | |
| EFI_STRING
 | |
| ConstructConfigHdr (
 | |
|   IN UINT8           *OpCodeData,
 | |
|   IN EFI_HANDLE      DriverHandle
 | |
|   )
 | |
| {
 | |
|   UINTN                     NameLength;
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
 | |
|   UINTN                     DevicePathSize;
 | |
|   CHAR16                    *String;
 | |
|   CHAR16                    *ReturnString;
 | |
|   UINTN                     Index;
 | |
|   UINT8                     *Buffer;
 | |
|   CHAR16                    *Name;
 | |
|   CHAR8                     *AsciiName;
 | |
|   UINTN                     NameSize;
 | |
|   EFI_GUID                  *Guid;
 | |
|   UINTN                     MaxLen;
 | |
| 
 | |
|   ASSERT (OpCodeData != NULL);
 | |
| 
 | |
|   switch (((EFI_IFR_OP_HEADER *)OpCodeData)->OpCode) {
 | |
|   case EFI_IFR_VARSTORE_OP:
 | |
|     Guid      = (EFI_GUID *)(UINTN *)&((EFI_IFR_VARSTORE *) OpCodeData)->Guid;
 | |
|     AsciiName = (CHAR8 *) ((EFI_IFR_VARSTORE *) OpCodeData)->Name;
 | |
|     break;
 | |
|   
 | |
|   case EFI_IFR_VARSTORE_NAME_VALUE_OP:
 | |
|     Guid      = (EFI_GUID *)(UINTN *)&((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->Guid;
 | |
|     AsciiName = NULL;
 | |
|     break;
 | |
|   
 | |
|   case EFI_IFR_VARSTORE_EFI_OP:
 | |
|     Guid      = (EFI_GUID *)(UINTN *)&((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Guid;
 | |
|     AsciiName = (CHAR8 *) ((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Name;
 | |
|     break;
 | |
|   
 | |
|   default:
 | |
|     ASSERT (FALSE);
 | |
|     Guid      = NULL;
 | |
|     AsciiName = NULL;
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   if (AsciiName != NULL) {
 | |
|     NameSize = AsciiStrSize (AsciiName);
 | |
|     Name = AllocateZeroPool (NameSize * sizeof (CHAR16));
 | |
|     ASSERT (Name != NULL);
 | |
|     AsciiStrToUnicodeStrS (AsciiName, Name, NameSize);
 | |
|   } else {
 | |
|     Name = NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Compute the length of Name in Unicode characters.  
 | |
|   // If Name is NULL, then the length is 0.
 | |
|   //
 | |
|   NameLength = 0;
 | |
|   if (Name != NULL) {
 | |
|     NameLength = StrLen (Name);
 | |
|   }
 | |
| 
 | |
|   DevicePath = NULL;
 | |
|   DevicePathSize = 0;
 | |
|   //
 | |
|   // Retrieve DevicePath Protocol associated with DriverHandle
 | |
|   //
 | |
|   if (DriverHandle != NULL) {
 | |
|     DevicePath = DevicePathFromHandle (DriverHandle);
 | |
|     if (DevicePath == NULL) {
 | |
|       return NULL;
 | |
|     }
 | |
|     //
 | |
|     // Compute the size of the device path in bytes
 | |
|     //
 | |
|     DevicePathSize = GetDevicePathSize (DevicePath);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // GUID=<HexCh>32&NAME=<Char>NameLength&PATH=<HexChar>DevicePathSize <Null>
 | |
|   // | 5 | sizeof (EFI_GUID) * 2 | 6 | NameStrLen*4 | 6 | DevicePathSize * 2 | 1 |
 | |
|   //
 | |
|   MaxLen = 5 + sizeof (EFI_GUID) * 2 + 6 + NameLength * 4 + 6 + DevicePathSize * 2 + 1;
 | |
|   String = AllocateZeroPool (MaxLen * sizeof (CHAR16));
 | |
|   if (String == NULL) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Start with L"GUID="
 | |
|   //
 | |
|   StrCpyS (String, MaxLen, L"GUID=");
 | |
|   ReturnString = String;
 | |
|   String += StrLen (String);
 | |
| 
 | |
|   if (Guid != NULL) {
 | |
|     //
 | |
|     // Append Guid converted to <HexCh>32
 | |
|     //
 | |
|     for (Index = 0, Buffer = (UINT8 *)Guid; Index < sizeof (EFI_GUID); Index++) {
 | |
|       String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(Buffer++), 2);
 | |
|     }
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Append L"&NAME="
 | |
|   //
 | |
|   StrCatS (ReturnString, MaxLen, L"&NAME=");
 | |
|   String += StrLen (String);
 | |
| 
 | |
|   if (Name != NULL) {
 | |
|     //
 | |
|     // Append Name converted to <Char>NameLength
 | |
|     //
 | |
|     for (; *Name != L'\0'; Name++) {
 | |
|       String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *Name, 4);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Append L"&PATH="
 | |
|   //
 | |
|   StrCatS (ReturnString, MaxLen, L"&PATH=");
 | |
|   String += StrLen (String);
 | |
| 
 | |
|   //
 | |
|   // Append the device path associated with DriverHandle converted to <HexChar>DevicePathSize
 | |
|   //
 | |
|   for (Index = 0, Buffer = (UINT8 *)DevicePath; Index < DevicePathSize; Index++) {
 | |
|     String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(Buffer++), 2);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Null terminate the Unicode string
 | |
|   //
 | |
|   *String = L'\0';
 | |
| 
 | |
|   //
 | |
|   // Convert all hex digits in range [A-F] in the configuration header to [a-f]
 | |
|   //
 | |
|   return InternalLowerConfigString (ReturnString);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Generate the Config request element for one question.
 | |
| 
 | |
|   @param   Name    The name info for one question.
 | |
|   @param   Offset  The offset info for one question.
 | |
|   @param   Width   The width info for one question.
 | |
| 
 | |
|   @return  Pointer to the Null-terminated Unicode request element string.
 | |
| 
 | |
| **/
 | |
| EFI_STRING
 | |
| ConstructRequestElement (
 | |
|   IN CHAR16      *Name,
 | |
|   IN UINT16      Offset,
 | |
|   IN UINT16      Width  
 | |
|   )
 | |
| {
 | |
|   CHAR16    *StringPtr;
 | |
|   UINTN     Length;
 | |
|   
 | |
|   if (Name != NULL) {
 | |
|     //
 | |
|     // Add <BlockName> length for each Name
 | |
|     //
 | |
|     // <BlockName> ::= Name + \0
 | |
|     //                 StrLen(Name) | 1
 | |
|     //
 | |
|     Length = StrLen (Name) + 1;
 | |
|   } else {
 | |
|     //
 | |
|     // Add <BlockName> length for each Offset/Width pair
 | |
|     //
 | |
|     // <BlockName> ::= OFFSET=1234&WIDTH=1234 + \0
 | |
|     //                 |  7   | 4 |   7  | 4 |  1
 | |
|     //
 | |
|     Length = (7 + 4 + 7 + 4 + 1);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Allocate buffer for the entire <ConfigRequest>
 | |
|   //
 | |
|   StringPtr = AllocateZeroPool (Length * sizeof (CHAR16));
 | |
|   ASSERT (StringPtr != NULL);
 | |
| 
 | |
|   if (Name != NULL) {
 | |
|     //
 | |
|     // Append Name\0
 | |
|     //
 | |
|     UnicodeSPrint (
 | |
|       StringPtr,
 | |
|       (StrLen (Name) + 1) * sizeof (CHAR16),
 | |
|       L"%s",
 | |
|       Name
 | |
|     );
 | |
|   } else {
 | |
|     //
 | |
|     // Append OFFSET=XXXX&WIDTH=YYYY\0
 | |
|     //
 | |
|     UnicodeSPrint (
 | |
|       StringPtr, 
 | |
|       (7 + 4 + 7 + 4 + 1) * sizeof (CHAR16), 
 | |
|       L"OFFSET=%04X&WIDTH=%04X", 
 | |
|       Offset, 
 | |
|       Width
 | |
|     );
 | |
|   }
 | |
| 
 | |
|   return StringPtr;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get string value for question's name field.
 | |
| 
 | |
|   @param  DatabaseRecord                 HII_DATABASE_RECORD format string.
 | |
|   @param  NameId                         The string id for the name field.
 | |
| 
 | |
|   @retval Name string.
 | |
| 
 | |
| **/
 | |
| CHAR16 *
 | |
| GetNameFromId (
 | |
|   IN HII_DATABASE_RECORD   *DatabaseRecord,
 | |
|   IN EFI_STRING_ID         NameId
 | |
|   )
 | |
| {
 | |
|   CHAR16      *Name;
 | |
|   CHAR8       *PlatformLanguage;
 | |
|   CHAR8       *SupportedLanguages;
 | |
|   CHAR8       *BestLanguage;
 | |
|   UINTN       StringSize;
 | |
|   CHAR16      TempString;
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   Name = NULL;
 | |
|   BestLanguage = NULL;
 | |
|   PlatformLanguage = NULL; 
 | |
|   SupportedLanguages = NULL;
 | |
| 
 | |
|   GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&PlatformLanguage, NULL);
 | |
|   SupportedLanguages = GetSupportedLanguages(DatabaseRecord->Handle);
 | |
| 
 | |
|   //
 | |
|   // Get the best matching language from SupportedLanguages
 | |
|   //
 | |
|   BestLanguage = GetBestLanguage (
 | |
|                    SupportedLanguages, 
 | |
|                    FALSE,                                             // RFC 4646 mode
 | |
|                    PlatformLanguage != NULL ? PlatformLanguage : "",  // Highest priority
 | |
|                    SupportedLanguages,                                // Lowest priority 
 | |
|                    NULL
 | |
|                    );
 | |
|   if (BestLanguage == NULL) {
 | |
|     BestLanguage = AllocateCopyPool (AsciiStrLen ("en-US"), "en-US");
 | |
|     ASSERT (BestLanguage != NULL);
 | |
|   }
 | |
| 
 | |
|   StringSize = 0;
 | |
|   Status = mPrivate.HiiString.GetString (
 | |
|                                  &mPrivate.HiiString,
 | |
|                                  BestLanguage,
 | |
|                                  DatabaseRecord->Handle,
 | |
|                                  NameId,
 | |
|                                  &TempString,
 | |
|                                  &StringSize,
 | |
|                                  NULL
 | |
|                                  );
 | |
|   if (Status != EFI_BUFFER_TOO_SMALL) {
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   Name = AllocateZeroPool (StringSize);
 | |
|   if (Name == NULL) {
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   Status = mPrivate.HiiString.GetString (
 | |
|                           &mPrivate.HiiString,
 | |
|                           BestLanguage,
 | |
|                           DatabaseRecord->Handle,
 | |
|                           NameId,
 | |
|                           Name,
 | |
|                           &StringSize,
 | |
|                           NULL
 | |
|                           );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     FreePool (Name);
 | |
|     Name = NULL;
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
| Done:
 | |
|   if (SupportedLanguages != NULL) {
 | |
|     FreePool(SupportedLanguages);
 | |
|   }
 | |
|   if (BestLanguage != NULL) {
 | |
|     FreePool (BestLanguage);
 | |
|   }
 | |
|   if (PlatformLanguage != NULL) {
 | |
|     FreePool (PlatformLanguage);
 | |
|   }
 | |
| 
 | |
|   return Name;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Base on the input parameter to generate the ConfigRequest string.
 | |
| 
 | |
|   This is a internal function.
 | |
| 
 | |
|   @param  DatabaseRecord                 HII_DATABASE_RECORD format string.
 | |
|   @param  KeywordStrId                   Keyword string id.
 | |
|   @param  OpCodeData                     The IFR data for this question.
 | |
|   @param  ConfigRequest                  Return the generate ConfigRequest string.
 | |
| 
 | |
|   @retval EFI_SUCCESS               Generate ConfigResp string success.
 | |
|   @retval EFI_OUT_OF_RESOURCES      System out of memory resource error.
 | |
|   @retval EFI_NOT_FOUND             Not found the question which use this string id
 | |
|                                     as the prompt string id.
 | |
| **/
 | |
| EFI_STATUS
 | |
| ExtractConfigRequest (
 | |
|   IN  HII_DATABASE_RECORD   *DatabaseRecord,
 | |
|   IN  EFI_STRING_ID         KeywordStrId,
 | |
|   OUT UINT8                 **OpCodeData,
 | |
|   OUT EFI_STRING            *ConfigRequest
 | |
|   ) 
 | |
| {
 | |
|   LIST_ENTRY                          *Link;
 | |
|   HII_DATABASE_PACKAGE_LIST_INSTANCE  *PackageListNode;
 | |
|   HII_IFR_PACKAGE_INSTANCE            *FormPackage;
 | |
|   EFI_IFR_QUESTION_HEADER             *Header;
 | |
|   UINT8                               *Storage;
 | |
|   UINT8                               *OpCode;
 | |
|   CHAR16                              *Name;
 | |
|   UINT16                              Offset;
 | |
|   UINT16                              Width;
 | |
|   CHAR16                              *ConfigHdr;
 | |
|   CHAR16                              *RequestElement;
 | |
|   UINTN                               MaxLen;
 | |
|   CHAR16                              *StringPtr;
 | |
| 
 | |
|   ASSERT (DatabaseRecord != NULL && OpCodeData != NULL && ConfigRequest != NULL);
 | |
| 
 | |
|   OpCode = NULL;
 | |
|   Name   = NULL;
 | |
|   Width  = 0;
 | |
|   Offset = 0;
 | |
| 
 | |
|   PackageListNode = DatabaseRecord->PackageList;
 | |
| 
 | |
|   //
 | |
|   // Search the languages in the specified packagelist.
 | |
|   //
 | |
|   for (Link = PackageListNode->FormPkgHdr.ForwardLink; Link != &PackageListNode->FormPkgHdr; Link = Link->ForwardLink) {
 | |
|     FormPackage = CR (Link, HII_IFR_PACKAGE_INSTANCE, IfrEntry, HII_IFR_PACKAGE_SIGNATURE);
 | |
| 
 | |
|     OpCode = FindQuestionFromStringId (FormPackage, KeywordStrId);
 | |
|     if (OpCode != NULL) {
 | |
|       *OpCodeData = OpCode;
 | |
|       Header = (EFI_IFR_QUESTION_HEADER *) (OpCode + sizeof (EFI_IFR_OP_HEADER));
 | |
|       //
 | |
|       // Header->VarStoreId == 0 means no storage for this question.
 | |
|       //
 | |
|       ASSERT (Header->VarStoreId != 0);
 | |
|       DEBUG ((EFI_D_INFO, "Varstore Id: 0x%x\n", Header->VarStoreId));
 | |
|       
 | |
|       Storage = FindStorageFromVarId (FormPackage, Header->VarStoreId);
 | |
|       ASSERT (Storage != NULL);
 | |
| 
 | |
|       if (((EFI_IFR_OP_HEADER *) Storage)->OpCode == EFI_IFR_VARSTORE_NAME_VALUE_OP) {
 | |
|         Name = GetNameFromId (DatabaseRecord, Header->VarStoreInfo.VarName);
 | |
|       } else {
 | |
|         Offset = Header->VarStoreInfo.VarOffset;
 | |
|         Width = GetWidth (OpCode);
 | |
|       }
 | |
|       RequestElement = ConstructRequestElement(Name, Offset, Width);
 | |
|       ConfigHdr = ConstructConfigHdr(Storage, DatabaseRecord->DriverHandle);
 | |
|       ASSERT (ConfigHdr != NULL);
 | |
| 
 | |
|       MaxLen = StrLen (ConfigHdr) + 1 + StrLen(RequestElement) + 1;
 | |
|       *ConfigRequest = AllocatePool (MaxLen * sizeof (CHAR16));
 | |
|       if (*ConfigRequest == NULL) {
 | |
|         FreePool (ConfigHdr);
 | |
|         FreePool (RequestElement);
 | |
|         return EFI_OUT_OF_RESOURCES;
 | |
|       }
 | |
|       StringPtr = *ConfigRequest;
 | |
| 
 | |
|       StrCpyS (StringPtr, MaxLen, ConfigHdr);
 | |
| 
 | |
|       StrCatS (StringPtr, MaxLen, L"&");
 | |
| 
 | |
|       StrCatS (StringPtr, MaxLen, RequestElement);
 | |
| 
 | |
|       FreePool (ConfigHdr);
 | |
|       FreePool (RequestElement);
 | |
| 
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Base on the input parameter to generate the ConfigResp string.
 | |
| 
 | |
|   This is a internal function.
 | |
| 
 | |
|   @param  DatabaseRecord                 HII_DATABASE_RECORD format string.
 | |
|   @param  KeywordStrId                   Keyword string id.
 | |
|   @param  ValueElement                   The value for the question which use keyword string id
 | |
|                                          as the prompt string id.
 | |
|   @param  OpCodeData                     The IFR data for this question.
 | |
|   @param  ConfigResp                     Return the generate ConfigResp string.
 | |
| 
 | |
|   @retval EFI_SUCCESS               Generate ConfigResp string success.
 | |
|   @retval EFI_OUT_OF_RESOURCES      System out of memory resource error.
 | |
|   @retval EFI_NOT_FOUND             Not found the question which use this string id
 | |
|                                     as the prompt string id.
 | |
| **/
 | |
| EFI_STATUS
 | |
| ExtractConfigResp (
 | |
|   IN  HII_DATABASE_RECORD   *DatabaseRecord,
 | |
|   IN  EFI_STRING_ID         KeywordStrId,
 | |
|   IN  EFI_STRING            ValueElement,
 | |
|   OUT UINT8                 **OpCodeData,
 | |
|   OUT EFI_STRING            *ConfigResp
 | |
|   ) 
 | |
| {
 | |
|   LIST_ENTRY                          *Link;
 | |
|   HII_DATABASE_PACKAGE_LIST_INSTANCE  *PackageListNode;
 | |
|   HII_IFR_PACKAGE_INSTANCE            *FormPackage;
 | |
|   EFI_IFR_QUESTION_HEADER             *Header;
 | |
|   UINT8                               *Storage;
 | |
|   UINT8                               *OpCode;
 | |
|   CHAR16                              *Name;
 | |
|   UINT16                              Offset;
 | |
|   UINT16                              Width;
 | |
|   CHAR16                              *ConfigHdr;
 | |
|   CHAR16                              *RequestElement;
 | |
|   UINTN                               MaxLen;
 | |
|   CHAR16                              *StringPtr;
 | |
| 
 | |
|   ASSERT ((DatabaseRecord != NULL) && (OpCodeData != NULL) && (ConfigResp != NULL) && (ValueElement != NULL));
 | |
| 
 | |
|   OpCode = NULL;
 | |
|   Name   = NULL;
 | |
|   Width  = 0;
 | |
|   Offset = 0;
 | |
| 
 | |
|   PackageListNode = DatabaseRecord->PackageList;
 | |
| 
 | |
|   //
 | |
|   // Search the languages in the specified packagelist.
 | |
|   //
 | |
|   for (Link = PackageListNode->FormPkgHdr.ForwardLink; Link != &PackageListNode->FormPkgHdr; Link = Link->ForwardLink) {
 | |
|     FormPackage = CR (Link, HII_IFR_PACKAGE_INSTANCE, IfrEntry, HII_IFR_PACKAGE_SIGNATURE);
 | |
| 
 | |
|     OpCode = FindQuestionFromStringId (FormPackage, KeywordStrId);
 | |
|     if (OpCode != NULL) {
 | |
|       *OpCodeData = OpCode;
 | |
|       Header = (EFI_IFR_QUESTION_HEADER *) (OpCode + sizeof (EFI_IFR_OP_HEADER));
 | |
|       //
 | |
|       // Header->VarStoreId == 0 means no storage for this question.
 | |
|       //
 | |
|       ASSERT (Header->VarStoreId != 0);
 | |
|       DEBUG ((EFI_D_INFO, "Varstore Id: 0x%x\n", Header->VarStoreId));
 | |
|       
 | |
|       Storage = FindStorageFromVarId (FormPackage, Header->VarStoreId);
 | |
|       ASSERT (Storage != NULL);
 | |
| 
 | |
|       if (((EFI_IFR_OP_HEADER *) Storage)->OpCode == EFI_IFR_VARSTORE_NAME_VALUE_OP) {
 | |
|         Name = GetNameFromId (DatabaseRecord, Header->VarStoreInfo.VarName);
 | |
|       } else {
 | |
|         Offset = Header->VarStoreInfo.VarOffset;
 | |
|         Width  = GetWidth (OpCode);
 | |
|       }
 | |
|       RequestElement = ConstructRequestElement(Name, Offset, Width);
 | |
| 
 | |
|       ConfigHdr = ConstructConfigHdr(Storage, DatabaseRecord->DriverHandle);
 | |
|       ASSERT (ConfigHdr != NULL);
 | |
| 
 | |
|       MaxLen = StrLen (ConfigHdr) + 1 + StrLen(RequestElement) + 1 + StrLen (L"VALUE=") + StrLen(ValueElement) + 1;
 | |
|       *ConfigResp = AllocatePool (MaxLen * sizeof (CHAR16));
 | |
|       if (*ConfigResp == NULL) {
 | |
|         FreePool (ConfigHdr);
 | |
|         FreePool (RequestElement);
 | |
|         return EFI_OUT_OF_RESOURCES;
 | |
|       }
 | |
|       StringPtr = *ConfigResp;
 | |
| 
 | |
|       StrCpyS (StringPtr, MaxLen, ConfigHdr);
 | |
| 
 | |
|       StrCatS (StringPtr, MaxLen, L"&");
 | |
| 
 | |
| 
 | |
|       StrCatS (StringPtr, MaxLen, RequestElement);
 | |
| 
 | |
|       StrCatS (StringPtr, MaxLen, L"&");
 | |
| 
 | |
|       StrCatS (StringPtr, MaxLen, L"VALUE=");
 | |
| 
 | |
|       StrCatS (StringPtr, MaxLen, ValueElement);
 | |
| 
 | |
|       FreePool (ConfigHdr);
 | |
|       FreePool (RequestElement);
 | |
| 
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get the Value section from the Hii driver.
 | |
| 
 | |
|   This is a internal function.
 | |
| 
 | |
|   @param  ConfigRequest                  The input ConfigRequest string.
 | |
|   @param  ValueElement                   The respond Value section from the hii driver.
 | |
| 
 | |
|   @retval Misc value                     The error status return from ExtractConfig function.
 | |
|   @retval EFI_OUT_OF_RESOURCES           The memory can't be allocated
 | |
|   @retval EFI_SUCCESS                    Get the value section success.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ExtractValueFromDriver (
 | |
|   IN  CHAR16           *ConfigRequest,
 | |
|   OUT CHAR16           **ValueElement
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS   Status;
 | |
|   EFI_STRING   Result;
 | |
|   EFI_STRING   Progress;
 | |
|   CHAR16       *StringPtr;
 | |
|   CHAR16       *StringEnd;
 | |
| 
 | |
|   ASSERT ((ConfigRequest != NULL) && (ValueElement != NULL));
 | |
| 
 | |
|   Status = mPrivate.ConfigRouting.ExtractConfig (
 | |
|                       &mPrivate.ConfigRouting,
 | |
|                       (EFI_STRING) ConfigRequest,
 | |
|                       &Progress,
 | |
|                       &Result
 | |
|                       );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Find Value Section and return it.
 | |
|   //
 | |
|   StringPtr = StrStr (Result, L"&VALUE=");
 | |
|   ASSERT (StringPtr != NULL);
 | |
|   StringEnd = StrStr (StringPtr + 1, L"&");
 | |
|   if (StringEnd != NULL) {
 | |
|     *StringEnd = L'\0';
 | |
|   }
 | |
| 
 | |
|   *ValueElement = AllocateCopyPool (StrSize (StringPtr), StringPtr);
 | |
|   if (*ValueElement == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   if (StringEnd != NULL) {
 | |
|     *StringEnd = L'&';
 | |
|   }
 | |
|   FreePool (Result);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get EFI_STRING_ID info from the input device path, namespace and keyword.
 | |
| 
 | |
|   This is a internal function.
 | |
| 
 | |
|   @param  DevicePath                     Input device path info.
 | |
|   @param  NameSpace                      NameSpace format string.
 | |
|   @param  KeywordData                    Keyword used to get string id.
 | |
|   @param  ProgressErr                    Return extra error type.
 | |
|   @param  KeywordStringId                Return EFI_STRING_ID.
 | |
|   @param  DataBaseRecord                 DataBase record data for this driver.
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER          Can't find the database record base on the input device path or namespace.
 | |
|   @retval EFI_NOT_FOUND                  Can't find the EFI_STRING_ID for the keyword.
 | |
|   @retval EFI_SUCCESS                    Find the EFI_STRING_ID.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| GetStringIdFromDatabase (
 | |
|   IN  EFI_DEVICE_PATH_PROTOCOL            **DevicePath,
 | |
|   IN  CHAR8                               **NameSpace,
 | |
|   IN  CHAR16                              *KeywordData,
 | |
|   OUT UINT32                              *ProgressErr,
 | |
|   OUT EFI_STRING_ID                       *KeywordStringId,
 | |
|   OUT HII_DATABASE_RECORD                 **DataBaseRecord
 | |
|  )
 | |
| {
 | |
|   HII_DATABASE_RECORD                 *Record;
 | |
|   LIST_ENTRY                          *Link;
 | |
|   BOOLEAN                             FindNameSpace;
 | |
|   EFI_DEVICE_PATH_PROTOCOL            *DestDevicePath;
 | |
|   UINT8                               *DevicePathPkg;
 | |
|   UINTN                               DevicePathSize;
 | |
| 
 | |
|   ASSERT ((NameSpace != NULL) && (KeywordData != NULL) && (ProgressErr != NULL) && (KeywordStringId != NULL) && (DataBaseRecord != NULL));
 | |
| 
 | |
|   FindNameSpace = FALSE;
 | |
| 
 | |
|   if (*DevicePath != NULL) {
 | |
|     //
 | |
|     // Get DataBaseRecord from device path protocol.
 | |
|     //
 | |
|     Record = GetRecordFromDevicePath(*DevicePath);
 | |
|     if (Record == NULL) {
 | |
|       //
 | |
|       // Can't find the DatabaseRecord base on the input device path info.
 | |
|       // NEED TO CONFIRM the return ProgressErr.
 | |
|       //
 | |
|       *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Get string id from the record.
 | |
|     //
 | |
|     *ProgressErr = GetStringIdFromRecord (Record, NameSpace, KeywordData, KeywordStringId);
 | |
|     switch (*ProgressErr) {
 | |
|     case KEYWORD_HANDLER_NO_ERROR:
 | |
|       *DataBaseRecord = Record;
 | |
|       return EFI_SUCCESS;
 | |
| 
 | |
|     case KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND:
 | |
|       return EFI_INVALID_PARAMETER;
 | |
| 
 | |
|     default:
 | |
|       ASSERT (*ProgressErr == KEYWORD_HANDLER_KEYWORD_NOT_FOUND);
 | |
|       return EFI_NOT_FOUND;
 | |
|     }
 | |
|   } else {
 | |
|     //
 | |
|     // Find driver which matches the routing data.
 | |
|     //
 | |
|     for (Link = mPrivate.DatabaseList.ForwardLink; Link != &mPrivate.DatabaseList; Link = Link->ForwardLink) {
 | |
|       Record = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
 | |
| 
 | |
|       *ProgressErr = GetStringIdFromRecord (Record, NameSpace, KeywordData, KeywordStringId);
 | |
|       if (*ProgressErr == KEYWORD_HANDLER_NO_ERROR) {
 | |
|         *DataBaseRecord = Record;
 | |
|         
 | |
|         if ((DevicePathPkg = Record->PackageList->DevicePathPkg) != NULL) {
 | |
|           DestDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) (DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER));
 | |
|           DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DestDevicePath);
 | |
|           *DevicePath = AllocateCopyPool (DevicePathSize, DestDevicePath);
 | |
|           if (*DevicePath == NULL) {
 | |
|             return EFI_OUT_OF_RESOURCES;
 | |
|           }
 | |
|         } else {
 | |
|           //
 | |
|           // Need to verify this ASSERT.
 | |
|           //
 | |
|           ASSERT (FALSE);
 | |
|         }
 | |
| 
 | |
|         return EFI_SUCCESS;
 | |
|       } else if (*ProgressErr == KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR) {
 | |
|         return EFI_OUT_OF_RESOURCES;
 | |
|       } else if (*ProgressErr == KEYWORD_HANDLER_KEYWORD_NOT_FOUND) {
 | |
|         FindNameSpace = TRUE;
 | |
|       }  
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // When PathHdr not input, if ever find the namespace, will return KEYWORD_HANDLER_KEYWORD_NOT_FOUND.
 | |
|     // This is a bit more progress than KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND.
 | |
|     //
 | |
|     if (FindNameSpace) {
 | |
|       return EFI_NOT_FOUND;
 | |
|     } else {
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Generate the KeywordResp String.
 | |
| 
 | |
|   <KeywordResp> ::= <NameSpaceId><PathHdr>'&'<Keyword>'&VALUE='<Number>['&READONLY']
 | |
| 
 | |
|   @param  NameSpace                      NameSpace format string.
 | |
|   @param  DevicePath                     Input device path info.
 | |
|   @param  KeywordData                    Keyword used to get string id.
 | |
|   @param  ValueStr                       The value section for the keyword.
 | |
|   @param  ReadOnly                       Whether this value is readonly.
 | |
|   @param  KeywordResp                    Return the point to the KeywordResp string.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES           The memory can't be allocated.
 | |
|   @retval EFI_SUCCESS                    Generate the KeywordResp string.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| GenerateKeywordResp (
 | |
|   IN  CHAR8                          *NameSpace, 
 | |
|   IN  EFI_DEVICE_PATH_PROTOCOL       *DevicePath,
 | |
|   IN  EFI_STRING                     KeywordData,
 | |
|   IN  EFI_STRING                     ValueStr,
 | |
|   IN  BOOLEAN                        ReadOnly,
 | |
|   OUT EFI_STRING                     *KeywordResp
 | |
|   )
 | |
| {
 | |
|   UINTN     RespStrLen;
 | |
|   CHAR16    *RespStr;
 | |
|   CHAR16    *PathHdr;
 | |
|   CHAR16    *UnicodeNameSpace;
 | |
|   UINTN     NameSpaceLength;
 | |
| 
 | |
|   ASSERT ((NameSpace != NULL) && (DevicePath != NULL) && (KeywordData != NULL) && (ValueStr != NULL) && (KeywordResp != NULL));
 | |
| 
 | |
|   //
 | |
|   // 1. Calculate the string length.
 | |
|   //
 | |
|   //
 | |
|   // 1.1 NameSpaceId size.
 | |
|   // 'NAMESPACE='<String>
 | |
|   //
 | |
|   NameSpaceLength = AsciiStrLen (NameSpace);
 | |
|   RespStrLen = 10 + NameSpaceLength;
 | |
|   UnicodeNameSpace = AllocatePool ((NameSpaceLength + 1) * sizeof (CHAR16));
 | |
|   if (UnicodeNameSpace == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   AsciiStrToUnicodeStrS (NameSpace, UnicodeNameSpace, NameSpaceLength + 1);
 | |
| 
 | |
|   //
 | |
|   // 1.2 PathHdr size.
 | |
|   // PATH=<UEFI binary Device Path represented as hex number>'&'
 | |
|   // Attention: The output include the '&' at the end.
 | |
|   //
 | |
|   GenerateSubStr (
 | |
|     L"&PATH=",
 | |
|     GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
 | |
|     (VOID *) DevicePath,
 | |
|     1,
 | |
|     &PathHdr
 | |
|     );
 | |
|   RespStrLen += StrLen (PathHdr);
 | |
| 
 | |
|   //
 | |
|   // 1.3 Keyword section.
 | |
|   // 'KEYWORD='<String>[':'<DecCh>(1/4)]
 | |
|   //
 | |
|   RespStrLen += 8 + StrLen (KeywordData);
 | |
| 
 | |
|   //
 | |
|   // 1.4 Value section.
 | |
|   // ValueStr = '&VALUE='<Number>
 | |
|   //
 | |
|   RespStrLen += StrLen (ValueStr);
 | |
| 
 | |
|   //
 | |
|   // 1.5 ReadOnly Section.
 | |
|   // '&READONLY'
 | |
|   //
 | |
|   if (ReadOnly) {
 | |
|     RespStrLen += 9;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // 2. Allocate the buffer and create the KeywordResp string include '\0'.
 | |
|   //
 | |
|   RespStrLen += 1;
 | |
|   *KeywordResp = AllocatePool (RespStrLen * sizeof (CHAR16));
 | |
|   if (*KeywordResp == NULL) {
 | |
|     if (UnicodeNameSpace != NULL) {
 | |
|       FreePool (UnicodeNameSpace);
 | |
|     }
 | |
| 
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   RespStr = *KeywordResp;
 | |
| 
 | |
|   //
 | |
|   // 2.1 Copy NameSpaceId section.
 | |
|   //
 | |
|   StrCpyS (RespStr, RespStrLen, L"NAMESPACE=");
 | |
| 
 | |
|   StrCatS (RespStr, RespStrLen, UnicodeNameSpace);
 | |
| 
 | |
|   //
 | |
|   // 2.2 Copy PathHdr section.
 | |
|   //
 | |
|   StrCatS (RespStr, RespStrLen, PathHdr);
 | |
| 
 | |
|   //
 | |
|   // 2.3 Copy Keyword section.
 | |
|   //
 | |
|   StrCatS (RespStr, RespStrLen, L"KEYWORD=");
 | |
| 
 | |
|   StrCatS (RespStr, RespStrLen, KeywordData);
 | |
| 
 | |
|   //
 | |
|   // 2.4 Copy the Value section.
 | |
|   //
 | |
|   StrCatS (RespStr, RespStrLen, ValueStr);
 | |
| 
 | |
|   //
 | |
|   // 2.5 Copy ReadOnly section if exist.
 | |
|   //
 | |
|   if (ReadOnly) {
 | |
|     StrCatS (RespStr, RespStrLen, L"&READONLY");
 | |
|   }
 | |
| 
 | |
|   if (UnicodeNameSpace != NULL) {
 | |
|     FreePool (UnicodeNameSpace);
 | |
|   }
 | |
|   if (PathHdr != NULL) {
 | |
|     FreePool (PathHdr);
 | |
|   }
 | |
|   
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Merge the KeywordResp String to MultiKeywordResp string.
 | |
| 
 | |
|   This is a internal function.
 | |
| 
 | |
|   @param  MultiKeywordResp               The existed multikeywordresp string.
 | |
|   @param  KeywordResp                    The input keywordResp string.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES           The memory can't be allocated.
 | |
|   @retval EFI_SUCCESS                    Generate the MultiKeywordResp string.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| MergeToMultiKeywordResp (
 | |
|   IN OUT EFI_STRING         *MultiKeywordResp,
 | |
|   IN     EFI_STRING         *KeywordResp
 | |
|   )
 | |
| {
 | |
|   UINTN       MultiKeywordRespLen;
 | |
|   EFI_STRING  StringPtr;
 | |
| 
 | |
|   if (*MultiKeywordResp == NULL) {
 | |
|     *MultiKeywordResp = *KeywordResp;
 | |
|     *KeywordResp = NULL;
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   MultiKeywordRespLen = (StrLen (*MultiKeywordResp) + 1 + StrLen (*KeywordResp) + 1) * sizeof (CHAR16);
 | |
| 
 | |
|   StringPtr = AllocateCopyPool (MultiKeywordRespLen, *MultiKeywordResp);
 | |
|   if (StringPtr == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   
 | |
|   FreePool (*MultiKeywordResp);
 | |
|   *MultiKeywordResp = StringPtr;
 | |
| 
 | |
|   StrCatS (StringPtr, MultiKeywordRespLen / sizeof (CHAR16), L"&");
 | |
| 
 | |
|   StrCatS (StringPtr, MultiKeywordRespLen / sizeof (CHAR16), *KeywordResp);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Enumerate all keyword in the system. 
 | |
|   
 | |
|   If error occur when parse one keyword, just skip it and parse the next one. 
 | |
| 
 | |
|   This is a internal function.
 | |
| 
 | |
|   @param  NameSpace                      The namespace used to search the string.
 | |
|   @param  MultiResp                      Return the MultiKeywordResp string for the system.
 | |
|   @param  ProgressErr                    Return the error status.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES           The memory can't be allocated.
 | |
|   @retval EFI_SUCCESS                    Generate the MultiKeywordResp string.
 | |
|   @retval EFI_NOT_FOUND                  No keyword found.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EnumerateAllKeywords (
 | |
|   IN  CHAR8             *NameSpace,
 | |
|   OUT EFI_STRING        *MultiResp,
 | |
|   OUT UINT32            *ProgressErr
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY                          *Link;
 | |
|   LIST_ENTRY                          *StringLink;
 | |
|   UINT8                               *DevicePathPkg;
 | |
|   UINT8                               *DevicePath;
 | |
|   HII_DATABASE_RECORD                 *DataBaseRecord;
 | |
|   HII_DATABASE_PACKAGE_LIST_INSTANCE  *PackageListNode;
 | |
|   HII_STRING_PACKAGE_INSTANCE         *StringPackage;
 | |
|   CHAR8                               *LocalNameSpace;
 | |
|   EFI_STRING_ID                       NextStringId;
 | |
|   EFI_STATUS                          Status;
 | |
|   UINT8                               *OpCode;
 | |
|   CHAR16                              *ConfigRequest;
 | |
|   CHAR16                              *ValueElement;
 | |
|   CHAR16                              *KeywordResp;
 | |
|   CHAR16                              *MultiKeywordResp;
 | |
|   CHAR16                              *KeywordData;
 | |
|   BOOLEAN                             ReadOnly;
 | |
|   BOOLEAN                             FindKeywordPackages;
 | |
| 
 | |
|   DataBaseRecord   = NULL;
 | |
|   Status           = EFI_SUCCESS;
 | |
|   MultiKeywordResp = NULL;
 | |
|   DevicePath       = NULL;
 | |
|   LocalNameSpace   = NULL;
 | |
|   ConfigRequest    = NULL;
 | |
|   ValueElement     = NULL;
 | |
|   KeywordResp      = NULL;
 | |
|   FindKeywordPackages = FALSE;
 | |
| 
 | |
|   if (NameSpace == NULL) {
 | |
|     NameSpace = UEFI_CONFIG_LANG;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Find driver which matches the routing data.
 | |
|   //
 | |
|   for (Link = mPrivate.DatabaseList.ForwardLink; Link != &mPrivate.DatabaseList; Link = Link->ForwardLink) {
 | |
|     DataBaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
 | |
|     if ((DevicePathPkg = DataBaseRecord->PackageList->DevicePathPkg) != NULL) {
 | |
|       DevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
 | |
|     }
 | |
|     PackageListNode = DataBaseRecord->PackageList;
 | |
| 
 | |
|     for (StringLink = PackageListNode->StringPkgHdr.ForwardLink; StringLink != &PackageListNode->StringPkgHdr; StringLink = StringLink->ForwardLink) {
 | |
|       StringPackage = CR (StringLink, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
 | |
| 
 | |
|       //
 | |
|       // Check whether has keyword string package.
 | |
|       //
 | |
|       if (AsciiStrnCmp(NameSpace, StringPackage->StringPkgHdr->Language, AsciiStrLen (NameSpace)) == 0) {
 | |
|         FindKeywordPackages = TRUE;
 | |
|         //
 | |
|         // Keep the NameSpace string.
 | |
|         //
 | |
|         LocalNameSpace = AllocateCopyPool (AsciiStrSize (StringPackage->StringPkgHdr->Language), StringPackage->StringPkgHdr->Language);
 | |
|         if (LocalNameSpace == NULL) {
 | |
|           return EFI_OUT_OF_RESOURCES;
 | |
|         }
 | |
| 
 | |
|         //
 | |
|         // 1 means just begin the enumerate the valid string ids.
 | |
|         // StringId == 1 is always used to save the language for this string package.
 | |
|         // Any valid string start from 2. so here initial it to 1.
 | |
|         //
 | |
|         NextStringId = 1;
 | |
|         
 | |
|         //
 | |
|         // Enumerate all valid stringid in the package.
 | |
|         //
 | |
|         while ((NextStringId = GetNextStringId (StringPackage, NextStringId, &KeywordData)) != 0) {
 | |
|           //
 | |
|           // 3.3 Construct the ConfigRequest string.
 | |
|           //
 | |
|           Status = ExtractConfigRequest (DataBaseRecord, NextStringId, &OpCode, &ConfigRequest);
 | |
|           if (EFI_ERROR (Status)) {
 | |
|             //
 | |
|             // If can't generate ConfigRequest for this question, skip it and start the next.
 | |
|             //
 | |
|             goto Error;
 | |
|           }
 | |
|           
 | |
|           //
 | |
|           // 3.4 Extract Value for the input keyword.
 | |
|           //
 | |
|           Status = ExtractValueFromDriver(ConfigRequest, &ValueElement);
 | |
|           if (EFI_ERROR (Status)) {
 | |
|             if (Status != EFI_OUT_OF_RESOURCES) {
 | |
|               //
 | |
|               // If can't generate ConfigRequest for this question, skip it and start the next.
 | |
|               //
 | |
|               goto Error;
 | |
|             }
 | |
|             //
 | |
|             // If EFI_OUT_OF_RESOURCES error occur, no need to continue.
 | |
|             //
 | |
|             goto Done;
 | |
|           }
 | |
| 
 | |
|           //
 | |
|           // Extract readonly flag from opcode.
 | |
|           //
 | |
|           ReadOnly = ExtractReadOnlyFromOpCode(OpCode);
 | |
| 
 | |
|           //
 | |
|           // 5. Generate KeywordResp string.
 | |
|           //
 | |
|           ASSERT (DevicePath != NULL);
 | |
|           Status = GenerateKeywordResp(LocalNameSpace, (EFI_DEVICE_PATH_PROTOCOL *)DevicePath, KeywordData, ValueElement, ReadOnly, &KeywordResp);
 | |
|           if (Status != EFI_SUCCESS) {
 | |
|             //
 | |
|             // If EFI_OUT_OF_RESOURCES error occur, no need to continue.
 | |
|             //
 | |
|             goto Done;
 | |
|           }
 | |
|           
 | |
|           //
 | |
|           // 6. Merge to the MultiKeywordResp string.
 | |
|           //
 | |
|           Status = MergeToMultiKeywordResp(&MultiKeywordResp, &KeywordResp);
 | |
|           if (EFI_ERROR (Status)) {
 | |
|             goto Done;
 | |
|           }
 | |
| Error:
 | |
|           //
 | |
|           // Clean the temp buffer to later use again.
 | |
|           //
 | |
|           if (ConfigRequest != NULL) {
 | |
|             FreePool (ConfigRequest);
 | |
|             ConfigRequest = NULL;
 | |
|           }
 | |
|           if (ValueElement != NULL) {
 | |
|             FreePool (ValueElement);
 | |
|             ValueElement = NULL;
 | |
|           }
 | |
|           if (KeywordResp != NULL) {
 | |
|             FreePool (KeywordResp);
 | |
|             KeywordResp = NULL;
 | |
|           } 
 | |
|         }
 | |
| 
 | |
|         if (LocalNameSpace != NULL) {
 | |
|           FreePool (LocalNameSpace);
 | |
|           LocalNameSpace = NULL;
 | |
|         }
 | |
|       }
 | |
|     } 
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // return the already get MultiKeywordString even error occurred.
 | |
|   //
 | |
|   if (MultiKeywordResp == NULL) {
 | |
|     Status = EFI_NOT_FOUND;
 | |
|     if (!FindKeywordPackages) {
 | |
|       *ProgressErr = KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND;
 | |
|     } else {
 | |
|       *ProgressErr = KEYWORD_HANDLER_KEYWORD_NOT_FOUND;
 | |
|     }
 | |
|   } else {
 | |
|     Status = EFI_SUCCESS;
 | |
|   }
 | |
|   *MultiResp = MultiKeywordResp;
 | |
|   
 | |
| Done:
 | |
|   if (LocalNameSpace != NULL) {
 | |
|     FreePool (LocalNameSpace);
 | |
|   }
 | |
|   if (ConfigRequest != NULL) {
 | |
|     FreePool (ConfigRequest);
 | |
|   }
 | |
|   if (ValueElement != NULL) {
 | |
|     FreePool (ValueElement);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   This function accepts a <MultiKeywordResp> formatted string, finds the associated
 | |
|   keyword owners, creates a <MultiConfigResp> string from it and forwards it to the
 | |
|   EFI_HII_ROUTING_PROTOCOL.RouteConfig function.
 | |
|   
 | |
|   If there is an issue in resolving the contents of the KeywordString, then the 
 | |
|   function returns an error and also sets the Progress and ProgressErr with the 
 | |
|   appropriate information about where the issue occurred and additional data about
 | |
|   the nature of the issue. 
 | |
|   
 | |
|   In the case when KeywordString containing multiple keywords, when an EFI_NOT_FOUND
 | |
|   error is generated during processing the second or later keyword element, the system
 | |
|   storage associated with earlier keywords is not modified. All elements of the 
 | |
|   KeywordString must successfully pass all tests for format and access prior to making
 | |
|   any modifications to storage.
 | |
|   
 | |
|   In the case when EFI_DEVICE_ERROR is returned from the processing of a KeywordString
 | |
|   containing multiple keywords, the state of storage associated with earlier keywords
 | |
|   is undefined.
 | |
| 
 | |
| 
 | |
|   @param This             Pointer to the EFI_KEYWORD_HANDLER _PROTOCOL instance.
 | |
| 
 | |
|   @param KeywordString    A null-terminated string in <MultiKeywordResp> format. 
 | |
| 
 | |
|   @param Progress         On return, points to a character in the KeywordString. 
 | |
|                           Points to the string's NULL terminator if the request 
 | |
|                           was successful. Points to the most recent '&' before 
 | |
|                           the first failing name / value pair (or the beginning
 | |
|                           of the string if the failure is in the first name / value
 | |
|                           pair) if the request was not successful.
 | |
| 
 | |
|   @param ProgressErr      If during the processing of the KeywordString there was
 | |
|                           a failure, this parameter gives additional information 
 | |
|                           about the possible source of the problem. The various 
 | |
|                           errors are defined in "Related Definitions" below.
 | |
| 
 | |
| 
 | |
|   @retval EFI_SUCCESS             The specified action was completed successfully.
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER   One or more of the following are TRUE:
 | |
|                                   1. KeywordString is NULL.
 | |
|                                   2. Parsing of the KeywordString resulted in an 
 | |
|                                      error. See Progress and ProgressErr for more data.
 | |
| 
 | |
|   @retval EFI_NOT_FOUND           An element of the KeywordString was not found. 
 | |
|                                   See ProgressErr for more data.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES    Required system resources could not be allocated.  
 | |
|                                   See ProgressErr for more data.
 | |
|                                   
 | |
|   @retval EFI_ACCESS_DENIED       The action violated system policy. See ProgressErr 
 | |
|                                   for more data.
 | |
| 
 | |
|   @retval EFI_DEVICE_ERROR        An unexpected system error occurred. See ProgressErr
 | |
|                                   for more data.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI 
 | |
| EfiConfigKeywordHandlerSetData (
 | |
|   IN EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *This,
 | |
|   IN CONST EFI_STRING                    KeywordString,
 | |
|   OUT EFI_STRING                         *Progress,
 | |
|   OUT UINT32                             *ProgressErr
 | |
|   )
 | |
| {
 | |
|   CHAR8                               *NameSpace;
 | |
|   EFI_STATUS                          Status;
 | |
|   CHAR16                              *StringPtr;
 | |
|   EFI_DEVICE_PATH_PROTOCOL            *DevicePath;
 | |
|   CHAR16                              *NextStringPtr;
 | |
|   CHAR16                              *KeywordData;
 | |
|   EFI_STRING_ID                       KeywordStringId;
 | |
|   UINT32                              RetVal;
 | |
|   HII_DATABASE_RECORD                 *DataBaseRecord;
 | |
|   UINT8                               *OpCode;
 | |
|   CHAR16                              *ConfigResp;
 | |
|   CHAR16                              *MultiConfigResp;
 | |
|   CHAR16                              *ValueElement;
 | |
|   BOOLEAN                             ReadOnly;
 | |
|   EFI_STRING                          InternalProgress;
 | |
|   CHAR16                              *TempString;
 | |
|   CHAR16                              *KeywordStartPos;
 | |
| 
 | |
|   if (This == NULL || Progress == NULL || ProgressErr == NULL || KeywordString == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   *Progress    = KeywordString;
 | |
|   *ProgressErr = KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR;
 | |
|   Status       = EFI_SUCCESS;
 | |
|   MultiConfigResp = NULL;
 | |
|   NameSpace       = NULL;
 | |
|   DevicePath      = NULL;
 | |
|   KeywordData     = NULL;
 | |
|   ValueElement    = NULL;
 | |
|   ConfigResp      = NULL;
 | |
|   KeywordStartPos = NULL;
 | |
|   KeywordStringId = 0;
 | |
| 
 | |
|   //
 | |
|   // Use temp string to avoid changing input string buffer.
 | |
|   //
 | |
|   TempString = AllocateCopyPool (StrSize (KeywordString), KeywordString);
 | |
|   ASSERT (TempString != NULL);
 | |
|   StringPtr = TempString;
 | |
| 
 | |
|   while ((StringPtr != NULL) && (*StringPtr != L'\0')) {
 | |
|     //
 | |
|     // 1. Get NameSpace from NameSpaceId keyword.
 | |
|     //
 | |
|     Status = ExtractNameSpace (StringPtr, &NameSpace, &NextStringPtr);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
 | |
|       goto Done;
 | |
|     }
 | |
|     ASSERT (NameSpace != NULL);
 | |
|     //
 | |
|     // 1.1 Check whether the input namespace is valid.
 | |
|     //
 | |
|     if (AsciiStrnCmp(NameSpace, UEFI_CONFIG_LANG, AsciiStrLen (UEFI_CONFIG_LANG)) != 0) {
 | |
|       *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     StringPtr = NextStringPtr;
 | |
| 
 | |
|     //
 | |
|     // 2. Get possible Device Path info from KeywordString.
 | |
|     //
 | |
|     Status = ExtractDevicePath (StringPtr, (UINT8 **)&DevicePath, &NextStringPtr);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
 | |
|       goto Done;
 | |
|     }
 | |
|     StringPtr = NextStringPtr;
 | |
| 
 | |
|     //
 | |
|     // 3. Extract keyword from the KeywordRequest string.
 | |
|     //
 | |
|     KeywordStartPos = StringPtr;
 | |
|     Status = ExtractKeyword(StringPtr, &KeywordData, &NextStringPtr);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // Can't find Keyword base on the input device path info.
 | |
|       //
 | |
|       *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto Done;
 | |
|     }
 | |
|     StringPtr = NextStringPtr;
 | |
| 
 | |
|     //
 | |
|     // 4. Extract Value from the KeywordRequest string.
 | |
|     //
 | |
|     Status = ExtractValue (StringPtr, &ValueElement, &NextStringPtr);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // Can't find Value base on the input device path info.
 | |
|       //
 | |
|       *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto Done;
 | |
|     }
 | |
|     StringPtr = NextStringPtr;
 | |
| 
 | |
|     //
 | |
|     // 5. Find READONLY tag.
 | |
|     //
 | |
|     if ((StringPtr != NULL) && StrnCmp (StringPtr, L"&READONLY", StrLen (L"&READONLY")) == 0) {
 | |
|       ReadOnly = TRUE;
 | |
|       StringPtr += StrLen (L"&READONLY");
 | |
|     } else {
 | |
|       ReadOnly = FALSE;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // 6. Get EFI_STRING_ID for the input keyword.
 | |
|     //
 | |
|     Status = GetStringIdFromDatabase (&DevicePath, &NameSpace, KeywordData, &RetVal, &KeywordStringId, &DataBaseRecord);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       *ProgressErr = RetVal;
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // 7. Construct the ConfigRequest string.
 | |
|     //
 | |
|     Status = ExtractConfigResp (DataBaseRecord, KeywordStringId, ValueElement, &OpCode, &ConfigResp);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // 8. Check the readonly flag.
 | |
|     //
 | |
|     if (ExtractReadOnlyFromOpCode (OpCode) != ReadOnly) {
 | |
|       //
 | |
|       // Extracting readonly flag form opcode and extracting "READONLY" tag form KeywordString should have the same results.
 | |
|       // If not, the input KeywordString must be incorrect, return the error status to caller.
 | |
|       //
 | |
|       *ProgressErr = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto Done;
 | |
|     }
 | |
|     if (ReadOnly) {
 | |
|       *ProgressErr = KEYWORD_HANDLER_ACCESS_NOT_PERMITTED;
 | |
|       Status = EFI_ACCESS_DENIED;
 | |
|       goto Done;
 | |
|     }
 | |
|     
 | |
|     //
 | |
|     // 9. Merge to the MultiKeywordResp string.
 | |
|     //
 | |
|     Status = MergeToMultiKeywordResp(&MultiConfigResp, &ConfigResp);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // 10. Clean the temp buffer point.
 | |
|     //
 | |
|     FreePool (NameSpace);
 | |
|     FreePool (DevicePath);
 | |
|     FreePool (KeywordData);
 | |
|     FreePool (ValueElement);
 | |
|     NameSpace = NULL;
 | |
|     DevicePath = NULL; 
 | |
|     KeywordData = NULL;
 | |
|     ValueElement = NULL;
 | |
|     if (ConfigResp != NULL) {
 | |
|       FreePool (ConfigResp);
 | |
|       ConfigResp = NULL;
 | |
|     }
 | |
|     KeywordStartPos = NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // 11. Set value to driver.
 | |
|   //
 | |
|   Status = mPrivate.ConfigRouting.RouteConfig(
 | |
|                     &mPrivate.ConfigRouting,
 | |
|                     (EFI_STRING) MultiConfigResp,
 | |
|                     &InternalProgress
 | |
|                     );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto Done;
 | |
|   }
 | |
|   
 | |
|   *ProgressErr = KEYWORD_HANDLER_NO_ERROR;
 | |
| 
 | |
| Done:
 | |
|   if (KeywordStartPos != NULL) {
 | |
|     *Progress = KeywordString + (KeywordStartPos - TempString);
 | |
|   } else {
 | |
|     *Progress = KeywordString + (StringPtr - TempString);
 | |
|   }
 | |
| 
 | |
|   ASSERT (TempString != NULL);
 | |
|   FreePool (TempString);
 | |
|   if (NameSpace != NULL) {
 | |
|     FreePool (NameSpace);
 | |
|   }
 | |
|   if (DevicePath != NULL) {
 | |
|     FreePool (DevicePath);
 | |
|   }
 | |
|   if (KeywordData != NULL) {
 | |
|     FreePool (KeywordData);
 | |
|   }
 | |
|   if (ValueElement != NULL) {
 | |
|     FreePool (ValueElement);
 | |
|   }
 | |
|   if (ConfigResp != NULL) {
 | |
|     FreePool (ConfigResp);
 | |
|   }
 | |
|   if (MultiConfigResp != NULL && MultiConfigResp != ConfigResp) {
 | |
|     FreePool (MultiConfigResp);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   This function accepts a <MultiKeywordRequest> formatted string, finds the underlying 
 | |
|   keyword owners, creates a <MultiConfigRequest> string from it and forwards it to the
 | |
|   EFI_HII_ROUTING_PROTOCOL.ExtractConfig function.
 | |
|   
 | |
|   If there is an issue in resolving the contents of the KeywordString, then the function
 | |
|   returns an EFI_INVALID_PARAMETER and also set the Progress and ProgressErr with the
 | |
|   appropriate information about where the issue occurred and additional data about the
 | |
|   nature of the issue.
 | |
|   
 | |
|   In the case when KeywordString is NULL, or contains multiple keywords, or when
 | |
|   EFI_NOT_FOUND is generated while processing the keyword elements, the Results string
 | |
|   contains values returned for all keywords processed prior to the keyword generating the 
 | |
|   error but no values for the keyword with error or any following keywords.
 | |
| 
 | |
|   
 | |
|   @param This           Pointer to the EFI_KEYWORD_HANDLER _PROTOCOL instance.
 | |
|   
 | |
|   @param NameSpaceId    A null-terminated string containing the platform configuration
 | |
|                         language to search through in the system. If a NULL is passed
 | |
|                         in, then it is assumed that any platform configuration language
 | |
|                         with the prefix of "x-UEFI-" are searched.
 | |
|                         
 | |
|   @param KeywordString  A null-terminated string in <MultiKeywordRequest> format. If a
 | |
|                         NULL is passed in the KeywordString field, all of the known 
 | |
|                         keywords in the system for the NameSpaceId specified are 
 | |
|                         returned in the Results field.
 | |
|   
 | |
|   @param Progress       On return, points to a character in the KeywordString. Points
 | |
|                         to the string's NULL terminator if the request was successful. 
 | |
|                         Points to the most recent '&' before the first failing name / value
 | |
|                         pair (or the beginning of the string if the failure is in the first
 | |
|                         name / value pair) if the request was not successful.
 | |
|                         
 | |
|   @param ProgressErr    If during the processing of the KeywordString there was a
 | |
|                         failure, this parameter gives additional information about the 
 | |
|                         possible source of the problem. See the definitions in SetData()
 | |
|                         for valid value definitions.
 | |
|   
 | |
|   @param Results        A null-terminated string in <MultiKeywordResp> format is returned
 | |
|                         which has all the values filled in for the keywords in the 
 | |
|                         KeywordString. This is a callee-allocated field, and must be freed
 | |
|                         by the caller after being used. 
 | |
| 
 | |
|   @retval EFI_SUCCESS             The specified action was completed successfully.
 | |
|   
 | |
|   @retval EFI_INVALID_PARAMETER   One or more of the following are TRUE:
 | |
|                                   1.Progress, ProgressErr, or Results is NULL.
 | |
|                                   2.Parsing of the KeywordString resulted in an error. See
 | |
|                                     Progress and ProgressErr for more data.
 | |
|   
 | |
| 
 | |
|   @retval EFI_NOT_FOUND           An element of the KeywordString was not found. See
 | |
|                                   ProgressErr for more data.
 | |
| 
 | |
|   @retval EFI_NOT_FOUND           The NamespaceId specified was not found.  See ProgressErr
 | |
|                                   for more data.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES    Required system resources could not be allocated.  See
 | |
|                                   ProgressErr for more data.
 | |
|                                   
 | |
|   @retval EFI_ACCESS_DENIED       The action violated system policy.  See ProgressErr for
 | |
|                                   more data.
 | |
| 
 | |
|   @retval EFI_DEVICE_ERROR        An unexpected system error occurred.  See ProgressErr
 | |
|                                   for more data.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI 
 | |
| EfiConfigKeywordHandlerGetData (
 | |
|   IN EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL  *This,
 | |
|   IN CONST EFI_STRING                     NameSpaceId, OPTIONAL
 | |
|   IN CONST EFI_STRING                     KeywordString, OPTIONAL
 | |
|   OUT EFI_STRING                          *Progress, 
 | |
|   OUT UINT32                              *ProgressErr,
 | |
|   OUT EFI_STRING                          *Results
 | |
|   )
 | |
| {
 | |
|   CHAR8                               *NameSpace;
 | |
|   EFI_STATUS                          Status;
 | |
|   EFI_DEVICE_PATH_PROTOCOL            *DevicePath;
 | |
|   HII_DATABASE_RECORD                 *DataBaseRecord;
 | |
|   CHAR16                              *StringPtr;
 | |
|   CHAR16                              *NextStringPtr;  
 | |
|   CHAR16                              *KeywordData;
 | |
|   EFI_STRING_ID                       KeywordStringId;
 | |
|   UINT8                               *OpCode;
 | |
|   CHAR16                              *ConfigRequest;
 | |
|   CHAR16                              *ValueElement;
 | |
|   UINT32                              RetVal;
 | |
|   BOOLEAN                             ReadOnly;
 | |
|   CHAR16                              *KeywordResp;
 | |
|   CHAR16                              *MultiKeywordResp;
 | |
|   CHAR16                              *TempString;
 | |
| 
 | |
|   if (This == NULL || Progress == NULL || ProgressErr == NULL || Results == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   *ProgressErr = KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR;
 | |
|   Status       = EFI_SUCCESS;
 | |
|   DevicePath   = NULL;
 | |
|   NameSpace    = NULL;
 | |
|   KeywordData  = NULL;
 | |
|   ConfigRequest= NULL;
 | |
|   StringPtr    = KeywordString;
 | |
|   ReadOnly     = FALSE;
 | |
|   MultiKeywordResp = NULL;
 | |
|   KeywordStringId  = 0;
 | |
|   TempString   = NULL;
 | |
| 
 | |
|   //
 | |
|   // Use temp string to avoid changing input string buffer.
 | |
|   //
 | |
|   if (NameSpaceId != NULL) {
 | |
|     TempString = AllocateCopyPool (StrSize (NameSpaceId), NameSpaceId);
 | |
|     ASSERT (TempString != NULL);
 | |
|   }
 | |
|   //
 | |
|   // 1. Get NameSpace from NameSpaceId keyword.
 | |
|   //
 | |
|   Status = ExtractNameSpace (TempString, &NameSpace, NULL);
 | |
|   if (TempString != NULL) {
 | |
|     FreePool (TempString);
 | |
|     TempString = NULL;
 | |
|   }
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // 1.1 Check whether the input namespace is valid.
 | |
|   //
 | |
|   if (NameSpace != NULL){
 | |
|     if (AsciiStrnCmp(NameSpace, UEFI_CONFIG_LANG, AsciiStrLen (UEFI_CONFIG_LANG)) != 0) {
 | |
|       *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
|   }
 | |
|   
 | |
|   if (KeywordString != NULL) {
 | |
|     //
 | |
|     // Use temp string to avoid changing input string buffer.
 | |
|     //
 | |
|     TempString = AllocateCopyPool (StrSize (KeywordString), KeywordString);
 | |
|     ASSERT (TempString != NULL);
 | |
|     StringPtr = TempString;
 | |
| 
 | |
|     while (*StringPtr != L'\0') {
 | |
|       //
 | |
|       // 2. Get possible Device Path info from KeywordString.
 | |
|       //
 | |
|       Status = ExtractDevicePath (StringPtr, (UINT8 **)&DevicePath, &NextStringPtr);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
 | |
|         goto Done;
 | |
|       }
 | |
|       StringPtr = NextStringPtr;
 | |
| 
 | |
|      
 | |
|       //
 | |
|       // 3. Process Keyword section from the input keywordRequest string.
 | |
|       //
 | |
|       // 3.1 Extract keyword from the KeywordRequest string.
 | |
|       //
 | |
|       Status = ExtractKeyword(StringPtr, &KeywordData, &NextStringPtr);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         //
 | |
|         // Can't find Keyword base on the input device path info.
 | |
|         //
 | |
|         *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
 | |
|         Status = EFI_INVALID_PARAMETER;
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // 3.2 Get EFI_STRING_ID for the input keyword.
 | |
|       //
 | |
|       Status = GetStringIdFromDatabase (&DevicePath, &NameSpace, KeywordData, &RetVal, &KeywordStringId, &DataBaseRecord);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         *ProgressErr = RetVal;
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // 3.3 Construct the ConfigRequest string.
 | |
|       //
 | |
|       Status = ExtractConfigRequest (DataBaseRecord, KeywordStringId, &OpCode, &ConfigRequest);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         goto Done;
 | |
|       }
 | |
|       
 | |
|       //
 | |
|       // 3.4 Extract Value for the input keyword.
 | |
|       //
 | |
|       Status = ExtractValueFromDriver(ConfigRequest, &ValueElement);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         if (Status != EFI_OUT_OF_RESOURCES) {
 | |
|           Status = EFI_DEVICE_ERROR;
 | |
|         }
 | |
|         goto Done;
 | |
|       }
 | |
|       StringPtr = NextStringPtr;
 | |
| 
 | |
|       //
 | |
|       // 4. Process the possible filter section.
 | |
|       //
 | |
|       RetVal = ValidateFilter (OpCode, StringPtr, &NextStringPtr, &ReadOnly);
 | |
|       if (RetVal != KEYWORD_HANDLER_NO_ERROR) {
 | |
|         *ProgressErr = RetVal;
 | |
|         Status = EFI_INVALID_PARAMETER;
 | |
|         goto Done;
 | |
|       }
 | |
|       StringPtr = NextStringPtr;
 | |
| 
 | |
| 
 | |
|       //
 | |
|       // 5. Generate KeywordResp string.
 | |
|       //
 | |
|       Status = GenerateKeywordResp(NameSpace, DevicePath, KeywordData, ValueElement, ReadOnly, &KeywordResp);
 | |
|       if (Status != EFI_SUCCESS) {
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // 6. Merge to the MultiKeywordResp string.
 | |
|       //
 | |
|       Status = MergeToMultiKeywordResp(&MultiKeywordResp, &KeywordResp);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // 7. Update return value.
 | |
|       //
 | |
|       *Results = MultiKeywordResp;
 | |
| 
 | |
|       //
 | |
|       // 8. Clean the temp buffer.
 | |
|       //
 | |
|       FreePool (DevicePath);
 | |
|       FreePool (KeywordData);
 | |
|       FreePool (ValueElement);
 | |
|       FreePool (ConfigRequest);
 | |
|       DevicePath = NULL; 
 | |
|       KeywordData = NULL;
 | |
|       ValueElement = NULL;
 | |
|       ConfigRequest = NULL;
 | |
|       if (KeywordResp != NULL) {
 | |
|         FreePool (KeywordResp);
 | |
|         KeywordResp = NULL;
 | |
|       }
 | |
|     }
 | |
|   } else {
 | |
|     //
 | |
|     // Enumerate all keyword in the system.
 | |
|     //
 | |
|     Status = EnumerateAllKeywords(NameSpace, &MultiKeywordResp, ProgressErr);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto Done;
 | |
|     }
 | |
|     *Results = MultiKeywordResp;
 | |
|   }
 | |
| 
 | |
|   *ProgressErr = KEYWORD_HANDLER_NO_ERROR;
 | |
| 
 | |
| Done:
 | |
|   *Progress = KeywordString + (StringPtr - TempString);
 | |
| 
 | |
|   if (TempString != NULL) {
 | |
|     FreePool (TempString);
 | |
|   }
 | |
|   if (NameSpace != NULL) {
 | |
|     FreePool (NameSpace);
 | |
|   }
 | |
|   if (DevicePath != NULL) {
 | |
|     FreePool (DevicePath);
 | |
|   }
 | |
|   if (KeywordData != NULL) {
 | |
|     FreePool (KeywordData);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 |