Add ACPI SDT support. Introduce PcdInstallAcpiSdtProtocol, default FALSE. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10501 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, accroding 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
 | |
|            );
 | |
| }
 |