Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Hao Wu <hao.a.wu@intel.com> Reviewed-by: Feng Tian <feng.tian@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@19598 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			453 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			453 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  ACPI Sdt Protocol Driver
 | 
						|
 | 
						|
  Copyright (c) 2010, Intel Corporation. All rights reserved. <BR>
 | 
						|
  This program and the accompanying materials
 | 
						|
  are licensed and made available under the terms and conditions of the BSD License
 | 
						|
  which accompanies this distribution.  The full text of the license may be found at
 | 
						|
  http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "AcpiTable.h"
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve option term according to AmlByteEncoding and Buffer.
 | 
						|
  
 | 
						|
  @param[in]    AmlByteEncoding      AML Byte Encoding.
 | 
						|
  @param[in]    Buffer               AML buffer.
 | 
						|
  @param[in]    MaxBufferSize        AML buffer MAX size. The parser can not parse any data exceed this region.
 | 
						|
  @param[in]    TermIndex            Index of the data to retrieve from the object.
 | 
						|
  @param[out]   DataType             Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
 | 
						|
                                     for the specified index.
 | 
						|
  @param[out]   Data                 Upon return, points to the pointer to the data.
 | 
						|
  @param[out]   DataSize             Upon return, points to the size of Data.
 | 
						|
  
 | 
						|
  @retval       EFI_SUCCESS           Success.
 | 
						|
  @retval       EFI_INVALID_PARAMETER Buffer does not refer to a valid ACPI object.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AmlParseOptionTerm (
 | 
						|
  IN AML_BYTE_ENCODING   *AmlByteEncoding,
 | 
						|
  IN UINT8               *Buffer,
 | 
						|
  IN UINTN               MaxBufferSize,
 | 
						|
  IN AML_OP_PARSE_INDEX  TermIndex,
 | 
						|
  OUT EFI_ACPI_DATA_TYPE *DataType,
 | 
						|
  OUT VOID               **Data,
 | 
						|
  OUT UINTN              *DataSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  AML_BYTE_ENCODING   *ChildAmlByteEncoding;
 | 
						|
  EFI_STATUS          Status;
 | 
						|
 | 
						|
  if (DataType != NULL) {
 | 
						|
    *DataType = AmlTypeToAcpiType (AmlByteEncoding->Format[TermIndex - 1]);
 | 
						|
  }
 | 
						|
  if (Data != NULL) {
 | 
						|
    *Data = Buffer;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Parse term according to AML type
 | 
						|
  //
 | 
						|
  switch (AmlByteEncoding->Format[TermIndex - 1]) {
 | 
						|
  case AML_UINT8:
 | 
						|
    *DataSize = sizeof(UINT8);
 | 
						|
    break;
 | 
						|
  case AML_UINT16:
 | 
						|
    *DataSize = sizeof(UINT16);
 | 
						|
    break;
 | 
						|
  case AML_UINT32:
 | 
						|
    *DataSize = sizeof(UINT32);
 | 
						|
    break;
 | 
						|
  case AML_UINT64:
 | 
						|
    *DataSize = sizeof(UINT64);
 | 
						|
    break;
 | 
						|
  case AML_STRING:
 | 
						|
    *DataSize = AsciiStrSize((CHAR8 *)Buffer);
 | 
						|
    break;
 | 
						|
  case AML_NAME:
 | 
						|
    Status = AmlGetNameStringSize (Buffer, DataSize);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  case AML_OBJECT:
 | 
						|
    ChildAmlByteEncoding = AmlSearchByOpByte (Buffer);
 | 
						|
    if (ChildAmlByteEncoding == NULL) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // NOTE: We need override DataType here, if there is a case the AML_OBJECT is AML_NAME.
 | 
						|
    // We need convert type from EFI_ACPI_DATA_TYPE_CHILD to EFI_ACPI_DATA_TYPE_NAME_STRING.
 | 
						|
    // We should not return CHILD because there is NO OpCode for NameString.
 | 
						|
    //
 | 
						|
    if ((ChildAmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) {
 | 
						|
      if (DataType != NULL) {
 | 
						|
        *DataType = AmlTypeToAcpiType (AML_NAME);
 | 
						|
      }
 | 
						|
      Status = AmlGetNameStringSize (Buffer, DataSize);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        return EFI_INVALID_PARAMETER;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // It is real AML_OBJECT
 | 
						|
    //
 | 
						|
    *DataSize = AmlGetObjectSize (
 | 
						|
                     ChildAmlByteEncoding,
 | 
						|
                     Buffer,
 | 
						|
                     MaxBufferSize
 | 
						|
                     );
 | 
						|
    if (*DataSize == 0) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  case AML_NONE:
 | 
						|
    //
 | 
						|
    // No term
 | 
						|
    //
 | 
						|
  case AML_OPCODE:
 | 
						|
  default:
 | 
						|
    ASSERT (FALSE);
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  if (*DataSize > MaxBufferSize) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve information according to AmlByteEncoding and Buffer.
 | 
						|
  
 | 
						|
  @param[in]    AmlByteEncoding      AML Byte Encoding.
 | 
						|
  @param[in]    Buffer               AML buffer.
 | 
						|
  @param[in]    MaxBufferSize        AML buffer MAX size. The parser can not parse any data exceed this region.
 | 
						|
  @param[in]    Index                Index of the data to retrieve from the object. In general, indexes read from left-to-right
 | 
						|
                                     in the ACPI encoding, with index 0 always being the ACPI opcode.
 | 
						|
  @param[out]   DataType             Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
 | 
						|
                                     for the specified index.
 | 
						|
  @param[out]   Data                 Upon return, points to the pointer to the data.
 | 
						|
  @param[out]   DataSize             Upon return, points to the size of Data.
 | 
						|
  
 | 
						|
  @retval       EFI_SUCCESS           Success.
 | 
						|
  @retval       EFI_INVALID_PARAMETER Buffer does not refer to a valid ACPI object.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AmlParseOptionCommon (
 | 
						|
  IN AML_BYTE_ENCODING   *AmlByteEncoding,
 | 
						|
  IN UINT8               *Buffer,
 | 
						|
  IN UINTN               MaxBufferSize,
 | 
						|
  IN AML_OP_PARSE_INDEX  Index,
 | 
						|
  OUT EFI_ACPI_DATA_TYPE *DataType,
 | 
						|
  OUT VOID               **Data,
 | 
						|
  OUT UINTN              *DataSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8               *CurrentBuffer;
 | 
						|
  UINTN               PkgLength;
 | 
						|
  UINTN               OpLength;
 | 
						|
  UINTN               PkgOffset;
 | 
						|
  AML_OP_PARSE_INDEX  TermIndex;
 | 
						|
  EFI_STATUS          Status;
 | 
						|
 | 
						|
  ASSERT ((Index <= AmlByteEncoding->MaxIndex) || (Index == AML_OP_PARSE_INDEX_GET_SIZE));
 | 
						|
 | 
						|
  //
 | 
						|
  // 0. Check if this is NAME string.
 | 
						|
  //
 | 
						|
  if ((AmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) {
 | 
						|
    //
 | 
						|
    // Only allow GET_SIZE
 | 
						|
    //
 | 
						|
    if (Index != AML_OP_PARSE_INDEX_GET_SIZE) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // return NameString size
 | 
						|
    //
 | 
						|
    Status = AmlGetNameStringSize (Buffer, DataSize);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
    if (*DataSize > MaxBufferSize) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Not NAME string, start parsing
 | 
						|
  //
 | 
						|
  CurrentBuffer = Buffer;
 | 
						|
 | 
						|
  //
 | 
						|
  // 1. Get OpCode
 | 
						|
  //
 | 
						|
  if (Index != AML_OP_PARSE_INDEX_GET_SIZE) {
 | 
						|
    *DataType = EFI_ACPI_DATA_TYPE_OPCODE;
 | 
						|
    *Data = (VOID *)CurrentBuffer;
 | 
						|
  }
 | 
						|
  if (*CurrentBuffer == AML_EXT_OP) {
 | 
						|
    OpLength = 2;
 | 
						|
  } else {
 | 
						|
    OpLength = 1;
 | 
						|
  }
 | 
						|
  *DataSize = OpLength;
 | 
						|
  if (Index == AML_OP_PARSE_INDEX_GET_OPCODE) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
  if (OpLength > MaxBufferSize) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  CurrentBuffer += OpLength;
 | 
						|
 | 
						|
  //
 | 
						|
  // 2. Skip PkgLength field, if have
 | 
						|
  //
 | 
						|
  if ((AmlByteEncoding->Attribute & AML_HAS_PKG_LENGTH) != 0) {
 | 
						|
    PkgOffset = AmlGetPkgLength(CurrentBuffer, &PkgLength);
 | 
						|
    //
 | 
						|
    // Override MaxBufferSize if it is valid PkgLength
 | 
						|
    //
 | 
						|
    if (OpLength + PkgLength > MaxBufferSize) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    } else {
 | 
						|
      MaxBufferSize = OpLength + PkgLength;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    PkgOffset = 0;
 | 
						|
    PkgLength = 0;
 | 
						|
  }
 | 
						|
  CurrentBuffer += PkgOffset;
 | 
						|
 | 
						|
  //
 | 
						|
  // 3. Get Term one by one.
 | 
						|
  //
 | 
						|
  TermIndex = AML_OP_PARSE_INDEX_GET_TERM1;
 | 
						|
  while ((Index >= TermIndex) && (TermIndex <= AmlByteEncoding->MaxIndex) && ((UINTN)CurrentBuffer < (UINTN)Buffer + MaxBufferSize)) {
 | 
						|
    Status = AmlParseOptionTerm (
 | 
						|
               AmlByteEncoding,
 | 
						|
               CurrentBuffer,
 | 
						|
               (UINTN)Buffer + MaxBufferSize - (UINTN)CurrentBuffer,
 | 
						|
               TermIndex,
 | 
						|
               DataType,
 | 
						|
               Data,
 | 
						|
               DataSize
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Index == TermIndex) {
 | 
						|
      //
 | 
						|
      // Done
 | 
						|
      //
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Parse next one
 | 
						|
    //
 | 
						|
    CurrentBuffer += *DataSize;
 | 
						|
    TermIndex ++;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Finish all options, but no option found.
 | 
						|
  //
 | 
						|
  if ((UINTN)CurrentBuffer > (UINTN)Buffer + MaxBufferSize) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  if ((UINTN)CurrentBuffer == (UINTN)Buffer + MaxBufferSize) {
 | 
						|
    if (Index != AML_OP_PARSE_INDEX_GET_SIZE) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 4. Finish parsing all node, return size
 | 
						|
  //
 | 
						|
  ASSERT (Index == AML_OP_PARSE_INDEX_GET_SIZE);
 | 
						|
  if ((AmlByteEncoding->Attribute & AML_HAS_PKG_LENGTH) != 0) {
 | 
						|
    *DataSize = OpLength + PkgLength;
 | 
						|
  } else {
 | 
						|
    *DataSize = (UINTN)CurrentBuffer - (UINTN)Buffer;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return object size.
 | 
						|
  
 | 
						|
  @param[in]    AmlByteEncoding      AML Byte Encoding.
 | 
						|
  @param[in]    Buffer               AML object buffer.
 | 
						|
  @param[in]    MaxBufferSize        AML object buffer MAX size. The parser can not parse any data exceed this region.
 | 
						|
  
 | 
						|
  @return       Size of the object.
 | 
						|
**/
 | 
						|
UINTN
 | 
						|
AmlGetObjectSize (
 | 
						|
  IN AML_BYTE_ENCODING   *AmlByteEncoding,
 | 
						|
  IN UINT8               *Buffer,
 | 
						|
  IN UINTN               MaxBufferSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS   Status;
 | 
						|
  UINTN        DataSize;
 | 
						|
 | 
						|
  Status = AmlParseOptionCommon (
 | 
						|
               AmlByteEncoding,
 | 
						|
               Buffer,
 | 
						|
               MaxBufferSize,
 | 
						|
               AML_OP_PARSE_INDEX_GET_SIZE,
 | 
						|
               NULL,
 | 
						|
               NULL,
 | 
						|
               &DataSize
 | 
						|
               );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return 0;
 | 
						|
  } else {
 | 
						|
    return DataSize;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return object name.
 | 
						|
  
 | 
						|
  @param[in]    AmlHandle            AML handle.
 | 
						|
  
 | 
						|
  @return       Name of the object.
 | 
						|
**/
 | 
						|
CHAR8 *
 | 
						|
AmlGetObjectName (
 | 
						|
  IN EFI_AML_HANDLE      *AmlHandle
 | 
						|
  )
 | 
						|
{
 | 
						|
  AML_BYTE_ENCODING   *AmlByteEncoding;
 | 
						|
  VOID                *NameString;
 | 
						|
  UINTN               NameSize;
 | 
						|
  AML_OP_PARSE_INDEX  TermIndex;
 | 
						|
  EFI_STATUS          Status;
 | 
						|
  EFI_ACPI_DATA_TYPE  DataType;
 | 
						|
 | 
						|
  AmlByteEncoding = AmlHandle->AmlByteEncoding;
 | 
						|
 | 
						|
  ASSERT ((AmlByteEncoding->Attribute & AML_IN_NAMESPACE) != 0);
 | 
						|
 | 
						|
  //
 | 
						|
  // Find out Last Name index, according to OpCode table.
 | 
						|
  // The last name will be the node name by design.
 | 
						|
  //
 | 
						|
  TermIndex = AmlByteEncoding->MaxIndex;
 | 
						|
  for (TermIndex = AmlByteEncoding->MaxIndex; TermIndex > 0; TermIndex--) {
 | 
						|
    if (AmlByteEncoding->Format[TermIndex - 1] == AML_NAME) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  ASSERT (TermIndex != 0);
 | 
						|
 | 
						|
  //
 | 
						|
  // Get Name for this node.
 | 
						|
  //
 | 
						|
  Status = AmlParseOptionHandleCommon (
 | 
						|
             AmlHandle,
 | 
						|
             TermIndex,
 | 
						|
             &DataType,
 | 
						|
             &NameString,
 | 
						|
             &NameSize
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
  ASSERT (DataType == EFI_ACPI_DATA_TYPE_NAME_STRING);
 | 
						|
 | 
						|
  return NameString;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return offset of last option.
 | 
						|
  
 | 
						|
  @param[in]    AmlHandle            AML Handle.
 | 
						|
  @param[out]   Buffer               Upon return, points to the offset after last option.
 | 
						|
  
 | 
						|
  @retval       EFI_SUCCESS           Success.
 | 
						|
  @retval       EFI_INVALID_PARAMETER AmlHandle does not refer to a valid ACPI object.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AmlGetOffsetAfterLastOption (
 | 
						|
  IN EFI_AML_HANDLE         *AmlHandle,
 | 
						|
  OUT UINT8                 **Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_ACPI_DATA_TYPE  DataType;
 | 
						|
  VOID                *Data;
 | 
						|
  UINTN               DataSize;
 | 
						|
  EFI_STATUS          Status;
 | 
						|
 | 
						|
  Status = AmlParseOptionHandleCommon (
 | 
						|
             AmlHandle,
 | 
						|
             AmlHandle->AmlByteEncoding->MaxIndex,
 | 
						|
             &DataType,
 | 
						|
             &Data,
 | 
						|
             &DataSize
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // We need to parse the rest buffer after last node.
 | 
						|
  //
 | 
						|
  *Buffer = (UINT8 *)((UINTN)Data + DataSize);
 | 
						|
 | 
						|
  //
 | 
						|
  // We need skip PkgLength if no Option
 | 
						|
  //
 | 
						|
  if (DataType == EFI_ACPI_DATA_TYPE_OPCODE) {
 | 
						|
    *Buffer += AmlGetPkgLength (*Buffer, &DataSize);
 | 
						|
  }
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve information according to AmlHandle
 | 
						|
  
 | 
						|
  @param[in]    AmlHandle            AML handle.
 | 
						|
  @param[in]    Index                Index of the data to retrieve from the object. In general, indexes read from left-to-right
 | 
						|
                                     in the ACPI encoding, with index 0 always being the ACPI opcode.
 | 
						|
  @param[out]   DataType             Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
 | 
						|
                                     for the specified index.
 | 
						|
  @param[out]   Data                 Upon return, points to the pointer to the data.
 | 
						|
  @param[out]   DataSize             Upon return, points to the size of Data.
 | 
						|
  
 | 
						|
  @retval       EFI_SUCCESS           Success.
 | 
						|
  @retval       EFI_INVALID_PARAMETER AmlHandle does not refer to a valid ACPI object.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AmlParseOptionHandleCommon (
 | 
						|
  IN EFI_AML_HANDLE      *AmlHandle,
 | 
						|
  IN AML_OP_PARSE_INDEX  Index,
 | 
						|
  OUT EFI_ACPI_DATA_TYPE *DataType,
 | 
						|
  OUT VOID               **Data,
 | 
						|
  OUT UINTN              *DataSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  return AmlParseOptionCommon (
 | 
						|
           AmlHandle->AmlByteEncoding,
 | 
						|
           AmlHandle->Buffer,
 | 
						|
           AmlHandle->Size,
 | 
						|
           Index,
 | 
						|
           DataType,
 | 
						|
           Data,
 | 
						|
           DataSize
 | 
						|
           );
 | 
						|
}
 |