From patchwork Mon Jun 15 12:48:16 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Colin Ian King X-Patchwork-Id: 484302 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) by ozlabs.org (Postfix) with ESMTP id 620BB140129; Mon, 15 Jun 2015 22:50:42 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.76) (envelope-from ) id 1Z4Tqb-0001Cq-AD; Mon, 15 Jun 2015 12:50:41 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtp (Exim 4.76) (envelope-from ) id 1Z4TqU-0001BU-TU for fwts-devel@lists.ubuntu.com; Mon, 15 Jun 2015 12:50:34 +0000 Received: from [10.172.65.212] (helo=localhost) by youngberry.canonical.com with esmtpsa (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1Z4TqU-0000ZE-Fw for fwts-devel@lists.ubuntu.com; Mon, 15 Jun 2015 12:50:34 +0000 From: Colin King To: fwts-devel@lists.ubuntu.com Subject: [PATCH 2/3] add ACPI SPMI table sanity checking (LP: #1465256) Date: Mon, 15 Jun 2015 13:48:16 +0100 Message-Id: <1434372497-17616-3-git-send-email-colin.king@canonical.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1434372497-17616-1-git-send-email-colin.king@canonical.com> References: <1434372497-17616-1-git-send-email-colin.king@canonical.com> X-BeenThere: fwts-devel@lists.ubuntu.com X-Mailman-Version: 2.1.14 Precedence: list List-Id: Firmware Test Suite Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: fwts-devel-bounces@lists.ubuntu.com Sender: fwts-devel-bounces@lists.ubuntu.com From: Colin Ian King Add SPMI (Service Processor Management Interface Description Table) test. Signed-off-by: Colin Ian King Acked-by: Alex Hung --- src/Makefile.am | 1 + src/acpi/spmi/spmi.c | 253 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 254 insertions(+) create mode 100644 src/acpi/spmi/spmi.c diff --git a/src/Makefile.am b/src/Makefile.am index ceeb45e..3fa679c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -54,6 +54,7 @@ fwts_SOURCES = main.c \ acpi/s3power/s3power.c \ acpi/s4/s4.c \ acpi/spcr/spcr.c \ + acpi/spmi/spmi.c \ acpi/srat/srat.c \ acpi/syntaxcheck/syntaxcheck.c \ acpi/wakealarm/wakealarm.c \ diff --git a/src/acpi/spmi/spmi.c b/src/acpi/spmi/spmi.c new file mode 100644 index 0000000..6afc63e --- /dev/null +++ b/src/acpi/spmi/spmi.c @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2015 Canonical + * + * Portions of this code original from the Linux-ready Firmware Developer Kit + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "fwts.h" + +#include +#include +#include +#include +#include + +static fwts_acpi_table_info *table; + +static int spmi_init(fwts_framework *fw) +{ + + if (fwts_acpi_find_table(fw, "SPMI", 0, &table) != FWTS_OK) { + fwts_log_error(fw, "Cannot read ACPI tables."); + return FWTS_ERROR; + } + if (table == NULL || (table && table->length == 0)) { + fwts_log_error(fw, "ACPI SPMI table does not exist, skipping test"); + return FWTS_SKIP; + } + + return FWTS_OK; +} + +/* + * SPMI Service Processor Management Interface Description Table + * see http://www.intel.com/content/www/us/en/servers/ipmi/ + * ipmi-intelligent-platform-mgt-interface-spec-2nd-gen-v2-0-spec-update.html + * pages 600-606 + */ +static int spmi_test1(fwts_framework *fw) +{ + char *interface_type; + bool passed = true; + fwts_acpi_table_spmi *spmi = (fwts_acpi_table_spmi *)table->data; + + if (table->length < sizeof(fwts_acpi_table_spmi)) { + passed = false; + fwts_failed(fw, LOG_LEVEL_HIGH, + "SPMITooShort", + "SPMI table too short, expecting %zu bytes, " + "instead got %zu bytes", + sizeof(fwts_acpi_table_spmi), table->length); + goto done; + } + + switch (spmi->interface_type) { + case 0x01: + interface_type = "Keyboard Controller Type (KCS)"; + break; + case 0x02: + interface_type = "Server Management Interface Chip (SMIC)"; + break; + case 0x03: + interface_type = "Block Transfer (BT)"; + break; + case 0x04: + interface_type = "SMBus System Interface (SSIF)"; + break; + default: + interface_type = "Reserved"; + break; + } + + fwts_log_info_verbatum(fw, "SPMI Service Processor Management Interface Description Table:"); + fwts_log_info_verbatum(fw, " Interface Type: 0x%2.2" PRIx8 " (%s)", + spmi->interface_type, interface_type); + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, spmi->reserved1); + fwts_log_info_verbatum(fw, " Specification Revision: 0x%2.2" PRIx8, spmi->specification_revision); + fwts_log_info_verbatum(fw, " Interrupt Type: 0x%2.2" PRIx8, spmi->interrupt_type); + fwts_log_info_verbatum(fw, " GPE: 0x%2.2" PRIx8, spmi->gpe); + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, spmi->reserved2); + fwts_log_info_verbatum(fw, " PCI Device Flag: 0x%2.2" PRIx8, spmi->pci_device_flag); + fwts_log_info_verbatum(fw, " Global System Interrupt 0x%8.8" PRIx32, spmi->global_system_interrupt); + fwts_log_info_verbatum(fw, " Base Address:"); + fwts_log_info_verbatum(fw, " Address Space ID: 0x%2.2" PRIx8, spmi->base_address.address_space_id); + fwts_log_info_verbatum(fw, " Register Bit Width 0x%2.2" PRIx8, spmi->base_address.register_bit_width); + fwts_log_info_verbatum(fw, " Register Bit Offset 0x%2.2" PRIx8, spmi->base_address.register_bit_offset); + fwts_log_info_verbatum(fw, " Access Size 0x%2.2" PRIx8, spmi->base_address.access_width); + fwts_log_info_verbatum(fw, " Address 0x%16.16" PRIx64, spmi->base_address.address); + fwts_log_info_verbatum(fw, " PCI Segment Group: 0x%2.2" PRIx8, spmi->pci_segment_group_number); + fwts_log_info_verbatum(fw, " PCI Bus: 0x%2.2" PRIx8, spmi->pci_bus_number); + fwts_log_info_verbatum(fw, " PCI Device: 0x%2.2" PRIx8, spmi->pci_device_number); + fwts_log_info_verbatum(fw, " PCI Function: 0x%2.2" PRIx8, spmi->pci_function_number); + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, spmi->reserved3); + fwts_log_nl(fw); + + if (spmi->interface_type < 1 || spmi->interface_type > 4) { + passed = false; + fwts_failed(fw, LOG_LEVEL_MEDIUM, + "SPMIInterfaceTypeReserved", + "SPMI Interface Type is 0x%2.2" PRIx8 " which " + "is a reserved type and probably incorrect.", + spmi->interface_type); + } + + if (spmi->reserved1 != 1) { + passed = false; + fwts_failed(fw, LOG_LEVEL_LOW, + "SPMIReserved1Not1", + "SPMI reserved field (offset 37) must be 0x01, got " + "0x%2.2" PRIx8 " instead", spmi->reserved1); + } + + /* Only bottom 2 bits should be set */ + if (spmi->interrupt_type & ~0x03) { + passed = false; + fwts_failed(fw, LOG_LEVEL_LOW, + "SPMIInterruptTypeReservedNonZero", + "SPMI Interrupt Type reserved bits [7:2] must be 0, got " + "0x%2.2" PRIx8 " instead", spmi->interrupt_type); + } + + /* Check for zero GPE on specific condition of interrupt type */ + if (((spmi->interrupt_type & 1) == 0) && + (spmi->gpe != 0)) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, + "SPMIGPENotZero", + "SPMI GPE is 0x%2.2" PRIx8 " and should be 0 if the Interrupt " + "Type bit 0 (SCI triggered through GPE) is set to 0", + spmi->gpe); + } + if (spmi->reserved2 != 0) { + passed = false; + fwts_failed(fw, LOG_LEVEL_LOW, + "SPMIReserved1NonZero", + "SPMI reserved field (offset 42) must be 0x00, got " + "0x%2.2" PRIx8 " instead", spmi->reserved2); + } + /* Only bottom 1 bit should be set */ + if (spmi->pci_device_flag & ~0x01) { + passed = false; + fwts_failed(fw, LOG_LEVEL_MEDIUM, + "SPMIPciDeviceFlag", + "SPMI PCI Device Flag reserved bits [7:1] must be 0, got " + "0x%2.2" PRIx8 " instead", spmi->pci_device_flag); + } + + /* For SSIF interfaces, if device flag [0] is set then PCI semgment group number is zero */ + if ((spmi->interface_type == 0x04) && + (spmi->pci_device_flag & 0x01) && + (spmi->pci_segment_group_number != 0)) { + passed = false; + fwts_failed(fw, LOG_LEVEL_MEDIUM, + "SPMIPciSegmentGroupNumber", + "SPMI PCI Segment Group Number should be 0 for SSIF interface " + "types when bit [0] of the PCI Device Flag is set"); + } + + if (((spmi->interrupt_type & 2) == 0) && + (spmi->global_system_interrupt != 0)) { + passed = false; + fwts_failed(fw, LOG_LEVEL_MEDIUM, + "SPMIGlobalSystemInterruptNonZero", + "SPMI Global System Interrupt is 0x%" PRIx32 " and " + "should be zero if bit [1] (I/O APIC/SAPIC interrupt) " + "of the Interrupt Type is not set", + spmi->global_system_interrupt); + } + + /* Base address must be one of 3 types, System Memory, System I/O or SMBUS */ + if ((spmi->base_address.address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_MEMORY) && + (spmi->base_address.address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_IO) && + (spmi->base_address.address_space_id != FWTS_GAS_ADDR_SPACE_ID_SMBUS)) { + passed = false; + fwts_failed(fw, LOG_LEVEL_MEDIUM, + "SPMIBaseAddressSpaceID", + "SPMI Base Address Space ID is 0x%2.2" PRIx8 " but should be one of " + "0x%2.2" PRIx8 " (System Memory), " + "0x%2.2" PRIx8 " (System I/O) or " + "0x%2.2" PRIx8 " (SMBUS)", + spmi->base_address.address_space_id, + FWTS_GAS_ADDR_SPACE_ID_SYSTEM_MEMORY, + FWTS_GAS_ADDR_SPACE_ID_SYSTEM_IO, + FWTS_GAS_ADDR_SPACE_ID_SMBUS); + } + /* + * For SSIF: The Address_Space_ID is SMBUS and the address field of the GAS + * holds the 7-bit slave address of the BMC on the host SMBus + * in the least significant byte. Note that the slave address is + * stored with the 7-bit slave address in the least significant 7- + * bits of the byte, and the most significant bit of the byte set to + */ + if (spmi->interface_type == 0x04) { + if (spmi->base_address.address_space_id != FWTS_GAS_ADDR_SPACE_ID_SMBUS) { + passed = false; + fwts_failed(fw, LOG_LEVEL_MEDIUM, + "SPMIInvalidAddressSpaceIDForSSIF", + "SPMI Base Address Space ID is 0x%2.2" PRIx8 + " but should be 0x%2.2" PRIx8 " (SMBUS) " + " for a SSIF Interface Type", + spmi->base_address.address_space_id, + FWTS_GAS_ADDR_SPACE_ID_SMBUS); + } + if (spmi->base_address.address & ~0x7f) { + passed = false; + fwts_failed(fw, LOG_LEVEL_MEDIUM, + "SPMIInvalidBaseAddressForSSIF", + "SPMI Base Address is 0x%16.16" PRIx64 + " but should be 0..127 for a SSIF Interface Type", + spmi->base_address.address); + } + } + /* + * Specification states that PCI device number bits [7:5] + * are reserved if PCI device flag bit [0] is set, however, + * it does not state if they should be zero or 1, so for + * now don't check these + * + * Also, PCI function number bits [7] and [5:3] are + * reserved, again, not sure if these need to be checked + * so ignore these too. + */ +done: + if (passed) + fwts_passed(fw, "No issues found in SPMI table."); + + return FWTS_OK; +} + +static fwts_framework_minor_test spmi_tests[] = { + { spmi_test1, "SPMI Service Processor Management Interface Description Table test." }, + { NULL, NULL } +}; + +static fwts_framework_ops spmi_ops = { + .description = "SPMI Service Processor Management Interface Description Table test.", + .init = spmi_init, + .minor_tests = spmi_tests +}; + +FWTS_REGISTER("spmi", &spmi_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_BATCH | FWTS_FLAG_ROOT_PRIV | FWTS_FLAG_TEST_ACPI)