REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the DynamicTablesPkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>
		
			
				
	
	
		
			1012 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1012 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   AML Utility.
 | |
| 
 | |
|   Copyright (c) 2019 - 2021, Arm Limited. All rights reserved.<BR>
 | |
| 
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| **/
 | |
| 
 | |
| #include <Utils/AmlUtility.h>
 | |
| 
 | |
| #include <AmlCoreInterface.h>
 | |
| #include <Tree/AmlNode.h>
 | |
| #include <Tree/AmlTree.h>
 | |
| 
 | |
| /** This function computes and updates the ACPI table checksum.
 | |
| 
 | |
|   @param  [in]  AcpiTable   Pointer to an Acpi table.
 | |
| 
 | |
|   @retval EFI_SUCCESS   The function completed successfully.
 | |
|   @retval EFI_INVALID_PARAMETER   Invalid parameter.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AcpiPlatformChecksum (
 | |
|   IN  EFI_ACPI_DESCRIPTION_HEADER  *AcpiTable
 | |
|   )
 | |
| {
 | |
|   UINT8   *Ptr;
 | |
|   UINT8   Sum;
 | |
|   UINT32  Size;
 | |
| 
 | |
|   if (AcpiTable == NULL) {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Ptr  = (UINT8 *)AcpiTable;
 | |
|   Size = AcpiTable->Length;
 | |
|   Sum  = 0;
 | |
| 
 | |
|   // Set the checksum field to 0 first.
 | |
|   AcpiTable->Checksum = 0;
 | |
| 
 | |
|   // Compute the checksum.
 | |
|   while ((Size--) != 0) {
 | |
|     Sum = (UINT8)(Sum + (*Ptr++));
 | |
|   }
 | |
| 
 | |
|   // Set the checksum.
 | |
|   AcpiTable->Checksum = (UINT8)(0xFF - Sum + 1);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /** A callback function that computes the size of a Node and adds it to the
 | |
|     Size pointer stored in the Context.
 | |
|     Calling this function on the root node will compute the total size of the
 | |
|     AML bytestream.
 | |
| 
 | |
|   @param  [in]      Node      Node to compute the size.
 | |
|   @param  [in, out] Context   Pointer holding the computed size.
 | |
|                               (UINT32 *) Context.
 | |
|   @param  [in, out] Status    Pointer holding:
 | |
|                                - At entry, the Status returned by the
 | |
|                                  last call to this exact function during
 | |
|                                  the enumeration;
 | |
|                                - At exit, he returned status of the
 | |
|                                  call to this function.
 | |
|                               Optional, can be NULL.
 | |
| 
 | |
|   @retval TRUE if the enumeration can continue or has finished without
 | |
|           interruption.
 | |
|   @retval FALSE if the enumeration needs to stopped or has stopped.
 | |
| **/
 | |
| STATIC
 | |
| BOOLEAN
 | |
| EFIAPI
 | |
| AmlComputeSizeCallback (
 | |
|   IN      AML_NODE_HEADER  *Node,
 | |
|   IN  OUT VOID             *Context,
 | |
|   IN  OUT EFI_STATUS       *Status   OPTIONAL
 | |
|   )
 | |
| {
 | |
|   UINT32                 Size;
 | |
|   EAML_PARSE_INDEX       IndexPtr;
 | |
|   CONST AML_OBJECT_NODE  *ParentNode;
 | |
| 
 | |
|   if (!IS_AML_NODE_VALID (Node) ||
 | |
|       (Context == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     if (Status != NULL) {
 | |
|       *Status = EFI_INVALID_PARAMETER;
 | |
|     }
 | |
| 
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   // Ignore the second fixed argument of method invocation nodes
 | |
|   // as the information stored there (the argument count) is not in the
 | |
|   // ACPI specification.
 | |
|   ParentNode = (CONST AML_OBJECT_NODE *)AmlGetParent (Node);
 | |
|   if (IS_AML_OBJECT_NODE (ParentNode)                             &&
 | |
|       AmlNodeCompareOpCode (ParentNode, AML_METHOD_INVOC_OP, 0)   &&
 | |
|       AmlIsNodeFixedArgument (Node, &IndexPtr))
 | |
|   {
 | |
|     if (IndexPtr == EAmlParseIndexTerm1) {
 | |
|       if (Status != NULL) {
 | |
|         *Status = EFI_SUCCESS;
 | |
|       }
 | |
| 
 | |
|       return TRUE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Size = *((UINT32 *)Context);
 | |
| 
 | |
|   if (IS_AML_DATA_NODE (Node)) {
 | |
|     Size += ((AML_DATA_NODE *)Node)->Size;
 | |
|   } else if (IS_AML_OBJECT_NODE (Node)  &&
 | |
|              !AmlNodeHasAttribute (
 | |
|                 (CONST AML_OBJECT_NODE *)Node,
 | |
|                 AML_IS_PSEUDO_OPCODE
 | |
|                 ))
 | |
|   {
 | |
|     // Ignore pseudo-opcodes as they are not part of the
 | |
|     // ACPI specification.
 | |
| 
 | |
|     Size += (((AML_OBJECT_NODE *)Node)->AmlByteEncoding->OpCode ==
 | |
|              AML_EXT_OP) ? 2 : 1;
 | |
| 
 | |
|     // Add the size of the PkgLen.
 | |
|     if (AmlNodeHasAttribute (
 | |
|           (AML_OBJECT_NODE *)Node,
 | |
|           AML_HAS_PKG_LENGTH
 | |
|           ))
 | |
|     {
 | |
|       Size += AmlComputePkgLengthWidth (((AML_OBJECT_NODE *)Node)->PkgLen);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Check for overflow.
 | |
|   // The root node has a null size, thus the strict comparison.
 | |
|   if (*((UINT32 *)Context) > Size) {
 | |
|     ASSERT (0);
 | |
|     *Status = EFI_INVALID_PARAMETER;
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   *((UINT32 *)Context) = Size;
 | |
| 
 | |
|   if (Status != NULL) {
 | |
|     *Status = EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /** Compute the size of a tree/sub-tree.
 | |
| 
 | |
|   @param  [in]      Node      Node to compute the size.
 | |
|   @param  [in, out] Size      Pointer holding the computed size.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The function completed successfully.
 | |
|   @retval EFI_INVALID_PARAMETER   Invalid parameter.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlComputeSize (
 | |
|   IN      CONST AML_NODE_HEADER  *Node,
 | |
|   IN  OUT       UINT32           *Size
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   if (!IS_AML_NODE_VALID (Node) ||
 | |
|       (Size == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   *Size = 0;
 | |
| 
 | |
|   AmlEnumTree (
 | |
|     (AML_NODE_HEADER *)Node,
 | |
|     AmlComputeSizeCallback,
 | |
|     (VOID *)Size,
 | |
|     &Status
 | |
|     );
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /** Get the value contained in an integer node.
 | |
| 
 | |
|   @param  [in]  Node    Pointer to an integer node.
 | |
|                         Must be an object node.
 | |
|   @param  [out] Value   Value contained in the integer node.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The function completed successfully.
 | |
|   @retval EFI_INVALID_PARAMETER   Invalid parameter.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlNodeGetIntegerValue (
 | |
|   IN  AML_OBJECT_NODE  *Node,
 | |
|   OUT UINT64           *Value
 | |
|   )
 | |
| {
 | |
|   AML_DATA_NODE  *DataNode;
 | |
| 
 | |
|   if ((!IsIntegerNode (Node)            &&
 | |
|        !IsSpecialIntegerNode (Node))    ||
 | |
|       (Value == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // For ZeroOp and OneOp, there is no data node.
 | |
|   if (IsSpecialIntegerNode (Node)) {
 | |
|     if (AmlNodeCompareOpCode (Node, AML_ZERO_OP, 0)) {
 | |
|       *Value = 0;
 | |
|     } else if (AmlNodeCompareOpCode (Node, AML_ONE_OP, 0)) {
 | |
|       *Value = 1;
 | |
|     } else {
 | |
|       // OnesOp cannot be handled: it represents a maximum value.
 | |
|       ASSERT (0);
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
| 
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   // For integer nodes, the value is in the first fixed argument.
 | |
|   DataNode = (AML_DATA_NODE *)Node->FixedArgs[EAmlParseIndexTerm0];
 | |
|   if (!IS_AML_DATA_NODE (DataNode) ||
 | |
|       (DataNode->DataType != EAmlNodeDataTypeUInt))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   switch (DataNode->Size) {
 | |
|     case 1:
 | |
|     {
 | |
|       *Value = *((UINT8 *)(DataNode->Buffer));
 | |
|       break;
 | |
|     }
 | |
|     case 2:
 | |
|     {
 | |
|       *Value = *((UINT16 *)(DataNode->Buffer));
 | |
|       break;
 | |
|     }
 | |
|     case 4:
 | |
|     {
 | |
|       *Value = *((UINT32 *)(DataNode->Buffer));
 | |
|       break;
 | |
|     }
 | |
|     case 8:
 | |
|     {
 | |
|       *Value = *((UINT64 *)(DataNode->Buffer));
 | |
|       break;
 | |
|     }
 | |
|     default:
 | |
|     {
 | |
|       ASSERT (0);
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
|   } // switch
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /** Replace a Zero (AML_ZERO_OP) or One (AML_ONE_OP) object node
 | |
|     with a byte integer (AML_BYTE_PREFIX) object node having the same value.
 | |
| 
 | |
|   @param  [in]  Node    Pointer to an integer node.
 | |
|                         Must be an object node having ZeroOp or OneOp.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The function completed successfully.
 | |
|   @retval EFI_INVALID_PARAMETER   Invalid parameter.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlUnwindSpecialInteger (
 | |
|   IN  AML_OBJECT_NODE  *Node
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   AML_DATA_NODE            *NewDataNode;
 | |
|   UINT8                    Value;
 | |
|   CONST AML_BYTE_ENCODING  *ByteEncoding;
 | |
| 
 | |
|   if (!IsSpecialIntegerNode (Node)) {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // Find the value.
 | |
|   if (AmlNodeCompareOpCode (Node, AML_ZERO_OP, 0)) {
 | |
|     Value = 0;
 | |
|   } else if (AmlNodeCompareOpCode (Node, AML_ONE_OP, 0)) {
 | |
|     Value = 1;
 | |
|   } else {
 | |
|     // OnesOp cannot be handled: it represents a maximum value.
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Status = AmlCreateDataNode (
 | |
|              EAmlNodeDataTypeUInt,
 | |
|              &Value,
 | |
|              sizeof (UINT8),
 | |
|              (AML_DATA_NODE **)&NewDataNode
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   // Change the encoding of the special node to a ByteOp encoding.
 | |
|   ByteEncoding = AmlGetByteEncodingByOpCode (AML_BYTE_PREFIX, 0);
 | |
|   if (ByteEncoding == NULL) {
 | |
|     ASSERT (0);
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto error_handler;
 | |
|   }
 | |
| 
 | |
|   // Update the ByteEncoding from ZERO_OP/ONE_OP to AML_BYTE_PREFIX.
 | |
|   Node->AmlByteEncoding = ByteEncoding;
 | |
| 
 | |
|   // Add the data node as the first fixed argument of the ByteOp object.
 | |
|   Status = AmlSetFixedArgument (
 | |
|              (AML_OBJECT_NODE *)Node,
 | |
|              EAmlParseIndexTerm0,
 | |
|              (AML_NODE_HEADER *)NewDataNode
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     goto error_handler;
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| 
 | |
| error_handler:
 | |
|   AmlDeleteTree ((AML_NODE_HEADER *)NewDataNode);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /** Set the value contained in an integer node.
 | |
| 
 | |
|   The OpCode is updated accordingly to the new value
 | |
|   (e.g.: If the original value was a UINT8 value, then the OpCode
 | |
|          would be AML_BYTE_PREFIX. If it the new value is a UINT16
 | |
|          value then the OpCode will be updated to AML_WORD_PREFIX).
 | |
| 
 | |
|   @param  [in]  Node            Pointer to an integer node.
 | |
|                                 Must be an object node.
 | |
|   @param  [in]  NewValue        New value to write in the integer node.
 | |
|   @param  [out] ValueWidthDiff  Difference in number of bytes used to store
 | |
|                                 the new value.
 | |
|                                 Can be negative.
 | |
| 
 | |
|   @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
 | |
| AmlNodeSetIntegerValue (
 | |
|   IN  AML_OBJECT_NODE  *Node,
 | |
|   IN  UINT64           NewValue,
 | |
|   OUT INT8             *ValueWidthDiff
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS     Status;
 | |
|   AML_DATA_NODE  *DataNode;
 | |
| 
 | |
|   UINT8  NewOpCode;
 | |
|   UINT8  NumberOfBytes;
 | |
| 
 | |
|   if ((!IsIntegerNode (Node)            &&
 | |
|        !IsSpecialIntegerNode (Node))    ||
 | |
|       (ValueWidthDiff == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   *ValueWidthDiff = 0;
 | |
|   // For ZeroOp and OneOp, there is no data node.
 | |
|   // Thus the object node is converted to a byte object node holding 0 or 1.
 | |
|   if (IsSpecialIntegerNode (Node)) {
 | |
|     switch (NewValue) {
 | |
|       case AML_ZERO_OP:
 | |
|         Node->AmlByteEncoding = AmlGetByteEncodingByOpCode (AML_ZERO_OP, 0);
 | |
|         return EFI_SUCCESS;
 | |
|       case AML_ONE_OP:
 | |
|         Node->AmlByteEncoding = AmlGetByteEncodingByOpCode (AML_ONE_OP, 0);
 | |
|         return EFI_SUCCESS;
 | |
|       default:
 | |
|       {
 | |
|         Status = AmlUnwindSpecialInteger (Node);
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           ASSERT (0);
 | |
|           return Status;
 | |
|         }
 | |
| 
 | |
|         // The AmlUnwindSpecialInteger functions converts a special integer
 | |
|         // node to a UInt8/Byte data node. Thus, the size increments by one:
 | |
|         // special integer are encoded as one byte (the opcode only) while byte
 | |
|         // integers are encoded as two bytes (the opcode + the value).
 | |
|         *ValueWidthDiff += sizeof (UINT8);
 | |
|       }
 | |
|     } // switch
 | |
|   } // IsSpecialIntegerNode (Node)
 | |
| 
 | |
|   // For integer nodes, the value is in the first fixed argument.
 | |
|   DataNode = (AML_DATA_NODE *)Node->FixedArgs[EAmlParseIndexTerm0];
 | |
|   if (!IS_AML_DATA_NODE (DataNode) ||
 | |
|       (DataNode->DataType != EAmlNodeDataTypeUInt))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // The value can be encoded with a special 0 or 1 OpCode.
 | |
|   // The AML_ONES_OP is not handled.
 | |
|   if (NewValue <= 1) {
 | |
|     NewOpCode             = (NewValue == 0) ? AML_ZERO_OP : AML_ONE_OP;
 | |
|     Node->AmlByteEncoding = AmlGetByteEncodingByOpCode (NewOpCode, 0);
 | |
| 
 | |
|     // The value is encoded with a AML_ZERO_OP or AML_ONE_OP.
 | |
|     // This means there is no need for a DataNode containing the value.
 | |
|     // The change in size is equal to the size of the DataNode's buffer.
 | |
|     *ValueWidthDiff = -((INT8)DataNode->Size);
 | |
| 
 | |
|     // Detach and free the DataNode containing the integer value.
 | |
|     DataNode->NodeHeader.Parent          = NULL;
 | |
|     Node->FixedArgs[EAmlParseIndexTerm0] = NULL;
 | |
|     Status                               = AmlDeleteNode ((AML_NODE_HEADER *)DataNode);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   // Check the number of bits needed to represent the value.
 | |
|   if (NewValue > MAX_UINT32) {
 | |
|     // Value is 64 bits.
 | |
|     NewOpCode     = AML_QWORD_PREFIX;
 | |
|     NumberOfBytes = 8;
 | |
|   } else if (NewValue > MAX_UINT16) {
 | |
|     // Value is 32 bits.
 | |
|     NewOpCode     = AML_DWORD_PREFIX;
 | |
|     NumberOfBytes = 4;
 | |
|   } else if (NewValue > MAX_UINT8) {
 | |
|     // Value is 16 bits.
 | |
|     NewOpCode     = AML_WORD_PREFIX;
 | |
|     NumberOfBytes = 2;
 | |
|   } else {
 | |
|     // Value is 8 bits.
 | |
|     NewOpCode     = AML_BYTE_PREFIX;
 | |
|     NumberOfBytes = 1;
 | |
|   }
 | |
| 
 | |
|   *ValueWidthDiff += (INT8)(NumberOfBytes - DataNode->Size);
 | |
| 
 | |
|   // Update the ByteEncoding as it may have changed between [8 .. 64] bits.
 | |
|   Node->AmlByteEncoding = AmlGetByteEncodingByOpCode (NewOpCode, 0);
 | |
|   if (Node->AmlByteEncoding == NULL) {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // Free the old DataNode buffer and allocate a buffer with the right size
 | |
|   // to store the new data.
 | |
|   if (*ValueWidthDiff != 0) {
 | |
|     FreePool (DataNode->Buffer);
 | |
|     DataNode->Buffer = AllocateZeroPool (NumberOfBytes);
 | |
|     if (DataNode->Buffer == NULL) {
 | |
|       ASSERT (0);
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     DataNode->Size = NumberOfBytes;
 | |
|   }
 | |
| 
 | |
|   // Write the new value.
 | |
|   CopyMem (DataNode->Buffer, &NewValue, NumberOfBytes);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /** Increment/decrement the value contained in the IntegerNode.
 | |
| 
 | |
|   @param  [in]  IntegerNode     Pointer to an object node containing
 | |
|                                 an integer.
 | |
|   @param  [in]  IsIncrement     Choose the operation to do:
 | |
|                                  - TRUE:  Increment the Node's size and
 | |
|                                           the Node's count;
 | |
|                                  - FALSE: Decrement the Node's size and
 | |
|                                           the Node's count.
 | |
|   @param  [in]  Diff            Value to add/subtract to the integer.
 | |
|   @param  [out] ValueWidthDiff  When modifying the integer, it can be
 | |
|                                 promoted/demoted, e.g. from UINT8 to UINT16.
 | |
|                                 Stores the change in width.
 | |
|                                 Can be negative.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The function completed successfully.
 | |
|   @retval EFI_INVALID_PARAMETER   Invalid parameter.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlNodeUpdateIntegerValue (
 | |
|   IN  AML_OBJECT_NODE  *IntegerNode,
 | |
|   IN  BOOLEAN          IsIncrement,
 | |
|   IN  UINT64           Diff,
 | |
|   OUT INT8             *ValueWidthDiff
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   UINT64      Value;
 | |
| 
 | |
|   if (ValueWidthDiff == NULL) {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // Get the current value.
 | |
|   // Checks on the IntegerNode are done in the call.
 | |
|   Status = AmlNodeGetIntegerValue (IntegerNode, &Value);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   // Check for UINT64 over/underflow.
 | |
|   if ((IsIncrement && (Value > (MAX_UINT64 - Diff))) ||
 | |
|       (!IsIncrement && (Value < Diff)))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // Compute the new value.
 | |
|   if (IsIncrement) {
 | |
|     Value += Diff;
 | |
|   } else {
 | |
|     Value -= Diff;
 | |
|   }
 | |
| 
 | |
|   Status = AmlNodeSetIntegerValue (
 | |
|              IntegerNode,
 | |
|              Value,
 | |
|              ValueWidthDiff
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /** Propagate the size information up the tree.
 | |
| 
 | |
|   The length of the ACPI table is updated in the RootNode,
 | |
|   but not the checksum.
 | |
| 
 | |
|   @param  [in]  Node          Pointer to a node.
 | |
|                               Must be a root node or an object node.
 | |
|   @param  [in]  IsIncrement   Choose the operation to do:
 | |
|                                - TRUE:  Increment the Node's size and
 | |
|                                         the Node's count;
 | |
|                                - FALSE: Decrement the Node's size and
 | |
|                                         the Node's count.
 | |
|   @param  [in]  Diff          Value to add/subtract to the Node's size.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The function completed successfully.
 | |
|   @retval EFI_INVALID_PARAMETER   Invalid parameter.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlPropagateSize (
 | |
|   IN  AML_NODE_HEADER  *Node,
 | |
|   IN  BOOLEAN          IsIncrement,
 | |
|   IN  UINT32           *Diff
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS       Status;
 | |
|   AML_OBJECT_NODE  *ObjectNode;
 | |
|   AML_NODE_HEADER  *ParentNode;
 | |
| 
 | |
|   UINT32  Value;
 | |
|   UINT32  InitialPkgLenWidth;
 | |
|   UINT32  NewPkgLenWidth;
 | |
|   UINT32  ReComputedPkgLenWidth;
 | |
|   INT8    FieldWidthChange;
 | |
| 
 | |
|   if (!IS_AML_OBJECT_NODE (Node) &&
 | |
|       !IS_AML_ROOT_NODE (Node))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (IS_AML_OBJECT_NODE (Node)) {
 | |
|     ObjectNode = (AML_OBJECT_NODE *)Node;
 | |
| 
 | |
|     // For BufferOp, the buffer size is stored in BufferSize. Therefore,
 | |
|     // BufferOp needs special handling to update the BufferSize.
 | |
|     // BufferSize must be updated before the PkgLen to accommodate any
 | |
|     // increment resulting from the update of the BufferSize.
 | |
|     // DefBuffer := BufferOp PkgLength BufferSize ByteList
 | |
|     // BufferOp := 0x11
 | |
|     // BufferSize := TermArg => Integer
 | |
|     if (AmlNodeCompareOpCode (ObjectNode, AML_BUFFER_OP, 0)) {
 | |
|       // First fixed argument of BufferOp is an integer (BufferSize)
 | |
|       // (can be a BYTE, WORD, DWORD or QWORD).
 | |
|       // BufferSize is an object node.
 | |
|       Status = AmlNodeUpdateIntegerValue (
 | |
|                  (AML_OBJECT_NODE *)AmlGetFixedArgument (
 | |
|                                       ObjectNode,
 | |
|                                       EAmlParseIndexTerm0
 | |
|                                       ),
 | |
|                  IsIncrement,
 | |
|                  (UINT64)(*Diff),
 | |
|                  &FieldWidthChange
 | |
|                  );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         ASSERT (0);
 | |
|         return Status;
 | |
|       }
 | |
| 
 | |
|       // FieldWidthChange is an integer.
 | |
|       // It must be positive if IsIncrement is TRUE, negative otherwise.
 | |
|       if ((IsIncrement              &&
 | |
|            (FieldWidthChange < 0))  ||
 | |
|           (!IsIncrement             &&
 | |
|            (FieldWidthChange > 0)))
 | |
|       {
 | |
|         ASSERT (0);
 | |
|         return EFI_INVALID_PARAMETER;
 | |
|       }
 | |
| 
 | |
|       // Check for UINT32 overflow.
 | |
|       if (*Diff > (MAX_UINT32 - (UINT32)ABS (FieldWidthChange))) {
 | |
|         ASSERT (0);
 | |
|         return EFI_INVALID_PARAMETER;
 | |
|       }
 | |
| 
 | |
|       // Update Diff if the field width changed.
 | |
|       *Diff = (UINT32)(*Diff + ABS (FieldWidthChange));
 | |
|     } // AML_BUFFER_OP node.
 | |
| 
 | |
|     // Update the PgkLen.
 | |
|     // Needs to be done at last to reflect the potential field width changes.
 | |
|     if (AmlNodeHasAttribute (ObjectNode, AML_HAS_PKG_LENGTH)) {
 | |
|       Value = ObjectNode->PkgLen;
 | |
| 
 | |
|       // Subtract the size of the PkgLen encoding. The size of the PkgLen
 | |
|       // encoding must be computed after having updated Value.
 | |
|       InitialPkgLenWidth = AmlComputePkgLengthWidth (Value);
 | |
|       Value             -= InitialPkgLenWidth;
 | |
| 
 | |
|       // Check for an over/underflows.
 | |
|       // PkgLen is a 28 bit value, cf 20.2.4 Package Length Encoding
 | |
|       // i.e. the maximum value is (2^28 - 1) = ((BIT0 << 28) - 1).
 | |
|       if ((IsIncrement && ((((BIT0 << 28) - 1) - Value) < *Diff))   ||
 | |
|           (!IsIncrement && (Value < *Diff)))
 | |
|       {
 | |
|         ASSERT (0);
 | |
|         return EFI_INVALID_PARAMETER;
 | |
|       }
 | |
| 
 | |
|       // Update the size.
 | |
|       if (IsIncrement) {
 | |
|         Value += *Diff;
 | |
|       } else {
 | |
|         Value -= *Diff;
 | |
|       }
 | |
| 
 | |
|       // Compute the new PkgLenWidth.
 | |
|       NewPkgLenWidth = AmlComputePkgLengthWidth (Value);
 | |
|       if (NewPkgLenWidth == 0) {
 | |
|         ASSERT (0);
 | |
|         return EFI_INVALID_PARAMETER;
 | |
|       }
 | |
| 
 | |
|       // Add it to the Value.
 | |
|       Value += NewPkgLenWidth;
 | |
| 
 | |
|       // Check that adding the PkgLenWidth didn't trigger a domino effect,
 | |
|       // increasing the encoding width of the PkgLen again.
 | |
|       // The PkgLen is encoded on at most 4 bytes. It is possible to increase
 | |
|       // the PkgLen width if its encoding is on less than 3 bytes.
 | |
|       ReComputedPkgLenWidth = AmlComputePkgLengthWidth (Value);
 | |
|       if (ReComputedPkgLenWidth != NewPkgLenWidth) {
 | |
|         if ((ReComputedPkgLenWidth != 0)   &&
 | |
|             (ReComputedPkgLenWidth < 4))
 | |
|         {
 | |
|           // No need to recompute the PkgLen since a new threshold cannot
 | |
|           // be reached by incrementing the value by one.
 | |
|           Value += 1;
 | |
|         } else {
 | |
|           ASSERT (0);
 | |
|           return EFI_INVALID_PARAMETER;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       *Diff += (InitialPkgLenWidth > ReComputedPkgLenWidth) ?
 | |
|                (InitialPkgLenWidth - ReComputedPkgLenWidth) :
 | |
|                (ReComputedPkgLenWidth - InitialPkgLenWidth);
 | |
|       ObjectNode->PkgLen = Value;
 | |
|     } // PkgLen update.
 | |
| 
 | |
|     // During CodeGeneration, the tree is incomplete and
 | |
|     // there is no root node at the top of the tree. Stop
 | |
|     // propagating the new size when finding a root node
 | |
|     // OR when a NULL parent is found.
 | |
|     ParentNode = AmlGetParent ((AML_NODE_HEADER *)Node);
 | |
|     if (ParentNode != NULL) {
 | |
|       // Propagate the size up the tree.
 | |
|       Status = AmlPropagateSize (
 | |
|                  Node->Parent,
 | |
|                  IsIncrement,
 | |
|                  Diff
 | |
|                  );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         ASSERT (0);
 | |
|         return Status;
 | |
|       }
 | |
|     }
 | |
|   } else if (IS_AML_ROOT_NODE (Node)) {
 | |
|     // Update the length field in the SDT header.
 | |
|     Value = ((AML_ROOT_NODE *)Node)->SdtHeader->Length;
 | |
| 
 | |
|     // Check for an over/underflows.
 | |
|     if ((IsIncrement && (Value > (MAX_UINT32 - *Diff))) ||
 | |
|         (!IsIncrement && (Value < *Diff)))
 | |
|     {
 | |
|       ASSERT (0);
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
| 
 | |
|     // Update the size.
 | |
|     if (IsIncrement) {
 | |
|       Value += *Diff;
 | |
|     } else {
 | |
|       Value -= *Diff;
 | |
|     }
 | |
| 
 | |
|     ((AML_ROOT_NODE *)Node)->SdtHeader->Length = Value;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /** Propagate the node count information up the tree.
 | |
| 
 | |
|   @param  [in]  ObjectNode        Pointer to an object node.
 | |
|   @param  [in]  IsIncrement       Choose the operation to do:
 | |
|                                    - TRUE:  Increment the Node's size and
 | |
|                                             the Node's count;
 | |
|                                    - FALSE: Decrement the Node's size and
 | |
|                                            the Node's count.
 | |
|   @param  [in]  NodeCount         Number of nodes added/removed (depends on the
 | |
|                                   value of Operation).
 | |
|   @param  [out] FieldWidthChange  When modifying the integer, it can be
 | |
|                                   promoted/demoted, e.g. from UINT8 to UINT16.
 | |
|                                   Stores the change in width.
 | |
|                                   Can be negative.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The function completed successfully.
 | |
|   @retval EFI_INVALID_PARAMETER   Invalid parameter.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlPropagateNodeCount (
 | |
|   IN  AML_OBJECT_NODE  *ObjectNode,
 | |
|   IN  BOOLEAN          IsIncrement,
 | |
|   IN  UINT8            NodeCount,
 | |
|   OUT INT8             *FieldWidthChange
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   AML_NODE_HEADER  *NodeCountArg;
 | |
|   UINT8            CurrNodeCount;
 | |
| 
 | |
|   // Currently there is no use case where (NodeCount > 1).
 | |
|   if (!IS_AML_OBJECT_NODE (ObjectNode)  ||
 | |
|       (FieldWidthChange == NULL)        ||
 | |
|       (NodeCount > 1))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   *FieldWidthChange = 0;
 | |
| 
 | |
|   // Update the number of elements stored in PackageOp and VarPackageOp.
 | |
|   // The number of elements is stored as the first fixed argument.
 | |
|   // DefPackage := PackageOp PkgLength NumElements PackageElementList
 | |
|   // PackageOp := 0x12
 | |
|   // DefVarPackage := VarPackageOp PkgLength VarNumElements PackageElementList
 | |
|   // VarPackageOp := 0x13
 | |
|   // NumElements := ByteData
 | |
|   // VarNumElements := TermArg => Integer
 | |
|   NodeCountArg = AmlGetFixedArgument (ObjectNode, EAmlParseIndexTerm0);
 | |
|   if (AmlNodeCompareOpCode (ObjectNode, AML_PACKAGE_OP, 0)) {
 | |
|     // First fixed argument of PackageOp stores the number of elements
 | |
|     // in the package. It is an UINT8.
 | |
| 
 | |
|     // Check for over/underflow.
 | |
|     CurrNodeCount = *(((AML_DATA_NODE *)NodeCountArg)->Buffer);
 | |
|     if ((IsIncrement && (CurrNodeCount == MAX_UINT8)) ||
 | |
|         (!IsIncrement && (CurrNodeCount == 0)))
 | |
|     {
 | |
|       ASSERT (0);
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
| 
 | |
|     // Update the node count in the DataNode.
 | |
|     CurrNodeCount                              = IsIncrement ? (CurrNodeCount + 1) : (CurrNodeCount - 1);
 | |
|     *(((AML_DATA_NODE *)NodeCountArg)->Buffer) =  CurrNodeCount;
 | |
|   } else if (AmlNodeCompareOpCode (ObjectNode, AML_VAR_PACKAGE_OP, 0)) {
 | |
|     // First fixed argument of PackageOp stores the number of elements
 | |
|     // in the package. It is an integer (can be a BYTE, WORD, DWORD, QWORD).
 | |
|     Status = AmlNodeUpdateIntegerValue (
 | |
|                (AML_OBJECT_NODE *)NodeCountArg,
 | |
|                IsIncrement,
 | |
|                NodeCount,
 | |
|                FieldWidthChange
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /** Propagate information up the tree.
 | |
| 
 | |
|   The information can be a new size, a new number of arguments.
 | |
| 
 | |
|   @param  [in]  Node          Pointer to a node.
 | |
|                               Must be a root node or an object node.
 | |
|   @param  [in]  IsIncrement   Choose the operation to do:
 | |
|                                - TRUE:  Increment the Node's size and
 | |
|                                         the Node's count;
 | |
|                                - FALSE: Decrement the Node's size and
 | |
|                                         the Node's count.
 | |
|   @param  [in]  Diff          Value to add/subtract to the Node's size.
 | |
|   @param  [in]  NodeCount     Number of nodes added/removed.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The function completed successfully.
 | |
|   @retval EFI_INVALID_PARAMETER   Invalid parameter.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlPropagateInformation (
 | |
|   IN  AML_NODE_HEADER  *Node,
 | |
|   IN  BOOLEAN          IsIncrement,
 | |
|   IN  UINT32           Diff,
 | |
|   IN  UINT8            NodeCount
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   INT8        FieldWidthChange;
 | |
| 
 | |
|   // Currently there is no use case where (NodeCount > 1).
 | |
|   if ((!IS_AML_ROOT_NODE (Node)     &&
 | |
|        !IS_AML_OBJECT_NODE (Node))  ||
 | |
|       (NodeCount > 1))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // Propagate the node count first as it may change the number of bytes
 | |
|   // needed to store the node count, and then impact FieldWidthChange.
 | |
|   if ((NodeCount != 0) &&
 | |
|       IS_AML_OBJECT_NODE (Node))
 | |
|   {
 | |
|     Status = AmlPropagateNodeCount (
 | |
|                (AML_OBJECT_NODE *)Node,
 | |
|                IsIncrement,
 | |
|                NodeCount,
 | |
|                &FieldWidthChange
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     // Propagate the potential field width change.
 | |
|     // Maximum change is between UINT8/UINT64: 8 bytes.
 | |
|     if ((ABS (FieldWidthChange) > 8)                          ||
 | |
|         (IsIncrement                                          &&
 | |
|          ((FieldWidthChange < 0)                             ||
 | |
|           ((Diff + (UINT8)FieldWidthChange) > MAX_UINT32)))  ||
 | |
|         (!IsIncrement                                         &&
 | |
|          ((FieldWidthChange > 0)                             ||
 | |
|           (Diff < (UINT32)ABS (FieldWidthChange)))))
 | |
|     {
 | |
|       ASSERT (0);
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
| 
 | |
|     Diff = (UINT32)(Diff + (UINT8)ABS (FieldWidthChange));
 | |
|   }
 | |
| 
 | |
|   // Diff can be zero if some data is updated without modifying the data size.
 | |
|   if (Diff != 0) {
 | |
|     Status = AmlPropagateSize (Node, IsIncrement, &Diff);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /** Find and set the EndTag's Checksum of a list of Resource Data elements.
 | |
| 
 | |
|   Lists of Resource Data elements end with an EndTag (most of the time). This
 | |
|   function finds the EndTag (if present) in a list of Resource Data elements
 | |
|   and sets the checksum.
 | |
| 
 | |
|   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]  BufferOpNode   Node having a list of Resource Data elements.
 | |
|   @param [in]  CheckSum       CheckSum to store in the EndTag.
 | |
|                               To ignore/avoid computing the checksum,
 | |
|                               give 0.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The function completed successfully.
 | |
|   @retval EFI_INVALID_PARAMETER   Invalid parameter.
 | |
|   @retval EFI_NOT_FOUND           No EndTag found.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlSetRdListCheckSum (
 | |
|   IN  AML_OBJECT_NODE  *BufferOpNode,
 | |
|   IN  UINT8            CheckSum
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS     Status;
 | |
|   AML_DATA_NODE  *LastRdNode;
 | |
|   AML_RD_HEADER  RdDataType;
 | |
| 
 | |
|   if (!AmlNodeCompareOpCode (BufferOpNode, AML_BUFFER_OP, 0)) {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // Get the last Resource data node in the variable list of
 | |
|   // argument of the BufferOp node.
 | |
|   LastRdNode = (AML_DATA_NODE *)AmlGetPreviousVariableArgument (
 | |
|                                   (AML_NODE_HEADER *)BufferOpNode,
 | |
|                                   NULL
 | |
|                                   );
 | |
|   if ((LastRdNode == NULL)             ||
 | |
|       !IS_AML_DATA_NODE (LastRdNode)   ||
 | |
|       (LastRdNode->DataType != EAmlNodeDataTypeResourceData))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Status = AmlGetResourceDataType (LastRdNode, &RdDataType);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   // Check the LastRdNode is an EndTag.
 | |
|   // It is possible to have only one Resource Data in a BufferOp with
 | |
|   // no EndTag. Return EFI_NOT_FOUND is such case.
 | |
|   if (!AmlRdCompareDescId (
 | |
|          &RdDataType,
 | |
|          AML_RD_BUILD_SMALL_DESC_ID (ACPI_SMALL_END_TAG_DESCRIPTOR_NAME)
 | |
|          ))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   Status = AmlRdSetEndTagChecksum (LastRdNode->Buffer, CheckSum);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   return Status;
 | |
| }
 |