/** @file
  AML Resource Data Code Generation.

  Copyright (c) 2020 - 2021, Arm Limited. All rights reserved.<BR>
  Copyright (C) 2023 - 2025 Advanced Micro Devices, Inc. All rights reserved.<BR>

  SPDX-License-Identifier: BSD-2-Clause-Patent

  @par Glossary:
  - Rd or RD   - Resource Data
  - Rds or RDS - Resource Data Small
  - Rdl or RDL - Resource Data Large
**/

#include <AmlNodeDefines.h>
#include <CodeGen/AmlResourceDataCodeGen.h>

#include <AmlCoreInterface.h>
#include <AmlDefines.h>
#include <Api/AmlApiHelper.h>
#include <Tree/AmlNode.h>
#include <ResourceData/AmlResourceData.h>

/** If ParentNode is not NULL, append RdNode.
    If NewRdNode is not NULL, update its value to RdNode.

  @param [in]  RdNode       Newly created Resource Data node.
                            RdNode is deleted if an error occurs.
  @param [in]  ParentNode   If not NULL, ParentNode must:
                             - be a NameOp node, i.e. have the AML_NAME_OP
                               opcode (cf "Name ()" ASL statement)
                             - contain a list of resource data elements
                               (cf "ResourceTemplate ()" ASL statement)
                            RdNode is then added at the end of the variable
                            list of resource data elements, but before the
                            "End Tag" Resource Data.
  @param [out] NewRdNode    If not NULL:
                             - and Success, contains RdNode.
                             - and Error, reset to NULL.

  @retval  EFI_SUCCESS            The function completed successfully.
  @retval  EFI_INVALID_PARAMETER  Invalid parameter.
**/
STATIC
EFI_STATUS
EFIAPI
LinkRdNode (
  IN  AML_DATA_NODE    *RdNode,
  IN  AML_OBJECT_NODE  *ParentNode,
  OUT AML_DATA_NODE    **NewRdNode
  )
{
  EFI_STATUS       Status;
  EFI_STATUS       Status1;
  AML_OBJECT_NODE  *BufferOpNode;

  if (NewRdNode != NULL) {
    *NewRdNode = NULL;
  }

  if (ParentNode != NULL) {
    // Check this is a NameOp node.
    if ((!AmlNodeHasOpCode (ParentNode, AML_NAME_OP, 0))) {
      ASSERT (0);
      Status = EFI_INVALID_PARAMETER;
      goto error_handler;
    }

    // Get the value which is represented as a BufferOp object node
    // which is the 2nd fixed argument (i.e. index 1).
    BufferOpNode = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument (
                                             ParentNode,
                                             EAmlParseIndexTerm1
                                             );
    if ((BufferOpNode == NULL)                                             ||
        (AmlGetNodeType ((AML_NODE_HANDLE)BufferOpNode) != EAmlNodeObject) ||
        (!AmlNodeHasOpCode (BufferOpNode, AML_BUFFER_OP, 0)))
    {
      ASSERT (0);
      Status = EFI_INVALID_PARAMETER;
      goto error_handler;
    }

    // Add RdNode as the last element, but before the EndTag.
    Status = AmlAppendRdNode (BufferOpNode, RdNode);
    if (EFI_ERROR (Status)) {
      ASSERT (0);
      goto error_handler;
    }
  }

  if (NewRdNode != NULL) {
    *NewRdNode = RdNode;
  }

  return EFI_SUCCESS;

error_handler:
  Status1 = AmlDeleteTree ((AML_NODE_HEADER *)RdNode);
  ASSERT_EFI_ERROR (Status1);
  // Return original error.
  return Status;
}

/** Construct the TypeSpecificFlags field for IO ranges.

  See ACPI 6.4 spec, s19.6.34 for more.

  @param [in]  IsaRanges            Possible values are:
                                     0-Reserved
                                     1-NonISAOnly
                                     2-ISAOnly
                                     3-EntireRange
                                    See ACPI 6.4 spec, s19.6.34 for more.
  @param [in]  IsDenseTranslation   TranslationDensity parameter.
  @param [in]  IsTypeStatic         TranslationType parameter.

  @return A type specific flags value.
          MAX_UINT8 if error.
**/
STATIC
UINT8
EFIAPI
RdIoRangeSpecificFlags (
  IN  UINT8    IsaRanges,
  IN  BOOLEAN  IsDenseTranslation,
  IN  BOOLEAN  IsTypeStatic
  )
{
  // Only check type specific parameters.
  if (IsaRanges > 3) {
    ASSERT (0);
    return MAX_UINT8;
  }

  // Construct TypeSpecificFlags and call the generic function.
  // Cf ACPI 6.4 specification, Table 6.50:
  // "Table 6.50: I/O Resource Flag (Resource Type = 1) Definitions"
  return IsaRanges                 |
         (IsTypeStatic ? 0 : BIT4) |
         (IsDenseTranslation ? 0 : BIT5);
}

/** Construct the TypeSpecificFlags field for Memory ranges.

  @param [in]  Cacheable            Possible values are:
                                    0-The memory is non-cacheable
                                    1-The memory is cacheable
                                    2-The memory is cacheable and supports
                                      write combining
                                    3-The memory is cacheable and prefetchable
  @param [in]  IsReadWrite          ReadAndWrite parameter.
  @param [in]  MemoryRangeType      Possible values are:
                                      0-AddressRangeMemory
                                      1-AddressRangeReserved
                                      2-AddressRangeACPI
                                      3-AddressRangeNVS
                                    See ACPI 6.4 spec, s19.6.35 for more.
  @param [in]  IsTypeStatic         TranslationType parameter.

  @return A type specific flags value.
          MAX_UINT8 if error.
**/
STATIC
UINT8
EFIAPI
MemoryRangeSpecificFlags (
  IN  UINT8    Cacheable,
  IN  BOOLEAN  IsReadWrite,
  IN  UINT8    MemoryRangeType,
  IN  BOOLEAN  IsTypeStatic
  )
{
  // Only check type specific parameters.
  if ((Cacheable > 3) ||
      (MemoryRangeType > 3))
  {
    ASSERT (0);
    return MAX_UINT8;
  }

  // Construct TypeSpecificFlags and call the generic function.
  // Cf ACPI 6.4 specification, Table 6.49:
  // "Memory Resource Flag (Resource Type = 0) Definitions"
  return (IsReadWrite ? BIT0 : 0)  |
         (Cacheable << 1)          |
         (MemoryRangeType << 3)    |
         (IsTypeStatic ? 0 : BIT5);
}

/** Construct the GeneralFlags field of any Address Space Resource Descriptors.

  E.g.:
  ACPI 6.4 specification, s6.4.3.5.1 "QWord Address Space Descriptor"
  for QWord

  See ACPI 6.4 spec, s19.6.36 for more.

  @param [in]  IsPosDecode          Decode parameter
  @param [in]  IsMinFixed           Minimum address is fixed.
  @param [in]  IsMaxFixed           Maximum address is fixed.

  @return A type specific flags value.
**/
STATIC
UINT8
EFIAPI
AddressSpaceGeneralFlags (
  IN  BOOLEAN  IsPosDecode,
  IN  BOOLEAN  IsMinFixed,
  IN  BOOLEAN  IsMaxFixed
  )
{
  return (IsPosDecode ? 0 : BIT1)    |
         (IsMinFixed ? BIT2 : 0)     |
         (IsMaxFixed ? BIT3 : 0);
}

/** Check Address Space Descriptor Fields.

  Cf. ACPI 6.4 Table 6.44:
  "Valid Combination of Address Space Descriptor Fields"

  See ACPI 6.4 spec, s19.6.36 for more.

  @param [in]  IsMinFixed           Minimum address is fixed.
  @param [in]  IsMaxFixed           Maximum address is fixed.
  @param [in]  AddressGranularity   Address granularity.
  @param [in]  AddressMinimum       Minimum address.
  @param [in]  AddressMaximum       Maximum address.
  @param [in]  AddressTranslation   Address translation.
  @param [in]  RangeLength          Range length.

  @retval EFI_SUCCESS             The function completed successfully.
  @retval EFI_INVALID_PARAMETER   Invalid parameter.
**/
STATIC
EFI_STATUS
EFIAPI
CheckAddressSpaceFields (
  IN  BOOLEAN  IsMinFixed,
  IN  BOOLEAN  IsMaxFixed,
  IN  UINT64   AddressGranularity,
  IN  UINT64   AddressMinimum,
  IN  UINT64   AddressMaximum,
  IN  UINT64   AddressTranslation,
  IN  UINT64   RangeLength
  )
{
  if ((AddressMinimum > AddressMaximum)                     ||
      (RangeLength > (AddressMaximum - AddressMinimum + 1)) ||
      ((AddressGranularity != 0) &&
       (((AddressGranularity + 1) & AddressGranularity) != 0)))
  {
    ASSERT (0);
    return EFI_INVALID_PARAMETER;
  }

  if (RangeLength != 0) {
    if (IsMinFixed ^ IsMaxFixed) {
      ASSERT (0);
      return EFI_INVALID_PARAMETER;
    } else if (IsMinFixed                 &&
               IsMaxFixed                 &&
               (AddressGranularity != 0)  &&
               ((AddressMaximum - AddressMinimum + 1) != RangeLength))
    {
      ASSERT (0);
      return EFI_INVALID_PARAMETER;
    }
  } else {
    if (IsMinFixed && IsMaxFixed) {
      ASSERT (0);
      return EFI_INVALID_PARAMETER;
    } else if (IsMinFixed &&
               ((AddressMinimum & AddressGranularity) != 0))
    {
      ASSERT (0);
      return EFI_INVALID_PARAMETER;
    } else if (IsMaxFixed &&
               (((AddressMaximum + 1) & AddressGranularity) != 0))
    {
      ASSERT (0);
      return EFI_INVALID_PARAMETER;
    }
  }

  return EFI_SUCCESS;
}

/** Code generation for the "DWordSpace ()" ASL function.

  The Resource Data effectively created is a DWord Address Space Resource
  Data. Cf ACPI 6.4:
   - s6.4.3.5.2 "DWord Address Space Descriptor".
   - s19.6.36 "DWordSpace".

  The created resource data node can be:
   - appended to the list of resource data elements of the NameOpNode.
     In such case NameOpNode must be defined by a the "Name ()" ASL statement
     and initially contain a "ResourceTemplate ()".
   - returned through the NewRdNode parameter.

  See ACPI 6.4 spec, s19.6.36 for more.

  @param [in]  ResourceType         Resource type.
                                    Possible values are:
                                      0:        Memory range
                                      1:        I/O range
                                      2:        Bus number range
                                      3-191:    Reserved
                                      192-255:  Hardware Vendor Defined
                                    See ACPI 6.4 spec, s6.4.3.5.2 for more.
  @param [in]  IsResourceConsumer   ResourceUsage parameter.
  @param [in]  IsPosDecode          Decode parameter
  @param [in]  IsMinFixed           Minimum address is fixed.
  @param [in]  IsMaxFixed           Maximum address is fixed.
  @param [in]  TypeSpecificFlags    Type specific flags.
                                    See ACPI 6.4 spec, s6.4.3.5.5
                                    "Resource Type Specific Flags".
  @param [in]  AddressGranularity   Address granularity.
  @param [in]  AddressMinimum       Minimum address.
  @param [in]  AddressMaximum       Maximum address.
  @param [in]  AddressTranslation   Address translation.
  @param [in]  RangeLength          Range length.
  @param [in]  ResourceSourceIndex  Resource Source index.
                                    Unused. Must be 0.
  @param [in]  ResourceSource       Resource Source.
                                    Unused. Must be NULL.
  @param [in]  NameOpNode           NameOp object node defining a named object.
                                    If provided, append the new resource data
                                    node to the list of resource data elements
                                    of this node.
  @param [out] NewRdNode            If provided and success,
                                    contain the created node.

  @retval EFI_SUCCESS             The function completed successfully.
  @retval EFI_INVALID_PARAMETER   Invalid parameter.
  @retval EFI_OUT_OF_RESOURCES    Could not allocate memory.
**/
STATIC
EFI_STATUS
EFIAPI
AmlCodeGenRdDWordSpace (
  IN        UINT8 ResourceType,
  IN        BOOLEAN IsResourceConsumer,
  IN        BOOLEAN IsPosDecode,
  IN        BOOLEAN IsMinFixed,
  IN        BOOLEAN IsMaxFixed,
  IN        UINT8 TypeSpecificFlags,
  IN        UINT32 AddressGranularity,
  IN        UINT32 AddressMinimum,
  IN        UINT32 AddressMaximum,
  IN        UINT32 AddressTranslation,
  IN        UINT32 RangeLength,
  IN        UINT8 ResourceSourceIndex,
  IN  CONST CHAR8 *ResourceSource,
  IN        AML_OBJECT_NODE_HANDLE NameOpNode, OPTIONAL
  OUT       AML_DATA_NODE_HANDLE    *NewRdNode  OPTIONAL
  )
{
  EFI_STATUS                               Status;
  AML_DATA_NODE                            *RdNode;
  EFI_ACPI_DWORD_ADDRESS_SPACE_DESCRIPTOR  RdDWord;

  // ResourceSource and ResourceSourceIndex are unused.
  if ((TypeSpecificFlags == MAX_UINT8)  ||
      (ResourceSourceIndex != 0)        ||
      (ResourceSource != NULL)          ||
      ((NameOpNode == NULL) && (NewRdNode == NULL)))
  {
    ASSERT (0);
    return EFI_INVALID_PARAMETER;
  }

  Status = CheckAddressSpaceFields (
             IsMinFixed,
             IsMaxFixed,
             AddressGranularity,
             AddressMinimum,
             AddressMaximum,
             AddressTranslation,
             RangeLength
             );
  if (EFI_ERROR (Status)) {
    ASSERT (0);
    return Status;
  }

  // Header
  RdDWord.Header.Header.Bits.Name =
    ACPI_LARGE_DWORD_ADDRESS_SPACE_DESCRIPTOR_NAME;
  RdDWord.Header.Header.Bits.Type = ACPI_LARGE_ITEM_FLAG;
  RdDWord.Header.Length           = sizeof (EFI_ACPI_DWORD_ADDRESS_SPACE_DESCRIPTOR) -
                                    sizeof (ACPI_LARGE_RESOURCE_HEADER);

  // Body
  RdDWord.ResType = ResourceType;
  RdDWord.GenFlag = AddressSpaceGeneralFlags (
                      IsPosDecode,
                      IsMinFixed,
                      IsMaxFixed
                      );
  RdDWord.SpecificFlag          = TypeSpecificFlags;
  RdDWord.AddrSpaceGranularity  = AddressGranularity;
  RdDWord.AddrRangeMin          = AddressMinimum;
  RdDWord.AddrRangeMax          = AddressMaximum;
  RdDWord.AddrTranslationOffset = AddressTranslation;
  RdDWord.AddrLen               = RangeLength;

  Status = AmlCreateDataNode (
             EAmlNodeDataTypeResourceData,
             (UINT8 *)&RdDWord,
             sizeof (EFI_ACPI_DWORD_ADDRESS_SPACE_DESCRIPTOR),
             &RdNode
             );
  if (EFI_ERROR (Status)) {
    ASSERT (0);
    return Status;
  }

  return LinkRdNode (RdNode, NameOpNode, NewRdNode);
}

/** Code generation for the "DWordIO ()" ASL function.

  The Resource Data effectively created is a DWord Address Space Resource
  Data. Cf ACPI 6.4:
   - s6.4.3.5.2 "DWord Address Space Descriptor".
   - s19.6.34 "DWordIO".

  The created resource data node can be:
   - appended to the list of resource data elements of the NameOpNode.
     In such case NameOpNode must be defined by a the "Name ()" ASL statement
     and initially contain a "ResourceTemplate ()".
   - returned through the NewRdNode parameter.

  See ACPI 6.4 spec, s19.6.34 for more.

  @param [in]  IsResourceConsumer   ResourceUsage parameter.
  @param [in]  IsMinFixed           Minimum address is fixed.
  @param [in]  IsMaxFixed           Maximum address is fixed.
  @param [in]  IsPosDecode          Decode parameter
  @param [in]  IsaRanges            Possible values are:
                                     0-Reserved
                                     1-NonISAOnly
                                     2-ISAOnly
                                     3-EntireRange
  @param [in]  AddressGranularity   Address granularity.
  @param [in]  AddressMinimum       Minimum address.
  @param [in]  AddressMaximum       Maximum address.
  @param [in]  AddressTranslation   Address translation.
  @param [in]  RangeLength          Range length.
  @param [in]  ResourceSourceIndex  Resource Source index.
                                    Unused. Must be 0.
  @param [in]  ResourceSource       Resource Source.
                                    Unused. Must be NULL.
  @param [in]  IsDenseTranslation   TranslationDensity parameter.
  @param [in]  IsTypeStatic         TranslationType parameter.
  @param [in]  NameOpNode           NameOp object node defining a named object.
                                    If provided, append the new resource data
                                    node to the list of resource data elements
                                    of this node.
  @param [out] NewRdNode            If provided and success,
                                    contain the created node.

  @retval EFI_SUCCESS             The function completed successfully.
  @retval EFI_INVALID_PARAMETER   Invalid parameter.
  @retval EFI_OUT_OF_RESOURCES    Could not allocate memory.
**/
EFI_STATUS
EFIAPI
AmlCodeGenRdDWordIo (
  IN        BOOLEAN IsResourceConsumer,
  IN        BOOLEAN IsMinFixed,
  IN        BOOLEAN IsMaxFixed,
  IN        BOOLEAN IsPosDecode,
  IN        UINT8 IsaRanges,
  IN        UINT32 AddressGranularity,
  IN        UINT32 AddressMinimum,
  IN        UINT32 AddressMaximum,
  IN        UINT32 AddressTranslation,
  IN        UINT32 RangeLength,
  IN        UINT8 ResourceSourceIndex,
  IN  CONST CHAR8 *ResourceSource,
  IN        BOOLEAN IsDenseTranslation,
  IN        BOOLEAN IsTypeStatic,
  IN        AML_OBJECT_NODE_HANDLE NameOpNode, OPTIONAL
  OUT       AML_DATA_NODE_HANDLE    *NewRdNode  OPTIONAL
  )
{
  return AmlCodeGenRdDWordSpace (
           ACPI_ADDRESS_SPACE_TYPE_IO,
           IsResourceConsumer,
           IsPosDecode,
           IsMinFixed,
           IsMaxFixed,
           RdIoRangeSpecificFlags (
             IsaRanges,
             IsDenseTranslation,
             IsTypeStatic
             ),
           AddressGranularity,
           AddressMinimum,
           AddressMaximum,
           AddressTranslation,
           RangeLength,
           ResourceSourceIndex,
           ResourceSource,
           NameOpNode,
           NewRdNode
           );
}

/** Code generation for the "DWordMemory ()" ASL function.

  The Resource Data effectively created is a DWord Address Space Resource
  Data. Cf ACPI 6.4:
   - s6.4.3.5.2 "DWord Address Space Descriptor".
   - s19.6.35 "DWordMemory".

  The created resource data node can be:
   - appended to the list of resource data elements of the NameOpNode.
     In such case NameOpNode must be defined by a the "Name ()" ASL statement
     and initially contain a "ResourceTemplate ()".
   - returned through the NewRdNode parameter.

  See ACPI 6.4 spec, s19.6.35 for more.

  @param [in]  IsResourceConsumer   ResourceUsage parameter.
  @param [in]  IsPosDecode          Decode parameter
  @param [in]  IsMinFixed           Minimum address is fixed.
  @param [in]  IsMaxFixed           Maximum address is fixed.
  @param [in]  Cacheable            Possible values are:
                                    0-The memory is non-cacheable
                                    1-The memory is cacheable
                                    2-The memory is cacheable and supports
                                      write combining
                                    3-The memory is cacheable and prefetchable
  @param [in]  IsReadWrite          ReadAndWrite parameter.
  @param [in]  AddressGranularity   Address granularity.
  @param [in]  AddressMinimum       Minimum address.
  @param [in]  AddressMaximum       Maximum address.
  @param [in]  AddressTranslation   Address translation.
  @param [in]  RangeLength          Range length.
  @param [in]  ResourceSourceIndex  Resource Source index.
                                    Unused. Must be 0.
  @param [in]  ResourceSource       Resource Source.
                                    Unused. Must be NULL.
  @param [in]  MemoryRangeType      Possible values are:
                                      0-AddressRangeMemory
                                      1-AddressRangeReserved
                                      2-AddressRangeACPI
                                      3-AddressRangeNVS
  @param [in]  IsTypeStatic         TranslationType parameter.
  @param [in]  NameOpNode           NameOp object node defining a named object.
                                    If provided, append the new resource data
                                    node to the list of resource data elements
                                    of this node.
  @param [out] NewRdNode            If provided and success,
                                    contain the created node.

  @retval EFI_SUCCESS             The function completed successfully.
  @retval EFI_INVALID_PARAMETER   Invalid parameter.
  @retval EFI_OUT_OF_RESOURCES    Could not allocate memory.
**/
EFI_STATUS
EFIAPI
AmlCodeGenRdDWordMemory (
  IN        BOOLEAN IsResourceConsumer,
  IN        BOOLEAN IsPosDecode,
  IN        BOOLEAN IsMinFixed,
  IN        BOOLEAN IsMaxFixed,
  IN        AML_MEMORY_ATTRIBUTES_MEM Cacheable,
  IN        BOOLEAN IsReadWrite,
  IN        UINT32 AddressGranularity,
  IN        UINT32 AddressMinimum,
  IN        UINT32 AddressMaximum,
  IN        UINT32 AddressTranslation,
  IN        UINT32 RangeLength,
  IN        UINT8 ResourceSourceIndex,
  IN  CONST CHAR8 *ResourceSource,
  IN        AML_MEMORY_ATTRIBUTES_MTP MemoryRangeType,
  IN        BOOLEAN IsTypeStatic,
  IN        AML_OBJECT_NODE_HANDLE NameOpNode, OPTIONAL
  OUT       AML_DATA_NODE_HANDLE    *NewRdNode  OPTIONAL
  )
{
  return AmlCodeGenRdDWordSpace (
           ACPI_ADDRESS_SPACE_TYPE_MEM,
           IsResourceConsumer,
           IsPosDecode,
           IsMinFixed,
           IsMaxFixed,
           MemoryRangeSpecificFlags (
             Cacheable,
             IsReadWrite,
             MemoryRangeType,
             IsTypeStatic
             ),
           AddressGranularity,
           AddressMinimum,
           AddressMaximum,
           AddressTranslation,
           RangeLength,
           ResourceSourceIndex,
           ResourceSource,
           NameOpNode,
           NewRdNode
           );
}

/** Code generation for the "Memory32Fixed ()" ASL macro.

  The Resource Data effectively created is a 32-bit Memory Resource
  Data. Cf ACPI 6.4:
   - s19.6.83 "Memory Resource Descriptor Macro".
   - s19.2.8 "Memory32FixedTerm".

  See ACPI 6.4 spec, s19.2.8 for more.

  @param [in]  IsReadWrite          ReadAndWrite parameter.
  @param [in]  Address              AddressBase parameter.
  @param [in]  RangeLength          Range length.
  @param [in]  NameOpNode           NameOp object node defining a named object.
                                    If provided, append the new resource data
                                    node to the list of resource data elements
                                    of this node.
  @param [out] NewMemNode           If provided and success,
                                    contain the created node.

  @retval EFI_SUCCESS             The function completed successfully.
  @retval EFI_INVALID_PARAMETER   Invalid parameter.
  @retval EFI_OUT_OF_RESOURCES    Could not allocate memory.
**/
EFI_STATUS
EFIAPI
AmlCodeGenRdMemory32Fixed (
  BOOLEAN                 IsReadWrite,
  UINT32                  Address,
  UINT32                  RangeLength,
  AML_OBJECT_NODE_HANDLE  NameOpNode,
  AML_DATA_NODE_HANDLE    *NewMemNode
  )
{
  EFI_STATUS                                     Status;
  AML_DATA_NODE                                  *MemNode;
  EFI_ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR  RangeDesc;

  RangeDesc.Header.Header.Byte = ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR;
  RangeDesc.Header.Length      = sizeof (EFI_ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR) -
                                 sizeof (ACPI_LARGE_RESOURCE_HEADER);
  RangeDesc.Information = IsReadWrite ? BIT0 : 0;
  RangeDesc.BaseAddress = Address;
  RangeDesc.Length      = RangeLength;

  Status = AmlCreateDataNode (
             EAmlNodeDataTypeResourceData,
             (UINT8 *)&RangeDesc,
             sizeof (RangeDesc),
             &MemNode
             );
  if (EFI_ERROR (Status)) {
    ASSERT (0);
    return Status;
  }

  return LinkRdNode (MemNode, NameOpNode, NewMemNode);
}

/** Code generation for the "WordSpace ()" ASL function.

  The Resource Data effectively created is a Word Address Space Resource
  Data. Cf ACPI 6.4:
   - s6.4.3.5.3 "Word Address Space Descriptor".
   - s19.6.151 "WordSpace".

  The created resource data node can be:
   - appended to the list of resource data elements of the NameOpNode.
     In such case NameOpNode must be defined by a the "Name ()" ASL statement
     and initially contain a "ResourceTemplate ()".
   - returned through the NewRdNode parameter.

  See ACPI 6.4 spec, s19.6.151 for more.

  @param [in]  ResourceType         Resource type.
                                    Possible values are:
                                      0:        Memory range
                                      1:        I/O range
                                      2:        Bus number range
                                      3-191:    Reserved
                                      192-255:  Hardware Vendor Defined
                                    See ACPI 6.4 spec, s6.4.3.5.3 for more.
  @param [in]  IsResourceConsumer   ResourceUsage parameter.
  @param [in]  IsPosDecode          Decode parameter
  @param [in]  IsMinFixed           Minimum address is fixed.
  @param [in]  IsMaxFixed           Maximum address is fixed.
  @param [in]  TypeSpecificFlags    Type specific flags.
                                    See ACPI 6.4 spec, s6.4.3.5.5
                                    "Resource Type Specific Flags".
  @param [in]  AddressGranularity   Address granularity.
  @param [in]  AddressMinimum       Minimum address.
  @param [in]  AddressMaximum       Maximum address.
  @param [in]  AddressTranslation   Address translation.
  @param [in]  RangeLength          Range length.
  @param [in]  ResourceSourceIndex  Resource Source index.
                                    Unused. Must be 0.
  @param [in]  ResourceSource       Resource Source.
                                    Unused. Must be NULL.
  @param [in]  NameOpNode           NameOp object node defining a named object.
                                    If provided, append the new resource data
                                    node to the list of resource data elements
                                    of this node.
  @param [out] NewRdNode            If provided and success,
                                    contain the created node.

  @retval EFI_SUCCESS             The function completed successfully.
  @retval EFI_INVALID_PARAMETER   Invalid parameter.
  @retval EFI_OUT_OF_RESOURCES    Could not allocate memory.
**/
STATIC
EFI_STATUS
EFIAPI
AmlCodeGenRdWordSpace (
  IN        UINT8 ResourceType,
  IN        BOOLEAN IsResourceConsumer,
  IN        BOOLEAN IsPosDecode,
  IN        BOOLEAN IsMinFixed,
  IN        BOOLEAN IsMaxFixed,
  IN        UINT8 TypeSpecificFlags,
  IN        UINT16 AddressGranularity,
  IN        UINT16 AddressMinimum,
  IN        UINT16 AddressMaximum,
  IN        UINT16 AddressTranslation,
  IN        UINT16 RangeLength,
  IN        UINT8 ResourceSourceIndex,
  IN  CONST CHAR8 *ResourceSource,
  IN        AML_OBJECT_NODE_HANDLE NameOpNode, OPTIONAL
  OUT       AML_DATA_NODE_HANDLE    *NewRdNode  OPTIONAL
  )
{
  EFI_STATUS                              Status;
  AML_DATA_NODE                           *RdNode;
  EFI_ACPI_WORD_ADDRESS_SPACE_DESCRIPTOR  Rdword;

  // ResourceSource and ResourceSourceIndex are unused.
  if ((TypeSpecificFlags == MAX_UINT8)  ||
      (ResourceSourceIndex != 0)        ||
      (ResourceSource != NULL)          ||
      ((NameOpNode == NULL) && (NewRdNode == NULL)))
  {
    ASSERT (0);
    return EFI_INVALID_PARAMETER;
  }

  Status = CheckAddressSpaceFields (
             IsMinFixed,
             IsMaxFixed,
             AddressGranularity,
             AddressMinimum,
             AddressMaximum,
             AddressTranslation,
             RangeLength
             );
  if (EFI_ERROR (Status)) {
    ASSERT (0);
    return Status;
  }

  // Header
  Rdword.Header.Header.Bits.Name =
    ACPI_LARGE_WORD_ADDRESS_SPACE_DESCRIPTOR_NAME;
  Rdword.Header.Header.Bits.Type = ACPI_LARGE_ITEM_FLAG;
  Rdword.Header.Length           = sizeof (EFI_ACPI_WORD_ADDRESS_SPACE_DESCRIPTOR) -
                                   sizeof (ACPI_LARGE_RESOURCE_HEADER);

  // Body
  Rdword.ResType = ResourceType;
  Rdword.GenFlag = AddressSpaceGeneralFlags (
                     IsPosDecode,
                     IsMinFixed,
                     IsMaxFixed
                     );
  Rdword.SpecificFlag          = TypeSpecificFlags;
  Rdword.AddrSpaceGranularity  = AddressGranularity;
  Rdword.AddrRangeMin          = AddressMinimum;
  Rdword.AddrRangeMax          = AddressMaximum;
  Rdword.AddrTranslationOffset = AddressTranslation;
  Rdword.AddrLen               = RangeLength;

  Status = AmlCreateDataNode (
             EAmlNodeDataTypeResourceData,
             (UINT8 *)&Rdword,
             sizeof (EFI_ACPI_WORD_ADDRESS_SPACE_DESCRIPTOR),
             &RdNode
             );
  if (EFI_ERROR (Status)) {
    ASSERT (0);
    return Status;
  }

  return LinkRdNode (RdNode, NameOpNode, NewRdNode);
}

/** Code generation for the "WordBusNumber ()" ASL function.

  The Resource Data effectively created is a Word Address Space Resource
  Data. Cf ACPI 6.4:
   - s6.4.3.5.3 "Word Address Space Descriptor".
   - s19.6.149 "WordBusNumber".

  The created resource data node can be:
   - appended to the list of resource data elements of the NameOpNode.
     In such case NameOpNode must be defined by a the "Name ()" ASL statement
     and initially contain a "ResourceTemplate ()".
   - returned through the NewRdNode parameter.

  See ACPI 6.4 spec, s19.6.149 for more.

  @param [in]  IsResourceConsumer   ResourceUsage parameter.
  @param [in]  IsMinFixed           Minimum address is fixed.
  @param [in]  IsMaxFixed           Maximum address is fixed.
  @param [in]  IsPosDecode          Decode parameter
  @param [in]  AddressGranularity   Address granularity.
  @param [in]  AddressMinimum       Minimum address.
  @param [in]  AddressMaximum       Maximum address.
  @param [in]  AddressTranslation   Address translation.
  @param [in]  RangeLength          Range length.
  @param [in]  ResourceSourceIndex  Resource Source index.
                                    Unused. Must be 0.
  @param [in]  ResourceSource       Resource Source.
                                    Unused. Must be NULL.
  @param [in]  NameOpNode           NameOp object node defining a named object.
                                    If provided, append the new resource data
                                    node to the list of resource data elements
                                    of this node.
  @param [out] NewRdNode            If provided and success,
                                    contain the created node.

  @retval EFI_SUCCESS             The function completed successfully.
  @retval EFI_INVALID_PARAMETER   Invalid parameter.
  @retval EFI_OUT_OF_RESOURCES    Could not allocate memory.
**/
EFI_STATUS
EFIAPI
AmlCodeGenRdWordBusNumber (
  IN        BOOLEAN IsResourceConsumer,
  IN        BOOLEAN IsMinFixed,
  IN        BOOLEAN IsMaxFixed,
  IN        BOOLEAN IsPosDecode,
  IN        UINT16 AddressGranularity,
  IN        UINT16 AddressMinimum,
  IN        UINT16 AddressMaximum,
  IN        UINT16 AddressTranslation,
  IN        UINT16 RangeLength,
  IN        UINT8 ResourceSourceIndex,
  IN  CONST CHAR8 *ResourceSource,
  IN        AML_OBJECT_NODE_HANDLE NameOpNode, OPTIONAL
  OUT       AML_DATA_NODE_HANDLE    *NewRdNode  OPTIONAL
  )
{
  // There is no Type Specific Flags for buses.
  return AmlCodeGenRdWordSpace (
           ACPI_ADDRESS_SPACE_TYPE_BUS,
           IsResourceConsumer,
           IsPosDecode,
           IsMinFixed,
           IsMaxFixed,
           0,
           AddressGranularity,
           AddressMinimum,
           AddressMaximum,
           AddressTranslation,
           RangeLength,
           ResourceSourceIndex,
           ResourceSource,
           NameOpNode,
           NewRdNode
           );
}

/** Code generation for the "WordIO ()" ASL function.

  The Resource Data effectively created is a Word Address Space Resource
  Data. Cf ACPI 6.5:
   - s6.4.3.5.3 "Word Address Space Descriptor".

  The created resource data node can be:
   - appended to the list of resource data elements of the NameOpNode.
     In such case NameOpNode must be defined by a the "Name ()" ASL statement
     and initially contain a "ResourceTemplate ()".
   - returned through the NewRdNode parameter.

  @param [in]  IsResourceConsumer   ResourceUsage parameter.
  @param [in]  IsMinFixed           Minimum address is fixed.
  @param [in]  IsMaxFixed           Maximum address is fixed.
  @param [in]  IsPosDecode          Decode parameter
  @param [in]  IsaRanges            Possible values are:
                                     0-Reserved
                                     1-NonISAOnly
                                     2-ISAOnly
                                     3-EntireRange
  @param [in]  AddressGranularity   Address granularity.
  @param [in]  AddressMinimum       Minimum address.
  @param [in]  AddressMaximum       Maximum address.
  @param [in]  AddressTranslation   Address translation.
  @param [in]  RangeLength          Range length.
  @param [in]  ResourceSourceIndex  Resource Source index.
                                    Not supported. Must be 0.
  @param [in]  ResourceSource       Resource Source.
                                    Not supported. Must be NULL.
  @param [in]  IsDenseTranslation   TranslationDensity parameter.
  @param [in]  IsTypeStatic         TranslationType parameter.
  @param [in]  NameOpNode           NameOp object node defining a named object.
                                    If provided, append the new resource data
                                    node to the list of resource data elements
                                    of this node.
  @param [out] NewRdNode            If provided and success,
                                    contain the created node.

  @retval EFI_SUCCESS             The function completed successfully.
  @retval EFI_INVALID_PARAMETER   Invalid parameter.
  @retval EFI_OUT_OF_RESOURCES    Could not allocate memory.
**/
EFI_STATUS
EFIAPI
AmlCodeGenRdWordIo (
  IN        BOOLEAN IsResourceConsumer,
  IN        BOOLEAN IsMinFixed,
  IN        BOOLEAN IsMaxFixed,
  IN        BOOLEAN IsPosDecode,
  IN        UINT8 IsaRanges,
  IN        UINT16 AddressGranularity,
  IN        UINT16 AddressMinimum,
  IN        UINT16 AddressMaximum,
  IN        UINT16 AddressTranslation,
  IN        UINT16 RangeLength,
  IN        UINT8 ResourceSourceIndex,
  IN  CONST CHAR8 *ResourceSource,
  IN        BOOLEAN IsDenseTranslation,
  IN        BOOLEAN IsTypeStatic,
  IN        AML_OBJECT_NODE_HANDLE NameOpNode, OPTIONAL
  OUT       AML_DATA_NODE_HANDLE    *NewRdNode  OPTIONAL
  )
{
  return AmlCodeGenRdWordSpace (
           ACPI_ADDRESS_SPACE_TYPE_IO,
           IsResourceConsumer,
           IsPosDecode,
           IsMinFixed,
           IsMaxFixed,
           RdIoRangeSpecificFlags (
             IsaRanges,
             IsDenseTranslation,
             IsTypeStatic
             ),
           AddressGranularity,
           AddressMinimum,
           AddressMaximum,
           AddressTranslation,
           RangeLength,
           ResourceSourceIndex,
           ResourceSource,
           NameOpNode,
           NewRdNode
           );
}

/** Code generation for the "QWordSpace ()" ASL function.

  The Resource Data effectively created is a QWord Address Space Resource
  Data. Cf ACPI 6.4:
   - s6.4.3.5.1 "QWord Address Space Descriptor".
   - s19.6.111 "QWordSpace".

  The created resource data node can be:
   - appended to the list of resource data elements of the NameOpNode.
     In such case NameOpNode must be defined by a the "Name ()" ASL statement
     and initially contain a "ResourceTemplate ()".
   - returned through the NewRdNode parameter.

  See ACPI 6.4 spec, s19.6.111 for more.

  @param [in]  ResourceType         Resource type.
                                    Possible values are:
                                      0:        Memory range
                                      1:        I/O range
                                      2:        Bus number range
                                      3-191:    Reserved
                                      192-255:  Hardware Vendor Defined
                                    See ACPI 6.4 spec, s6.4.3.5.1 for more.
  @param [in]  IsResourceConsumer   ResourceUsage parameter.
  @param [in]  IsPosDecode          Decode parameter
  @param [in]  IsMinFixed           Minimum address is fixed.
  @param [in]  IsMaxFixed           Maximum address is fixed.
  @param [in]  TypeSpecificFlags    Type specific flags.
                                    See ACPI 6.4 spec, s6.4.3.5.5
                                    "Resource Type Specific Flags".
  @param [in]  AddressGranularity   Address granularity.
  @param [in]  AddressMinimum       Minimum address.
  @param [in]  AddressMaximum       Maximum address.
  @param [in]  AddressTranslation   Address translation.
  @param [in]  RangeLength          Range length.
  @param [in]  ResourceSourceIndex  Resource Source index.
                                    Unused. Must be 0.
  @param [in]  ResourceSource       Resource Source.
                                    Unused. Must be NULL.
  @param [in]  NameOpNode           NameOp object node defining a named object.
                                    If provided, append the new resource data
                                    node to the list of resource data elements
                                    of this node.
  @param [out] NewRdNode            If provided and success,
                                    contain the created node.

  @retval EFI_SUCCESS             The function completed successfully.
  @retval EFI_INVALID_PARAMETER   Invalid parameter.
  @retval EFI_OUT_OF_RESOURCES    Could not allocate memory.
**/
STATIC
EFI_STATUS
EFIAPI
AmlCodeGenRdQWordSpace (
  IN        UINT8 ResourceType,
  IN        BOOLEAN IsResourceConsumer,
  IN        BOOLEAN IsPosDecode,
  IN        BOOLEAN IsMinFixed,
  IN        BOOLEAN IsMaxFixed,
  IN        UINT8 TypeSpecificFlags,
  IN        UINT64 AddressGranularity,
  IN        UINT64 AddressMinimum,
  IN        UINT64 AddressMaximum,
  IN        UINT64 AddressTranslation,
  IN        UINT64 RangeLength,
  IN        UINT8 ResourceSourceIndex,
  IN  CONST CHAR8 *ResourceSource,
  IN        AML_OBJECT_NODE_HANDLE NameOpNode, OPTIONAL
  OUT       AML_DATA_NODE_HANDLE    *NewRdNode  OPTIONAL
  )
{
  EFI_STATUS                               Status;
  AML_DATA_NODE                            *RdNode;
  EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR  RdQword;

  // ResourceSource and ResourceSourceIndex are unused.
  if ((TypeSpecificFlags == MAX_UINT8)  ||
      (ResourceSourceIndex != 0)        ||
      (ResourceSource != NULL)          ||
      ((NameOpNode == NULL) && (NewRdNode == NULL)))
  {
    ASSERT (0);
    return EFI_INVALID_PARAMETER;
  }

  Status = CheckAddressSpaceFields (
             IsMinFixed,
             IsMaxFixed,
             AddressGranularity,
             AddressMinimum,
             AddressMaximum,
             AddressTranslation,
             RangeLength
             );
  if (EFI_ERROR (Status)) {
    ASSERT (0);
    return Status;
  }

  // Header
  RdQword.Header.Header.Bits.Name =
    ACPI_LARGE_QWORD_ADDRESS_SPACE_DESCRIPTOR_NAME;
  RdQword.Header.Header.Bits.Type = ACPI_LARGE_ITEM_FLAG;
  RdQword.Header.Length           = sizeof (EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR) -
                                    sizeof (ACPI_LARGE_RESOURCE_HEADER);

  // Body
  RdQword.ResType = ResourceType;
  RdQword.GenFlag = AddressSpaceGeneralFlags (
                      IsPosDecode,
                      IsMinFixed,
                      IsMaxFixed
                      );
  RdQword.SpecificFlag          = TypeSpecificFlags;
  RdQword.AddrSpaceGranularity  = AddressGranularity;
  RdQword.AddrRangeMin          = AddressMinimum;
  RdQword.AddrRangeMax          = AddressMaximum;
  RdQword.AddrTranslationOffset = AddressTranslation;
  RdQword.AddrLen               = RangeLength;

  Status = AmlCreateDataNode (
             EAmlNodeDataTypeResourceData,
             (UINT8 *)&RdQword,
             sizeof (EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR),
             &RdNode
             );
  if (EFI_ERROR (Status)) {
    ASSERT (0);
    return Status;
  }

  return LinkRdNode (RdNode, NameOpNode, NewRdNode);
}

/** Code generation for the "QWordIO ()" ASL function.

  The Resource Data effectively created is a QWord Address Space Resource
  Data. Cf ACPI 6.4:
   - s6.4.3.5.1 "QWord Address Space Descriptor".
   - s19.6.109 "QWordIO".

  The created resource data node can be:
   - appended to the list of resource data elements of the NameOpNode.
     In such case NameOpNode must be defined by a the "Name ()" ASL statement
     and initially contain a "ResourceTemplate ()".
   - returned through the NewRdNode parameter.

  See ACPI 6.4 spec, s19.6.109 for more.

  @param [in]  IsResourceConsumer   ResourceUsage parameter.
  @param [in]  IsMinFixed           Minimum address is fixed.
  @param [in]  IsMaxFixed           Maximum address is fixed.
  @param [in]  IsPosDecode          Decode parameter
  @param [in]  IsaRanges            Possible values are:
                                     0-Reserved
                                     1-NonISAOnly
                                     2-ISAOnly
                                     3-EntireRange
  @param [in]  AddressGranularity   Address granularity.
  @param [in]  AddressMinimum       Minimum address.
  @param [in]  AddressMaximum       Maximum address.
  @param [in]  AddressTranslation   Address translation.
  @param [in]  RangeLength          Range length.
  @param [in]  ResourceSourceIndex  Resource Source index.
                                    Unused. Must be 0.
  @param [in]  ResourceSource       Resource Source.
                                    Unused. Must be NULL.
  @param [in]  IsDenseTranslation   TranslationDensity parameter.
  @param [in]  IsTypeStatic         TranslationType parameter.
  @param [in]  NameOpNode           NameOp object node defining a named object.
                                    If provided, append the new resource data
                                    node to the list of resource data elements
                                    of this node.
  @param [out] NewRdNode            If provided and success,
                                    contain the created node.

  @retval EFI_SUCCESS             The function completed successfully.
  @retval EFI_INVALID_PARAMETER   Invalid parameter.
  @retval EFI_OUT_OF_RESOURCES    Could not allocate memory.
**/
EFI_STATUS
EFIAPI
AmlCodeGenRdQWordIo (
  IN        BOOLEAN IsResourceConsumer,
  IN        BOOLEAN IsMinFixed,
  IN        BOOLEAN IsMaxFixed,
  IN        BOOLEAN IsPosDecode,
  IN        UINT8 IsaRanges,
  IN        UINT64 AddressGranularity,
  IN        UINT64 AddressMinimum,
  IN        UINT64 AddressMaximum,
  IN        UINT64 AddressTranslation,
  IN        UINT64 RangeLength,
  IN        UINT8 ResourceSourceIndex,
  IN  CONST CHAR8 *ResourceSource,
  IN        BOOLEAN IsDenseTranslation,
  IN        BOOLEAN IsTypeStatic,
  IN        AML_OBJECT_NODE_HANDLE NameOpNode, OPTIONAL
  OUT       AML_DATA_NODE_HANDLE    *NewRdNode  OPTIONAL
  )
{
  return AmlCodeGenRdQWordSpace (
           ACPI_ADDRESS_SPACE_TYPE_IO,
           IsResourceConsumer,
           IsPosDecode,
           IsMinFixed,
           IsMaxFixed,
           RdIoRangeSpecificFlags (
             IsaRanges,
             IsDenseTranslation,
             IsTypeStatic
             ),
           AddressGranularity,
           AddressMinimum,
           AddressMaximum,
           AddressTranslation,
           RangeLength,
           ResourceSourceIndex,
           ResourceSource,
           NameOpNode,
           NewRdNode
           );
}

/** Code generation for the "QWordMemory ()" ASL function.

  The Resource Data effectively created is a QWord Address Space Resource
  Data. Cf ACPI 6.4:
   - s6.4.3.5.1 "QWord Address Space Descriptor".
   - s19.6.110 "QWordMemory".

  The created resource data node can be:
   - appended to the list of resource data elements of the NameOpNode.
     In such case NameOpNode must be defined by a the "Name ()" ASL statement
     and initially contain a "ResourceTemplate ()".
   - returned through the NewRdNode parameter.

  See ACPI 6.4 spec, s19.6.110 for more.

  @param [in]  IsResourceConsumer   ResourceUsage parameter.
  @param [in]  IsPosDecode          Decode parameter.
  @param [in]  IsMinFixed           Minimum address is fixed.
  @param [in]  IsMaxFixed           Maximum address is fixed.
  @param [in]  Cacheable            Possible values are:
                                    0-The memory is non-cacheable
                                    1-The memory is cacheable
                                    2-The memory is cacheable and supports
                                      write combining
                                    3-The memory is cacheable and prefetchable
  @param [in]  IsReadWrite          ReadAndWrite parameter.
  @param [in]  AddressGranularity   Address granularity.
  @param [in]  AddressMinimum       Minimum address.
  @param [in]  AddressMaximum       Maximum address.
  @param [in]  AddressTranslation   Address translation.
  @param [in]  RangeLength          Range length.
  @param [in]  ResourceSourceIndex  Resource Source index.
                                    Unused. Must be 0.
  @param [in]  ResourceSource       Resource Source.
                                    Unused. Must be NULL.
  @param [in]  MemoryRangeType      Possible values are:
                                      0-AddressRangeMemory
                                      1-AddressRangeReserved
                                      2-AddressRangeACPI
                                      3-AddressRangeNVS
  @param [in]  IsTypeStatic         TranslationType parameter.
  @param [in]  NameOpNode           NameOp object node defining a named object.
                                    If provided, append the new resource data
                                    node to the list of resource data elements
                                    of this node.
  @param [out] NewRdNode            If provided and success,
                                    contain the created node.

  @retval EFI_SUCCESS             The function completed successfully.
  @retval EFI_INVALID_PARAMETER   Invalid parameter.
  @retval EFI_OUT_OF_RESOURCES    Could not allocate memory.
**/
EFI_STATUS
EFIAPI
AmlCodeGenRdQWordMemory (
  IN        BOOLEAN IsResourceConsumer,
  IN        BOOLEAN IsPosDecode,
  IN        BOOLEAN IsMinFixed,
  IN        BOOLEAN IsMaxFixed,
  IN        AML_MEMORY_ATTRIBUTES_MEM Cacheable,
  IN        BOOLEAN IsReadWrite,
  IN        UINT64 AddressGranularity,
  IN        UINT64 AddressMinimum,
  IN        UINT64 AddressMaximum,
  IN        UINT64 AddressTranslation,
  IN        UINT64 RangeLength,
  IN        UINT8 ResourceSourceIndex,
  IN  CONST CHAR8 *ResourceSource,
  IN        AML_MEMORY_ATTRIBUTES_MTP MemoryRangeType,
  IN        BOOLEAN IsTypeStatic,
  IN        AML_OBJECT_NODE_HANDLE NameOpNode, OPTIONAL
  OUT       AML_DATA_NODE_HANDLE    *NewRdNode  OPTIONAL
  )
{
  return AmlCodeGenRdQWordSpace (
           ACPI_ADDRESS_SPACE_TYPE_MEM,
           IsResourceConsumer,
           IsPosDecode,
           IsMinFixed,
           IsMaxFixed,
           MemoryRangeSpecificFlags (
             Cacheable,
             IsReadWrite,
             MemoryRangeType,
             IsTypeStatic
             ),
           AddressGranularity,
           AddressMinimum,
           AddressMaximum,
           AddressTranslation,
           RangeLength,
           ResourceSourceIndex,
           ResourceSource,
           NameOpNode,
           NewRdNode
           );
}

/** Code generation for the "Interrupt ()" ASL function.

  The Resource Data effectively created is an Extended Interrupt Resource
  Data. Cf ACPI 6.4:
   - s6.4.3.6 "Extended Interrupt Descriptor"
   - s19.6.64 "Interrupt (Interrupt Resource Descriptor Macro)"

  The created resource data node can be:
   - appended to the list of resource data elements of the NameOpNode.
     In such case NameOpNode must be defined by a the "Name ()" ASL statement
     and initially contain a "ResourceTemplate ()".
   - returned through the NewRdNode parameter.

  @param  [in]  ResourceConsumer The device consumes the specified interrupt
                                 or produces it for use by a child device.
  @param  [in]  EdgeTriggered    The interrupt is edge triggered or
                                 level triggered.
  @param  [in]  ActiveLow        The interrupt is active-high or active-low.
  @param  [in]  Shared           The interrupt can be shared with other
                                 devices or not (Exclusive).
  @param  [in]  IrqList          Interrupt list. Must be non-NULL.
  @param  [in]  IrqCount         Interrupt count. Must be non-zero.
  @param  [in]  NameOpNode       NameOp object node defining a named object.
                                 If provided, append the new resource data node
                                 to the list of resource data elements of this
                                 node.
  @param  [out] NewRdNode        If provided and success,
                                 contain the created node.

  @retval EFI_SUCCESS             The function completed successfully.
  @retval EFI_INVALID_PARAMETER   Invalid parameter.
  @retval EFI_OUT_OF_RESOURCES    Could not allocate memory.
**/
EFI_STATUS
EFIAPI
AmlCodeGenRdInterrupt (
  IN  BOOLEAN                 ResourceConsumer,
  IN  BOOLEAN                 EdgeTriggered,
  IN  BOOLEAN                 ActiveLow,
  IN  BOOLEAN                 Shared,
  IN  UINT32                  *IrqList,
  IN  UINT8                   IrqCount,
  IN  AML_OBJECT_NODE_HANDLE  NameOpNode  OPTIONAL,
  OUT AML_DATA_NODE_HANDLE    *NewRdNode  OPTIONAL
  )
{
  EFI_STATUS  Status;

  AML_DATA_NODE                           *RdNode;
  EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR  RdInterrupt;
  UINT32                                  *FirstInterrupt;

  if ((IrqList == NULL) ||
      (IrqCount == 0)   ||
      ((NameOpNode == NULL) && (NewRdNode == NULL)))
  {
    ASSERT (0);
    return EFI_INVALID_PARAMETER;
  }

  // Header
  RdInterrupt.Header.Header.Bits.Name =
    ACPI_LARGE_EXTENDED_IRQ_DESCRIPTOR_NAME;
  RdInterrupt.Header.Header.Bits.Type = ACPI_LARGE_ITEM_FLAG;
  RdInterrupt.Header.Length           = sizeof (EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR) -
                                        sizeof (ACPI_LARGE_RESOURCE_HEADER);

  // Body
  RdInterrupt.InterruptVectorFlags = (ResourceConsumer ? BIT0 : 0) |
                                     (EdgeTriggered ? BIT1 : 0)    |
                                     (ActiveLow ? BIT2 : 0)        |
                                     (Shared ? BIT3 : 0);
  RdInterrupt.InterruptTableLength = IrqCount;

  // Get the address of the first interrupt field.
  FirstInterrupt = RdInterrupt.InterruptNumber;

  // Copy the list of interrupts.
  CopyMem (FirstInterrupt, IrqList, (sizeof (UINT32) * IrqCount));

  Status = AmlCreateDataNode (
             EAmlNodeDataTypeResourceData,
             (UINT8 *)&RdInterrupt,
             sizeof (EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR),
             &RdNode
             );
  if (EFI_ERROR (Status)) {
    ASSERT (0);
    return Status;
  }

  return LinkRdNode (RdNode, NameOpNode, NewRdNode);
}

/** Code generation for the "Register ()" ASL function.

  The Resource Data effectively created is a Generic Register Descriptor.
  Data. Cf ACPI 6.4:
   - s6.4.3.7 "Generic Register Descriptor".
   - s19.6.114 "Register".

  The created resource data node can be:
   - appended to the list of resource data elements of the NameOpNode.
     In such case NameOpNode must be defined by a the "Name ()" ASL statement
     and initially contain a "ResourceTemplate ()".
   - returned through the NewRdNode parameter.

  @param [in]  AddressSpace    Address space where the register exists.
                               Can be one of I/O space, System Memory, etc.
  @param [in]  BitWidth        Number of bits in the register.
  @param [in]  BitOffset       Offset in bits from the start of the register
                               indicated by the Address.
  @param [in]  Address         Register address.
  @param [in]  AccessSize      Size of data values used when accessing the
                               address space. Can be one of:
                                 0 - Undefined, legacy (EFI_ACPI_6_4_UNDEFINED)
                                 1 - Byte access (EFI_ACPI_6_4_BYTE)
                                 2 - Word access (EFI_ACPI_6_4_WORD)
                                 3 - DWord access (EFI_ACPI_6_4_DWORD)
                                 4 - QWord access (EFI_ACPI_6_4_QWORD)
  @param  [in]  NameOpNode       NameOp object node defining a named object.
                                 If provided, append the new resource data node
                                 to the list of resource data elements of this
                                 node.
  @param  [out] NewRdNode        If provided and success,
                                 contain the created node.

  @retval EFI_SUCCESS             The function completed successfully.
  @retval EFI_INVALID_PARAMETER   Invalid parameter.
  @retval EFI_OUT_OF_RESOURCES    Could not allocate memory.
**/
EFI_STATUS
EFIAPI
AmlCodeGenRdRegister (
  IN  UINT8                   AddressSpace,
  IN  UINT8                   BitWidth,
  IN  UINT8                   BitOffset,
  IN  UINT64                  Address,
  IN  UINT8                   AccessSize,
  IN  AML_OBJECT_NODE_HANDLE  NameOpNode  OPTIONAL,
  OUT AML_DATA_NODE_HANDLE    *NewRdNode  OPTIONAL
  )
{
  EFI_STATUS                            Status;
  AML_DATA_NODE                         *RdNode;
  EFI_ACPI_GENERIC_REGISTER_DESCRIPTOR  RdRegister;

  // Cf. ACPI 6.4, s14.7 Referencing the PCC address space
  // The AccessSize represents the Subspace Id for the PCC address space.
  if (((AddressSpace != EFI_ACPI_6_4_PLATFORM_COMMUNICATION_CHANNEL) &&
       (AccessSize > EFI_ACPI_6_4_QWORD)) ||
      ((NameOpNode == NULL) && (NewRdNode == NULL)))
  {
    ASSERT (0);
    return EFI_INVALID_PARAMETER;
  }

  // Header
  RdRegister.Header.Header.Bits.Name =
    ACPI_LARGE_GENERIC_REGISTER_DESCRIPTOR_NAME;
  RdRegister.Header.Header.Bits.Type = ACPI_LARGE_ITEM_FLAG;
  RdRegister.Header.Length           = sizeof (EFI_ACPI_GENERIC_REGISTER_DESCRIPTOR) -
                                       sizeof (ACPI_LARGE_RESOURCE_HEADER);

  // Body
  RdRegister.AddressSpaceId    = AddressSpace;
  RdRegister.RegisterBitWidth  = BitWidth;
  RdRegister.RegisterBitOffset = BitOffset;
  RdRegister.AddressSize       = AccessSize;
  RdRegister.RegisterAddress   = Address;

  Status = AmlCreateDataNode (
             EAmlNodeDataTypeResourceData,
             (UINT8 *)&RdRegister,
             sizeof (EFI_ACPI_GENERIC_REGISTER_DESCRIPTOR),
             &RdNode
             );
  if (EFI_ERROR (Status)) {
    ASSERT (0);
    return Status;
  }

  return LinkRdNode (RdNode, NameOpNode, NewRdNode);
}

/** Code generation for the "IO ()" ASL function.

  The Resource Data effectively created is a IO Resource
  Data. Cf ACPI 6.5:
   - s19.6.65 IO (IO Resource Descriptor Macro)
   - s6.4.2.5 I/O Port Descriptor

  The created resource data node can be:
   - appended to the list of resource data elements of the NameOpNode.
     In such case NameOpNode must be defined by a the "Name ()" ASL statement
     and initially contain a "ResourceTemplate ()".
   - returned through the NewRdNode parameter.

  @param [in]  IsDecoder16          Decoder parameter.
                                    TRUE if 16-bit decoder.
                                    FALSE if 10-bit decoder.
  @param [in]  AddressMinimum       Minimum address.
  @param [in]  AddressMaximum       Maximum address.
  @param [in]  Alignment            Alignment.
  @param [in]  RangeLength          Range length.
  @param [in]  NameOpNode           NameOp object node defining a named object.
                                    If provided, append the new resource data
                                    node to the list of resource data elements
                                    of this node.
  @param [out] NewRdNode            If provided and success,
                                    contain the created node.

  @retval EFI_SUCCESS               The function completed successfully.
  @retval EFI_INVALID_PARAMETER     Invalid parameter.
**/
EFI_STATUS
EFIAPI
AmlCodeGenRdIo (
  IN  BOOLEAN IsDecoder16,
  IN  UINT16 AddressMinimum,
  IN  UINT16 AddressMaximum,
  IN  UINT8 Alignment,
  IN  UINT8 RangeLength,
  IN  AML_OBJECT_NODE_HANDLE NameOpNode, OPTIONAL
  OUT AML_DATA_NODE_HANDLE  *NewRdNode  OPTIONAL
  )
{
  EFI_STATUS                   Status;
  EFI_ACPI_IO_PORT_DESCRIPTOR  IoDesc;
  AML_DATA_NODE                *IoNode;

  if (AddressMinimum > AddressMaximum) {
    return EFI_INVALID_PARAMETER;
  }

  if (Alignment != 0) {
    /// check the alignment
    if ((AddressMinimum % Alignment) != 0) {
      return EFI_INVALID_PARAMETER;
    }

    if ((AddressMaximum % Alignment) != 0) {
      return EFI_INVALID_PARAMETER;
    }
  }

  IoDesc.Header.Byte = ACPI_IO_PORT_DESCRIPTOR;
  IoDesc.Information = IsDecoder16 ? BIT0 : 0;

  IoDesc.BaseAddressMin = AddressMinimum;
  IoDesc.BaseAddressMax = AddressMaximum;
  IoDesc.Alignment      = Alignment;
  IoDesc.Length         = RangeLength;

  Status = AmlCreateDataNode (
             EAmlNodeDataTypeResourceData,
             (UINT8 *)&IoDesc,
             sizeof (IoDesc),
             &IoNode
             );
  if (EFI_ERROR (Status)) {
    ASSERT (0);
    return Status;
  }

  return LinkRdNode (IoNode, NameOpNode, NewRdNode);
}

/** Code generation for the EndTag resource data.

  The EndTag resource data is automatically generated by the ASL compiler
  at the end of a list of resource data elements. Thus, it doesn't have
  a corresponding ASL function.

  This function allocates memory to create a data node. It is the caller's
  responsibility to either:
   - attach this node to an AML tree;
   - delete this node.

  ACPI 6.4, s6.4.2.9 "End Tag":
  "This checksum is generated such that adding it to the sum of all the data
  bytes will produce a zero sum."
  "If the checksum field is zero, the resource data is treated as if the
  checksum operation succeeded. Configuration proceeds normally."

  To avoid re-computing checksums, if a new resource data elements is
  added/removed/modified in a list of resource data elements, the AmlLib
  resets the checksum to 0.

  @param [in]  CheckSum        CheckSum to store in the EndTag.
                               To ignore/avoid computing the checksum,
                               give 0.
  @param [in]  ParentNode      If not NULL, add the generated node
                               to the end of the variable list of
                               argument of the ParentNode.
                               The ParentNode must not initially contain
                               an EndTag resource data element.
  @param  [out] NewRdNode      If success, contains the generated node.

  @retval EFI_SUCCESS             The function completed successfully.
  @retval EFI_INVALID_PARAMETER   Invalid parameter.
  @retval EFI_OUT_OF_RESOURCES    Could not allocate memory.
**/
EFI_STATUS
EFIAPI
AmlCodeGenEndTag (
  IN  UINT8            CheckSum    OPTIONAL,
  IN  AML_OBJECT_NODE  *ParentNode  OPTIONAL,
  OUT AML_DATA_NODE    **NewRdNode   OPTIONAL
  )
{
  EFI_STATUS                   Status;
  AML_DATA_NODE                *RdNode;
  EFI_ACPI_END_TAG_DESCRIPTOR  EndTag;
  ACPI_SMALL_RESOURCE_HEADER   SmallResHdr;

  if ((ParentNode == NULL) && (NewRdNode == NULL)) {
    ASSERT (0);
    return EFI_INVALID_PARAMETER;
  }

  RdNode = NULL;

  // Header
  SmallResHdr.Bits.Length = sizeof (EFI_ACPI_END_TAG_DESCRIPTOR) -
                            sizeof (ACPI_SMALL_RESOURCE_HEADER);
  SmallResHdr.Bits.Name = ACPI_SMALL_END_TAG_DESCRIPTOR_NAME;
  SmallResHdr.Bits.Type = ACPI_SMALL_ITEM_FLAG;

  // Body
  EndTag.Desc     = SmallResHdr.Byte;
  EndTag.Checksum = CheckSum;

  Status = AmlCreateDataNode (
             EAmlNodeDataTypeResourceData,
             (UINT8 *)&EndTag,
             sizeof (EFI_ACPI_END_TAG_DESCRIPTOR),
             &RdNode
             );
  if (EFI_ERROR (Status)) {
    ASSERT (0);
    return Status;
  }

  if (NewRdNode != NULL) {
    *NewRdNode = RdNode;
  }

  if (ParentNode != NULL) {
    // Check the BufferOp doesn't contain any resource data yet.
    // This is a hard check: do not allow to add an EndTag if the BufferNode
    // already has resource data elements attached. Indeed, the EndTag should
    // have already been added.
    if (AmlGetNextVariableArgument ((AML_NODE_HEADER *)ParentNode, NULL) !=
        NULL)
    {
      ASSERT (0);
      Status = EFI_INVALID_PARAMETER;
      goto error_handler;
    }

    // Add the EndTag RdNode. Indeed, the AmlAppendRdNode function
    // is looking for an EndTag, which we are adding here.
    Status = AmlVarListAddTail (
               (AML_NODE_HEADER *)ParentNode,
               (AML_NODE_HEADER *)RdNode
               );
    if (EFI_ERROR (Status)) {
      ASSERT (0);
      goto error_handler;
    }
  }

  return Status;

error_handler:
  if (RdNode != NULL) {
    AmlDeleteTree ((AML_NODE_HEADER *)RdNode);
  }

  return Status;
}

/** Code generation for the IRQ Descriptor.

  The Resource Data effectively created is an IRQ Resource
  Data. Cf ACPI 6.5 specification:
   - s6.4.2.1 "IRQ Descriptor"
   - s19.6.66 "IRQ (Interrupt Resource Descriptor Macro)"


  The created resource data node can be:
   - appended to the list of resource data elements of the NameOpNode.
     In such case NameOpNode must be defined by a the "Name ()" ASL statement
     and initially contain a "ResourceTemplate ()".
   - returned through the NewRdNode parameter.

  @param  [in]  IsEdgeTriggered The interrupt is edge triggered or
                                level triggered.
  @param  [in]  IsActiveLow     The interrupt is active-high or active-low.
  @param  [in]  IsShared        The interrupt can be shared with other
                                devices or not (Exclusive).
  @param  [in]  IrqList         List of IRQ numbers. Must be non-NULL.
  @param  [in]  IrqCount        Number of IRQs in IrqList. Must be > 0 and <= 16.
  @param  [in]  NameOpNode      NameOp object node defining a named object.
                                If provided, append the new resource data node
                                to the list of resource data elements of this node.
  @param  [out] NewRdNode       If provided and success, contain the created node.

  @retval EFI_SUCCESS           The function completed successfully.
  @retval EFI_INVALID_PARAMETER Invalid parameter.
  @retval various               Other errors as indicated.
**/
EFI_STATUS
EFIAPI
AmlCodeGenRdIrq (
  IN  BOOLEAN                 IsEdgeTriggered,
  IN  BOOLEAN                 IsActiveLow,
  IN  BOOLEAN                 IsShared,
  IN  UINT8                   *IrqList,
  IN  UINT8                   IrqCount,
  IN  AML_OBJECT_NODE_HANDLE  NameOpNode  OPTIONAL,
  OUT AML_DATA_NODE_HANDLE    *NewRdNode  OPTIONAL
  )
{
  AML_DATA_NODE            *RdNode;
  EFI_ACPI_IRQ_DESCRIPTOR  IrqDesc;
  EFI_STATUS               Status;
  UINT8                    Index;
  UINT16                   Mask;

  if ((NameOpNode == NULL) && (NewRdNode == NULL)) {
    ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
    return EFI_INVALID_PARAMETER;
  }

 #if defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64)
  if ((IsEdgeTriggered && !IsActiveLow) ||
      (!IsEdgeTriggered && IsActiveLow))
  {
    ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
    return EFI_INVALID_PARAMETER;
  }

 #endif

  if ((IrqList == NULL) || (IrqCount == 0) || (IrqCount > 16)) {
    ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
    return EFI_INVALID_PARAMETER;
  }

  Mask = 0;
  for (Index = 0; Index < IrqCount; Index++) {
    if (IrqList[Index] > 16) {
      ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
      return EFI_INVALID_PARAMETER;
    }

    if ((Mask & (1 << IrqList[Index])) != 0) {
      ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
      return EFI_INVALID_PARAMETER;
    }

    Mask |= (1 << IrqList[Index]);
  }

  if (Mask == 0) {
    ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
    return EFI_INVALID_PARAMETER;
  }

  IrqDesc.Header.Bits.Type   = ACPI_SMALL_ITEM_FLAG;
  IrqDesc.Header.Bits.Name   = ACPI_SMALL_IRQ_DESCRIPTOR_NAME;
  IrqDesc.Header.Bits.Length = sizeof (EFI_ACPI_IRQ_DESCRIPTOR) -
                               sizeof (ACPI_SMALL_RESOURCE_HEADER);
  IrqDesc.Mask        = Mask;
  IrqDesc.Information = (IsEdgeTriggered ? BIT0 : 0) |
                        (IsActiveLow ? BIT3 : 0)    |
                        (IsShared ? BIT4 : 0);

  Status = AmlCreateDataNode (
             EAmlNodeDataTypeResourceData,
             (UINT8 *)&IrqDesc,
             sizeof (EFI_ACPI_IRQ_DESCRIPTOR),
             &RdNode
             );
  if (EFI_ERROR (Status)) {
    ASSERT_EFI_ERROR (Status);
    return Status;
  }

  return LinkRdNode (RdNode, NameOpNode, NewRdNode);
}

/** Code generation for the UART Serial Bus Connection Resource Descriptor.

  The Resource Data effectively created is a UART Serial Bus Connection
  Resource Descriptor Resource Data.
  Cf ACPI 6.5:
   - s19.6.143 UARTSerialBusV2
     (UART Serial Bus Connection Resource Descriptor Version 2 Macro)
   - s6.4.3.8.2.3 UART Serial Bus Connection Resource Descriptor

  The created resource data node can be:
   - appended to the list of resource data elements of the NameOpNode.
     In such case NameOpNode must be defined by a the "Name ()" ASL statement
     and initially contain a "ResourceTemplate ()".
   - returned through the NewRdNode parameter.

  @param [in] IsResourceConsumer          ResourceUsage parameter.
  @param [in] IsSlaveMode                 Indicates whether the uart operates in slave mode.
  @param [in] IsBigEndian                 Indicates whether the bit transfer is big-endian.
  @param [in] BitsPerByte                 Indicates the number of bits per byte.
  @param [in] StopBits                    Specifies the stop bits format used.
  @param [in] FlowControl                 Specifies the flow control protocol used.
  @param [in] BaudRate                    Specifies the baud rate.
  @param [in] RxFifo                      Number of bytes in the receiver FIFO.
  @param [in] TxFifo                      Number of bytes in the transmitter FIFO.
  @param [in] Parity                      Specifies the parity format used.
  @param [in] SerialLinesEnabled          Specifies which serial lines are enabled.
  @param [in] VendorDefinedData           VendorDefinedData parameter.
  @param [in] VendorDefinedDataLength     VendorDefinedDataLength parameter.
  @param [in] ResourceSource              Name of source resource used.
  @param [in] ResourceSourceLength        Resource Source Length.
  @param [in] NameOpNode                  NameOpNode object node defining a named object.
                                          If provided, append the new resource data
                                          node to the list of resource data elements
                                          of this node.
  @param [out] NewRdNode                  If provided and success,
                                          contain the created node.

  @retval EFI_SUCCESS           The function completed successfully.
  @retval EFI_INVALID_PARAMETER Invalid parameter.
  @retval EFI_OUT_OF_RESOURCES  Could not allocate memory.
  @retval various               Other errors as indicated.

**/
STATIC
EFI_STATUS
EFIAPI
AmlCodeGenRdUartSerialBus (
  IN  BOOLEAN                 IsResourceConsumer,
  IN  BOOLEAN                 IsSlaveMode,
  IN  BOOLEAN                 IsBigEndian,
  IN  UINT8                   BitsPerByte,
  IN  UINT8                   StopBits,
  IN  UINT8                   FlowControl,
  IN  UINT32                  BaudRate,
  IN  UINT16                  RxFifo,
  IN  UINT16                  TxFifo,
  IN  UINT8                   Parity,
  IN  UINT8                   SerialLinesEnabled,
  IN  UINT8                   *VendorDefinedData OPTIONAL,
  IN  UINT16                  VendorDefinedDataLength,
  IN  CHAR8                   *ResourceSource,
  IN  UINT16                  ResourceSourceLength,
  IN  AML_OBJECT_NODE_HANDLE  NameOpNode OPTIONAL,
  OUT AML_DATA_NODE_HANDLE    *NewRdNode OPTIONAL
  )
{
  AML_DATA_NODE  *RdNode;
  EFI_STATUS     Status;
  UINT16         UartDescBuffLength;
  UINT8          *UartDescBuff;
  UINT8          BitsPerByteMask;

  EFI_ACPI_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR  UartDesc;

  if ((NameOpNode == NULL) && (NewRdNode == NULL)) {
    ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
    return EFI_INVALID_PARAMETER;
  }

  if (((VendorDefinedData == NULL) && (VendorDefinedDataLength > 0)) ||
      ((VendorDefinedData != NULL) && (VendorDefinedDataLength == 0)))
  {
    ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
    return EFI_INVALID_PARAMETER;
  }

  if ((ResourceSource == NULL) || (ResourceSourceLength <= 0)) {
    ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
    return EFI_INVALID_PARAMETER;
  }

  if (StopBits > EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_TSF_STOP_BIT_2) {
    ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
    return EFI_INVALID_PARAMETER;
  }

  if (FlowControl > EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_TSF_FC_XON_XOFF) {
    ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
    return EFI_INVALID_PARAMETER;
  }

  if (Parity > EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_PARITY_SPACE) {
    ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
    return EFI_INVALID_PARAMETER;
  }

  switch (BitsPerByte) {
    case 5:
      BitsPerByteMask = EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_TSF_5_BITS_PER_BYTE;
      break;
    case 6:
      BitsPerByteMask = EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_TSF_6_BITS_PER_BYTE;
      break;
    case 7:
      BitsPerByteMask = EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_TSF_7_BITS_PER_BYTE;
      break;
    case 8:
      BitsPerByteMask = EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_TSF_8_BITS_PER_BYTE;
      break;
    case 9:
      BitsPerByteMask = EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_TSF_9_BITS_PER_BYTE;
      break;
    default:
      ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
      return EFI_INVALID_PARAMETER;
  }

  /// as per spec last two bits are reserved and must be 0.
  if ((SerialLinesEnabled &
       ~(EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_LIN_RTS |
         EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_LIN_CTS |
         EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_LIN_DTR |
         EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_LIN_DSR |
         EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_LIN_RI |
         EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_LIN_DTD)) != 0)
  {
    ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
    return EFI_INVALID_PARAMETER;
  }

  UartDesc.Header.Header.Bits.Type = ACPI_LARGE_ITEM_FLAG;
  UartDesc.Header.Header.Bits.Name = ACPI_LARGE_GENERIC_SERIAL_BUS_CONNECTION_DESCRIPTOR_NAME;
  UartDesc.RevisionId              = EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_REVISION_ID;
  UartDesc.ResourceSourceIndex     = 0;
  UartDesc.SerialBusType           = EFI_ACPI_SERIAL_BUS_RESOURCE_TYPE_UART;
  UartDesc.GeneralFlags            = (IsResourceConsumer ? BIT1 : 0) |
                                     (IsSlaveMode ? BIT0 : 0);
  UartDesc.TypeSpecificFlags = (IsBigEndian ? BIT7 : 0) |
                               (BitsPerByteMask << 4) |
                               (StopBits << 2)        |
                               (FlowControl);
  UartDesc.TypeSpecificRevisionId = EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_REVISION_ID;
  /// TypeDataLength is the length of the data following the TypeDataLength,
  /// up to the Additional vendor supplied data (not included).
  UartDesc.TypeDataLength = sizeof (UartDesc.DefaultBaudRate) +
                            sizeof (UartDesc.RxFIFO) +
                            sizeof (UartDesc.TxFIFO) +
                            sizeof (UartDesc.Parity) +
                            sizeof (UartDesc.SerialLinesEnabled) +
                            VendorDefinedDataLength;
  UartDesc.DefaultBaudRate    = BaudRate;
  UartDesc.RxFIFO             = RxFifo;
  UartDesc.TxFIFO             = TxFifo;
  UartDesc.Parity             = Parity;
  UartDesc.SerialLinesEnabled = SerialLinesEnabled;

  UartDescBuffLength = sizeof (EFI_ACPI_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR) +
                       VendorDefinedDataLength +
                       ResourceSourceLength;

  UartDesc.Header.Length = UartDescBuffLength - sizeof (ACPI_LARGE_RESOURCE_HEADER);

  UartDescBuff = AllocateZeroPool (UartDescBuffLength);
  if (UartDescBuff == NULL) {
    ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES);
    return EFI_OUT_OF_RESOURCES;
  }

  CopyMem (
    UartDescBuff,
    &UartDesc,
    sizeof (EFI_ACPI_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR)
    );

  if (VendorDefinedData != NULL) {
    CopyMem (
      UartDescBuff + sizeof (EFI_ACPI_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR),
      VendorDefinedData,
      VendorDefinedDataLength
      );
  }

  CopyMem (
    UartDescBuff +
    sizeof (EFI_ACPI_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR) +
    VendorDefinedDataLength,
    ResourceSource,
    ResourceSourceLength
    );

  Status = AmlCreateDataNode (
             EAmlNodeDataTypeResourceData,
             UartDescBuff,
             UartDescBuffLength,
             &RdNode
             );
  FreePool (UartDescBuff);
  if (EFI_ERROR (Status)) {
    ASSERT_EFI_ERROR (Status);
    return Status;
  }

  return LinkRdNode (RdNode, NameOpNode, NewRdNode);
}

/** Code generation for the UARTSerialBusV2() ASL macro.

  The Resource Data effectively created is a UART Serial Bus Connection
  Resource Descriptor Resource Data.
  Cf ACPI 6.5:
   - s19.6.143 UARTSerialBusV2
     (UART Serial Bus Connection Resource Descriptor Version 2 Macro)
   - s6.4.3.8.2.3 UART Serial Bus Connection Resource Descriptor

  The created resource data node can be:
   - appended to the list of resource data elements of the NameOpNode.
     In such case NameOpNode must be defined by a the "Name ()" ASL statement
     and initially contain a "ResourceTemplate ()".
   - returned through the NewRdNode parameter.

  @param [in]  InitialBaudRate           Initial baud rate.
  @param [in]  BitsPerByte               Number of bits per byte.
                                         Optional, default is 8.
  @param [in]  StopBits                  Number of stop bits.
                                         Optional, default is 1.
  @param [in]  LinesInUse                Number of lines in use.
  @param [in]  IsBigEndian               Indicates whether the bit transfer is big-endian.
                                         Optional, default is FALSE (little-endian).
  @param [in]  Parity                    Parity format used.
                                          Optional, default is no parity.
  @param [in]  FlowControl               Flow control protocol used.
                                          Optional, default is no flow control.
  @param [in]  ReceiveBufferSize         Size of the receive buffer.
  @param [in]  TransmitBufferSize        Size of the transmit buffer.
  @param [in]  ResourceSource            Name of source resource used.
  @param [in]  ResourceSourceLength      Length of the Resource Source.
  @param [in]  ResourceSourceIndex       Resource Source index.
                                         Optional, default is 0.
  @param [in]  ResourceUsage             Resource usage, TRUE for consumer,
                                         FALSE for producer.
                                         Optional, default is TRUE (consumer).
  @param [in]  IsShared                  Indicates whether the resource is shared.
                                         Optional, default is FALSE (exclusive).
  @param [in]  VendorDefinedData         Vendor defined data.
                                         Optional, can be NULL.
  @param [in]  VendorDefinedDataLength   Length of the vendor defined data.
  @param [in]  NameOpNode                NameOp object node defining a named object.
                                         If provided, append the new resource data
                                         node to the list of resource data elements
                                         of this node.
  @param [out] NewRdNode                 If provided and success,
                                         contain the created node.

  @retval EFI_SUCCESS                   The function completed successfully.
  @retval EFI_INVALID_PARAMETER         Invalid parameter.
  @retval various                       Various failure values of called functions.
**/
EFI_STATUS
EFIAPI
AmlCodeGenRdUartSerialBusV2 (
  IN  UINT32                  InitialBaudRate,
  IN  UINT8                   *BitsPerByte OPTIONAL,
  IN  UINT8                   *StopBits OPTIONAL,
  IN  UINT8                   LinesInUse,
  IN  BOOLEAN                 *IsBigEndian OPTIONAL,
  IN  UINT8                   *Parity OPTIONAL,
  IN  UINT8                   *FlowControl OPTIONAL,
  IN  UINT16                  ReceiveBufferSize,
  IN  UINT16                  TransmitBufferSize,
  IN  CHAR8                   *ResourceSource,
  IN  UINT16                  ResourceSourceLength,
  IN  UINT8                   *ResourceSourceIndex OPTIONAL,
  IN  BOOLEAN                 *ResourceUsage OPTIONAL,
  IN  BOOLEAN                 *IsShared OPTIONAL,
  IN  UINT8                   *VendorDefinedData OPTIONAL,
  IN  UINT16                  VendorDefinedDataLength,
  IN  AML_OBJECT_NODE_HANDLE  NameOpNode OPTIONAL,
  OUT AML_DATA_NODE_HANDLE    *NewRdNode OPTIONAL
  )
{
  EFI_STATUS  Status;

  if ((NameOpNode == NULL) && (NewRdNode == NULL)) {
    ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
    return EFI_INVALID_PARAMETER;
  }

  if (((VendorDefinedData == NULL) && (VendorDefinedDataLength > 0)) ||
      ((VendorDefinedData != NULL) && (VendorDefinedDataLength == 0)))
  {
    ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
    return EFI_INVALID_PARAMETER;
  }

  if ((ResourceSource == NULL) || (ResourceSourceLength <= 0)) {
    ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
    return EFI_INVALID_PARAMETER;
  }

  if (ResourceSourceIndex != NULL) {
    if (*ResourceSourceIndex != 0) {
      ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
      return EFI_INVALID_PARAMETER;
    }
  }

  Status = AmlCodeGenRdUartSerialBus (
             /// default is resource consumer
             (ResourceUsage != NULL) ? *ResourceUsage : TRUE,
             /// slave mode
             TRUE,
             /// default is little-endian
             (IsBigEndian != NULL) ? *IsBigEndian : FALSE,
             /// default is 8 bits per byte
             (BitsPerByte != NULL) ? *BitsPerByte : 8,
             /// default is 1 stop bit
             (StopBits != NULL) ? *StopBits : EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_TSF_STOP_BIT_1,
             /// default is no flow control
             (FlowControl != NULL) ? *FlowControl : EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_TSF_FC_NONE,
             InitialBaudRate,
             ReceiveBufferSize,
             TransmitBufferSize,
             /// default is no parity
             (Parity != NULL) ? *Parity : EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_PARITY_NONE,
             LinesInUse,
             VendorDefinedData,
             VendorDefinedDataLength,
             ResourceSource,
             ResourceSourceLength,
             NameOpNode,
             NewRdNode
             );
  if (EFI_ERROR (Status)) {
    ASSERT_EFI_ERROR (Status);
    return Status;
  }

  return Status;
}
