/****************************************************************************** * * Module Name: dttable1.c - handling for specific ACPI tables * *****************************************************************************/ /* * Copyright (C) 2000 - 2023, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification. * 2. Redistributions in binary form must reproduce at minimum a disclaimer * substantially similar to the "NO WARRANTY" disclaimer below * ("Disclaimer") and any redistribution must be conditioned upon * including a substantially similar Disclaimer requirement for further * binary redistribution. * 3. Neither the names of the above-listed copyright holders nor the names * of any contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. */ /* Compile all complex data tables, signatures starting with A-I */ #include "aslcompiler.h" #define _COMPONENT DT_COMPILER ACPI_MODULE_NAME ("dttable1") static ACPI_DMTABLE_INFO TableInfoAsfAddress[] = { {ACPI_DMT_BUFFER, 0, "Addresses", 0}, {ACPI_DMT_EXIT, 0, NULL, 0} }; static ACPI_DMTABLE_INFO TableInfoDmarPciPath[] = { {ACPI_DMT_PCI_PATH, 0, "PCI Path", 0}, {ACPI_DMT_EXIT, 0, NULL, 0} }; /****************************************************************************** * * FUNCTION: DtCompileAest * * PARAMETERS: List - Current field list pointer * * RETURN: Status * * DESCRIPTION: Compile AEST. * * NOTE: Assumes the following table structure: * For all AEST Error Nodes: * 1) An AEST Error Node, followed immediately by: * 2) Any node-specific data * 3) An Interface Structure (one) * 4) A list (array) of Interrupt Structures, the count as specified * in the NodeInterruptCount field of the Error Node header. * * AEST - ARM Error Source table. Conforms to: * ACPI for the Armv8 RAS Extensions 1.1 Platform Design Document Sep 2020 * *****************************************************************************/ ACPI_STATUS DtCompileAest ( void **List) { ACPI_AEST_HEADER *ErrorNodeHeader; ACPI_AEST_PROCESSOR *AestProcessor; DT_SUBTABLE *Subtable; DT_SUBTABLE *ParentTable; ACPI_DMTABLE_INFO *InfoTable; ACPI_STATUS Status; UINT32 i; UINT32 Offset; DT_FIELD **PFieldList = (DT_FIELD **) List; ACPI_AEST_NODE_INTERFACE_HEADER *AestNodeHeader; UINT8 Revision; ACPI_TABLE_HEADER *Header; ParentTable = DtPeekSubtable (); Header = ACPI_CAST_PTR (ACPI_TABLE_HEADER, ParentTable->Buffer); Revision = Header->Revision; while (*PFieldList) { /* Compile the common error node header */ Status = DtCompileTable (PFieldList, AcpiDmTableInfoAestHdr, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); /* Everything past the error node header will be a subtable */ DtPushSubtable (Subtable); /* * Compile the node-specific structure (Based on the error * node header Type field) */ ErrorNodeHeader = ACPI_CAST_PTR (ACPI_AEST_HEADER, Subtable->Buffer); /* Point past the common error node header */ Offset = sizeof (ACPI_AEST_HEADER); ErrorNodeHeader->NodeSpecificOffset = Offset; /* Decode the error node type */ switch (ErrorNodeHeader->Type) { case ACPI_AEST_PROCESSOR_ERROR_NODE: InfoTable = AcpiDmTableInfoAestProcError; break; case ACPI_AEST_MEMORY_ERROR_NODE: InfoTable = AcpiDmTableInfoAestMemError; break; case ACPI_AEST_SMMU_ERROR_NODE: InfoTable = AcpiDmTableInfoAestSmmuError; break; case ACPI_AEST_VENDOR_ERROR_NODE: switch (Revision) { case 1: InfoTable = AcpiDmTableInfoAestVendorError; break; case 2: InfoTable = AcpiDmTableInfoAestVendorV2Error; break; default: AcpiOsPrintf ("Unknown AEST Vendor Error Revision: %X\n", Revision); return (AE_ERROR); } break; case ACPI_AEST_GIC_ERROR_NODE: InfoTable = AcpiDmTableInfoAestGicError; break; case ACPI_AEST_PCIE_ERROR_NODE: InfoTable = AcpiDmTableInfoAestPCIeError; break; case ACPI_AEST_PROXY_ERROR_NODE: InfoTable = AcpiDmTableInfoAestProxyError; break; /* Error case below */ default: AcpiOsPrintf ("Unknown AEST Subtable Type: %X\n", ErrorNodeHeader->Type); return (AE_ERROR); } Status = DtCompileTable (PFieldList, InfoTable, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } /* Point past the node-specific structure */ Offset += Subtable->Length; ErrorNodeHeader->NodeInterfaceOffset = Offset; ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); /* Compile any additional node-specific substructures */ if (ErrorNodeHeader->Type == ACPI_AEST_PROCESSOR_ERROR_NODE) { /* * Special handling for PROCESSOR_ERROR_NODE subtables * (to handle the Resource Substructure via the ResourceType * field). */ AestProcessor = ACPI_CAST_PTR (ACPI_AEST_PROCESSOR, Subtable->Buffer); switch (AestProcessor->ResourceType) { case ACPI_AEST_CACHE_RESOURCE: InfoTable = AcpiDmTableInfoAestCacheRsrc; break; case ACPI_AEST_TLB_RESOURCE: InfoTable = AcpiDmTableInfoAestTlbRsrc; break; case ACPI_AEST_GENERIC_RESOURCE: InfoTable = AcpiDmTableInfoAestGenRsrc; AcpiOsPrintf ("Generic Resource Type (%X) is not supported at this time\n", AestProcessor->ResourceType); return (AE_ERROR); /* Error case below */ default: AcpiOsPrintf ("Unknown AEST Processor Resource Type: %X\n", AestProcessor->ResourceType); return (AE_ERROR); } Status = DtCompileTable (PFieldList, InfoTable, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } /* Point past the resource substructure subtable */ Offset += Subtable->Length; ErrorNodeHeader->NodeInterfaceOffset = Offset; ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); } /* Compile the (required) node interface structure */ if (Revision == 1) { InfoTable = AcpiDmTableInfoAestXface; } else if (Revision == 2) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoAestXfaceHeader, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); Offset += Subtable->Length; AestNodeHeader = ACPI_CAST_PTR (ACPI_AEST_NODE_INTERFACE_HEADER, Subtable->Buffer); switch (AestNodeHeader->GroupFormat) { case ACPI_AEST_NODE_GROUP_FORMAT_4K: InfoTable = AcpiDmTableInfoAestXface4k; break; case ACPI_AEST_NODE_GROUP_FORMAT_16K: InfoTable = AcpiDmTableInfoAestXface16k; break; case ACPI_AEST_NODE_GROUP_FORMAT_64K: InfoTable = AcpiDmTableInfoAestXface64k; break; /* Error case below */ default: AcpiOsPrintf ("Unknown AEST Interface Group Format: %X\n", AestNodeHeader->GroupFormat); return (AE_ERROR); } } else { AcpiOsPrintf ("Unknown AEST Revision: %X\n", Revision); } Status = DtCompileTable (PFieldList, InfoTable, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ErrorNodeHeader->NodeInterruptOffset = 0; ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); /* Compile each of the node interrupt structures */ if (ErrorNodeHeader->NodeInterruptCount) { /* Point to the first interrupt structure */ Offset += Subtable->Length; ErrorNodeHeader->NodeInterruptOffset = Offset; } /* Compile each of the interrupt structures */ for (i = 0; i < ErrorNodeHeader->NodeInterruptCount; i++) { switch (Revision) { case 1: InfoTable = AcpiDmTableInfoAestXrupt; break; case 2: InfoTable = AcpiDmTableInfoAestXruptV2; break; default: AcpiOsPrintf ("Unknown AEST Revision: %X\n", Revision); return (AE_ERROR); } Status = DtCompileTable (PFieldList, InfoTable, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); } /* Prepare for the next AEST Error node */ DtPopSubtable (); } return (AE_OK); } /****************************************************************************** * * FUNCTION: DtCompileApmt * * PARAMETERS: List - Current field list pointer * * RETURN: Status * * DESCRIPTION: Compile APMT. * *****************************************************************************/ ACPI_STATUS DtCompileApmt ( void **List) { ACPI_STATUS Status; ACPI_TABLE_HEADER *Header; ACPI_APMT_NODE *ApmtNode; ACPI_APMT_NODE *PeerApmtNode; DT_SUBTABLE *Subtable; DT_SUBTABLE *PeerSubtable; DT_SUBTABLE *ParentTable; DT_FIELD **PFieldList = (DT_FIELD**)List; DT_FIELD *SubtableStart; UINT32 CurLength; char MsgBuffer[64] = ""; ParentTable = DtPeekSubtable(); Header = ACPI_CAST_PTR(ACPI_TABLE_HEADER, ParentTable->Buffer); CurLength = sizeof(ACPI_TABLE_HEADER); /* Walk the parse tree */ while (*PFieldList) { /* APMT Node Subtable */ SubtableStart = *PFieldList; Status = DtCompileTable(PFieldList, AcpiDmTableInfoApmtNode, &Subtable); if (ACPI_FAILURE(Status)) { return (Status); } ApmtNode = ACPI_CAST_PTR(ACPI_APMT_NODE, Subtable->Buffer); if (ApmtNode->Length != sizeof(ACPI_APMT_NODE)) { DtFatal(ASL_MSG_INVALID_LENGTH, SubtableStart, "APMT"); return (AE_ERROR); } if (ApmtNode->Type >= ACPI_APMT_NODE_TYPE_COUNT) { snprintf(MsgBuffer, 64, "Node Type : 0x%X", ApmtNode->Type); DtFatal(ASL_MSG_INVALID_TYPE, SubtableStart, MsgBuffer); return (AE_ERROR); } PeerSubtable = DtGetNextSubtable(ParentTable, NULL); /* Validate the node id needs to be unique. */ while(PeerSubtable) { PeerApmtNode = ACPI_CAST_PTR(ACPI_APMT_NODE, PeerSubtable->Buffer); if (PeerApmtNode->Id == ApmtNode->Id) { snprintf(MsgBuffer, 64, "Node Id : 0x%X existed", ApmtNode->Id); DtFatal(ASL_MSG_DUPLICATE_ITEM, SubtableStart, MsgBuffer); return (AE_ERROR); } PeerSubtable = DtGetNextSubtable(ParentTable, PeerSubtable); } CurLength += ApmtNode->Length; DtInsertSubtable(ParentTable, Subtable); } if (Header->Length != CurLength) { snprintf(MsgBuffer, 64, " - APMT Length : %u (expected: %u)", Header->Length, CurLength); DtFatal(ASL_MSG_INVALID_LENGTH, NULL, MsgBuffer); return (AE_ERROR); } return (AE_OK); } /****************************************************************************** * * FUNCTION: DtCompileAsf * * PARAMETERS: List - Current field list pointer * * RETURN: Status * * DESCRIPTION: Compile ASF!. * *****************************************************************************/ ACPI_STATUS DtCompileAsf ( void **List) { ACPI_ASF_INFO *AsfTable; DT_SUBTABLE *Subtable; DT_SUBTABLE *ParentTable; ACPI_DMTABLE_INFO *InfoTable; ACPI_DMTABLE_INFO *DataInfoTable = NULL; UINT32 DataCount = 0; ACPI_STATUS Status; UINT32 i; DT_FIELD **PFieldList = (DT_FIELD **) List; DT_FIELD *SubtableStart; while (*PFieldList) { SubtableStart = *PFieldList; Status = DtCompileTable (PFieldList, AcpiDmTableInfoAsfHdr, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); DtPushSubtable (Subtable); AsfTable = ACPI_CAST_PTR (ACPI_ASF_INFO, Subtable->Buffer); switch (AsfTable->Header.Type & 0x7F) /* Mask off top bit */ { case ACPI_ASF_TYPE_INFO: InfoTable = AcpiDmTableInfoAsf0; break; case ACPI_ASF_TYPE_ALERT: InfoTable = AcpiDmTableInfoAsf1; break; case ACPI_ASF_TYPE_CONTROL: InfoTable = AcpiDmTableInfoAsf2; break; case ACPI_ASF_TYPE_BOOT: InfoTable = AcpiDmTableInfoAsf3; break; case ACPI_ASF_TYPE_ADDRESS: InfoTable = AcpiDmTableInfoAsf4; break; default: DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "ASF!"); return (AE_ERROR); } Status = DtCompileTable (PFieldList, InfoTable, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); switch (AsfTable->Header.Type & 0x7F) /* Mask off top bit */ { case ACPI_ASF_TYPE_INFO: DataInfoTable = NULL; break; case ACPI_ASF_TYPE_ALERT: DataInfoTable = AcpiDmTableInfoAsf1a; DataCount = ACPI_CAST_PTR (ACPI_ASF_ALERT, ACPI_SUB_PTR (UINT8, Subtable->Buffer, sizeof (ACPI_ASF_HEADER)))->Alerts; break; case ACPI_ASF_TYPE_CONTROL: DataInfoTable = AcpiDmTableInfoAsf2a; DataCount = ACPI_CAST_PTR (ACPI_ASF_REMOTE, ACPI_SUB_PTR (UINT8, Subtable->Buffer, sizeof (ACPI_ASF_HEADER)))->Controls; break; case ACPI_ASF_TYPE_BOOT: DataInfoTable = NULL; break; case ACPI_ASF_TYPE_ADDRESS: DataInfoTable = TableInfoAsfAddress; DataCount = ACPI_CAST_PTR (ACPI_ASF_ADDRESS, ACPI_SUB_PTR (UINT8, Subtable->Buffer, sizeof (ACPI_ASF_HEADER)))->Devices; break; default: DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "ASF!"); return (AE_ERROR); } if (DataInfoTable) { switch (AsfTable->Header.Type & 0x7F) { case ACPI_ASF_TYPE_ADDRESS: while (DataCount > 0) { Status = DtCompileTable (PFieldList, DataInfoTable, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); DataCount = DataCount - Subtable->Length; } break; default: for (i = 0; i < DataCount; i++) { Status = DtCompileTable (PFieldList, DataInfoTable, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); } break; } } DtPopSubtable (); } return (AE_OK); } /****************************************************************************** * * FUNCTION: DtCompileAspt * * PARAMETERS: List - Current field list pointer * * RETURN: Status * * DESCRIPTION: Compile ASPT. * *****************************************************************************/ ACPI_STATUS DtCompileAspt ( void **List) { ACPI_ASPT_HEADER *AsptTable; DT_SUBTABLE *Subtable; DT_SUBTABLE *ParentTable; ACPI_DMTABLE_INFO *InfoTable; ACPI_STATUS Status; DT_FIELD **PFieldList = (DT_FIELD **) List; DT_FIELD *SubtableStart; Status = DtCompileTable (PFieldList, AcpiDmTableInfoAspt, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); while (*PFieldList) { SubtableStart = *PFieldList; Status = DtCompileTable (PFieldList, AcpiDmTableInfoAsptHdr, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); DtPushSubtable (Subtable); AsptTable = ACPI_CAST_PTR (ACPI_ASPT_HEADER, Subtable->Buffer); switch (AsptTable->Type) /* Mask off top bit */ { case ACPI_ASPT_TYPE_GLOBAL_REGS: InfoTable = AcpiDmTableInfoAspt0; break; case ACPI_ASPT_TYPE_SEV_MBOX_REGS: InfoTable = AcpiDmTableInfoAspt1; break; case ACPI_ASPT_TYPE_ACPI_MBOX_REGS: InfoTable = AcpiDmTableInfoAspt2; break; default: DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "ASPT"); return (AE_ERROR); } Status = DtCompileTable (PFieldList, InfoTable, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); DtPopSubtable (); } return (AE_OK); } /****************************************************************************** * * FUNCTION: DtCompileCdat * * PARAMETERS: List - Current field list pointer * * RETURN: Status * * DESCRIPTION: Compile CDAT. * *****************************************************************************/ ACPI_STATUS DtCompileCdat ( void **List) { ACPI_STATUS Status = AE_OK; DT_SUBTABLE *Subtable; DT_SUBTABLE *ParentTable; DT_FIELD **PFieldList = (DT_FIELD **) List; ACPI_CDAT_HEADER *CdatHeader; ACPI_DMTABLE_INFO *InfoTable = NULL; DT_FIELD *SubtableStart; /* Walk the parse tree. * * Note: Main table consists of only the CDAT table header * (This is not the standard ACPI table header, however)-- * Followed by some number of subtables. */ while (*PFieldList) { SubtableStart = *PFieldList; /* Compile the expected CDAT Subtable header */ Status = DtCompileTable (PFieldList, AcpiDmTableInfoCdatHeader, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); DtPushSubtable (Subtable); CdatHeader = ACPI_CAST_PTR (ACPI_CDAT_HEADER, Subtable->Buffer); /* Decode the subtable by type */ switch (CdatHeader->Type) { case ACPI_CDAT_TYPE_DSMAS: InfoTable = AcpiDmTableInfoCdat0; break; case ACPI_CDAT_TYPE_DSLBIS: InfoTable = AcpiDmTableInfoCdat1; break; case ACPI_CDAT_TYPE_DSMSCIS: InfoTable = AcpiDmTableInfoCdat2; break; case ACPI_CDAT_TYPE_DSIS: InfoTable = AcpiDmTableInfoCdat3; break; case ACPI_CDAT_TYPE_DSEMTS: InfoTable = AcpiDmTableInfoCdat4; break; case ACPI_CDAT_TYPE_SSLBIS: InfoTable = AcpiDmTableInfoCdat5; break; default: DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "CDAT"); } /* Compile the CDAT subtable */ Status = DtCompileTable (PFieldList, InfoTable, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); switch (CdatHeader->Type) { /* Multiple entries supported for this type */ case ACPI_CDAT_TYPE_SSLBIS: /* * Check for multiple SSLBEs */ while (*PFieldList && !AcpiUtStricmp ((*PFieldList)->Name, "Port X ID")) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoCdatEntries, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); } break; default: break; } /* Pop off the CDAT Subtable header subtree */ DtPopSubtable (); } return (AE_OK); } /****************************************************************************** * * FUNCTION: DtCompileCedt * * PARAMETERS: List - Current field list pointer * * RETURN: Status * * DESCRIPTION: Compile CEDT. * *****************************************************************************/ ACPI_STATUS DtCompileCedt ( void **List) { ACPI_STATUS Status; DT_SUBTABLE *Subtable; DT_SUBTABLE *ParentTable; DT_FIELD **PFieldList = (DT_FIELD **) List; ACPI_CEDT_HEADER *CedtHeader; DT_FIELD *SubtableStart; /* Walk the parse tree */ while (*PFieldList) { /* if CFMWS and has more than one target, then set to zero later */ int InsertFlag = 1; SubtableStart = *PFieldList; /* CEDT Header */ Status = DtCompileTable (PFieldList, AcpiDmTableInfoCedtHdr, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); DtPushSubtable (Subtable); CedtHeader = ACPI_CAST_PTR (ACPI_CEDT_HEADER, Subtable->Buffer); switch (CedtHeader->Type) { case ACPI_CEDT_TYPE_CHBS: Status = DtCompileTable (PFieldList, AcpiDmTableInfoCedt0, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } break; case ACPI_CEDT_TYPE_CFMWS: { unsigned char *dump; unsigned int idx, offset, max = 0; /* Compile table with first "Interleave target" */ Status = DtCompileTable (PFieldList, AcpiDmTableInfoCedt1, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } /* Look in buffer for the number of targets */ offset = (unsigned int) ACPI_OFFSET (ACPI_CEDT_CFMWS, InterleaveWays); dump = (unsigned char *) Subtable->Buffer - 4; /* place at beginning of cedt1 */ max = 0x01 << dump[offset]; /* 2^max, so 0=1, 1=2, 2=4, 3=8. 8 is MAX */ if (max > 8) max=1; /* Error in encoding Interleaving Ways. */ if (max == 1) /* if only one target, then break here. */ break; /* break if only one target. */ /* We need to add more interleave targets, so write the current Subtable. */ ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); /* Insert AcpiDmTableInfoCedt1 table so we can put in */ DtPushSubtable (Subtable); /* the targets > the first. */ /* Now, find out all interleave targets beyond the first. */ for (idx = 1; idx < max; idx++) { ParentTable = DtPeekSubtable (); if (*PFieldList) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoCedt1_te, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } if (Subtable) { DtInsertSubtable (ParentTable, Subtable); /* got a target, so insert table. */ InsertFlag = 0; } } } DtPopSubtable (); ParentTable = DtPeekSubtable (); break; } case ACPI_CEDT_TYPE_CXIMS: { unsigned char *dump; unsigned int idx, offset, max = 0; /* Compile table with first "Xor map" */ Status = DtCompileTable (PFieldList, AcpiDmTableInfoCedt2, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } /* Look in buffer for the number of Xor maps */ offset = (unsigned int) ACPI_OFFSET (ACPI_CEDT_CXIMS, NrXormaps); dump = (unsigned char *) Subtable->Buffer - 4; /* place at beginning of cedt2 */ max = dump[offset]; /* We need to add more XOR maps, so write the current Subtable. */ ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); /* Insert AcpiDmTableInfoCedt2 table so we can put in */ DtPushSubtable (Subtable); /* Now, find out all Xor maps beyond the first. */ for (idx = 1; idx < max; idx++) { ParentTable = DtPeekSubtable (); if (*PFieldList) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoCedt2_te, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } if (Subtable) { DtInsertSubtable (ParentTable, Subtable); /* got an Xor map, so insert table. */ InsertFlag = 0; } } } DtPopSubtable (); ParentTable = DtPeekSubtable (); break; } default: DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "CEDT"); return (AE_ERROR); } ParentTable = DtPeekSubtable (); if (InsertFlag == 1) { DtInsertSubtable (ParentTable, Subtable); } DtPopSubtable (); } return (AE_OK); } /****************************************************************************** * * FUNCTION: DtCompileCpep * * PARAMETERS: List - Current field list pointer * * RETURN: Status * * DESCRIPTION: Compile CPEP. * *****************************************************************************/ ACPI_STATUS DtCompileCpep ( void **List) { ACPI_STATUS Status; Status = DtCompileTwoSubtables (List, AcpiDmTableInfoCpep, AcpiDmTableInfoCpep0); return (Status); } /****************************************************************************** * * FUNCTION: DtCompileCsrt * * PARAMETERS: List - Current field list pointer * * RETURN: Status * * DESCRIPTION: Compile CSRT. * *****************************************************************************/ ACPI_STATUS DtCompileCsrt ( void **List) { ACPI_STATUS Status = AE_OK; DT_SUBTABLE *Subtable; DT_SUBTABLE *ParentTable; DT_FIELD **PFieldList = (DT_FIELD **) List; UINT32 DescriptorCount; UINT32 GroupLength; /* Subtables (Resource Groups) */ ParentTable = DtPeekSubtable (); while (*PFieldList) { /* Resource group subtable */ Status = DtCompileTable (PFieldList, AcpiDmTableInfoCsrt0, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } /* Compute the number of resource descriptors */ GroupLength = (ACPI_CAST_PTR (ACPI_CSRT_GROUP, Subtable->Buffer))->Length - (ACPI_CAST_PTR (ACPI_CSRT_GROUP, Subtable->Buffer))->SharedInfoLength - sizeof (ACPI_CSRT_GROUP); DescriptorCount = (GroupLength / sizeof (ACPI_CSRT_DESCRIPTOR)); DtInsertSubtable (ParentTable, Subtable); DtPushSubtable (Subtable); ParentTable = DtPeekSubtable (); /* Shared info subtable (One per resource group) */ Status = DtCompileTable (PFieldList, AcpiDmTableInfoCsrt1, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); /* Sub-Subtables (Resource Descriptors) */ while (*PFieldList && DescriptorCount) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoCsrt2, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); DtPushSubtable (Subtable); ParentTable = DtPeekSubtable (); if (*PFieldList) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoCsrt2a, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } if (Subtable) { DtInsertSubtable (ParentTable, Subtable); } } DtPopSubtable (); ParentTable = DtPeekSubtable (); DescriptorCount--; } DtPopSubtable (); ParentTable = DtPeekSubtable (); } return (Status); } /****************************************************************************** * * FUNCTION: DtCompileDbg2 * * PARAMETERS: List - Current field list pointer * * RETURN: Status * * DESCRIPTION: Compile DBG2. * *****************************************************************************/ ACPI_STATUS DtCompileDbg2 ( void **List) { ACPI_STATUS Status; DT_SUBTABLE *Subtable; DT_SUBTABLE *ParentTable; DT_FIELD **PFieldList = (DT_FIELD **) List; UINT32 SubtableCount; ACPI_DBG2_HEADER *Dbg2Header; ACPI_DBG2_DEVICE *DeviceInfo; UINT16 CurrentOffset; UINT32 i; /* Main table */ Status = DtCompileTable (PFieldList, AcpiDmTableInfoDbg2, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); /* Main table fields */ Dbg2Header = ACPI_CAST_PTR (ACPI_DBG2_HEADER, Subtable->Buffer); Dbg2Header->InfoOffset = sizeof (ACPI_TABLE_HEADER) + ACPI_PTR_DIFF ( ACPI_ADD_PTR (UINT8, Dbg2Header, sizeof (ACPI_DBG2_HEADER)), Dbg2Header); SubtableCount = Dbg2Header->InfoCount; DtPushSubtable (Subtable); /* Process all Device Information subtables (Count = InfoCount) */ while (*PFieldList && SubtableCount) { /* Subtable: Debug Device Information */ Status = DtCompileTable (PFieldList, AcpiDmTableInfoDbg2Device, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DeviceInfo = ACPI_CAST_PTR (ACPI_DBG2_DEVICE, Subtable->Buffer); CurrentOffset = (UINT16) sizeof (ACPI_DBG2_DEVICE); ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); DtPushSubtable (Subtable); ParentTable = DtPeekSubtable (); /* BaseAddressRegister GAS array (Required, size is RegisterCount) */ DeviceInfo->BaseAddressOffset = CurrentOffset; for (i = 0; *PFieldList && (i < DeviceInfo->RegisterCount); i++) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoDbg2Addr, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } CurrentOffset += (UINT16) sizeof (ACPI_GENERIC_ADDRESS); DtInsertSubtable (ParentTable, Subtable); } /* AddressSize array (Required, size = RegisterCount) */ DeviceInfo->AddressSizeOffset = CurrentOffset; for (i = 0; *PFieldList && (i < DeviceInfo->RegisterCount); i++) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoDbg2Size, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } CurrentOffset += (UINT16) sizeof (UINT32); DtInsertSubtable (ParentTable, Subtable); } /* NamespaceString device identifier (Required, size = NamePathLength) */ DeviceInfo->NamepathOffset = CurrentOffset; Status = DtCompileTable (PFieldList, AcpiDmTableInfoDbg2Name, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } /* Update the device info header */ DeviceInfo->NamepathLength = (UINT16) Subtable->Length; CurrentOffset += (UINT16) DeviceInfo->NamepathLength; DtInsertSubtable (ParentTable, Subtable); /* OemData - Variable-length data (Optional, size = OemDataLength) */ Status = DtCompileTable (PFieldList, AcpiDmTableInfoDbg2OemData, &Subtable); if (Status == AE_END_OF_TABLE) { /* optional field was not found and we're at the end of the file */ goto subtableDone; } else if (ACPI_FAILURE (Status)) { return (Status); } /* Update the device info header (zeros if no OEM data present) */ DeviceInfo->OemDataOffset = 0; DeviceInfo->OemDataLength = 0; /* Optional subtable (OemData) */ if (Subtable && Subtable->Length) { DeviceInfo->OemDataOffset = CurrentOffset; DeviceInfo->OemDataLength = (UINT16) Subtable->Length; DtInsertSubtable (ParentTable, Subtable); } subtableDone: SubtableCount--; DtPopSubtable (); /* Get next Device Information subtable */ } DtPopSubtable (); return (AE_OK); } /****************************************************************************** * * FUNCTION: DtCompileDmar * * PARAMETERS: List - Current field list pointer * * RETURN: Status * * DESCRIPTION: Compile DMAR. * *****************************************************************************/ ACPI_STATUS DtCompileDmar ( void **List) { ACPI_STATUS Status; DT_SUBTABLE *Subtable; DT_SUBTABLE *ParentTable; DT_FIELD **PFieldList = (DT_FIELD **) List; DT_FIELD *SubtableStart; ACPI_DMTABLE_INFO *InfoTable; ACPI_DMAR_HEADER *DmarHeader; ACPI_DMAR_DEVICE_SCOPE *DmarDeviceScope; UINT32 DeviceScopeLength; UINT32 PciPathLength; Status = DtCompileTable (PFieldList, AcpiDmTableInfoDmar, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); DtPushSubtable (Subtable); while (*PFieldList) { /* DMAR Header */ SubtableStart = *PFieldList; Status = DtCompileTable (PFieldList, AcpiDmTableInfoDmarHdr, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); DtPushSubtable (Subtable); DmarHeader = ACPI_CAST_PTR (ACPI_DMAR_HEADER, Subtable->Buffer); switch (DmarHeader->Type) { case ACPI_DMAR_TYPE_HARDWARE_UNIT: InfoTable = AcpiDmTableInfoDmar0; break; case ACPI_DMAR_TYPE_RESERVED_MEMORY: InfoTable = AcpiDmTableInfoDmar1; break; case ACPI_DMAR_TYPE_ROOT_ATS: InfoTable = AcpiDmTableInfoDmar2; break; case ACPI_DMAR_TYPE_HARDWARE_AFFINITY: InfoTable = AcpiDmTableInfoDmar3; break; case ACPI_DMAR_TYPE_NAMESPACE: InfoTable = AcpiDmTableInfoDmar4; break; case ACPI_DMAR_TYPE_SATC: InfoTable = AcpiDmTableInfoDmar5; break; default: DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "DMAR"); return (AE_ERROR); } /* DMAR Subtable */ Status = DtCompileTable (PFieldList, InfoTable, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); /* * Optional Device Scope subtables */ if ((DmarHeader->Type == ACPI_DMAR_TYPE_HARDWARE_AFFINITY) || (DmarHeader->Type == ACPI_DMAR_TYPE_NAMESPACE)) { /* These types do not support device scopes */ DtPopSubtable (); continue; } DtPushSubtable (Subtable); DeviceScopeLength = DmarHeader->Length - Subtable->Length - ParentTable->Length; while (DeviceScopeLength) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoDmarScope, &Subtable); if (Status == AE_NOT_FOUND) { break; } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); DtPushSubtable (Subtable); DmarDeviceScope = ACPI_CAST_PTR (ACPI_DMAR_DEVICE_SCOPE, Subtable->Buffer); /* Optional PCI Paths */ PciPathLength = DmarDeviceScope->Length - Subtable->Length; while (PciPathLength) { Status = DtCompileTable (PFieldList, TableInfoDmarPciPath, &Subtable); if (Status == AE_NOT_FOUND) { DtPopSubtable (); break; } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); PciPathLength -= Subtable->Length; } DtPopSubtable (); DeviceScopeLength -= DmarDeviceScope->Length; } DtPopSubtable (); DtPopSubtable (); } return (AE_OK); } /****************************************************************************** * * FUNCTION: DtCompileDrtm * * PARAMETERS: List - Current field list pointer * * RETURN: Status * * DESCRIPTION: Compile DRTM. * *****************************************************************************/ ACPI_STATUS DtCompileDrtm ( void **List) { ACPI_STATUS Status; DT_SUBTABLE *Subtable; DT_SUBTABLE *ParentTable; DT_FIELD **PFieldList = (DT_FIELD **) List; UINT32 Count; /* ACPI_TABLE_DRTM *Drtm; */ ACPI_DRTM_VTABLE_LIST *DrtmVtl; ACPI_DRTM_RESOURCE_LIST *DrtmRl; /* ACPI_DRTM_DPS_ID *DrtmDps; */ ParentTable = DtPeekSubtable (); /* Compile DRTM header */ Status = DtCompileTable (PFieldList, AcpiDmTableInfoDrtm, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); /* * Using ACPI_SUB_PTR, We needn't define a separate structure. Care * should be taken to avoid accessing ACPI_TABLE_HADER fields. */ #if 0 Drtm = ACPI_SUB_PTR (ACPI_TABLE_DRTM, Subtable->Buffer, sizeof (ACPI_TABLE_HEADER)); #endif /* Compile VTL */ Status = DtCompileTable (PFieldList, AcpiDmTableInfoDrtm0, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); DrtmVtl = ACPI_CAST_PTR (ACPI_DRTM_VTABLE_LIST, Subtable->Buffer); DtPushSubtable (Subtable); ParentTable = DtPeekSubtable (); Count = 0; while (*PFieldList) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoDrtm0a, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } if (!Subtable) { break; } DtInsertSubtable (ParentTable, Subtable); Count++; } DrtmVtl->ValidatedTableCount = Count; DtPopSubtable (); ParentTable = DtPeekSubtable (); /* Compile RL */ Status = DtCompileTable (PFieldList, AcpiDmTableInfoDrtm1, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); DrtmRl = ACPI_CAST_PTR (ACPI_DRTM_RESOURCE_LIST, Subtable->Buffer); DtPushSubtable (Subtable); ParentTable = DtPeekSubtable (); Count = 0; while (*PFieldList) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoDrtm1a, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } if (!Subtable) { break; } DtInsertSubtable (ParentTable, Subtable); Count++; } DrtmRl->ResourceCount = Count; DtPopSubtable (); ParentTable = DtPeekSubtable (); /* Compile DPS */ Status = DtCompileTable (PFieldList, AcpiDmTableInfoDrtm2, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); /* DrtmDps = ACPI_CAST_PTR (ACPI_DRTM_DPS_ID, Subtable->Buffer);*/ return (AE_OK); } /****************************************************************************** * * FUNCTION: DtCompileEinj * * PARAMETERS: List - Current field list pointer * * RETURN: Status * * DESCRIPTION: Compile EINJ. * *****************************************************************************/ ACPI_STATUS DtCompileEinj ( void **List) { ACPI_STATUS Status; Status = DtCompileTwoSubtables (List, AcpiDmTableInfoEinj, AcpiDmTableInfoEinj0); return (Status); } /****************************************************************************** * * FUNCTION: DtCompileErst * * PARAMETERS: List - Current field list pointer * * RETURN: Status * * DESCRIPTION: Compile ERST. * *****************************************************************************/ ACPI_STATUS DtCompileErst ( void **List) { ACPI_STATUS Status; Status = DtCompileTwoSubtables (List, AcpiDmTableInfoErst, AcpiDmTableInfoEinj0); return (Status); } /****************************************************************************** * * FUNCTION: DtCompileGtdt * * PARAMETERS: List - Current field list pointer * * RETURN: Status * * DESCRIPTION: Compile GTDT. * *****************************************************************************/ ACPI_STATUS DtCompileGtdt ( void **List) { ACPI_STATUS Status; DT_SUBTABLE *Subtable; DT_SUBTABLE *ParentTable; DT_FIELD **PFieldList = (DT_FIELD **) List; DT_FIELD *SubtableStart; ACPI_SUBTABLE_HEADER *GtdtHeader; ACPI_DMTABLE_INFO *InfoTable; UINT32 GtCount; ACPI_TABLE_HEADER *Header; ParentTable = DtPeekSubtable (); Header = ACPI_CAST_PTR (ACPI_TABLE_HEADER, ParentTable->Buffer); /* Compile the main table */ Status = DtCompileTable (PFieldList, AcpiDmTableInfoGtdt, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } /* GTDT revision 3 later contains 2 extra fields before subtables */ if (Header->Revision > 2) { ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); Status = DtCompileTable (PFieldList, AcpiDmTableInfoGtdtEl2, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); while (*PFieldList) { SubtableStart = *PFieldList; Status = DtCompileTable (PFieldList, AcpiDmTableInfoGtdtHdr, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); DtPushSubtable (Subtable); GtdtHeader = ACPI_CAST_PTR (ACPI_SUBTABLE_HEADER, Subtable->Buffer); switch (GtdtHeader->Type) { case ACPI_GTDT_TYPE_TIMER_BLOCK: InfoTable = AcpiDmTableInfoGtdt0; break; case ACPI_GTDT_TYPE_WATCHDOG: InfoTable = AcpiDmTableInfoGtdt1; break; default: DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "GTDT"); return (AE_ERROR); } Status = DtCompileTable (PFieldList, InfoTable, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); /* * Additional GT block subtable data */ switch (GtdtHeader->Type) { case ACPI_GTDT_TYPE_TIMER_BLOCK: DtPushSubtable (Subtable); ParentTable = DtPeekSubtable (); GtCount = (ACPI_CAST_PTR (ACPI_GTDT_TIMER_BLOCK, Subtable->Buffer - sizeof(ACPI_GTDT_HEADER)))->TimerCount; while (GtCount) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoGtdt0a, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); GtCount--; } DtPopSubtable (); break; default: break; } DtPopSubtable (); } return (AE_OK); } /****************************************************************************** * * FUNCTION: DtCompileFpdt * * PARAMETERS: List - Current field list pointer * * RETURN: Status * * DESCRIPTION: Compile FPDT. * *****************************************************************************/ ACPI_STATUS DtCompileFpdt ( void **List) { ACPI_STATUS Status; ACPI_FPDT_HEADER *FpdtHeader; DT_SUBTABLE *Subtable; DT_SUBTABLE *ParentTable; ACPI_DMTABLE_INFO *InfoTable; DT_FIELD **PFieldList = (DT_FIELD **) List; DT_FIELD *SubtableStart; while (*PFieldList) { SubtableStart = *PFieldList; Status = DtCompileTable (PFieldList, AcpiDmTableInfoFpdtHdr, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); DtPushSubtable (Subtable); FpdtHeader = ACPI_CAST_PTR (ACPI_FPDT_HEADER, Subtable->Buffer); switch (FpdtHeader->Type) { case ACPI_FPDT_TYPE_BOOT: InfoTable = AcpiDmTableInfoFpdt0; break; case ACPI_FPDT_TYPE_S3PERF: InfoTable = AcpiDmTableInfoFpdt1; break; default: DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "FPDT"); return (AE_ERROR); break; } Status = DtCompileTable (PFieldList, InfoTable, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); DtPopSubtable (); } return (AE_OK); } /****************************************************************************** * * FUNCTION: DtCompileHest * * PARAMETERS: List - Current field list pointer * * RETURN: Status * * DESCRIPTION: Compile HEST. * *****************************************************************************/ ACPI_STATUS DtCompileHest ( void **List) { ACPI_STATUS Status; DT_SUBTABLE *Subtable; DT_SUBTABLE *ParentTable; DT_FIELD **PFieldList = (DT_FIELD **) List; DT_FIELD *SubtableStart; ACPI_DMTABLE_INFO *InfoTable; UINT16 Type; UINT32 BankCount; Status = DtCompileTable (PFieldList, AcpiDmTableInfoHest, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); while (*PFieldList) { /* Get subtable type */ SubtableStart = *PFieldList; DtCompileInteger ((UINT8 *) &Type, *PFieldList, 2, 0); switch (Type) { case ACPI_HEST_TYPE_IA32_CHECK: InfoTable = AcpiDmTableInfoHest0; break; case ACPI_HEST_TYPE_IA32_CORRECTED_CHECK: InfoTable = AcpiDmTableInfoHest1; break; case ACPI_HEST_TYPE_IA32_NMI: InfoTable = AcpiDmTableInfoHest2; break; case ACPI_HEST_TYPE_AER_ROOT_PORT: InfoTable = AcpiDmTableInfoHest6; break; case ACPI_HEST_TYPE_AER_ENDPOINT: InfoTable = AcpiDmTableInfoHest7; break; case ACPI_HEST_TYPE_AER_BRIDGE: InfoTable = AcpiDmTableInfoHest8; break; case ACPI_HEST_TYPE_GENERIC_ERROR: InfoTable = AcpiDmTableInfoHest9; break; case ACPI_HEST_TYPE_GENERIC_ERROR_V2: InfoTable = AcpiDmTableInfoHest10; break; case ACPI_HEST_TYPE_IA32_DEFERRED_CHECK: InfoTable = AcpiDmTableInfoHest11; break; default: /* Cannot continue on unknown type */ DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "HEST"); return (AE_ERROR); } Status = DtCompileTable (PFieldList, InfoTable, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); /* * Additional subtable data - IA32 Error Bank(s) */ BankCount = 0; switch (Type) { case ACPI_HEST_TYPE_IA32_CHECK: BankCount = (ACPI_CAST_PTR (ACPI_HEST_IA_MACHINE_CHECK, Subtable->Buffer))->NumHardwareBanks; break; case ACPI_HEST_TYPE_IA32_CORRECTED_CHECK: BankCount = (ACPI_CAST_PTR (ACPI_HEST_IA_CORRECTED, Subtable->Buffer))->NumHardwareBanks; break; case ACPI_HEST_TYPE_IA32_DEFERRED_CHECK: BankCount = (ACPI_CAST_PTR (ACPI_HEST_IA_DEFERRED_CHECK, Subtable->Buffer))->NumHardwareBanks; break; default: break; } while (BankCount) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoHestBank, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); BankCount--; } } return (AE_OK); } /****************************************************************************** * * FUNCTION: DtCompileHmat * * PARAMETERS: List - Current field list pointer * * RETURN: Status * * DESCRIPTION: Compile HMAT. * *****************************************************************************/ ACPI_STATUS DtCompileHmat ( void **List) { ACPI_STATUS Status; DT_SUBTABLE *Subtable; DT_SUBTABLE *ParentTable; DT_FIELD **PFieldList = (DT_FIELD **) List; DT_FIELD *SubtableStart; DT_FIELD *EntryStart; ACPI_HMAT_STRUCTURE *HmatStruct; ACPI_HMAT_LOCALITY *HmatLocality; ACPI_HMAT_CACHE *HmatCache; ACPI_DMTABLE_INFO *InfoTable; UINT32 IntPDNumber; UINT32 TgtPDNumber; UINT64 EntryNumber; UINT16 SMBIOSHandleNumber; ParentTable = DtPeekSubtable (); Status = DtCompileTable (PFieldList, AcpiDmTableInfoHmat, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); while (*PFieldList) { /* Compile HMAT structure header */ SubtableStart = *PFieldList; Status = DtCompileTable (PFieldList, AcpiDmTableInfoHmatHdr, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); HmatStruct = ACPI_CAST_PTR (ACPI_HMAT_STRUCTURE, Subtable->Buffer); HmatStruct->Length = Subtable->Length; /* Compile HMAT structure body */ switch (HmatStruct->Type) { case ACPI_HMAT_TYPE_ADDRESS_RANGE: InfoTable = AcpiDmTableInfoHmat0; break; case ACPI_HMAT_TYPE_LOCALITY: InfoTable = AcpiDmTableInfoHmat1; break; case ACPI_HMAT_TYPE_CACHE: InfoTable = AcpiDmTableInfoHmat2; break; default: DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "HMAT"); return (AE_ERROR); } Status = DtCompileTable (PFieldList, InfoTable, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); HmatStruct->Length += Subtable->Length; /* Compile HMAT structure additional */ switch (HmatStruct->Type) { case ACPI_HMAT_TYPE_LOCALITY: HmatLocality = ACPI_SUB_PTR (ACPI_HMAT_LOCALITY, Subtable->Buffer, sizeof (ACPI_HMAT_STRUCTURE)); /* Compile initiator proximity domain list */ IntPDNumber = 0; while (*PFieldList) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoHmat1a, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } if (!Subtable) { break; } DtInsertSubtable (ParentTable, Subtable); HmatStruct->Length += Subtable->Length; IntPDNumber++; } HmatLocality->NumberOfInitiatorPDs = IntPDNumber; /* Compile target proximity domain list */ TgtPDNumber = 0; while (*PFieldList) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoHmat1b, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } if (!Subtable) { break; } DtInsertSubtable (ParentTable, Subtable); HmatStruct->Length += Subtable->Length; TgtPDNumber++; } HmatLocality->NumberOfTargetPDs = TgtPDNumber; /* Save start of the entries for reporting errors */ EntryStart = *PFieldList; /* Compile latency/bandwidth entries */ EntryNumber = 0; while (*PFieldList) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoHmat1c, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } if (!Subtable) { break; } DtInsertSubtable (ParentTable, Subtable); HmatStruct->Length += Subtable->Length; EntryNumber++; } /* Validate number of entries */ if (EntryNumber != ((UINT64)IntPDNumber * (UINT64)TgtPDNumber)) { DtFatal (ASL_MSG_INVALID_EXPRESSION, EntryStart, "HMAT"); return (AE_ERROR); } break; case ACPI_HMAT_TYPE_CACHE: /* Compile SMBIOS handles */ HmatCache = ACPI_SUB_PTR (ACPI_HMAT_CACHE, Subtable->Buffer, sizeof (ACPI_HMAT_STRUCTURE)); SMBIOSHandleNumber = 0; while (*PFieldList) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoHmat2a, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } if (!Subtable) { break; } DtInsertSubtable (ParentTable, Subtable); HmatStruct->Length += Subtable->Length; SMBIOSHandleNumber++; } HmatCache->NumberOfSMBIOSHandles = SMBIOSHandleNumber; break; default: break; } } return (AE_OK); } /****************************************************************************** * * FUNCTION: DtCompileIort * * PARAMETERS: List - Current field list pointer * * RETURN: Status * * DESCRIPTION: Compile IORT. * *****************************************************************************/ ACPI_STATUS DtCompileIort ( void **List) { ACPI_STATUS Status; DT_SUBTABLE *Subtable; DT_SUBTABLE *ParentTable; DT_FIELD **PFieldList = (DT_FIELD **) List; DT_FIELD *SubtableStart; ACPI_TABLE_HEADER *Table; ACPI_TABLE_IORT *Iort; ACPI_IORT_NODE *IortNode; ACPI_IORT_ITS_GROUP *IortItsGroup; ACPI_IORT_SMMU *IortSmmu; ACPI_IORT_RMR *IortRmr; UINT32 NodeNumber; UINT32 NodeLength; UINT32 IdMappingNumber; UINT32 ItsNumber; UINT32 ContextIrptNumber; UINT32 PmuIrptNumber; UINT32 PaddingLength; UINT8 Revision; UINT32 RmrCount; ParentTable = DtPeekSubtable (); Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); Table = ACPI_CAST_PTR (ACPI_TABLE_HEADER, ParentTable->Buffer); Revision = Table->Revision; /* IORT Revisions E, E.a & E.c have known issues and are not supported */ if (Revision == 1 || Revision == 2 || Revision == 4) { DtError (ASL_ERROR, ASL_MSG_UNSUPPORTED, NULL, "IORT table revision"); return (AE_ERROR); } /* * Using ACPI_SUB_PTR, We needn't define a separate structure. Care * should be taken to avoid accessing ACPI_TABLE_HEADER fields. */ Iort = ACPI_SUB_PTR (ACPI_TABLE_IORT, Subtable->Buffer, sizeof (ACPI_TABLE_HEADER)); /* * OptionalPadding - Variable-length data * (Optional, size = OffsetToNodes - sizeof (ACPI_TABLE_IORT)) * Optionally allows the generic data types to be used for filling * this field. */ Iort->NodeOffset = sizeof (ACPI_TABLE_IORT); Status = DtCompileTable (PFieldList, AcpiDmTableInfoIortPad, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } if (Subtable) { DtInsertSubtable (ParentTable, Subtable); Iort->NodeOffset += Subtable->Length; } else { Status = DtCompileGeneric (ACPI_CAST_PTR (void *, PFieldList), AcpiDmTableInfoIortHdr[0].Name, &PaddingLength); if (ACPI_FAILURE (Status)) { return (Status); } Iort->NodeOffset += PaddingLength; } NodeNumber = 0; while (*PFieldList) { SubtableStart = *PFieldList; if (Revision == 0) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoIortHdr, &Subtable); } else if (Revision >= 3) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoIortHdr3, &Subtable); } if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); IortNode = ACPI_CAST_PTR (ACPI_IORT_NODE, Subtable->Buffer); NodeLength = ACPI_OFFSET (ACPI_IORT_NODE, NodeData); DtPushSubtable (Subtable); ParentTable = DtPeekSubtable (); switch (IortNode->Type) { case ACPI_IORT_NODE_ITS_GROUP: Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort0, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); IortItsGroup = ACPI_CAST_PTR (ACPI_IORT_ITS_GROUP, Subtable->Buffer); NodeLength += Subtable->Length; ItsNumber = 0; while (*PFieldList) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort0a, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } if (!Subtable) { break; } DtInsertSubtable (ParentTable, Subtable); NodeLength += Subtable->Length; ItsNumber++; } IortItsGroup->ItsCount = ItsNumber; break; case ACPI_IORT_NODE_NAMED_COMPONENT: Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort1, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); NodeLength += Subtable->Length; /* * Padding - Variable-length data * Optionally allows the offset of the ID mappings to be used * for filling this field. */ Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort1a, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } if (Subtable) { DtInsertSubtable (ParentTable, Subtable); NodeLength += Subtable->Length; } else { if (NodeLength > IortNode->MappingOffset) { return (AE_BAD_DATA); } if (NodeLength < IortNode->MappingOffset) { Status = DtCompilePadding ( IortNode->MappingOffset - NodeLength, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); NodeLength = IortNode->MappingOffset; } } break; case ACPI_IORT_NODE_PCI_ROOT_COMPLEX: Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort2, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); NodeLength += Subtable->Length; break; case ACPI_IORT_NODE_SMMU: Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort3, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); IortSmmu = ACPI_CAST_PTR (ACPI_IORT_SMMU, Subtable->Buffer); NodeLength += Subtable->Length; /* Compile global interrupt array */ IortSmmu->GlobalInterruptOffset = NodeLength; Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort3a, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); NodeLength += Subtable->Length; /* Compile context interrupt array */ ContextIrptNumber = 0; IortSmmu->ContextInterruptOffset = NodeLength; while (*PFieldList) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort3b, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } if (!Subtable) { break; } DtInsertSubtable (ParentTable, Subtable); NodeLength += Subtable->Length; ContextIrptNumber++; } IortSmmu->ContextInterruptCount = ContextIrptNumber; /* Compile PMU interrupt array */ PmuIrptNumber = 0; IortSmmu->PmuInterruptOffset = NodeLength; while (*PFieldList) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort3c, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } if (!Subtable) { break; } DtInsertSubtable (ParentTable, Subtable); NodeLength += Subtable->Length; PmuIrptNumber++; } IortSmmu->PmuInterruptCount = PmuIrptNumber; break; case ACPI_IORT_NODE_SMMU_V3: Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort4, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); NodeLength += Subtable->Length; break; case ACPI_IORT_NODE_PMCG: Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort5, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); NodeLength += Subtable->Length; break; case ACPI_IORT_NODE_RMR: Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort6, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); IortRmr = ACPI_CAST_PTR (ACPI_IORT_RMR, Subtable->Buffer); NodeLength += Subtable->Length; /* Compile RMR Descriptors */ RmrCount = 0; IortRmr->RmrOffset = NodeLength; while (*PFieldList) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoIort6a, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } if (!Subtable) { break; } DtInsertSubtable (ParentTable, Subtable); NodeLength += sizeof (ACPI_IORT_RMR_DESC); RmrCount++; } IortRmr->RmrCount = RmrCount; break; default: DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "IORT"); return (AE_ERROR); } /* Compile Array of ID mappings */ IortNode->MappingOffset = NodeLength; IdMappingNumber = 0; while (*PFieldList) { Status = DtCompileTable (PFieldList, AcpiDmTableInfoIortMap, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } if (!Subtable) { break; } DtInsertSubtable (ParentTable, Subtable); NodeLength += sizeof (ACPI_IORT_ID_MAPPING); IdMappingNumber++; } IortNode->MappingCount = IdMappingNumber; if (!IdMappingNumber) { IortNode->MappingOffset = 0; } /* * Node length can be determined by DT_LENGTH option * IortNode->Length = NodeLength; */ DtPopSubtable (); ParentTable = DtPeekSubtable (); NodeNumber++; } Iort->NodeCount = NodeNumber; return (AE_OK); } /****************************************************************************** * * FUNCTION: DtCompileIvrs * * PARAMETERS: List - Current field list pointer * * RETURN: Status * * DESCRIPTION: Compile IVRS. Notes: * The IVRS is essentially a flat table, with the following * structure: *
*
* * * ... * * * * ... * *****************************************************************************/ ACPI_STATUS DtCompileIvrs ( void **List) { ACPI_STATUS Status; DT_SUBTABLE *Subtable; DT_SUBTABLE *ParentTable; DT_SUBTABLE *MainSubtable; DT_FIELD **PFieldList = (DT_FIELD **) List; DT_FIELD *SubtableStart; ACPI_DMTABLE_INFO *InfoTable = NULL; UINT8 SubtableType; UINT8 Temp64[16]; UINT8 Temp8; /* Main table */ Status = DtCompileTable (PFieldList, AcpiDmTableInfoIvrs, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ParentTable = DtPeekSubtable (); DtInsertSubtable (ParentTable, Subtable); DtPushSubtable (Subtable); /* Save a pointer to the main subtable */ MainSubtable = Subtable; while (*PFieldList) { SubtableStart = *PFieldList; /* Compile the SubtableType integer */ DtCompileInteger (&SubtableType, *PFieldList, 1, 0); switch (SubtableType) { /* Type 10h, IVHD (I/O Virtualization Hardware Definition) */ case ACPI_IVRS_TYPE_HARDWARE1: InfoTable = AcpiDmTableInfoIvrsHware1; break; /* Types 11h, 40h, IVHD (I/O Virtualization Hardware Definition) */ case ACPI_IVRS_TYPE_HARDWARE2: case ACPI_IVRS_TYPE_HARDWARE3: InfoTable = AcpiDmTableInfoIvrsHware23; break; /* Types 20h, 21h, 22h, IVMD (I/O Virtualization Memory Definition Block) */ case ACPI_IVRS_TYPE_MEMORY1: case ACPI_IVRS_TYPE_MEMORY2: case ACPI_IVRS_TYPE_MEMORY3: InfoTable = AcpiDmTableInfoIvrsMemory; break; /* 4-byte device entries */ case ACPI_IVRS_TYPE_PAD4: case ACPI_IVRS_TYPE_ALL: case ACPI_IVRS_TYPE_SELECT: case ACPI_IVRS_TYPE_START: case ACPI_IVRS_TYPE_END: InfoTable = AcpiDmTableInfoIvrs4; break; /* 8-byte device entries, type A */ case ACPI_IVRS_TYPE_ALIAS_SELECT: case ACPI_IVRS_TYPE_ALIAS_START: InfoTable = AcpiDmTableInfoIvrs8a; break; /* 8-byte device entries, type B */ case ACPI_IVRS_TYPE_EXT_SELECT: case ACPI_IVRS_TYPE_EXT_START: InfoTable = AcpiDmTableInfoIvrs8b; break; /* 8-byte device entries, type C */ case ACPI_IVRS_TYPE_SPECIAL: InfoTable = AcpiDmTableInfoIvrs8c; break; /* Variable device entries, type F0h */ case ACPI_IVRS_TYPE_HID: InfoTable = AcpiDmTableInfoIvrsHid; break; default: DtFatal (ASL_MSG_UNKNOWN_SUBTABLE, SubtableStart, "IVRS Device Entry"); return (AE_ERROR); } /* Compile the InfoTable from above */ Status = DtCompileTable (PFieldList, InfoTable, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } ParentTable = DtPeekSubtable (); if (SubtableType != ACPI_IVRS_TYPE_HARDWARE1 && SubtableType != ACPI_IVRS_TYPE_HARDWARE2 && SubtableType != ACPI_IVRS_TYPE_HARDWARE3 && SubtableType != ACPI_IVRS_TYPE_HID && SubtableType != ACPI_IVRS_TYPE_MEMORY1 && SubtableType != ACPI_IVRS_TYPE_MEMORY2 && SubtableType != ACPI_IVRS_TYPE_MEMORY3) { if (ParentTable) DtInsertSubtable (ParentTable, Subtable); } switch (SubtableType) { case ACPI_IVRS_TYPE_HARDWARE1: case ACPI_IVRS_TYPE_HARDWARE2: case ACPI_IVRS_TYPE_HARDWARE3: case ACPI_IVRS_TYPE_MEMORY1: case ACPI_IVRS_TYPE_MEMORY2: case ACPI_IVRS_TYPE_MEMORY3: /* Insert these IVHDs/IVMDs at the root subtable */ DtInsertSubtable (MainSubtable, Subtable); DtPushSubtable (Subtable); break; case ACPI_IVRS_TYPE_HID: /* Special handling for the HID named device entry (0xF0) */ if (ParentTable) { DtInsertSubtable (ParentTable, Subtable); } /* * Process the HID value. First, get the HID value as a string. */ DtCompileOneField ((UINT8 *) &Temp64, *PFieldList, 16, DT_FIELD_TYPE_STRING, 0); /* * Determine if the HID is an integer or a string. * An integer is defined to be 32 bits, with the upper 32 bits * set to zero. (from the ACPI Spec): "The HID can be a 32-bit * integer or a character string. If an integer, the lower * 4 bytes of the field contain the integer and the upper * 4 bytes are padded with 0". */ if (UtIsIdInteger ((UINT8 *) &Temp64)) { /* Compile the HID value as an integer */ DtCompileOneField ((UINT8 *) &Temp64, *PFieldList, 8, DT_FIELD_TYPE_INTEGER, 0); Status = DtCompileTable (PFieldList, AcpiDmTableInfoIvrsHidInteger, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } } else { /* Compile the HID value as a string */ Status = DtCompileTable (PFieldList, AcpiDmTableInfoIvrsHidString, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } } DtInsertSubtable (ParentTable, Subtable); /* * Process the CID value. First, get the CID value as a string. */ DtCompileOneField ((UINT8 *) &Temp64, *PFieldList, 16, DT_FIELD_TYPE_STRING, 0); if (UtIsIdInteger ((UINT8 *) &Temp64)) { /* Compile the CID value as an integer */ DtCompileOneField ((UINT8 *) &Temp64, *PFieldList, 8, DT_FIELD_TYPE_INTEGER, 0); Status = DtCompileTable (PFieldList, AcpiDmTableInfoIvrsCidInteger, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } } else { /* Compile the CID value as a string */ Status = DtCompileTable (PFieldList, AcpiDmTableInfoIvrsCidString, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } } DtInsertSubtable (ParentTable, Subtable); /* * Process the UID value. First, get and decode the "UID Format" field (Integer). */ if (!*PFieldList) { return (AE_OK); } DtCompileOneField (&Temp8, *PFieldList, 1, DT_FIELD_TYPE_INTEGER, 0); switch (Temp8) { case ACPI_IVRS_UID_NOT_PRESENT: break; case ACPI_IVRS_UID_IS_INTEGER: Status = DtCompileTable (PFieldList, AcpiDmTableInfoIvrsUidInteger, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); break; case ACPI_IVRS_UID_IS_STRING: Status = DtCompileTable (PFieldList, AcpiDmTableInfoIvrsUidString, &Subtable); if (ACPI_FAILURE (Status)) { return (Status); } DtInsertSubtable (ParentTable, Subtable); break; default: DtFatal (ASL_MSG_UNKNOWN_FORMAT, SubtableStart, "IVRS Device Entry"); return (AE_ERROR); } default: /* All other subtable types come through here */ break; } } return (AE_OK); }