public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-platforms][PATCH 1/2] Platform/AMD: Initial commit of AmdPlatformPkg
@ 2023-06-20  9:31 Chang, Abner
  2023-06-20  9:31 ` [edk2-platforms][PATCH 2/2] AmdPlatformPkg/HiiConfigRouting: AMD HiiConfigRouting module Chang, Abner
  0 siblings, 1 reply; 2+ messages in thread
From: Chang, Abner @ 2023-06-20  9:31 UTC (permalink / raw)
  To: devel; +Cc: Abdul Lateef Attar

From: Abner Chang <abner.chang@amd.com>

Platform/AMD/AmdPlatformPkg provides the AMD edk2 common
platform drivers and libraries for AMD server, client
and Strategic Silicon Solutions (S3) platforms.

Signed-off-by: Abner Chang <abner.chang@amd.com>
Cc: Abdul Lateef Attar <abdattar@amd.com>
---
 .../AMD/AmdPlatformPkg/AmdPlatformPkg.dec     | 18 +++++++++++++++
 .../AMD/AmdPlatformPkg/AmdPlatformPkg.dsc     | 22 +++++++++++++++++++
 2 files changed, 40 insertions(+)
 create mode 100644 Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dec
 create mode 100644 Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc

diff --git a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dec b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dec
new file mode 100644
index 0000000000..1fe7f94dc7
--- /dev/null
+++ b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dec
@@ -0,0 +1,18 @@
+## @file
+# AMD Platform common Package DEC file
+# This is the package provides the AMD edk2 common platform drivers
+# and libraries for AMD Server, Clinet and Gaming console platforms.
+#
+# Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  DEC_SPECIFICATION = 1.27
+  PACKAGE_NAME      = AmdPlatformPkg
+  PACKAGE_GUID      = 2CB1238B-18E2-4837-B714-9DAB2B30A3C2
+  PACKAGE_VERSION   = 1.0
+
+[Guids]
+  gAmdPlatformPkgTokenSpaceGuid   = { 0x663DE733, 0x70E0, 0x4D37, { 0xBB, 0x30, 0x7D, 0x9E, 0xAF, 0x9B, 0xDA, 0xE9 }}
diff --git a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc
new file mode 100644
index 0000000000..d3368c87ee
--- /dev/null
+++ b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc
@@ -0,0 +1,22 @@
+## @file
+# AMD Platform common Package DSC file
+# This is the package provides the AMD edk2 common platform drivers
+# and libraries for AMD Server, Clinet and Gaming console platforms.
+#
+# Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  PLATFORM_NAME                  = AmdPlatformPkg
+  PLATFORM_GUID                  = ACFD1C98-D451-45FE-B300-4049C5AD553B
+  PLATFORM_VERSION               = 1.0
+  DSC_SPECIFICATION              = 1.28
+  OUTPUT_DIRECTORY               = Build/AmdPlatformPkg
+  SUPPORTED_ARCHITECTURES        = IA32|X64
+  BUILD_TARGETS                  = DEBUG|RELEASE|NOOPT
+  SKUID_IDENTIFIER               = DEFAULT
+
+[Packages]
+  AmdPlatformPkg/AmdPlatformPkg.dec
-- 
2.37.1.windows.1


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [edk2-platforms][PATCH 2/2] AmdPlatformPkg/HiiConfigRouting: AMD HiiConfigRouting module
  2023-06-20  9:31 [edk2-platforms][PATCH 1/2] Platform/AMD: Initial commit of AmdPlatformPkg Chang, Abner
@ 2023-06-20  9:31 ` Chang, Abner
  0 siblings, 0 replies; 2+ messages in thread
From: Chang, Abner @ 2023-06-20  9:31 UTC (permalink / raw)
  To: devel; +Cc: Abdul Lateef Attar, Mark Wilson

From: Mark Wilson <mark.wilson@amd.com>

This module overrides BlockToConfig and ConfigToBlock
interfaces for the better performance.

Signed-off-by: Abner Chang <abner.chang@amd.com>
Cc: Abdul Lateef Attar <abdattar@amd.com>
Cc: Mark Wilson <mark.wilson@amd.com>
---
 .../AMD/AmdPlatformPkg/AmdPlatformPkg.dsc     |   33 +
 .../HiiConfigRouting/AmdConfigRouting.inf     |   45 +
 .../HiiConfigRouting/AmdHiiConfigRouting.h    |  188 +++
 .../HiiConfigRouting/AmdConfigRoutingEntry.c  |   45 +
 .../HiiConfigRouting/AmdHiiConfigRouting.c    | 1098 +++++++++++++++++
 5 files changed, 1409 insertions(+)
 create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRouting.inf
 create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdHiiConfigRouting.h
 create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRoutingEntry.c
 create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdHiiConfigRouting.c

diff --git a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc
index d3368c87ee..ee6708a1a8 100644
--- a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc
+++ b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc
@@ -20,3 +20,36 @@
 
 [Packages]
   AmdPlatformPkg/AmdPlatformPkg.dec
+
+!include MdePkg/MdeLibs.dsc.inc
+
+[LibraryClasses.Common]
+  BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
+  UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
+  UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
+  UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
+  UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf
+  PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+  DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
+
+!if $(TARGET) == RELEASE
+  DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
+!else
+  DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
+!endif
+
+  DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+  BaseMemoryLib|MdePkg/Library/BaseMemoryLibRepStr/BaseMemoryLibRepStr.inf
+  PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+  SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf
+  UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
+  HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
+  UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
+
+[LibraryClasses.common.DXE_CORE, LibraryClasses.common.DXE_SMM_DRIVER, LibraryClasses.common.SMM_CORE, LibraryClasses.common.DXE_DRIVER, LibraryClasses.common.DXE_RUNTIME_DRIVER, LibraryClasses.common.UEFI_DRIVER, LibraryClasses.common.UEFI_APPLICATION]
+  MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+  ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
+
+[Components.common.DXE_DRIVER]
+  AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRouting.inf
+
diff --git a/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRouting.inf b/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRouting.inf
new file mode 100644
index 0000000000..f30527fb9d
--- /dev/null
+++ b/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRouting.inf
@@ -0,0 +1,45 @@
+## @file
+#  AMD HII Config routing driver INF file.
+#  This module provides better performance of BlockToConfig and ConfigToBlock
+#  functions.
+#
+#  Copyright (C) 2021-2023 Advanced Micro Devices, Inc. All rights reserved.
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = AmdConfigRouting
+  FILE_GUID                      = 64302048-7006-49C4-AF0A-5ACE61257437
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = AmdConfigRoutingEntry
+
+[Sources]
+  AmdConfigRoutingEntry.c
+  AmdHiiConfigRouting.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  BaseLib
+  UefiLib
+  DebugLib
+  BaseMemoryLib
+  MemoryAllocationLib
+  UefiDriverEntryPoint
+  UefiBootServicesTableLib
+
+[Protocols]
+  gEfiHiiConfigRoutingProtocolGuid
+
+[Pcd]
+  gEfiMdePkgTokenSpaceGuid.PcdMaximumUnicodeStringLength
+
+[Guids]
+
+[Depex]
+  gEfiHiiConfigRoutingProtocolGuid
diff --git a/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdHiiConfigRouting.h b/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdHiiConfigRouting.h
new file mode 100644
index 0000000000..c27fab703b
--- /dev/null
+++ b/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdHiiConfigRouting.h
@@ -0,0 +1,188 @@
+/** @file
+  Provide optimized implementation of HII_CONFIG_ROUTING Protocol
+  functions HiiBlockToConfig and HiiConfigToBlock.
+
+  Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef AMD_HII_CONFIG_ROUTING_H_
+#define AMD_HII_CONFIG_ROUTING_H_
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#define MAX_STRING_LENGTH  1024
+
+///
+/// Returns the size of a Null-terminated Unicode string in bytes, including the
+/// Null terminator.
+///
+#define HiiStrSize(str)  ((HiiStrLen (str) + 1) * sizeof (*str))
+
+///
+/// HII_NUMBER definitions
+///
+typedef struct {
+  // Public variables
+  UINT8    *NumberPtr;        ///< Pointer to a number in array of bytes.
+  UINTN    NumberPtrLength;   ///< 2 * number of bytes. Note: changing this to
+                              ///< number of bytes will impact existing code and
+                              ///< hard to test.
+  UINTN    Value;             ///< If Value is less than or equal to 64-bits,
+                              ///< store value here as an unsigned integer.
+  UINTN    StringLength;      ///< Input string length.
+
+  // Private variables
+  UINTN    PrivateBufferSize; ///< Size of allocated NumberPtr. This reduces
+                              ///< reallocations as this can be used for
+                              ///< multiple numbers.
+} HII_NUMBER;
+
+///
+/// HII_STRING definitions
+///
+typedef struct {
+  // Public variables
+  EFI_STRING    String;           ///< String that is maintained here, and futures
+                                  ///< calls will append to it.
+  UINTN         StringLength;     ///< Length of String.
+
+  // Private variables
+  UINTN         PrivateBufferSize; ///< Length of allocated String. This reduces
+                                   ///< reallocations as strings are appended.
+} HII_STRING;
+
+#define FIXED_STR_LEN(String)  (sizeof (String) / sizeof (CHAR16) - 1)
+
+typedef enum {
+  ELEMENT_GUID_HDR   = 0,
+  ELEMENT_NAME_HDR   = 1,
+  ELEMENT_PATH_HDR   = 2,
+  ELEMENT_OFFSET_HDR = 3,
+  ELEMENT_WIDTH_HDR  = 4,
+  ELEMENT_VALUE_HDR  = 5
+} ELEMENT_HDR;
+
+typedef struct {
+  EFI_STRING    ElementString;
+  UINTN         ElementLength;
+} HII_ELEMENT;
+
+/**
+  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_NOT_FOUND           Target for the specified routing data was not
+                                  found. Progress points to the "G" in "GUID" of
+                                  the errant routing data.
+  @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
+  );
+
+/**
+  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 largest index of
+                                  the modified byte in the Block, or the required
+                                  buffer.
+                                  size if the Block is not large enough.
+  @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_NOT_FOUND           Target for the specified routing data was not
+                                  found. Progress points to the "G" in "GUID" of
+                                  the errant routing data.
+  @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>.
+  @retval EFI_BUFFER_TOO_SMALL    Block not large enough. Progress undefined.
+                                  BlockSize is updated with the required buffer
+                                  size.
+
+**/
+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
+  );
+
+#endif // AMD_HII_CONFIG_ROUTING_H_
diff --git a/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRoutingEntry.c b/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRoutingEntry.c
new file mode 100644
index 0000000000..39dd2cdca4
--- /dev/null
+++ b/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRoutingEntry.c
@@ -0,0 +1,45 @@
+/** @file
+  AMD implementation of interface functions for EFI_HII_CONFIG_ROUTING_PROTOCOL.
+  This module overrides BlockToConfig and ConfigToBlock for the better performance.
+
+  Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "AmdHiiConfigRouting.h"
+
+EFI_STATUS
+EFIAPI
+AmdConfigRoutingEntry (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS                       Status;
+  EFI_HII_CONFIG_ROUTING_PROTOCOL  *HiiConfigRouting = NULL;
+
+  Status = gBS->LocateProtocol (
+                  &gEfiHiiConfigRoutingProtocolGuid,
+                  NULL,
+                  (VOID **)&HiiConfigRouting
+                  );
+  if (!EFI_ERROR (Status)) {
+    ASSERT (HiiConfigRouting != NULL);
+    DEBUG ((
+      DEBUG_INFO,
+      "HiiConfigRouting->BlockToConfig: 0x%lX\n",
+      (UINTN)HiiBlockToConfig
+      ));
+    DEBUG ((
+      DEBUG_INFO,
+      "HiiConfigRouting->ConfigToBlock: 0x%lX\n",
+      (UINTN)HiiConfigToBlock
+      ));
+
+    HiiConfigRouting->BlockToConfig = HiiBlockToConfig;
+    HiiConfigRouting->ConfigToBlock = HiiConfigToBlock;
+  }
+
+  return Status;
+}
diff --git a/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdHiiConfigRouting.c b/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdHiiConfigRouting.c
new file mode 100644
index 0000000000..bec64bec5f
--- /dev/null
+++ b/Platform/AMD/AmdPlatformPkg/Universal/HiiConfigRouting/AmdHiiConfigRouting.c
@@ -0,0 +1,1098 @@
+/** @file
+  AMD implementation of interfaces function for EFI_HII_CONFIG_ROUTING_PROTOCOL.
+  This file provides better performance of BlockToConfig and ConfigToBlock
+  functions.
+
+  Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+  Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "AmdHiiConfigRouting.h"
+
+HII_ELEMENT  gElementInfo[] = {
+  { L"GUID=",   FIXED_STR_LEN (L"GUID=")   },
+  { L"NAME=",   FIXED_STR_LEN (L"NAME=")   },
+  { L"PATH=",   FIXED_STR_LEN (L"PATH=")   },
+  { L"OFFSET=", FIXED_STR_LEN (L"OFFSET=") },
+  { L"WIDTH=",  FIXED_STR_LEN (L"WIDTH=")  },
+  { L"VALUE=",  FIXED_STR_LEN (L"VALUE=")  }
+};
+
+/**
+  Converts the unicode character of the string from uppercase to lowercase.
+  This is a internal function.
+
+  @param ConfigString  String to be converted
+
+**/
+VOID
+EFIAPI
+HiiToLower (
+  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;
+}
+
+//
+// Updated EDK2 functions to improve performance.
+//
+
+/**
+  Returns the length of a Null-terminated Unicode string.
+
+  This function returns the number of Unicode characters in the Null-terminated
+  Unicode string specified by String.
+
+  @param  String  A pointer to a Null-terminated Unicode string.
+
+  @retval The length of String.
+
+**/
+UINTN
+EFIAPI
+HiiStrLen (
+  IN EFI_STRING  String
+  )
+{
+  UINTN  Length;
+
+  ASSERT (String != NULL);
+
+  for (Length = 0; String[Length] != L'\0'; Length++) {
+  }
+
+  //
+  // If PcdMaximumUnicodeStringLength is not zero,
+  // length should not more than PcdMaximumUnicodeStringLength
+  //
+  if (PcdGet32 (PcdMaximumUnicodeStringLength) != 0) {
+    ASSERT (Length < PcdGet32 (PcdMaximumUnicodeStringLength));
+  }
+
+  return Length;
+}
+
+/**
+  Compares up to a specified length the contents of two Null-terminated Unicode
+  strings, and returns the difference between the first mismatched Unicode
+  characters.
+
+  This function compares the Null-terminated Unicode string FirstString to the
+  Null-terminated Unicode string SecondString. At most, Length Unicode
+  characters will be compared. If Length is 0, then 0 is returned. If
+  FirstString is identical to SecondString, then 0 is returned. Otherwise, the
+  value returned is the first mismatched Unicode character in SecondString
+  subtracted from the first mismatched Unicode character in FirstString.
+
+  @param[in]  FirstString   A pointer to a Null-terminated Unicode string.
+  @param[in]  SecondString  A pointer to a Null-terminated Unicode string.
+  @param[in]  Length        The maximum number of Unicode characters to compare.
+
+  @retval 0      FirstString is identical to SecondString.
+  @retval others FirstString is not identical to SecondString.
+
+**/
+INTN
+EFIAPI
+HiiStrnCmp (
+  IN EFI_STRING  FirstString,
+  IN EFI_STRING  SecondString,
+  IN UINTN       Length
+  )
+{
+  if (Length == 0) {
+    return 0;
+  }
+
+  ASSERT (FirstString != NULL);
+  ASSERT (SecondString != NULL);
+  if (PcdGet32 (PcdMaximumUnicodeStringLength) != 0) {
+    ASSERT (Length <= PcdGet32 (PcdMaximumUnicodeStringLength));
+  }
+
+  while ((*FirstString != L'\0') &&
+         (*SecondString != L'\0') &&
+         (*FirstString == *SecondString) &&
+         (Length > 1))
+  {
+    FirstString++;
+    SecondString++;
+    Length--;
+  }
+
+  return *FirstString - *SecondString;
+}
+
+/**
+  Initializes HII_NUMBER instance to 0.
+
+  @param[in]  This    Pointer to HII_NUMBER instances.
+
+**/
+VOID
+HiiNumberInit (
+  IN OUT HII_NUMBER  *This
+  )
+{
+  ASSERT (This != NULL);
+
+  This->NumberPtr         = 0;
+  This->NumberPtrLength   = 0;
+  This->Value             = 0;
+  This->PrivateBufferSize = 0;
+}
+
+/**
+  Frees buffer in HII_NUMBER instance.
+
+  @param[in]  This    Pointer to HII_NUMBER instance.
+
+**/
+VOID
+HiiNumberFree (
+  IN OUT HII_NUMBER  *This
+  )
+{
+  ASSERT (This != NULL);
+
+  if (This->NumberPtr != NULL) {
+    FreePool (This->NumberPtr);
+    This->NumberPtr         = NULL;
+    This->PrivateBufferSize = 0;
+  }
+}
+
+/**
+  If buffer doesn't exist, allocate it. If the existing buffer is less than
+  requested, allocate a larger one.
+
+  @param[in]  This    Pointer to HII_NUMBER instance.
+  @param[in]  Size    Requested buffer size.
+
+  @retval EFI_SUCCESS           Buffer allocated.
+  @retval EFI_OUT_OF_RESOURCES  OUt of memory.
+
+**/
+EFI_STATUS
+HiiNumberSetMinBufferSize (
+  IN OUT HII_NUMBER  *This,
+  IN UINTN           Size
+  )
+{
+  ASSERT (This != NULL);
+
+  if (This->PrivateBufferSize < Size) {
+    Size           += MAX_STRING_LENGTH;
+    This->NumberPtr = ReallocatePool (This->PrivateBufferSize, Size, This->NumberPtr);
+    if (This->NumberPtr == NULL) {
+      This->PrivateBufferSize = 0;
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    This->PrivateBufferSize = Size;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Get value of number from string and update HII_NUMBER instance.
+
+  @param[in]  This    Pointer to HII_NUMBER instance.
+  @param[in]  String  String to get value from. String may end in \0 or &.
+
+  @retval EFI_SUCCESS           Buffer allocated.
+  @retval EFI_OUT_OF_RESOURCES  OUt of memory.
+
+**/
+EFI_STATUS
+GetValueOfNumber (
+  IN OUT HII_NUMBER  *This,
+  IN EFI_STRING      String
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       Index;
+  UINTN       StringLength;
+  UINTN       NumLen;
+  CHAR16      Digit;
+  UINT8       DigitUint8;
+  EFI_STRING  EndOfString;
+
+  if ((This == NULL) || (String == NULL) || (*String == L'\0')) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  EndOfString  = String;
+  StringLength = 0;
+
+  while (*EndOfString != L'\0' && *EndOfString != L'&') {
+    EndOfString++;
+    StringLength++;
+  }
+
+  This->StringLength = StringLength;
+
+  NumLen = (StringLength + 1) / 2;
+
+  Status = HiiNumberSetMinBufferSize (This, NumLen);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  for (Index = 0; Index < StringLength; Index++) {
+    Digit = String[StringLength - Index - 1];
+    if (Digit < L'0') {
+      DigitUint8 = 0;
+    } else if (Digit <= L'9') {
+      DigitUint8 = (UINT8)(Digit - L'0');
+    } else if (Digit < L'A') {
+      DigitUint8 = 0;
+    } else if (Digit <= L'F') {
+      DigitUint8 = (UINT8)(Digit - L'A' + 0xa);
+    } else if (Digit < L'a') {
+      DigitUint8 = 0;
+    } else if (Digit <= L'f') {
+      DigitUint8 = (UINT8)(Digit - L'a' + 0xa);
+    } else {
+      DigitUint8 = 0;
+    }
+
+    if ((Index & 1) == 0) {
+      This->NumberPtr[Index / 2] = DigitUint8;
+    } else {
+      This->NumberPtr[Index / 2] = (UINT8)((DigitUint8 << 4) + This->NumberPtr[Index / 2]);
+    }
+  }
+
+  This->NumberPtrLength = StringLength;
+  This->Value           = 0;
+
+  if (StringLength <= sizeof (UINTN) * sizeof (CHAR16)) {
+    CopyMem (
+      &This->Value,
+      This->NumberPtr,
+      NumLen < sizeof (UINTN) ? NumLen : sizeof (UINTN)
+      );
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Initializes HII_STRING instance allocating buffer.
+
+  @param[in]  This    Pointer to HII_STRING instance.
+  @param[in]  Size    Size of intitial allocation.
+
+  @retval EFI_SUCCESS           Allocated buffer successfully.
+  @retval EFI_OUT_OF_RESOURCES  Out of memory.
+**/
+EFI_STATUS
+HiiStringInit (
+  IN OUT HII_STRING  *This,
+  IN UINTN           Size
+  )
+{
+  ASSERT (This != NULL);
+
+  This->StringLength = 0;
+
+  if (Size == 0) {
+    This->String            = NULL;
+    This->PrivateBufferSize = 0;
+    return EFI_SUCCESS;
+  }
+
+  This->String = (EFI_STRING)AllocatePool (Size);
+
+  if (This->String != NULL) {
+    This->String[0]         = L'\0';
+    This->PrivateBufferSize = Size;
+  } else {
+    This->PrivateBufferSize = 0;
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Frees HiiString Buffer
+
+  @param[in]  This    Pointer to HII_STRING instance.
+
+**/
+VOID
+HiiStringFree (
+  IN OUT HII_STRING  *This
+  )
+{
+  ASSERT (This != NULL);
+
+  if (This->String != NULL) {
+    FreePool (This->String);
+    This->String            = NULL;
+    This->PrivateBufferSize = 0;
+  }
+}
+
+/**
+  If buffer doesn't exist, allocate it. If the existing buffer is less than
+  requested, allocate a larger one.
+
+  @param[in]  This    Pointer to HII_STRING instance.
+  @param[in]  Size    Requested buffer size.
+
+  @retval EFI_SUCCESS           Buffer allocated.
+  @retval EFI_OUT_OF_RESOURCES  OUt of memory.
+
+**/
+EFI_STATUS
+HiiStringSetMinBufferSize (
+  IN OUT HII_STRING  *This,
+  IN UINTN           Size
+  )
+{
+  UINTN       ThisStringSize = (This->StringLength + 1) * sizeof (CHAR16);
+  EFI_STRING  NewAlloc;
+
+  if (Size > This->PrivateBufferSize) {
+    NewAlloc = (EFI_STRING)AllocatePool (Size);
+    if (NewAlloc == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    CopyMem (NewAlloc, This->String, ThisStringSize);
+    FreePool (This->String);
+    This->String            = NewAlloc;
+    This->PrivateBufferSize = Size;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Append a string to the string in HII_STRING instance.
+
+  @param[in]  This    Pointer to HII_STRING instance.
+  @param[in]  String  String to append.
+
+  @retval EFI_SUCCESS           String is appended.
+  @retval EFI_OUT_OF_RESOURCES  OUt of memory.
+
+**/
+EFI_STATUS
+HiiStringAppend (
+  IN OUT HII_STRING  *This,
+  IN EFI_STRING      String
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       ThisStringSize;
+  UINTN       StringSize;
+  UINTN       MaxLen;
+
+  if ((This == NULL) || (String == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ThisStringSize = (This->StringLength + 1) * sizeof (CHAR16);
+  StringSize     = HiiStrSize (String);
+
+  if (ThisStringSize + StringSize > This->PrivateBufferSize) {
+    MaxLen = (ThisStringSize + StringSize) * 2;
+    Status = HiiStringSetMinBufferSize (This, MaxLen);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+
+  //
+  // Append the incoming string
+  //
+  CopyMem (&This->String[This->StringLength], String, StringSize);
+  This->StringLength += StringSize / sizeof (CHAR16) - 1;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Append a number converted to a string to the string in HII_STRING instance.
+
+  @param[in]  This    Pointer to HII_STRING instance.
+  @param[in]  Number  Pointer to Number.
+  @param[in]  Length  Length of Number
+
+  @retval EFI_SUCCESS           String is appended.
+  @retval EFI_OUT_OF_RESOURCES  OUt of memory.
+
+**/EFI_STATUS
+HiiStringAppendValue (
+  IN OUT  HII_STRING  *This,
+  IN      UINT8       *Number,
+  IN      UINTN       Length
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       ThisStringSize;
+  UINTN       Index;
+  UINTN       Index2;
+  UINT8       Nibble;
+  UINTN       MaxLen;
+
+  CHAR16  *String;
+
+  if (Length == 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ThisStringSize = (This->StringLength + 1) * sizeof (CHAR16);
+
+  if (ThisStringSize + Length * 2 * sizeof (CHAR16) > This->PrivateBufferSize) {
+    MaxLen = (ThisStringSize + Length * 2 * sizeof (CHAR16)) * 2; // Double requested string length.
+    Status = HiiStringSetMinBufferSize (This, MaxLen);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+
+  String              = This->String + This->StringLength;
+  This->StringLength += Length * 2;
+
+  Index = Length;
+
+  do {
+    Index--;
+    Nibble = Number[Index] >> 4;
+
+    for (Index2 = 0; Index2 < 2; Index2++) {
+      if (Nibble < 0xa) {
+        *String = '0' + Nibble;
+      } else {
+        *String = 'a' + Nibble - 0xa;
+      }
+
+      Nibble = Number[Index] & 0xf;
+      String++;
+    }
+  } while (Index > 0);
+
+  *String = '\0';
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Find an element header in the input string, and return pointer it is value.
+
+  This is a internal function.
+
+  @param[in]  Hdr           Element Header to sarch for.
+  @param[in]  String        Search for element header in this string.
+
+  @retval Pointer to value in element header.
+  @retval NULL if element header not found or end of string.
+
+**/
+EFI_STRING
+FindElmentValue (
+  IN ELEMENT_HDR  Hdr,
+  IN EFI_STRING   String
+  )
+{
+  ASSERT (String != NULL);
+
+  if (HiiStrnCmp (String, gElementInfo[Hdr].ElementString, gElementInfo[Hdr].ElementLength) != 0) {
+    return NULL;
+  }
+
+  return String + gElementInfo[Hdr].ElementLength;
+}
+
+/**
+  Find pointer after value for element header in string.
+
+  This is a internal function.
+
+  @param[in]  String    String to search.
+
+  @retval Pointer after value in element header.
+
+**/
+EFI_STRING
+SkipElementValue (
+  IN EFI_STRING  String
+  )
+{
+  ASSERT (String != NULL);
+
+  while (*String != 0 && *String != L'&') {
+    String++;
+  }
+
+  if (*String == L'&') {
+    String++;     // Skip '&'
+  }
+
+  return String;
+}
+
+/**
+  Return pointer after ConfigHdr.
+
+  This is a internal function.
+
+  @param[in]  String String to search.
+
+  @retval  Pointer after ConfigHdr.
+  @retval  NULL if Config header not formed correctly.
+
+**/
+EFI_STRING
+GetEndOfConfigHdr (
+  IN EFI_STRING  String
+  )
+{
+  ASSERT (String != NULL);
+
+  String = FindElmentValue (ELEMENT_GUID_HDR, String);
+  if (String == NULL) {
+    return NULL;
+  }
+
+  String = SkipElementValue (String);
+  if (*String == 0) {
+    return NULL;
+  }
+
+  while (*String != 0 &&
+         HiiStrnCmp (
+           String,
+           gElementInfo[ELEMENT_PATH_HDR].ElementString,
+           gElementInfo[ELEMENT_PATH_HDR].ElementLength
+           )
+         != 0)
+  {
+    String++;
+  }
+
+  if (*String != 0) {
+    String = String + gElementInfo[ELEMENT_PATH_HDR].ElementLength;
+  }
+
+  String = SkipElementValue (String);
+  return String;
+}
+
+/**
+  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[in]  This                   A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+                                 instance.
+  @param[in]  ConfigRequest          A null-terminated Unicode string in
+                                 <ConfigRequest> format.
+  @param[in]  Block                  Array of bytes defining the block's configuration.
+  @param[in]  BlockSize              Length in bytes of Block.
+  @param[out]  Config                 Filled-in configuration string. String allocated
+                                 by the function. Returned only if call is
+                                 successful. It is <ConfigResp> string format.
+  @param[out]  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
+  )
+{
+  EFI_STATUS  Status;
+  EFI_STRING  StringPtr;
+  EFI_STRING  OrigPtr;
+  CHAR16      CharBackup;
+  UINTN       Offset;
+  UINTN       Width;
+  UINT8       *Value;
+  HII_STRING  HiiString;
+  HII_NUMBER  HiiNumber;
+
+  if ((This == NULL) || (Progress == NULL) || (Config == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Block == NULL) || (ConfigRequest == NULL)) {
+    *Progress = ConfigRequest;
+    return EFI_INVALID_PARAMETER;
+  }
+
+  StringPtr = ConfigRequest;
+
+  Status = HiiStringInit (&HiiString, MAX_STRING_LENGTH);
+  if (EFI_ERROR (Status)) {
+    *Progress = ConfigRequest;
+    return Status;
+  }
+
+  HiiNumberInit (&HiiNumber);
+
+  //
+  // Jump <ConfigHdr>
+  //
+  StringPtr = GetEndOfConfigHdr (StringPtr);
+  if (StringPtr == NULL) {
+    //
+    //  Invalid header.
+    //
+    *Progress = ConfigRequest;
+    Status    = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  if (*StringPtr == L'\0') {
+    *Progress = StringPtr;
+    HiiStringAppend (&HiiString, ConfigRequest);
+    HiiToLower (HiiString.String);
+
+    //
+    // Do not free HiiString.String with HiiStringFree;
+    //
+    *Config = HiiString.String;
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Copy <ConfigHdr> and an additional '&' to <ConfigResp>
+  //
+  CharBackup   = StringPtr[0];
+  StringPtr[0] = L'\0';         // Temporarily change & to L'\0'
+  Status       = HiiStringAppend (&HiiString, ConfigRequest);
+  if (EFI_ERROR (Status)) {
+    *Progress = ConfigRequest;
+    goto Exit;
+  }
+
+  StringPtr[0] = CharBackup;
+
+  //
+  // Parse each <RequestElement> if exists
+  // Only <BlockName> format is supported by this help function.
+  // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>
+  //
+
+  //
+  // while search for "OFFSET="
+  // When "OFFSET=" is found, OrigPtr starts at "OFFSET=", and StringPtr points to value.
+  //
+  while (*StringPtr != 0 &&
+         (OrigPtr = StringPtr, (StringPtr = FindElmentValue (ELEMENT_OFFSET_HDR, StringPtr)) != NULL)
+         )
+  {
+    //
+    // Get Offset
+    //
+    Status = GetValueOfNumber (&HiiNumber, StringPtr);
+    if (EFI_ERROR (Status)) {
+      if (Status == EFI_OUT_OF_RESOURCES) {
+        *Progress = ConfigRequest;  // Out of memory
+      } else {
+        *Progress = OrigPtr - 1;
+      }
+
+      goto Exit;
+    }
+
+    Offset     = HiiNumber.Value;
+    StringPtr += HiiNumber.StringLength + 1;
+
+    //
+    // Get Width
+    //
+    StringPtr = FindElmentValue (ELEMENT_WIDTH_HDR, StringPtr);
+    if (StringPtr == NULL) {
+      *Progress = OrigPtr - 1;
+      Status    = EFI_INVALID_PARAMETER;
+      goto Exit;
+    }
+
+    Status = GetValueOfNumber (&HiiNumber, StringPtr);
+    if (EFI_ERROR (Status)) {
+      if (Status == EFI_OUT_OF_RESOURCES) {
+        *Progress = ConfigRequest;  // Out of memory
+      } else {
+        *Progress = OrigPtr - 1;
+      }
+
+      goto Exit;
+    }
+
+    Width      = HiiNumber.Value;
+    StringPtr += HiiNumber.StringLength;
+
+    if ((*StringPtr != 0) && (*StringPtr != L'&')) {
+      *Progress =  OrigPtr - 1;
+      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 *)Block + Offset;
+
+    CharBackup = *StringPtr;
+    *StringPtr = L'\0';
+
+    Status = HiiStringAppend (&HiiString, OrigPtr);
+    if (EFI_ERROR (Status)) {
+      *Progress = ConfigRequest;  // Out of memory
+      goto Exit;
+    }
+
+    *StringPtr = CharBackup;  // End of section of string OrigPtr
+
+    Status = HiiStringAppend (&HiiString, L"&VALUE=");
+    if (EFI_ERROR (Status)) {
+      *Progress = ConfigRequest;  // Out of memory
+      goto Exit;
+    }
+
+    Status = HiiStringAppendValue (&HiiString, Value, Width);
+    if (EFI_ERROR (Status)) {
+      if (Status == EFI_OUT_OF_RESOURCES) {
+        *Progress = ConfigRequest;  // Out of memory
+      } else {
+        *Progress =  OrigPtr - 1;
+      }
+
+      goto Exit;
+    }
+
+    //
+    // If L'\0', parsing is finished. Otherwise skip L'&' to continue
+    //
+    if (*StringPtr == L'\0') {
+      break;
+    }
+
+    Status = HiiStringAppend (&HiiString, L"&");
+    if (EFI_ERROR (Status)) {
+      *Progress = ConfigRequest;  // Out of memory
+      goto Exit;
+    }
+
+    StringPtr++;  // Skip L'&'
+  }
+
+  if (*StringPtr != L'\0') {
+    *Progress = StringPtr - 1;
+    Status    = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  HiiToLower (HiiString.String);
+  *Progress = StringPtr;
+
+  HiiNumberFree (&HiiNumber);
+
+  //
+  // Do not free HiiString.String with HiiStringFree. The caller will
+  // consume it when EFI_SUCCESS.
+  //
+  *Config = HiiString.String;
+
+  return EFI_SUCCESS;
+
+Exit:
+  HiiStringFree (&HiiString);
+  HiiNumberFree (&HiiNumber);
+
+  *Config = NULL;
+
+  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[in]  This                   A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+                                 instance.
+  @param[in]  ConfigResp             A null-terminated Unicode string in <ConfigResp>
+                                 format.
+  @param[in, out]  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[in, out]  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 largest index of the
+                                 modified byte in the Block, or the required buffer
+                                 size if the Block is not large enough.
+  @param[out]  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>.
+  @retval EFI_BUFFER_TOO_SMALL   Block not large enough. Progress undefined.
+                                 BlockSize is updated with the required buffer size.
+  @retval EFI_NOT_FOUND          Target for the specified routing data was not found.
+                                 Progress points to the "G" in "GUID" of the errant
+                                 routing data.
+
+**/
+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
+  )
+{
+  EFI_STATUS  Status;
+  EFI_STRING  StringPtr;
+  EFI_STRING  OrigPtr;
+  UINTN       Offset;
+  UINTN       Width;
+  UINTN       BufferSize;
+  UINTN       MaxBlockSize;
+  HII_NUMBER  HiiNumber;
+
+  if ((This == NULL) || (BlockSize == NULL) || (Progress == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *Progress = ConfigResp;
+  if (ConfigResp == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  StringPtr    = ConfigResp;
+  BufferSize   = *BlockSize;
+  MaxBlockSize = 0;
+
+  HiiNumberInit (&HiiNumber);
+  //
+  // Jump <ConfigHdr>
+  //
+  StringPtr = GetEndOfConfigHdr (StringPtr);
+  if (StringPtr == NULL) {
+    //
+    //  Invalid header.
+    //
+    *Progress = ConfigResp;
+    Status    = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  if (*StringPtr == L'\0') {
+    *Progress = StringPtr;
+    Status    = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  //
+  // Parse each <ConfigElement> if exists
+  // Only '&'<BlockConfig> format is supported by this help function.
+  // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
+  //
+  while (*StringPtr != L'\0' &&
+         (OrigPtr = StringPtr, (StringPtr = FindElmentValue (ELEMENT_OFFSET_HDR, StringPtr)) != NULL)
+         )
+  {
+    //
+    // Get Offset
+    //
+    Status = GetValueOfNumber (&HiiNumber, StringPtr);
+    if (EFI_ERROR (Status)) {
+      if (Status == EFI_OUT_OF_RESOURCES) {
+        *Progress = ConfigResp;  // Out of memory
+      } else {
+        *Progress = OrigPtr - 1;
+      }
+
+      goto Exit;
+    }
+
+    Offset     = HiiNumber.Value;
+    StringPtr += HiiNumber.StringLength + 1;
+
+    //
+    // Get Width
+    //
+    StringPtr = FindElmentValue (ELEMENT_WIDTH_HDR, StringPtr);
+    if (StringPtr == NULL) {
+      *Progress = OrigPtr - 1;
+      Status    = EFI_INVALID_PARAMETER;
+      goto Exit;
+    }
+
+    Status = GetValueOfNumber (&HiiNumber, StringPtr);
+    if (EFI_ERROR (Status)) {
+      if (Status == EFI_OUT_OF_RESOURCES) {
+        *Progress = ConfigResp;  // Out of memory
+      } else {
+        *Progress = OrigPtr - 1;
+      }
+
+      goto Exit;
+    }
+
+    Width      = HiiNumber.Value;
+    StringPtr += HiiNumber.StringLength + 1;
+
+    //
+    // Get Value
+    //
+    StringPtr = FindElmentValue (ELEMENT_VALUE_HDR, StringPtr);
+    if (StringPtr == NULL) {
+      *Progress = OrigPtr - 1;
+      Status    = EFI_INVALID_PARAMETER;
+      goto Exit;
+    }
+
+    Status = GetValueOfNumber (&HiiNumber, StringPtr);
+    if (EFI_ERROR (Status)) {
+      if (Status == EFI_OUT_OF_RESOURCES) {
+        *Progress = ConfigResp;  // Out of memory
+      } else {
+        *Progress = OrigPtr - 1;
+      }
+
+      goto Exit;
+    }
+
+    //
+    // Update the Block with configuration info
+    //
+    if ((Block != NULL) && (Offset + Width <= BufferSize)) {
+      CopyMem (Block + Offset, HiiNumber.NumberPtr, Width);
+    }
+
+    if (Offset + Width > MaxBlockSize) {
+      MaxBlockSize = Offset + Width;
+    }
+
+    StringPtr += HiiNumber.StringLength;
+
+    if ((*StringPtr != L'\0') && (*StringPtr != L'&')) {
+      *Progress = OrigPtr - 1;
+      Status    = EFI_INVALID_PARAMETER;
+      goto Exit;
+    }
+
+    //
+    // If L'\0', parsing is finished.
+    //
+    if (*StringPtr == L'\0') {
+      break;
+    }
+
+    StringPtr++;  // Skip L'&'
+  }
+
+  //
+  // The input string is not ConfigResp format, return error.
+  //
+  if (*StringPtr != L'\0') {
+    *Progress = StringPtr;
+    Status    = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  *Progress  = StringPtr + HiiStrLen (StringPtr);
+  *BlockSize = MaxBlockSize - 1;
+
+  if (MaxBlockSize > BufferSize) {
+    *BlockSize = MaxBlockSize;
+    if (Block != NULL) {
+      Status = EFI_BUFFER_TOO_SMALL;
+      goto Exit;
+    }
+  }
+
+  if (Block == NULL) {
+    *Progress = ConfigResp;
+    Status    = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  Status = EFI_SUCCESS;
+
+Exit:
+
+  HiiNumberFree (&HiiNumber);
+
+  return Status;
+}
-- 
2.37.1.windows.1


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2023-06-20  9:32 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-06-20  9:31 [edk2-platforms][PATCH 1/2] Platform/AMD: Initial commit of AmdPlatformPkg Chang, Abner
2023-06-20  9:31 ` [edk2-platforms][PATCH 2/2] AmdPlatformPkg/HiiConfigRouting: AMD HiiConfigRouting module Chang, Abner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox