summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c')
-rw-r--r--MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c2116
1 files changed, 2116 insertions, 0 deletions
diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c b/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c
new file mode 100644
index 0000000..15a55d7
--- /dev/null
+++ b/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c
@@ -0,0 +1,2116 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ ConfigRouting.c
+
+Abstract:
+
+ Implementation for EFI_HII_CONFIG_ROUTING_PROTOCOL.
+
+Revision History
+
+
+**/
+
+
+#include "HiiDatabase.h"
+
+#ifndef DISABLE_UNUSED_HII_PROTOCOLS
+
+STATIC
+CHAR16
+NibbleToHexCharPrivate (
+ IN UINT8 Nibble
+ )
+/*++
+
+ Routine Description:
+ Converts the low nibble of a byte to hex unicode character.
+
+ Arguments:
+ Nibble - lower nibble of a byte.
+
+ Returns:
+ Hex unicode character between L'0' to L'f'.
+
+--*/
+{
+ Nibble &= 0x0F;
+
+ if (Nibble <= 0x9) {
+ return (CHAR16)(Nibble + L'0');
+ }
+
+ return (CHAR16)(Nibble - 0xA + L'a');
+}
+
+
+/**
+ Converts Unicode string to binary buffer.
+ The conversion may be partial.
+ The first character in the string that is not hex digit stops the conversion.
+ At a minimum, any blob of data could be represented as a hex string.
+
+ @param Buf Pointer to buffer that receives the data.
+ @param Len Length in bytes of the buffer to hold converted
+ data. If routine return with EFI_SUCCESS,
+ containing length of converted data. If routine
+ return with EFI_BUFFER_TOO_SMALL, containg length
+ of buffer desired.
+ @param Str String to be converted from.
+ @param ConvertedStrLen Length of the Hex String consumed.
+
+ @retval EFI_SUCCESS Routine Success.
+ @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold converted data.
+
+**/
+STATIC
+EFI_STATUS
+HexStringToBufPrivate (
+ IN OUT UINT8 *Buf,
+ IN OUT UINTN *Len,
+ IN CHAR16 *Str,
+ OUT UINTN *ConvertedStrLen OPTIONAL
+ )
+{
+ UINTN HexCnt;
+ UINTN Idx;
+ UINTN BufferLength;
+ UINT8 Digit;
+ UINT8 Byte;
+
+ //
+ // Find out how many hex characters the string has.
+ //
+ for (Idx = 0, HexCnt = 0; R8_IsHexDigit (&Digit, Str[Idx]); Idx++, HexCnt++);
+
+ if (HexCnt == 0) {
+ *Len = 0;
+ return EFI_SUCCESS;
+ }
+ //
+ // Two Unicode characters make up 1 buffer byte. Round up.
+ //
+ BufferLength = (HexCnt + 1) / 2;
+
+ //
+ // Test if buffer is passed enough.
+ //
+ if (BufferLength > (*Len)) {
+ *Len = BufferLength;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *Len = BufferLength;
+
+ for (Idx = 0; Idx < HexCnt; Idx++) {
+
+ R8_IsHexDigit (&Digit, Str[Idx]);
+
+ //
+ // For odd charaters, write the lower nibble for each buffer byte,
+ // and for even characters, the upper nibble.
+ //
+ if ((Idx & 1) == 0) {
+ Byte = (UINT8) (Digit << 4);
+ } else {
+ Byte = Buf[Idx / 2];
+ Byte &= 0xF0;
+ Byte = (UINT8) (Byte | Digit);
+ }
+
+ Buf[Idx / 2] = Byte;
+ }
+
+ if (ConvertedStrLen != NULL) {
+ *ConvertedStrLen = HexCnt;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Converts binary buffer to Unicode string.
+ At a minimum, any blob of data could be represented as a hex string.
+
+ @param Str Pointer to the string.
+ @param HexStringBufferLength Length in bytes of buffer to hold the hex string.
+ Includes tailing '\0' character. If routine return
+ with EFI_SUCCESS, containing length of hex string
+ buffer. If routine return with
+ EFI_BUFFER_TOO_SMALL, containg length of hex
+ string buffer desired.
+ @param Buf Buffer to be converted from.
+ @param Len Length in bytes of the buffer to be converted.
+ @param Flag If TRUE, encode the data in the same order as the
+ it resides in the Buf. Else encode it in the
+ reverse direction.
+
+ @retval EFI_SUCCESS Routine success.
+ @retval EFI_BUFFER_TOO_SMALL The hex string buffer is too small.
+
+**/
+STATIC
+EFI_STATUS
+BufToHexStringPrivate (
+ IN OUT CHAR16 *Str,
+ IN OUT UINTN *HexStringBufferLength,
+ IN UINT8 *Buf,
+ IN UINTN Len,
+ IN BOOLEAN Flag
+ )
+{
+ UINTN Idx;
+ UINT8 Byte;
+ UINTN StrLen;
+
+ //
+ // Make sure string is either passed or allocate enough.
+ // It takes 2 Unicode characters (4 bytes) to represent 1 byte of the binary buffer.
+ // Plus the Unicode termination character.
+ //
+ StrLen = Len * 2;
+ if ((*HexStringBufferLength) < (StrLen + 1) * sizeof (CHAR16)) {
+ *HexStringBufferLength = (StrLen + 1) * sizeof (CHAR16);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *HexStringBufferLength = (StrLen + 1) * sizeof (CHAR16);
+
+ //
+ // Ends the string.
+ //
+ Str[StrLen] = 0;
+
+ for (Idx = 0; Idx < Len; Idx++) {
+
+ Byte = Buf[Idx];
+ if (Flag) {
+ Str[Idx * 2] = NibbleToHexCharPrivate ((UINT8)(Byte >> 4));
+ Str[Idx * 2 + 1] = NibbleToHexCharPrivate (Byte);
+ } else {
+ Str[StrLen - 1 - Idx * 2] = NibbleToHexCharPrivate (Byte);
+ Str[StrLen - 2 - Idx * 2] = NibbleToHexCharPrivate ((UINT8)(Byte >> 4));
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Calculate the number of Unicode characters of the incoming Configuration string,
+ not including NULL terminator.
+
+ @param String String in <MultiConfigRequest> or
+ <MultiConfigResp> format.
+
+ @return The number of Unicode characters.
+
+**/
+STATIC
+UINTN
+CalculateConfigStringLen (
+ IN EFI_STRING String
+ )
+{
+ UINTN Length;
+
+ //
+ // "GUID=" should be the first element of incoming string.
+ //
+ ASSERT (String != NULL);
+ ASSERT (StrnCmp (String, L"GUID=", StrLen (L"GUID=")) == 0);
+
+ Length = StrLen (L"GUID=");
+ String += Length;
+
+ //
+ // The beginning of next <ConfigRequest>/<ConfigResp> should be "&GUID=".
+ // Will meet '\0' if there is only one <ConfigRequest>/<ConfigResp>.
+ //
+ while (*String != 0 && StrnCmp (String, L"&GUID=", StrLen (L"&GUID=")) != 0) {
+ Length++;
+ String++;
+ }
+
+ return Length;
+}
+
+
+/**
+ Convert the hex UNICODE %02x encoding of a UEFI device path to binary
+ from <PathHdr> of <ConfigHdr>.
+
+ @param String UEFI configuration string
+ @param DevicePath binary of a UEFI device path.
+
+ @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
+ @retval EFI_OUT_OF_RESOURCES Lake of resources to store neccesary structures.
+ @retval EFI_SUCCESS The device path is retrieved and translated to
+ binary format.
+
+**/
+STATIC
+EFI_STATUS
+GetDevicePath (
+ IN EFI_STRING String,
+ OUT UINT8 **DevicePath
+ )
+{
+ UINTN Length;
+ EFI_STRING PathHdr;
+ EFI_STRING DevicePathString;
+
+ if (String == NULL || DevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Find the 'PATH=' of <PathHdr> and skip it.
+ //
+ for (; (*String != 0 && StrnCmp (String, L"PATH=", StrLen (L"PATH=")) != 0); String++);
+ if (*String == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ String += StrLen (L"PATH=");
+ 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++);
+ DevicePathString = (EFI_STRING) AllocateZeroPool ((Length + 1) * sizeof (CHAR16));
+ if (DevicePathString == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ StrnCpy (DevicePathString, PathHdr, Length);
+ *(DevicePathString + Length) = 0;
+
+ //
+ // 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.
+ // Two Unicode characters make up 1 buffer byte.
+ //
+ Length /= 2;
+ *DevicePath = (UINT8 *) AllocateZeroPool (Length);
+ if (*DevicePath == NULL) {
+ SafeFreePool (DevicePathString);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ HexStringToBufPrivate (*DevicePath, &Length, DevicePathString, NULL);
+
+ SafeFreePool (DevicePathString);
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ Extract Storage from all Form Packages in current hii database.
+
+ @param HiiDatabase EFI_HII_DATABASE_PROTOCOL instance.
+ @param StorageListHead Storage link List head.
+
+ @retval EFI_NOT_FOUND There is no form package in current hii database.
+ @retval EFI_INVALID_PARAMETER Any parameter is invalid.
+ @retval EFI_SUCCESS All existing storage is exported.
+
+**/
+STATIC
+EFI_STATUS
+ExportAllStorage (
+ IN EFI_HII_DATABASE_PROTOCOL *HiiDatabase,
+ IN OUT LIST_ENTRY *StorageListHead
+)
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ UINTN HandleCount;
+ EFI_HII_HANDLE *HandleBuffer;
+ UINTN Index;
+ UINTN Index2;
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
+ EFI_HII_PACKAGE_HEADER *Package;
+ UINT8 *OpCodeData;
+ UINT8 Operand;
+ UINT32 Offset;
+ HII_FORMSET_STORAGE *Storage;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HANDLE DriverHandle;
+ CHAR8 *AsciiString;
+ UINT32 PackageListLength;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+
+ //
+ // Find the package list which contains Form package.
+ //
+ BufferSize = 0;
+ HandleBuffer = NULL;
+ Status = HiiListPackageLists (
+ HiiDatabase,
+ EFI_HII_PACKAGE_FORM,
+ NULL,
+ &BufferSize,
+ HandleBuffer
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ HandleBuffer = AllocateZeroPool (BufferSize);
+ ASSERT (HandleBuffer != NULL);
+
+ Status = HiiListPackageLists (
+ HiiDatabase,
+ EFI_HII_PACKAGE_FORM,
+ NULL,
+ &BufferSize,
+ HandleBuffer
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ SafeFreePool (HandleBuffer);
+ return Status;
+ }
+
+ HandleCount = BufferSize / sizeof (EFI_HII_HANDLE);
+ for (Index = 0; Index < HandleCount; Index++) {
+ HiiHandle = HandleBuffer[Index];
+
+ BufferSize = 0;
+ HiiPackageList = NULL;
+ Status = HiiExportPackageLists (HiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ HiiPackageList = AllocateZeroPool (BufferSize);
+ ASSERT (HiiPackageList != NULL);
+ Status = HiiExportPackageLists (HiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
+ }
+ if (EFI_ERROR (Status)) {
+ SafeFreePool (HandleBuffer);
+ SafeFreePool (HiiPackageList);
+ return Status;
+ }
+
+ //
+ // Get Form package from this HII package List
+ //
+ Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
+ CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
+ Package = NULL;
+ ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
+
+ while (Offset < PackageListLength) {
+ Package = (EFI_HII_PACKAGE_HEADER *) (((UINT8 *) HiiPackageList) + Offset);
+ CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
+ if (PackageHeader.Type == EFI_HII_PACKAGE_FORM) {
+ break;
+ }
+ Offset += PackageHeader.Length;
+ }
+ if (Offset >= PackageListLength) {
+ //
+ // Error here: No Form package found in this Package List
+ //
+ ASSERT (FALSE);
+ }
+
+ //
+ // Search Storage definition in this Form package
+ //
+ Offset = sizeof (EFI_HII_PACKAGE_HEADER);
+ while (Offset < PackageHeader.Length) {
+ OpCodeData = ((UINT8 *) Package) + Offset;
+ Offset += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
+
+ Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode;
+
+ if ((Operand == EFI_IFR_VARSTORE_OP) ||
+ (Operand == EFI_IFR_VARSTORE_NAME_VALUE_OP) ||
+ (Operand == EFI_IFR_VARSTORE_EFI_OP)) {
+
+ Storage = AllocateZeroPool (sizeof (HII_FORMSET_STORAGE));
+ ASSERT (Storage != NULL);
+ InsertTailList (StorageListHead, &Storage->Entry);
+
+ Storage->Signature = HII_FORMSET_STORAGE_SIGNATURE;
+ Storage->HiiHandle = HiiHandle;
+
+ Status = HiiGetPackageListHandle (HiiDatabase, HiiHandle, &DriverHandle);
+ if (EFI_ERROR (Status)) {
+ SafeFreePool (HandleBuffer);
+ SafeFreePool (HiiPackageList);
+ SafeFreePool (Storage);
+ return Status;
+ }
+ Storage->DriverHandle = DriverHandle;
+
+ if (Operand == EFI_IFR_VARSTORE_OP) {
+ Storage->Type = EFI_HII_VARSTORE_BUFFER;
+
+ CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE *) OpCodeData)->Guid, sizeof (EFI_GUID));
+ CopyMem (&Storage->Size, &((EFI_IFR_VARSTORE *) OpCodeData)->Size, sizeof (UINT16));
+
+ AsciiString = (CHAR8 *) ((EFI_IFR_VARSTORE *) OpCodeData)->Name;
+ Storage->Name = AllocateZeroPool (AsciiStrSize (AsciiString) * 2);
+ ASSERT (Storage->Name != NULL);
+ for (Index2 = 0; AsciiString[Index2] != 0; Index2++) {
+ Storage->Name[Index2] = (CHAR16) AsciiString[Index2];
+ }
+ //
+ // Append '\0' to the end of the unicode string.
+ //
+ Storage->Name[Index2] = 0;
+ } else if (Operand == EFI_IFR_VARSTORE_NAME_VALUE_OP) {
+ Storage->Type = EFI_HII_VARSTORE_NAME_VALUE;
+
+ CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->Guid, sizeof (EFI_GUID));
+ } else if (Operand == EFI_IFR_VARSTORE_EFI_OP) {
+ Storage->Type = EFI_HII_VARSTORE_EFI_VARIABLE;
+
+ CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Guid, sizeof (EFI_GUID));
+ }
+ }
+ }
+
+ SafeFreePool (HiiPackageList);
+ }
+
+ SafeFreePool (HandleBuffer);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Generate a sub string then output it.
+
+ @param String A constant string which is the prefix of the to be
+ generated string, e.g. GUID=
+ @param BufferLen The length of the Buffer in bytes.
+ @param Buffer Points to a buffer which will be converted to hex
+ string and to be the content of the generated
+ string.
+ @param Flag If TRUE, convert the buffer data in the same order
+ as the it resides in the Buffer. Else convert it
+ in the reverse direction.
+ @param SubStr Points to the output string. It's caller's
+ responsibility to free this buffer.
+
+
+**/
+STATIC
+VOID
+GenerateSubStr (
+ IN CONST EFI_STRING String,
+ IN UINTN BufferLen,
+ IN UINT8 *Buffer,
+ IN BOOLEAN Flag,
+ OUT EFI_STRING *SubStr
+ )
+{
+ UINTN Length;
+ EFI_STRING Str;
+ EFI_STATUS Status;
+
+ ASSERT (String != NULL && SubStr != NULL);
+
+ if (Buffer == NULL) {
+ *SubStr = AllocateCopyPool (StrSize (String), String);
+ ASSERT (*SubStr != NULL);
+ return ;
+ }
+
+ Length = BufferLen * 2 + 1 + StrLen (String) + 1;
+ Str = AllocateZeroPool (Length * sizeof (CHAR16));
+ ASSERT (Str != NULL);
+
+ StrCpy (Str, String);
+ Length = (BufferLen * 2 + 1) * sizeof (CHAR16);
+
+ Status = BufToHexStringPrivate (
+ Str + StrLen (String),
+ &Length,
+ Buffer,
+ BufferLen,
+ Flag
+ );
+
+ ASSERT_EFI_ERROR (Status);
+ StrCat (Str, L"&");
+
+ *SubStr = Str;
+}
+
+
+/**
+ Retrieve the <ConfigBody> from String then output it.
+
+ @param String A sub string of a configuration string in
+ <MultiConfigAltResp> format.
+ @param ConfigBody Points to the output string. It's caller's
+ responsibility to free this buffer.
+
+ @retval EFI_INVALID_PARAMETER There is no form package in current hii database.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to finish this operation.
+ @retval EFI_SUCCESS All existing storage is exported.
+
+**/
+STATIC
+EFI_STATUS
+OutputConfigBody (
+ IN EFI_STRING String,
+ OUT EFI_STRING *ConfigBody
+ )
+{
+ EFI_STRING TmpPtr;
+ EFI_STRING Result;
+ UINTN Length;
+
+ if (String == NULL || ConfigBody == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TmpPtr = StrStr (String, L"GUID=");
+ if (TmpPtr == NULL) {
+ //
+ // It is the last <ConfigResp> of the incoming configuration string.
+ //
+ Result = AllocateCopyPool (StrSize (String), String);
+ if (Result == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ } else {
+ *ConfigBody = Result;
+ return EFI_SUCCESS;
+ }
+ }
+
+ Length = TmpPtr - String;
+ Result = AllocateCopyPool (Length * sizeof (CHAR16), String);
+ if (Result == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *(Result + Length - 1) = 0;
+ *ConfigBody = Result;
+ return EFI_SUCCESS;
+
+}
+
+
+#endif
+
+VOID *
+ReallocatePool (
+ IN VOID *OldPool,
+ IN UINTN OldSize,
+ IN UINTN NewSize
+ )
+/*++
+
+Routine Description:
+ Adjusts the size of a previously allocated buffer.
+
+Arguments:
+ OldPool - A pointer to the buffer whose size is being adjusted.
+ OldSize - The size of the current buffer.
+ NewSize - The size of the new buffer.
+
+Returns:
+ Points to the new buffer
+
+--*/
+{
+ VOID *NewPool;
+
+ NewPool = NULL;
+ if (NewSize) {
+ NewPool = AllocateZeroPool (NewSize);
+ }
+
+ if (OldPool) {
+ if (NewPool) {
+ CopyMem (NewPool, OldPool, OldSize < NewSize ? OldSize : NewSize);
+ }
+
+ gBS->FreePool (OldPool);
+ }
+
+ return NewPool;
+}
+
+
+/**
+ Append a string to a multi-string format.
+
+ @param MultiString String in <MultiConfigRequest>,
+ <MultiConfigAltResp>, or <MultiConfigResp>. On
+ input, the buffer length of this string is
+ MAX_STRING_LENGTH. On output, the buffer length
+ might be updated.
+ @param AppendString NULL-terminated Unicode string.
+
+ @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
+ @retval EFI_SUCCESS AppendString is append to the end of MultiString
+
+**/
+STATIC
+EFI_STATUS
+AppendToMultiString (
+ IN OUT EFI_STRING *MultiString,
+ IN EFI_STRING AppendString
+ )
+{
+ UINTN AppendStringSize;
+ UINTN MultiStringSize;
+
+ if (MultiString == NULL || *MultiString == NULL || AppendString == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AppendStringSize = StrSize (AppendString);
+ MultiStringSize = StrSize (*MultiString);
+
+ //
+ // Enlarge the buffer each time when length exceeds MAX_STRING_LENGTH.
+ //
+ if (MultiStringSize + AppendStringSize > MAX_STRING_LENGTH ||
+ MultiStringSize > MAX_STRING_LENGTH) {
+ *MultiString = (EFI_STRING) ReallocatePool (
+ (VOID *) (*MultiString),
+ MultiStringSize,
+ MultiStringSize + AppendStringSize
+ );
+ }
+
+ //
+ // Append the incoming string
+ //
+ StrCat (*MultiString, AppendString);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
+ or WIDTH or VALUE.
+ <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
+
+ @param StringPtr String in <BlockConfig> format and points to the
+ first character of <Number>.
+ @param Number The output value. Caller takes the responsibility
+ to free memory.
+ @param Len Length of the <Number>, in characters.
+
+ @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary
+ structures.
+ @retval EFI_SUCCESS Value of <Number> is outputted in Number
+ successfully.
+
+**/
+STATIC
+EFI_STATUS
+GetValueOfNumber (
+ IN EFI_STRING StringPtr,
+ OUT UINT8 **Number,
+ OUT UINTN *Len
+ )
+{
+ EFI_STRING TmpPtr;
+ UINTN Length;
+ EFI_STRING Str;
+ UINT8 *Buf;
+ EFI_STATUS Status;
+
+ ASSERT (StringPtr != NULL && Number != NULL && Len != NULL);
+ ASSERT (*StringPtr != 0);
+
+ Buf = NULL;
+
+ TmpPtr = StringPtr;
+ while (*StringPtr != 0 && *StringPtr != L'&') {
+ StringPtr++;
+ }
+ *Len = StringPtr - TmpPtr;
+ Length = *Len + 1;
+
+ Str = (EFI_STRING) AllocateZeroPool (Length * sizeof (EFI_STRING));
+ if (Str == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ CopyMem (Str, TmpPtr, *Len * sizeof (CHAR16));
+ *(Str + *Len) = 0;
+
+ Length = (Length + 1) / 2;
+ Buf = (UINT8 *) AllocateZeroPool (Length);
+ if (Buf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ Status = R8_HexStringToBuf (Buf, &Length, Str, NULL);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ *Number = Buf;
+ Status = EFI_SUCCESS;
+
+Exit:
+ SafeFreePool (Str);
+ return Status;
+}
+
+
+/**
+ This function allows a caller to extract the current configuration
+ for one or more named elements from one or more drivers.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param Request A null-terminated Unicode string in
+ <MultiConfigRequest> format.
+ @param Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ & before the first failing name / value pair (or
+ the beginning of the string if the failure is in
+ the first name / value pair) if the request was
+ not successful.
+ @param Results Null-terminated Unicode string in
+ <MultiConfigAltResp> format which has all values
+ filled in for the names in the Request string.
+ String to be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results string is filled with the values
+ corresponding to all requested names.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
+ results that must be stored awaiting possible
+ future protocols.
+ @retval EFI_NOT_FOUND Routing data doesn't match any known driver.
+ Progress set to the "G" in "GUID" of the routing
+ header that doesn't match. Note: There is no
+ requirement that all routing data be validated
+ before any configuration extraction.
+ @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request
+ parameter would result in this type of error. The
+ Progress parameter is set to NULL.
+ @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent &
+ before the error or the beginning of the string.
+ @retval EFI_INVALID_PARAMETER Unknown name. Progress points to the & before the
+ name in question.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiConfigRoutingExtractConfig (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+#ifndef DISABLE_UNUSED_HII_PROTOCOLS
+
+ HII_DATABASE_PRIVATE_DATA *Private;
+ EFI_STRING StringPtr;
+ EFI_STRING ConfigRequest;
+ UINTN Length;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ HII_DATABASE_RECORD *Database;
+ UINT8 *CurrentDevicePath;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
+ EFI_STRING AccessProgress;
+ EFI_STRING AccessResults;
+ UINTN RemainSize;
+ EFI_STRING TmpPtr;
+
+ if (This == NULL || Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Request == NULL) {
+ *Progress = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ StringPtr = Request;
+ *Progress = StringPtr;
+
+ //
+ // The first element of <MultiConfigRequest> should be
+ // <GuidHdr>, which is in 'GUID='<Guid> syntax.
+ //
+ if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Allocate a fix length of memory to store Results. Reallocate memory for
+ // Results if this fix length is insufficient.
+ //
+ *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
+ if (*Results == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
+ //
+ // If parsing error, set Progress to the beginning of the <MultiConfigRequest>
+ // or most recent & before the error.
+ //
+ if (StringPtr == Request) {
+ *Progress = StringPtr;
+ } else {
+ *Progress = StringPtr - 1;
+ }
+
+ //
+ // Process each <ConfigRequest> of <MultiConfigRequest>
+ //
+ Length = CalculateConfigStringLen (StringPtr);
+ ConfigRequest = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
+ if (ConfigRequest == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *(ConfigRequest + Length) = 0;
+
+ //
+ // Get the UEFI device path
+ //
+ Status = GetDevicePath (ConfigRequest, (UINT8 **) &DevicePath);
+ if (EFI_ERROR (Status)) {
+ SafeFreePool (ConfigRequest);
+ return Status;
+ }
+
+ //
+ // Find driver which matches the routing data.
+ //
+ DriverHandle = NULL;
+ for (Link = Private->DatabaseList.ForwardLink;
+ Link != &Private->DatabaseList;
+ Link = Link->ForwardLink
+ ) {
+ Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ CurrentDevicePath = Database->PackageList->DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
+ if (CurrentDevicePath != NULL) {
+ if (CompareMem (
+ DevicePath,
+ CurrentDevicePath,
+ GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
+ ) == 0) {
+ DriverHandle = Database->DriverHandle;
+ break;
+ }
+ }
+ }
+
+ SafeFreePool (DevicePath);
+
+ if (DriverHandle == NULL) {
+ //
+ // Routing data does not match any known driver.
+ // Set Progress to the 'G' in "GUID" of the routing header.
+ //
+ *Progress = StringPtr;
+ SafeFreePool (ConfigRequest);
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Call corresponding ConfigAccess protocol to extract settings
+ //
+ Status = gBS->HandleProtocol (
+ DriverHandle,
+ &gEfiHiiConfigAccessProtocolGuid,
+ (VOID **) &ConfigAccess
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = ConfigAccess->ExtractConfig (
+ ConfigAccess,
+ ConfigRequest,
+ &AccessProgress,
+ &AccessResults
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // AccessProgress indicates the parsing progress on <ConfigRequest>.
+ // Map it to the progress on <MultiConfigRequest> then return it.
+ //
+ RemainSize = StrSize (AccessProgress);
+ for (TmpPtr = StringPtr; CompareMem (TmpPtr, AccessProgress, RemainSize) != 0; TmpPtr++);
+ *Progress = TmpPtr;
+
+ SafeFreePool (ConfigRequest);
+ return Status;
+ }
+
+ //
+ // Attach this <ConfigAltResp> to a <MultiConfigAltResp>
+ //
+ ASSERT (*AccessProgress == 0);
+ Status = AppendToMultiString (Results, AccessResults);
+ ASSERT_EFI_ERROR (Status);
+ SafeFreePool (AccessResults);
+ AccessResults = NULL;
+ SafeFreePool (ConfigRequest);
+ ConfigRequest = NULL;
+
+ //
+ // Go to next <ConfigRequest> (skip '&').
+ //
+ StringPtr += Length;
+ if (*StringPtr == 0) {
+ *Progress = StringPtr;
+ break;
+ }
+
+ StringPtr++;
+
+ }
+
+ return EFI_SUCCESS;
+#else
+ return EFI_UNSUPPORTED;
+#endif
+
+}
+
+
+/**
+ This function allows the caller to request the current configuration for the
+ entirety of the current HII database and returns the data in a
+ null-terminated Unicode string.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param Results Null-terminated Unicode string in
+ <MultiConfigAltResp> format which has all values
+ filled in for the names in the Request string.
+ String to be allocated by the called function.
+ De-allocation is up to the caller.
+
+ @retval EFI_SUCCESS The Results string is filled with the values
+ corresponding to all requested names.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
+ results that must be stored awaiting possible
+ future protocols.
+ @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results
+ parameter would result in this type of error.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiConfigRoutingExportConfig (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ OUT EFI_STRING *Results
+ )
+{
+#ifndef DISABLE_UNUSED_HII_PROTOCOLS
+
+ EFI_STATUS Status;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ LIST_ENTRY StorageListHdr;
+ HII_FORMSET_STORAGE *Storage;
+ LIST_ENTRY *Link;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN Length;
+ EFI_STRING PathHdr;
+ UINTN PathHdrSize;
+ EFI_STRING ConfigRequest;
+ UINTN RequestSize;
+ EFI_STRING StringPtr;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
+ EFI_STRING AccessProgress;
+ EFI_STRING AccessResults;
+ UINTN TmpSize;
+
+ if (This == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ InitializeListHead (&StorageListHdr);
+
+ Status = ExportAllStorage (&Private->HiiDatabase, &StorageListHdr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Allocate a fix length of memory to store Results. Reallocate memory for
+ // Results if this fix length is insufficient.
+ //
+ *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
+ if (*Results == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Parsing all formset storages.
+ //
+ for (Link = StorageListHdr.ForwardLink; Link != &StorageListHdr; Link = Link->ForwardLink) {
+ Storage = CR (Link, HII_FORMSET_STORAGE, Entry, HII_FORMSET_STORAGE_SIGNATURE);
+ //
+ // Find the corresponding device path instance
+ //
+ Status = gBS->HandleProtocol (
+ Storage->DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Convert the device path binary to hex UNICODE %02x bytes in the same order
+ // as the device path resides in RAM memory.
+ //
+ Length = GetDevicePathSize (DevicePath);
+ PathHdrSize = (Length * 2 + 1) * sizeof (CHAR16);
+ PathHdr = (EFI_STRING) AllocateZeroPool (PathHdrSize);
+ if (PathHdr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = BufToHexStringPrivate (PathHdr, &PathHdrSize, (UINT8 *) DevicePath, Length, TRUE);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Generate a <ConfigRequest> with one <ConfigHdr> and zero <RequestElement>.
+ // It means extract all possible configurations from this specific driver.
+ //
+ TmpSize = StrLen (L"GUID=&NAME=&PATH=");
+ RequestSize = (TmpSize + sizeof (EFI_GUID) * 2 + StrLen (Storage->Name))
+ * sizeof (CHAR16) + PathHdrSize;
+ ConfigRequest = (EFI_STRING) AllocateZeroPool (RequestSize);
+ if (ConfigRequest == NULL) {
+ SafeFreePool (PathHdr);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Add <GuidHdr>
+ // <GuidHdr> ::= 'GUID='<Guid>
+ //
+ StringPtr = ConfigRequest;
+ StrnCpy (StringPtr, L"GUID=", StrLen (L"GUID="));
+ StringPtr += StrLen (L"GUID=");
+
+ Status = BufToHexStringPrivate (
+ StringPtr,
+ &RequestSize,
+ (UINT8 *) (&Storage->Guid),
+ sizeof (EFI_GUID),
+ FALSE
+ );
+ ASSERT_EFI_ERROR (Status);
+ StringPtr += RequestSize / 2 - 1;
+ ASSERT (*StringPtr == 0);
+ *StringPtr = L'&';
+ StringPtr++;
+
+ //
+ // Add <NameHdr>
+ // <NameHdr> ::= 'NAME='<String>
+ //
+ StrnCpy (StringPtr, L"NAME=", StrLen (L"NAME="));
+ StringPtr += StrLen (L"NAME=");
+ StrnCpy (StringPtr, Storage->Name, StrLen (Storage->Name));
+ StringPtr += StrLen (Storage->Name);
+ *StringPtr = L'&';
+ StringPtr++;
+
+ //
+ // Add <PathHdr>
+ // <PathHdr> ::= '<PATH=>'<UEFI binary represented as hex UNICODE %02x>
+ //
+ StrnCpy (StringPtr, L"PATH=", StrLen (L"PATH="));
+ StringPtr += StrLen (L"PATH=");
+ StrCpy (StringPtr, PathHdr);
+
+ SafeFreePool (PathHdr);
+ PathHdr = NULL;
+
+ //
+ // BUGBUG: The "Implementation note" of ExportConfig() in UEFI spec makes the
+ // code somewhat complex. Let's TBD here whether a <ConfigRequest> or a <ConfigHdr>
+ // is required to call ConfigAccess.ExtractConfig().
+ //
+ // Here we use <ConfigHdr> to call ConfigAccess instance. It requires ConfigAccess
+ // to handle such kind of "ConfigRequest". It is not supported till now.
+ //
+ // Either the ExportConfig will be updated or the ConfigAccess.ExtractConfig()
+ // will be updated as soon as the decision is made.
+
+ //
+ // Route the request to corresponding ConfigAccess protocol to extract settings.
+ //
+ Status = gBS->HandleProtocol (
+ Storage->DriverHandle,
+ &gEfiHiiConfigAccessProtocolGuid,
+ (VOID **) &ConfigAccess
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = ConfigAccess->ExtractConfig (
+ ConfigAccess,
+ ConfigRequest,
+ &AccessProgress,
+ &AccessResults
+ );
+ if (EFI_ERROR (Status)) {
+ SafeFreePool (ConfigRequest);
+ SafeFreePool (AccessResults);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Attach this <ConfigAltResp> to a <MultiConfigAltResp>
+ //
+ ASSERT (*AccessProgress == 0);
+ Status = AppendToMultiString (Results, AccessResults);
+ ASSERT_EFI_ERROR (Status);
+ SafeFreePool (AccessResults);
+ AccessResults = NULL;
+ SafeFreePool (ConfigRequest);
+ ConfigRequest = NULL;
+
+ }
+
+ //
+ // Free the exported storage resource
+ //
+ while (!IsListEmpty (&StorageListHdr)) {
+ Storage = CR (
+ StorageListHdr.ForwardLink,
+ HII_FORMSET_STORAGE,
+ Entry,
+ HII_FORMSET_STORAGE_SIGNATURE
+ );
+ RemoveEntryList (&Storage->Entry);
+ SafeFreePool (Storage->Name);
+ SafeFreePool (Storage);
+ }
+
+ return EFI_SUCCESS;
+#else
+ return EFI_UNSUPPORTED;
+#endif
+}
+
+
+/**
+ This function processes the results of processing forms and routes it to the
+ appropriate handlers or storage.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param Configuration A null-terminated Unicode string in
+ <MulltiConfigResp> format.
+ @param Progress A pointer to a string filled in with the offset of
+ the most recent & before the first failing name /
+ value pair (or the beginning of the string if the
+ failure is in the first name / value pair) or the
+ terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The results have been distributed or are awaiting
+ distribution.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
+ results that must be stored awaiting possible
+ future protocols.
+ @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter
+ would result in this type of error.
+ @retval EFI_NOT_FOUND Target for the specified routing data was not
+ found.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiConfigRoutingRoutConfig (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+#ifndef DISABLE_UNUSED_HII_PROTOCOLS
+
+ HII_DATABASE_PRIVATE_DATA *Private;
+ EFI_STRING StringPtr;
+ EFI_STRING ConfigResp;
+ UINTN Length;
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ LIST_ENTRY *Link;
+ HII_DATABASE_RECORD *Database;
+ UINT8 *CurrentDevicePath;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
+ EFI_STRING AccessProgress;
+ UINTN RemainSize;
+ EFI_STRING TmpPtr;
+
+ if (This == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Configuration == NULL) {
+ *Progress = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ StringPtr = Configuration;
+ *Progress = StringPtr;
+
+ //
+ // The first element of <MultiConfigResp> should be
+ // <GuidHdr>, which is in 'GUID='<Guid> syntax.
+ //
+ if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
+ //
+ // If parsing error, set Progress to the beginning of the <MultiConfigResp>
+ // or most recent & before the error.
+ //
+ if (StringPtr == Configuration) {
+ *Progress = StringPtr;
+ } else {
+ *Progress = StringPtr - 1;
+ }
+
+ //
+ // Process each <ConfigResp> of <MultiConfigResp>
+ //
+ Length = CalculateConfigStringLen (StringPtr);
+ ConfigResp = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
+ if (ConfigResp == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Append '\0' to the end of ConfigRequest
+ //
+ *(ConfigResp + Length) = 0;
+
+ //
+ // Get the UEFI device path
+ //
+ Status = GetDevicePath (ConfigResp, (UINT8 **) &DevicePath);
+ if (EFI_ERROR (Status)) {
+ SafeFreePool (ConfigResp);
+ return Status;
+ }
+
+ //
+ // Find driver which matches the routing data.
+ //
+ DriverHandle = NULL;
+ for (Link = Private->DatabaseList.ForwardLink;
+ Link != &Private->DatabaseList;
+ Link = Link->ForwardLink
+ ) {
+ Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ CurrentDevicePath = Database->PackageList->DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
+ if (CurrentDevicePath != NULL) {
+ if (CompareMem (
+ DevicePath,
+ CurrentDevicePath,
+ GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
+ ) == 0) {
+ DriverHandle = Database->DriverHandle;
+ break;
+ }
+ }
+ }
+
+ SafeFreePool (DevicePath);
+
+ if (DriverHandle == NULL) {
+ //
+ // Routing data does not match any known driver.
+ // Set Progress to the 'G' in "GUID" of the routing header.
+ //
+ *Progress = StringPtr;
+ SafeFreePool (ConfigResp);
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Call corresponding ConfigAccess protocol to route settings
+ //
+ Status = gBS->HandleProtocol (
+ DriverHandle,
+ &gEfiHiiConfigAccessProtocolGuid,
+ (VOID **) &ConfigAccess
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = ConfigAccess->RouteConfig (
+ ConfigAccess,
+ ConfigResp,
+ &AccessProgress
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // AccessProgress indicates the parsing progress on <ConfigResp>.
+ // Map it to the progress on <MultiConfigResp> then return it.
+ //
+ RemainSize = StrSize (AccessProgress);
+ for (TmpPtr = StringPtr; CompareMem (TmpPtr, AccessProgress, RemainSize) != 0; TmpPtr++);
+ *Progress = TmpPtr;
+
+ SafeFreePool (ConfigResp);
+ return Status;
+ }
+
+ SafeFreePool (ConfigResp);
+ ConfigResp = NULL;
+
+ //
+ // Go to next <ConfigResp> (skip '&').
+ //
+ StringPtr += Length;
+ if (*StringPtr == 0) {
+ *Progress = StringPtr;
+ break;
+ }
+
+ StringPtr++;
+
+ }
+
+ return EFI_SUCCESS;
+#else
+ return EFI_UNSUPPORTED;
+#endif
+}
+
+
+/**
+ This helper function is to be called by drivers to map configuration data
+ stored in byte array ("block") formats such as UEFI Variables into current
+ configuration strings.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param ConfigRequest A null-terminated Unicode string in
+ <ConfigRequest> format.
+ @param Block Array of bytes defining the block's configuration.
+ @param BlockSize Length in bytes of Block.
+ @param Config Filled-in configuration string. String allocated
+ by the function. Returned only if call is
+ successful.
+ @param Progress A pointer to a string filled in with the offset of
+ the most recent & before the first failing
+ name/value pair (or the beginning of the string if
+ the failure is in the first name / value pair) or
+ the terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The request succeeded. Progress points to the null
+ terminator at the end of the ConfigRequest
+ string.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
+ points to the first character of ConfigRequest.
+ @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or
+ Block parameter would result in this type of
+ error. Progress points to the first character of
+ ConfigRequest.
+ @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
+ @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.
+ Block is left updated and Progress points at
+ the "&" preceding the first non-<BlockName>.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiBlockToConfig (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ IN CONST EFI_STRING ConfigRequest,
+ IN CONST UINT8 *Block,
+ IN CONST UINTN BlockSize,
+ OUT EFI_STRING *Config,
+ OUT EFI_STRING *Progress
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ EFI_STRING StringPtr;
+ UINTN Length;
+ EFI_STATUS Status;
+ EFI_STRING TmpPtr;
+ UINT8 *TmpBuffer;
+ UINTN Offset;
+ UINTN Width;
+ UINT8 *Value;
+ EFI_STRING ValueStr;
+ EFI_STRING ConfigElement;
+
+ if (This == NULL || Progress == NULL || Config == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Block == NULL || ConfigRequest == NULL) {
+ *Progress = ConfigRequest;
+ return EFI_INVALID_PARAMETER;
+ }
+
+
+ Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ ASSERT (Private != NULL);
+
+ StringPtr = ConfigRequest;
+ ValueStr = NULL;
+ Value = NULL;
+ ConfigElement = NULL;
+
+ //
+ // Allocate a fix length of memory to store Results. Reallocate memory for
+ // Results if this fix length is insufficient.
+ //
+ *Config = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
+ if (*Config == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Jump <ConfigHdr>
+ //
+ if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
+ *Progress = StringPtr;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
+ StringPtr++;
+ }
+ if (*StringPtr == 0) {
+ *Progress = StringPtr;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ while (*StringPtr++ != L'&');
+
+ //
+ // Copy <ConfigHdr> and an additional '&' to <ConfigResp>
+ //
+ Length = StringPtr - ConfigRequest;
+ CopyMem (*Config, ConfigRequest, Length * sizeof (CHAR16));
+
+ //
+ // Parse each <RequestElement> if exists
+ // Only <BlockName> format is supported by this help function.
+ // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>
+ //
+ while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
+ //
+ // Back up the header of one <BlockName>
+ //
+ TmpPtr = StringPtr;
+
+ StringPtr += StrLen (L"OFFSET=");
+ //
+ // Get Offset
+ //
+ Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ *Progress = ConfigRequest;
+ goto Exit;
+ }
+ Offset = 0;
+ CopyMem (
+ &Offset,
+ TmpBuffer,
+ (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
+ );
+ SafeFreePool (TmpBuffer);
+
+ StringPtr += Length;
+ if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
+ *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ StringPtr += StrLen (L"&WIDTH=");
+
+ //
+ // Get Width
+ //
+ Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ *Progress = ConfigRequest;
+ goto Exit;
+ }
+ Width = 0;
+ CopyMem (
+ &Width,
+ TmpBuffer,
+ (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
+ );
+ SafeFreePool (TmpBuffer);
+
+ StringPtr += Length;
+ if (*StringPtr != 0 && *StringPtr != L'&') {
+ *Progress = StringPtr - Length - StrLen (L"&WIDTH=");
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ //
+ // Calculate Value and convert it to hex string.
+ //
+ if (Offset + Width > BlockSize) {
+ *Progress = StringPtr;
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Value = (UINT8 *) AllocateZeroPool (Width);
+ if (Value == NULL) {
+ *Progress = ConfigRequest;
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ CopyMem (Value, (UINT8 *) Block + Offset, Width);
+
+ Length = Width * 2 + 1;
+ ValueStr = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
+ if (ValueStr == NULL) {
+ *Progress = ConfigRequest;
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ Status = R8_BufToHexString (ValueStr, &Length, Value, Width);
+ ASSERT_EFI_ERROR (Status);
+ SafeFreePool (Value);
+ Value = NULL;
+
+ //
+ // Build a ConfigElement
+ //
+ Length += StringPtr - TmpPtr + 1 + StrLen (L"VALUE=");
+ ConfigElement = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
+ if (ConfigElement == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ CopyMem (ConfigElement, TmpPtr, (StringPtr - TmpPtr + 1) * sizeof (CHAR16));
+ if (*StringPtr == 0) {
+ *(ConfigElement + (StringPtr - TmpPtr)) = L'&';
+ }
+ *(ConfigElement + (StringPtr - TmpPtr) + 1) = 0;
+ StrCat (ConfigElement, L"VALUE=");
+ StrCat (ConfigElement, ValueStr);
+
+ AppendToMultiString (Config, ConfigElement);
+
+ SafeFreePool (ConfigElement);
+ SafeFreePool (ValueStr);
+ ConfigElement = NULL;
+ ValueStr = NULL;
+
+ //
+ // If '\0', parsing is finished. Otherwise skip '&' to continue
+ //
+ if (*StringPtr == 0) {
+ break;
+ }
+ AppendToMultiString (Config, L"&");
+ StringPtr++;
+
+ }
+
+ if (*StringPtr != 0) {
+ *Progress = StringPtr - 1;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ *Progress = StringPtr;
+ return EFI_SUCCESS;
+
+Exit:
+
+ SafeFreePool (*Config);
+ SafeFreePool (ValueStr);
+ SafeFreePool (Value);
+ SafeFreePool (ConfigElement);
+
+ return Status;
+
+}
+
+
+/**
+ This helper function is to be called by drivers to map configuration strings
+ to configurations stored in byte array ("block") formats such as UEFI Variables.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param ConfigResp A null-terminated Unicode string in <ConfigResp>
+ format.
+ @param Block A possibly null array of bytes representing the
+ current block. Only bytes referenced in the
+ ConfigResp string in the block are modified. If
+ this parameter is null or if the *BlockSize
+ parameter is (on input) shorter than required by
+ the Configuration string, only the BlockSize
+ parameter is updated and an appropriate status
+ (see below) is returned.
+ @param BlockSize The length of the Block in units of UINT8. On
+ input, this is the size of the Block. On output,
+ if successful, contains the index of the last
+ modified byte in the Block.
+ @param Progress On return, points to an element of the ConfigResp
+ string filled in with the offset of the most
+ recent '&' before the first failing name / value
+ pair (or the beginning of the string if the
+ failure is in the first name / value pair) or the
+ terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The request succeeded. Progress points to the null
+ terminator at the end of the ConfigResp string.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
+ points to the first character of ConfigResp.
+ @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or
+ Block parameter would result in this type of
+ error. Progress points to the first character of
+ ConfigResp.
+ @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /
+ value pair. Block is left updated and
+ Progress points at the '&' preceding the first
+ non-<BlockName>.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiConfigToBlock (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ IN CONST EFI_STRING ConfigResp,
+ IN OUT UINT8 *Block,
+ IN OUT UINTN *BlockSize,
+ OUT EFI_STRING *Progress
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ EFI_STRING StringPtr;
+ UINTN Length;
+ EFI_STATUS Status;
+ UINT8 *TmpBuffer;
+ UINTN Offset;
+ UINTN Width;
+ UINT8 *Value;
+ UINTN BufferSize;
+
+ if (This == NULL || BlockSize == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ConfigResp == NULL || Block == NULL) {
+ *Progress = ConfigResp;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ ASSERT (Private != NULL);
+
+ StringPtr = ConfigResp;
+ BufferSize = *BlockSize;
+ Value = NULL;
+
+ //
+ // Jump <ConfigHdr>
+ //
+ if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
+ *Progress = StringPtr;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
+ StringPtr++;
+ }
+ if (*StringPtr == 0) {
+ *Progress = StringPtr;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ while (*StringPtr++ != L'&');
+
+ //
+ // Parse each <ConfigElement> if exists
+ // Only <BlockConfig> format is supported by this help function.
+ // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
+ //
+ while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
+ StringPtr += StrLen (L"OFFSET=");
+ //
+ // Get Offset
+ //
+ Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ *Progress = ConfigResp;
+ goto Exit;
+ }
+ Offset = 0;
+ CopyMem (
+ &Offset,
+ TmpBuffer,
+ (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
+ );
+ SafeFreePool (TmpBuffer);
+
+ StringPtr += Length;
+ if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
+ *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ StringPtr += StrLen (L"&WIDTH=");
+
+ //
+ // Get Width
+ //
+ Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ *Progress = ConfigResp;
+ goto Exit;
+ }
+ Width = 0;
+ CopyMem (
+ &Width,
+ TmpBuffer,
+ (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
+ );
+ SafeFreePool (TmpBuffer);
+
+ StringPtr += Length;
+ if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {
+ *Progress = StringPtr - Length - StrLen (L"&WIDTH=");
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ StringPtr += StrLen (L"&VALUE=");
+
+ //
+ // Get Value
+ //
+ Status = GetValueOfNumber (StringPtr, &Value, &Length);
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ *Progress = ConfigResp;
+ goto Exit;
+ }
+
+ StringPtr += Length;
+ if (*StringPtr != 0 && *StringPtr != L'&') {
+ *Progress = StringPtr - Length - 7;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ //
+ // Update the Block with configuration info
+ //
+
+ if (Offset + Width > BufferSize) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ CopyMem (Block + Offset, Value, Width);
+ *BlockSize = Offset + Width - 1;
+
+ SafeFreePool (Value);
+ Value = NULL;
+
+ //
+ // If '\0', parsing is finished. Otherwise skip '&' to continue
+ //
+ if (*StringPtr == 0) {
+ break;
+ }
+
+ StringPtr++;
+ }
+
+ if (*StringPtr != 0) {
+ *Progress = StringPtr - 1;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ *Progress = StringPtr;
+ return EFI_SUCCESS;
+
+Exit:
+
+ SafeFreePool (Value);
+ return Status;
+}
+
+
+/**
+ This helper function is to be called by drivers to extract portions of
+ a larger configuration string.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param Configuration A null-terminated Unicode string in
+ <MultiConfigAltResp> format.
+ @param Guid A pointer to the GUID value to search for in the
+ routing portion of the ConfigResp string when
+ retrieving the requested data. If Guid is NULL,
+ then all GUID values will be searched for.
+ @param Name A pointer to the NAME value to search for in the
+ routing portion of the ConfigResp string when
+ retrieving the requested data. If Name is NULL,
+ then all Name values will be searched for.
+ @param DevicePath A pointer to the PATH value to search for in the
+ routing portion of the ConfigResp string when
+ retrieving the requested data. If DevicePath is
+ NULL, then all DevicePath values will be searched
+ for.
+ @param AltCfgId A pointer to the ALTCFG value to search for in the
+ routing portion of the ConfigResp string when
+ retrieving the requested data. If this parameter
+ is NULL, then the current setting will be
+ retrieved.
+ @param AltCfgResp A pointer to a buffer which will be allocated by
+ the function which contains the retrieved string
+ as requested. This buffer is only allocated if
+ the call was successful.
+
+ @retval EFI_SUCCESS The request succeeded. The requested data was
+ extracted and placed in the newly allocated
+ AltCfgResp buffer.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.
+ @retval EFI_INVALID_PARAMETER Any parameter is invalid.
+ @retval EFI_NOT_FOUND Target for the specified routing data was not
+ found.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetAltCfg (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ IN CONST EFI_GUID *Guid,
+ IN CONST EFI_STRING Name,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN CONST UINT16 *AltCfgId,
+ OUT EFI_STRING *AltCfgResp
+ )
+{
+#ifndef DISABLE_UNUSED_HII_PROTOCOLS
+
+ EFI_STATUS Status;
+ EFI_STRING StringPtr;
+ EFI_STRING HdrStart = NULL;
+ EFI_STRING HdrEnd = NULL;
+ EFI_STRING TmpPtr;
+ UINTN Length;
+ EFI_STRING GuidStr = NULL;
+ EFI_STRING NameStr = NULL;
+ EFI_STRING PathStr = NULL;
+ EFI_STRING AltIdStr = NULL;
+ EFI_STRING Result = NULL;
+ BOOLEAN GuidFlag = FALSE;
+ BOOLEAN NameFlag = FALSE;
+ BOOLEAN PathFlag = FALSE;
+
+ if (This == NULL || Configuration == NULL || AltCfgResp == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ StringPtr = Configuration;
+ if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Generate the sub string for later matching.
+ //
+ GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (UINT8 *) Guid, FALSE, &GuidStr);
+ GenerateSubStr (
+ L"PATH=",
+ GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
+ (UINT8 *) DevicePath,
+ TRUE,
+ &PathStr
+ );
+ if (AltCfgId != NULL) {
+ GenerateSubStr (L"ALTCFG=", sizeof (UINT16), (UINT8 *) AltCfgId, FALSE, &AltIdStr);
+ }
+ if (Name != NULL) {
+ Length = StrLen (Name);
+ Length += StrLen (L"NAME=&") + 1;
+ NameStr = AllocateZeroPool (Length * sizeof (CHAR16));
+ if (NameStr == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ StrCpy (NameStr, L"NAME=");
+ StrCat (NameStr, Name);
+ StrCat (NameStr, L"&");
+ } else {
+ GenerateSubStr (L"NAME=", 0, NULL, FALSE, &NameStr);
+ }
+
+ while (*StringPtr != 0) {
+ //
+ // Try to match the GUID
+ //
+ if (!GuidFlag) {
+ TmpPtr = StrStr (StringPtr, GuidStr);
+ if (TmpPtr == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+ HdrStart = TmpPtr;
+
+ //
+ // Jump to <NameHdr>
+ //
+ if (Guid != NULL) {
+ StringPtr = TmpPtr + StrLen (GuidStr);
+ } else {
+ StringPtr = StrStr (TmpPtr, L"NAME=");
+ if (StringPtr == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+ }
+ GuidFlag = TRUE;
+ }
+
+ //
+ // Try to match the NAME
+ //
+ if (GuidFlag && !NameFlag) {
+ if (StrnCmp (StringPtr, NameStr, StrLen (NameStr)) != 0) {
+ GuidFlag = FALSE;
+ } else {
+ //
+ // Jump to <PathHdr>
+ //
+ if (Name != NULL) {
+ StringPtr += StrLen (NameStr);
+ } else {
+ StringPtr = StrStr (StringPtr, L"PATH=");
+ if (StringPtr == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+ }
+ NameFlag = TRUE;
+ }
+ }
+
+ //
+ // Try to match the DevicePath
+ //
+ if (GuidFlag && NameFlag && !PathFlag) {
+ if (StrnCmp (StringPtr, PathStr, StrLen (PathStr)) != 0) {
+ GuidFlag = FALSE;
+ NameFlag = FALSE;
+ } else {
+ //
+ // Jump to '&' before <DescHdr> or <ConfigBody>
+ //
+ if (DevicePath != NULL) {
+ StringPtr += StrLen (PathStr);
+ } else {
+ StringPtr = StrStr (StringPtr, L"&");
+ if (StringPtr == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+ }
+ PathFlag = TRUE;
+ HdrEnd = ++StringPtr;
+ }
+ }
+
+ //
+ // Try to match the AltCfgId
+ //
+ if (GuidFlag && NameFlag && PathFlag) {
+ if (AltCfgId == NULL) {
+ //
+ // Return Current Setting when AltCfgId is NULL.
+ //
+ Status = OutputConfigBody (StringPtr, &Result);
+ goto Exit;
+ }
+ //
+ // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.
+ //
+ if (StrnCmp (StringPtr, AltIdStr, StrLen (AltIdStr)) != 0) {
+ GuidFlag = FALSE;
+ NameFlag = FALSE;
+ PathFlag = FALSE;
+ } else {
+ Status = OutputConfigBody (StringPtr, &Result);
+ goto Exit;
+ }
+ }
+ }
+
+ Status = EFI_NOT_FOUND;
+
+Exit:
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Copy the <ConfigHdr> and <ConfigBody>
+ //
+ Length = HdrEnd - HdrStart + StrLen (Result);
+ *AltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
+ if (*AltCfgResp == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ StrnCpy (*AltCfgResp, HdrStart, HdrEnd - HdrStart);
+ StrCat (*AltCfgResp, Result);
+ Status = EFI_SUCCESS;
+ }
+ }
+
+ SafeFreePool (GuidStr);
+ SafeFreePool (NameStr);
+ SafeFreePool (PathStr);
+ SafeFreePool (AltIdStr);
+ SafeFreePool (Result);
+
+ return Status;
+
+#else
+ return EFI_UNSUPPORTED;
+#endif
+
+}
+