From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from EUR04-HE1-obe.outbound.protection.outlook.com (EUR04-HE1-obe.outbound.protection.outlook.com [40.107.7.80]) by mx.groups.io with SMTP id smtpd.web11.10670.1588693581644966031 for ; Tue, 05 May 2020 08:46:22 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@armh.onmicrosoft.com header.s=selector2-armh-onmicrosoft-com header.b=7Ytil1tf; spf=pass (domain: arm.com, ip: 40.107.7.80, mailfrom: krzysztof.koch@arm.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=armh.onmicrosoft.com; s=selector2-armh-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=tnTfuXJ6Oxi/2FUJsIY+z+5T5SlS4dyWmDa7z7opZkQ=; b=7Ytil1tf5XyMmdtG9RY5MGR795w1495m7NTl+iF7z3uDJvqWf8aFk5qbbyDLfwye06ANbHOQnDPvQhimGnXDGJfOk3Kikr3tmqAuudddd2NVYtKH2QprPPokWsfRDGCYQhwGx9IFsaKzvBt2/69AfngKuBxmTF6HVGqVlEWmx+c= Received: from AM5PR0502CA0011.eurprd05.prod.outlook.com (2603:10a6:203:91::21) by AM6PR08MB3703.eurprd08.prod.outlook.com (2603:10a6:20b:83::17) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2958.29; Tue, 5 May 2020 15:46:18 +0000 Received: from VE1EUR03FT050.eop-EUR03.prod.protection.outlook.com (2603:10a6:203:91:cafe::36) by AM5PR0502CA0011.outlook.office365.com (2603:10a6:203:91::21) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2958.20 via Frontend Transport; Tue, 5 May 2020 15:46:18 +0000 Authentication-Results: spf=pass (sender IP is 63.35.35.123) smtp.mailfrom=arm.com; edk2.groups.io; dkim=pass (signature was verified) header.d=armh.onmicrosoft.com;edk2.groups.io; dmarc=bestguesspass action=none header.from=arm.com; Received-SPF: Pass (protection.outlook.com: domain of arm.com designates 63.35.35.123 as permitted sender) receiver=protection.outlook.com; client-ip=63.35.35.123; helo=64aa7808-outbound-1.mta.getcheckrecipient.com; Received: from 64aa7808-outbound-1.mta.getcheckrecipient.com (63.35.35.123) by VE1EUR03FT050.mail.protection.outlook.com (10.152.19.209) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2958.20 via Frontend Transport; Tue, 5 May 2020 15:46:17 +0000 Received: ("Tessian outbound fb9de21a7e90:v54"); Tue, 05 May 2020 15:46:17 +0000 X-CheckRecipientChecked: true X-CR-MTA-CID: 114de6f2728fa0d4 X-CR-MTA-TID: 64aa7808 Received: from 09ed360f50b7.1 by 64aa7808-outbound-1.mta.getcheckrecipient.com id 05EC1071-0604-4F23-81E2-CA206DAFB089.1; Tue, 05 May 2020 15:46:11 +0000 Received: from EUR04-DB3-obe.outbound.protection.outlook.com by 64aa7808-outbound-1.mta.getcheckrecipient.com with ESMTPS id 09ed360f50b7.1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384); Tue, 05 May 2020 15:46:11 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=I2bbRMYdzgnpyOJcdoLpBvnr1hcsOBACJ3p/yTb9o9pxrtRRiQARvLDvNhW3yiHPChxnDxLb99v6DAciIPiWEgfDwe53OW+gOOYeihie+zikDhI1im0cr5shl8Fgu19JqCNnG77G5iU2QtGkpYdwaMweuxw6EmFeBc63nmLisozCLI2E9b947F1FYtSkFNz4HUWi4CtdwbPT1dRhR7wfaJfTRLrtUD6XjKt7h6n2bRBKXbtkNPVa5HxlxRz/Xv/yM4uG+u7MbPT+4Lm487QoDsIEACXozqfKuPlrSeLub/3dM9TzzO+tF3l7BQ4pH7ZH9FtNiUjL9TcHV2ZeaLVpfw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=tnTfuXJ6Oxi/2FUJsIY+z+5T5SlS4dyWmDa7z7opZkQ=; b=DHzQuWi14sZRPZulOck+m/lAxWD39G7zdvIfa2V5GprtfLtHua90m1s2/eY/UGtZKDLhAuFfR0P0CbY7Ynn53Fd34utQeCrpd4uttSu33ytl3e5Y6DRUHd2UEnEjTZO+rI4VfQXFMO4xuXxBc9lJhtu/EJf6yzoBBNn4I+nXX6tIq38YIdTGDwQGwu24zOmJE2VWny/n+E+kVcR7BnvkjIvOawHVzA48uUAK7c5ID5xws4iHUOvPaKsBMCUOx9vtsWBGEjy/aEwYGZy6y7cIoYZ6y6eE2FUfkuuM7QByCbsm1rMTAu7WiSFhyNsTG1NYOnX+X0eX8314pQEO/qLPcw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 40.67.248.234) smtp.rcpttodomain=edk2.groups.io smtp.mailfrom=arm.com; dmarc=bestguesspass action=none header.from=arm.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=armh.onmicrosoft.com; s=selector2-armh-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=tnTfuXJ6Oxi/2FUJsIY+z+5T5SlS4dyWmDa7z7opZkQ=; b=7Ytil1tf5XyMmdtG9RY5MGR795w1495m7NTl+iF7z3uDJvqWf8aFk5qbbyDLfwye06ANbHOQnDPvQhimGnXDGJfOk3Kikr3tmqAuudddd2NVYtKH2QprPPokWsfRDGCYQhwGx9IFsaKzvBt2/69AfngKuBxmTF6HVGqVlEWmx+c= Received: from DB6PR07CA0111.eurprd07.prod.outlook.com (2603:10a6:6:2c::25) by VI1PR0801MB1709.eurprd08.prod.outlook.com (2603:10a6:800:59::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2958.19; Tue, 5 May 2020 15:46:09 +0000 Received: from DB5EUR03FT021.eop-EUR03.prod.protection.outlook.com (2603:10a6:6:2c:cafe::a0) by DB6PR07CA0111.outlook.office365.com (2603:10a6:6:2c::25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2979.11 via Frontend Transport; Tue, 5 May 2020 15:46:09 +0000 Authentication-Results-Original: spf=pass (sender IP is 40.67.248.234) smtp.mailfrom=arm.com; edk2.groups.io; dkim=none (message not signed) header.d=none;edk2.groups.io; dmarc=bestguesspass action=none header.from=arm.com; Received-SPF: Pass (protection.outlook.com: domain of arm.com designates 40.67.248.234 as permitted sender) receiver=protection.outlook.com; client-ip=40.67.248.234; helo=nebula.arm.com; Received: from nebula.arm.com (40.67.248.234) by DB5EUR03FT021.mail.protection.outlook.com (10.152.20.238) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.2958.20 via Frontend Transport; Tue, 5 May 2020 15:46:09 +0000 Received: from AZ-NEU-EX01.Emea.Arm.com (10.251.26.4) by AZ-NEU-EX04.Arm.com (10.251.24.32) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) id 15.1.1415.2; Tue, 5 May 2020 15:46:06 +0000 Received: from AZ-NEU-EX03.Arm.com (10.251.24.31) by AZ-NEU-EX01.Emea.Arm.com (10.251.26.4) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1779.2; Tue, 5 May 2020 15:46:05 +0000 Received: from E119924.Arm.com (10.57.59.39) by mail.arm.com (10.251.24.31) with Microsoft SMTP Server id 15.1.1415.2 via Frontend Transport; Tue, 5 May 2020 15:46:05 +0000 From: "Krzysztof Koch" To: CC: , , , , Subject: [PATCH v1 1/6] ShellPkg: acpiview: Add interface for data-driven table parsing Date: Tue, 5 May 2020 16:45:59 +0100 Message-ID: <20200505154604.9848-2-krzysztof.koch@arm.com> X-Mailer: git-send-email 2.16.2.windows.1 In-Reply-To: <20200505154604.9848-1-krzysztof.koch@arm.com> References: <20200505154604.9848-1-krzysztof.koch@arm.com> MIME-Version: 1.0 X-EOPAttributedMessage: 1 X-MS-Office365-Filtering-HT: Tenant X-Forefront-Antispam-Report-Untrusted: CIP:40.67.248.234;CTRY:IE;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:nebula.arm.com;PTR:InfoDomainNonexistent;CAT:NONE;SFTY:;SFS:(4636009)(136003)(346002)(396003)(376002)(39860400002)(46966005)(33430700001)(82310400002)(54906003)(478600001)(356005)(47076004)(8936002)(70586007)(426003)(6916009)(8676002)(86362001)(81166007)(70206006)(6666004)(336012)(44832011)(36756003)(26005)(186003)(82740400003)(5660300002)(316002)(7696005)(30864003)(2616005)(33440700001)(1076003)(2906002)(4326008);DIR:OUT;SFP:1101; X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 74caf2a0-3637-4eae-9d31-08d7f10b7365 X-MS-TrafficTypeDiagnostic: VI1PR0801MB1709:|AM6PR08MB3703: X-Microsoft-Antispam-PRVS: x-checkrecipientrouted: true NoDisclaimer: true X-MS-Oob-TLC-OOBClassifiers: OLM:10000;OLM:10000; X-Forefront-PRVS: 0394259C80 X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam-Untrusted: BCL:0; X-Microsoft-Antispam-Message-Info-Original: +O6eeCqqMay5AS7ibBtn+JHkb5rlu6mzZuIg6lmxdM8S31JvUMclhjVBFYwPA73+3aGGC4P9eoWJVnDQ25s4PwAO4b9recZE6r3A7qPhKcRoDo/KwN3UKC6hDLtHxAACDr4kPmrzYn5IN2O6fSvQUgOjmATlIpodJ3+yZJldL7/2RGe+5qA/+GUNw3SbkU2TLfkLTtw17ifgLFlYFOcfYlG/mwrl5fEA1+gg03kPRweq57o9/vN1gezZb7Wu1XkgSGXh1R+1flfeMhyfpi078BraHkLAHFb2DIlrymFjiChBpF4FRgNbejeN4EqwK+RwWr7b95kehURwdtWaTK3laB2OHrh8KPdlzCRHyzFDKkZPJX/1mGQmwZX5FgUBbcbG4XBy8lQ/auso1aldaSVyYVod7XBcjdcpsTk23lmUkSQHtfmCit4YDtkBDPZYEFQOvsx3J/eqNhj9lo4/BJgzqInb8XHz6wk4QYRsRhW6/3h7HvDLqbbPpoKb3kZVj4WjiYmZhogyDPGUpxxt1U77FxrSf/3hiDhjuPFLPzgFNSQQVeNj1TJKP6ais+G3xkW5sM+JNfBWQuRtU3ssrFXKWQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR0801MB1709 Original-Authentication-Results: spf=pass (sender IP is 40.67.248.234) smtp.mailfrom=arm.com; edk2.groups.io; dkim=none (message not signed) header.d=none;edk2.groups.io; dmarc=bestguesspass action=none header.from=arm.com; Return-Path: Krzysztof.Koch@arm.com X-MS-Exchange-Transport-CrossTenantHeadersStripped: VE1EUR03FT050.eop-EUR03.prod.protection.outlook.com X-Forefront-Antispam-Report: CIP:63.35.35.123;CTRY:IE;LANG:en;SCL:1;SRV:;IPV:CAL;SFV:NSPM;H:64aa7808-outbound-1.mta.getcheckrecipient.com;PTR:ec2-63-35-35-123.eu-west-1.compute.amazonaws.com;CAT:NONE;SFTY:;SFS:(4636009)(136003)(396003)(39860400002)(376002)(346002)(46966005)(33430700001)(478600001)(33440700001)(2906002)(6916009)(316002)(36906005)(54906003)(70206006)(70586007)(7696005)(186003)(36756003)(4326008)(26005)(30864003)(8676002)(1076003)(8936002)(82310400002)(5660300002)(82740400003)(81166007)(6666004)(44832011)(86362001)(47076004)(426003)(336012)(2616005);DIR:OUT;SFP:1101; X-MS-Office365-Filtering-Correlation-Id-Prvs: ff872611-ac55-495f-66ec-08d7f10b6e79 X-Forefront-PRVS: 0394259C80 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: 7rGcOURciUnSW88AkhMpuYiwlGeMVf+ce7uD8VEVFOuapKrq9f7CE+AM7lsNhcTd7n3lelsRiVnelIUvmkJ1luUslTeBCDev9v+flxC/AkIuxO+2uzg6SD/36+/25XosiTeMR6m25GonPTFFvgBOQcxeM9iGx8e95gqDsFWGoBWlXQeWdtdtkJmSji3G/HLbT3uEtu0zd2jaOTXkVf7HVYgAFmAj7YEdUQSRhvHvce1tjMpxMAuOeHrG5rM6j6BClLsCGXvcZXNUIjE9vWdzxlYKjCEIJKTS3/ytlqXzJT3/F62SXItuqeKgc+lqoy0bcatBaK+NOKILDXcAqVKN0eFAGb2DvCVzBsXx4Qlz12wfd8r482wQwunBIkTj5k9QlBxJ4P+DWp2dfkA81VcV/1ijJuPUYgmXidNbkaI7+uU6VGGB6IV1FKAGAet4IcX29qjV7hTGQMlLG4AfxCZz7mUjEySvost9cxvK1iZZnIe/KSnjstOMYEoGa8eEZ4lXTZcC1YqUxsXQJZPnAq7VCFPG/B7BgfsLR7D1ti8AK9X+RxUZXPdlCRMvUv05nWorITus1iGTwiz/V0zPd20lhw== X-OriginatorOrg: arm.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 05 May 2020 15:46:17.7810 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 74caf2a0-3637-4eae-9d31-08d7f10b7365 X-MS-Exchange-CrossTenant-Id: f34e5979-57d9-4aaa-ad4d-b122a662184d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=f34e5979-57d9-4aaa-ad4d-b122a662184d;Ip=[63.35.35.123];Helo=[64aa7808-outbound-1.mta.getcheckrecipient.com] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM6PR08MB3703 Content-Type: text/plain Define and implement an interface to streamline metadata collection and validation for structures present in each ACPI table. Most ACPI tables define substructures which constitute the table. These substructures are identified by their 'Type' field value. The range of possible 'Type' values is defined on a per-table basis. For more sophisticated ACPI table validation, additional data about each structure type needs to be maintained. This patch defines a new ACPI_STRUCT_INFO structure. It stores additional metadata about a building block of an ACPI table. ACPI_STRUCT_INFO's are organised into ACPI_STRUCT_DATABASE's. ACPI_STRUCT_DATABASE is an array of ACPI_STRUCT_INFO elements which are indexed using structure's type value. For example, in the Multiple APIC Description Table (MADT) all Interrupt Controller Structure types form a single database. In the database, the GIC CPU Interface (GICC) structure's metadata is the 11th entry (i.e. Type = 0xB). ACPI_STRUCT_INFO structure consists of: - ASCII name of the structure - ACPI-defined stucture Type - bitmask defining the validity of the structure for various architectures - instance counter - a handler for the structure (ACPI_STRUCT_HANDLER) The bitmask allows detection of structures in a table which are not compatible with the target platform. For example, the Multiple APIC Description Table (MADT) contains Interrupt Controller Structure definitions which apply to either the Advanced Programmable Interrupt Controller (APIC) model or the Generic Interrupt Controller (GIC) model. Presence of APIC-related structures on an Arm-based platform is a bug which is now detected and reported by acpiview. This patch adds support for compatibility checks with the Arm architecture only. However, provisions are made to allow extensions to other architectures. ACPI_STRUCT_HANDLER describes how the contents of the structure can be parsed. The possible options are: - An ACPI_PARSER array which can be passed to the ParseAcpi() function - A dedicated function for parsing the structure (ACPI_STRUCT_PARSER_FUNC) If neither of these options is provided, it is assumed that the parsing logic is not implemented. ACPI_STRUCT_PARSER_FUNC expects the the first two arguments to be the pointer to the start of the structure to parse and the length of structure's buffer. The remaining two optional arguments are context specific. This patch adds methods for: - Resetting the instance count for all structure types in a table. - Getting the combined instance count for all types in a table. - Validating the compatibility of a structure with the target arch. - Printing structure counts for the types which are compatible with the target architecture and validating that the non-compatible structures are not present in the table. - Parsing the structure according to the information provided by its handle. Finally, define a helper PrintAcpiStructName () function to streamline the printing of ACPI structure name together with the structure's current occurrence count. References: - ACPI 6.3, January 2019 Signed-off-by: Krzysztof Koch --- Notes: v1: - Add interface for data-driven table parsing [Krzysztof] ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.c | 263 ++++++++++++++++++++ ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h | 234 +++++++++++++++++ 2 files changed, 497 insertions(+) diff --git a/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.c b/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.c index 3f12a33050a4e4ab3be2187c90ef8dcf0882283d..32566101e2de2eec3ccf44563ee79379404bff62 100644 --- a/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.c +++ b/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.c @@ -6,6 +6,8 @@ **/ #include +#include +#include #include #include #include "AcpiParser.h" @@ -466,6 +468,267 @@ PrintFieldName ( ); } +/** + Produce a Null-terminated ASCII string with the name and index of an + ACPI structure. + + The output string is in the following format: [] + + @param [in] Name Structure name. + @param [in] Index Structure index. + @param [in] BufferSize The size, in bytes, of the output buffer. + @param [out] Buffer Buffer for the output string. + + @return The number of bytes written to the buffer (not including Null-byte) +**/ +UINTN +EFIAPI +PrintAcpiStructName ( + IN CONST CHAR8* Name, + IN UINT32 Index, + IN UINTN BufferSize, + OUT CHAR8* Buffer + ) +{ + ASSERT (Name != NULL); + ASSERT (Buffer != NULL); + + return AsciiSPrint (Buffer, BufferSize, "%a [%d]", Name , Index); +} + +/** + Set all ACPI structure instance counts to 0. + + @param [in,out] StructDb ACPI structure database with counts to reset. +**/ +VOID +EFIAPI +ResetAcpiStructCounts ( + IN OUT ACPI_STRUCT_DATABASE* StructDb + ) +{ + UINT32 Type; + + ASSERT (StructDb != NULL); + ASSERT (StructDb->Entries != NULL); + + for (Type = 0; Type < StructDb->EntryCount; Type++) { + StructDb->Entries[Type].Count = 0; + } +} + +/** + Sum all ACPI structure instance counts. + + @param [in] StructDb ACPI structure database with per-type counts to sum. + + @return Total number of structure instances recorded in the database. +**/ +UINT32 +EFIAPI +SumAcpiStructCounts ( + IN CONST ACPI_STRUCT_DATABASE* StructDb + ) +{ + UINT32 Type; + UINT32 Total; + + ASSERT (StructDb != NULL); + ASSERT (StructDb->Entries != NULL); + + Total = 0; + + for (Type = 0; Type < StructDb->EntryCount; Type++) { + Total += StructDb->Entries[Type].Count; + } + + return Total; +} + +/** + Validate that a structure with a given type value is defined for the given + ACPI table and target architecture. + + The target architecture is evaluated from the firmare build parameters. + + @param [in] Type ACPI-defined structure type. + @param [in] StructDb ACPI structure database with architecture + compatibility info. + + @retval TRUE Structure is valid. + @retval FALSE Structure is not valid. +**/ +BOOLEAN +EFIAPI +IsAcpiStructTypeValid ( + IN UINT32 Type, + IN CONST ACPI_STRUCT_DATABASE* StructDb + ) +{ + UINT32 Compatible; + + ASSERT (StructDb != NULL); + ASSERT (StructDb->Entries != NULL); + + if (Type >= StructDb->EntryCount) { + return FALSE; + } + +#if defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64) + Compatible = StructDb->Entries[Type].CompatArch & + (ARCH_COMPAT_ARM | ARCH_COMPAT_AARCH64); +#else + Compatible = StructDb->Entries[Type].CompatArch; +#endif + + return (Compatible != 0); +} + +/** + Print the instance count of each structure in an ACPI table that is + compatible with the target architecture. + + For structures which are not allowed for the target architecture, + validate that their instance counts are 0. + + @param [in] StructDb ACPI structure database with counts to validate. + + @retval TRUE All structures are compatible. + @retval FALSE One or more incompatible structures present. +**/ +BOOLEAN +EFIAPI +ValidateAcpiStructCounts ( + IN CONST ACPI_STRUCT_DATABASE* StructDb + ) +{ + BOOLEAN AllValid; + UINT32 Type; + + ASSERT (StructDb != NULL); + ASSERT (StructDb->Entries != NULL); + + AllValid = TRUE; + Print (L"\nTable Breakdown:\n"); + + for (Type = 0; Type < StructDb->EntryCount; Type++) { + ASSERT (Type == StructDb->Entries[Type].Type); + + if (IsAcpiStructTypeValid (Type, StructDb)) { + Print ( + L"%*a%-*a : %d\n", + INSTANCE_COUNT_INDENT, + "", + OUTPUT_FIELD_COLUMN_WIDTH - INSTANCE_COUNT_INDENT, + StructDb->Entries[Type].Name, + StructDb->Entries[Type].Count + ); + } else if (StructDb->Entries[Type].Count > 0) { + AllValid = FALSE; + IncrementErrorCount (); + Print ( + L"ERROR: %a Structure is not valid for the target architecture " \ + L"(found %d)\n", + StructDb->Entries[Type].Name, + StructDb->Entries[Type].Count + ); + } + } + + return AllValid; +} + +/** + Parse the ACPI structure with the type value given according to instructions + defined in the ACPI structure database. + + If the input structure type is defined in the database, increment structure's + instance count. + + If ACPI_PARSER array is used to parse the input structure, the index of the + structure (instance count for the type before update) gets printed alongside + the structure name. This helps debugging if there are many instances of the + type in a table. For ACPI_STRUCT_PARSER_FUNC, the printing of the index must + be implemented separately. + + @param [in] Indent Number of spaces to indent the output. + @param [in] Ptr Ptr to the start of the structure. + @param [in,out] StructDb ACPI structure database with instructions on how + parse every structure type. + @param [in] Offset Structure offset from the start of the table. + @param [in] Type ACPI-defined structure type. + @param [in] Length Length of the structure in bytes. + @param [in] OptArg0 First optional argument to pass to parser function. + @param [in] OptArg1 Second optional argument to pass to parser function. + + @retval TRUE ACPI structure parsed successfully. + @retval FALSE Undefined structure type or insufficient data to parse. +**/ +BOOLEAN +EFIAPI +ParseAcpiStruct ( + IN UINT32 Indent, + IN UINT8* Ptr, + IN OUT ACPI_STRUCT_DATABASE* StructDb, + IN UINT32 Offset, + IN UINT32 Type, + IN UINT32 Length, + IN CONST VOID* OptArg0 OPTIONAL, + IN CONST VOID* OptArg1 OPTIONAL + ) +{ + ACPI_STRUCT_PARSER_FUNC ParserFunc; + CHAR8 Buffer[80]; + + ASSERT (Ptr != NULL); + ASSERT (StructDb != NULL); + ASSERT (StructDb->Entries != NULL); + ASSERT (StructDb->Name != NULL); + + PrintFieldName (Indent, L"* Offset *"); + Print (L"0x%x\n", Offset); + + if (Type >= StructDb->EntryCount) { + IncrementErrorCount (); + Print (L"ERROR: Unknown %a. Type = %d\n", StructDb->Name, Type); + return FALSE; + } + + if (StructDb->Entries[Type].Handler.ParserFunc != NULL) { + ParserFunc = StructDb->Entries[Type].Handler.ParserFunc; + ParserFunc (Ptr, Length, OptArg0, OptArg1); + } else if (StructDb->Entries[Type].Handler.ParserArray != NULL) { + ASSERT (StructDb->Entries[Type].Handler.Elements != 0); + + PrintAcpiStructName ( + StructDb->Entries[Type].Name, + StructDb->Entries[Type].Count, + sizeof (Buffer), + Buffer + ); + + ParseAcpi ( + TRUE, + Indent, + Buffer, + Ptr, + Length, + StructDb->Entries[Type].Handler.ParserArray, + StructDb->Entries[Type].Handler.Elements + ); + } else { + StructDb->Entries[Type].Count++; + Print ( + L"ERROR: Parsing of %a Structure is not implemented\n", + StructDb->Entries[Type].Name + ); + return FALSE; + } + + StructDb->Entries[Type].Count++; + return TRUE; +} + /** This function is used to parse an ACPI table buffer. diff --git a/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h b/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h index f81ccac7e118378aa185db4b625e5bcd75f78347..70e540b3a76de0ff9ce70bcabed8548063bea0ff 100644 --- a/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h +++ b/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h @@ -300,6 +300,240 @@ typedef struct AcpiParser { VOID* Context; } ACPI_PARSER; +/** + Produce a Null-terminated ASCII string with the name and index of an + ACPI structure. + + The output string is in the following format: [] + + @param [in] Name Structure name. + @param [in] Index Structure index. + @param [in] BufferSize The size, in bytes, of the output buffer. + @param [out] Buffer Buffer for the output string. + + @return The number of bytes written to the buffer (not including Null-byte) +**/ +UINTN +EFIAPI +PrintAcpiStructName ( + IN CONST CHAR8* Name, + IN UINT32 Index, + IN UINTN BufferSize, + OUT CHAR8* Buffer + ); + +/** + Indentation for printing instance counts for structures in an ACPI table. +**/ +#define INSTANCE_COUNT_INDENT 2 + +/** + Common signature for functions which parse ACPI structures. + + @param [in] Ptr Pointer to the start of structure's buffer. + @param [in] Length Length of the buffer. + @param [in] OptArg0 First optional argument. + @param [in] OptArg1 Second optional argument. +*/ +typedef VOID (*ACPI_STRUCT_PARSER_FUNC) ( + IN UINT8* Ptr, + IN UINT32 Length, + IN CONST VOID* OptArg0 OPTIONAL, + IN CONST VOID* OptArg1 OPTIONAL + ); + +/** + Description of how an ACPI structure should be parsed. + + One of ParserFunc or ParserArray should be not NULL. Otherwise, it is + assumed that parsing of an ACPI structure is not supported. If both + ParserFunc and ParserArray are defined, ParserFunc is used. +**/ +typedef struct AcpiStructHandler { + /// Dedicated function for parsing an ACPI structure + ACPI_STRUCT_PARSER_FUNC ParserFunc; + /// Array of instructions on how each structure field should be parsed + CONST ACPI_PARSER* ParserArray; + /// Number of elements in ParserArray if ParserArray is defined + UINT32 Elements; +} ACPI_STRUCT_HANDLER; + +/** + ACPI structure compatiblity with various architectures. + + Some ACPI tables define structures which are, for example, only valid in + the X64 or Arm context. For instance, the Multiple APIC Description Table + (MADT) describes both APIC and GIC interrupt models. + + These definitions provide means to describe the belonging of a structure + in an ACPI table to a particular architecture. This way, incompatible + structures can be detected. +**/ +#define ARCH_COMPAT_IA32 BIT0 +#define ARCH_COMPAT_X64 BIT1 +#define ARCH_COMPAT_ARM BIT2 +#define ARCH_COMPAT_AARCH64 BIT3 +#define ARCH_COMPAT_RISCV64 BIT4 + +/** + Information about a structure which constitutes an ACPI table +**/ +typedef struct AcpiStructInfo { + /// ACPI-defined structure Name + CONST CHAR8* Name; + /// ACPI-defined structure Type + CONST UINT32 Type; + /// Architecture(s) for which this structure is valid + CONST UINT32 CompatArch; + /// Structure's instance count in a table + UINT32 Count; + /// Information on how to handle the structure + CONST ACPI_STRUCT_HANDLER Handler; +} ACPI_STRUCT_INFO; + +/** + Macro for defining ACPI structure info when an ACPI_PARSER array must + be used to parse the structure. +**/ +#define ADD_ACPI_STRUCT_INFO_ARRAY(Name, Type, Compat, Array) \ +{ \ + Name, Type, Compat, 0, {NULL, Array, ARRAY_SIZE (Array)} \ +} + +/** + Macro for defining ACPI structure info when an ACPI_STRUCT_PARSER_FUNC + must be used to parse the structure. +**/ +#define ADD_ACPI_STRUCT_INFO_FUNC(Name, Type, Compat, Func) \ +{ \ + Name, Type, Compat, 0, {Func, NULL, 0} \ +} + +/** + Macro for defining ACPI structure info when the structure is defined in + the ACPI spec but no parsing information is provided. +**/ +#define ACPI_STRUCT_INFO_PARSER_NOT_IMPLEMENTED(Name, Type, Compat) \ +{ \ + Name, Type, Compat, 0, {NULL, NULL, 0} \ +} + +/** + Database collating information about every structure type defined by + an ACPI table. +**/ +typedef struct AcpiStructDatabase { + /// ACPI-defined name for the structures being described in the database + CONST CHAR8* Name; + /// Per-structure-type information. The list must be ordered by the types + /// defined for the table. All entries must be unique and there should be + /// no gaps. + ACPI_STRUCT_INFO* Entries; + /// Total number of unique types defined for the table + CONST UINT32 EntryCount; +} ACPI_STRUCT_DATABASE; + +/** + Set all ACPI structure instance counts to 0. + + @param [in,out] StructDb ACPI structure database with counts to reset. +**/ +VOID +EFIAPI +ResetAcpiStructCounts ( + IN OUT ACPI_STRUCT_DATABASE* StructDb + ); + +/** + Sum all ACPI structure instance counts. + + @param [in] StructDb ACPI structure database with per-type counts to sum. + + @return Total number of structure instances recorded in the database. +**/ +UINT32 +EFIAPI +SumAcpiStructCounts ( + IN CONST ACPI_STRUCT_DATABASE* StructDb + ); + +/** + Validate that a structure with a given type value is defined for the given + ACPI table and target architecture. + + The target architecture is evaluated from the firmare build parameters. + + @param [in] Type ACPI-defined structure type. + @param [in] StructDb ACPI structure database with architecture + compatibility info. + + @retval TRUE Structure is valid. + @retval FALSE Structure is not valid. +**/ +BOOLEAN +EFIAPI +IsAcpiStructTypeValid ( + IN UINT32 Type, + IN CONST ACPI_STRUCT_DATABASE* StructDb + ); + +/** + Print the instance count of each structure in an ACPI table that is + compatible with the target architecture. + + For structures which are not allowed for the target architecture, + validate that their instance counts are 0. + + @param [in] StructDb ACPI structure database with counts to validate. + + @retval TRUE All structures are compatible. + @retval FALSE One or more incompatible structures present. +**/ +BOOLEAN +EFIAPI +ValidateAcpiStructCounts ( + IN CONST ACPI_STRUCT_DATABASE* StructDb + ); + +/** + Parse the ACPI structure with the type value given according to instructions + defined in the ACPI structure database. + + If the input structure type is defined in the database, increment structure's + instance count. + + If ACPI_PARSER array is used to parse the input structure, the index of the + structure (instance count for the type before update) gets printed alongside + the structure name. This helps debugging if there are many instances of the + type in a table. For ACPI_STRUCT_PARSER_FUNC, the printing of the index must + be implemented separately. + + @param [in] Indent Number of spaces to indent the output. + @param [in] Ptr Ptr to the start of the structure. + @param [in,out] StructDb ACPI structure database with instructions on how + parse every structure type. + @param [in] Offset Structure offset from the start of the table. + @param [in] Type ACPI-defined structure type. + @param [in] Length Length of the structure in bytes. + @param [in] OptArg0 First optional argument to pass to parser function. + @param [in] OptArg1 Second optional argument to pass to parser function. + + @retval TRUE ACPI structure parsed successfully. + @retval FALSE Undefined structure type or insufficient data to parse. +**/ +BOOLEAN +EFIAPI +ParseAcpiStruct ( + IN UINT32 Indent, + IN UINT8* Ptr, + IN OUT ACPI_STRUCT_DATABASE* StructDb, + IN UINT32 Offset, + IN UINT32 Type, + IN UINT32 Length, + IN CONST VOID* OptArg0 OPTIONAL, + IN CONST VOID* OptArg1 OPTIONAL + ); + /** A structure used to store the pointers to the members of the ACPI description header structure that was parsed. -- 'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'