From patchwork Thu Jul 30 16:24:50 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: 502202 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 729891402D1; Fri, 31 Jul 2015 02:25:26 +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 1ZKqe5-0005zs-BG; Thu, 30 Jul 2015 16:25:25 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtp (Exim 4.76) (envelope-from ) id 1ZKqdx-0005zF-Uj for fwts-devel@lists.ubuntu.com; Thu, 30 Jul 2015 16:25:17 +0000 Received: from 1.general.cking.uk.vpn ([10.172.193.212] helo=localhost) by youngberry.canonical.com with esmtpsa (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1ZKqdx-00088i-Ny for fwts-devel@lists.ubuntu.com; Thu, 30 Jul 2015 16:25:17 +0000 From: Colin King To: fwts-devel@lists.ubuntu.com Subject: [PATCH 2/3] acpi: Add support for ASF! Table (LP: #1479736) Date: Thu, 30 Jul 2015 17:24:50 +0100 Message-Id: <1438273491-25968-3-git-send-email-colin.king@canonical.com> X-Mailer: git-send-email 2.4.6 In-Reply-To: <1438273491-25968-1-git-send-email-colin.king@canonical.com> References: <1438273491-25968-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 This add ASF! ACPI table test. It has a debug dump option built in, and because ASF! can be rather lengthy I've disabled this for the moment. Signed-off-by: Colin Ian King Acked-by: Ivan Hu Acked-by: Alex Hung --- src/Makefile.am | 1 + src/acpi/asf/asf.c | 557 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 558 insertions(+) create mode 100644 src/acpi/asf/asf.c diff --git a/src/Makefile.am b/src/Makefile.am index e9b7180..11aa37b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -29,6 +29,7 @@ fwts_SOURCES = main.c \ acpi/acpiinfo/acpiinfo.c \ acpi/acpitables/acpitables.c \ acpi/apicinstance/apicinstance.c \ + acpi/asf/asf.c \ acpi/battery/battery.c \ acpi/bert/bert.c \ acpi/bgrt/bgrt.c \ diff --git a/src/acpi/asf/asf.c b/src/acpi/asf/asf.c new file mode 100644 index 0000000..9d2be64 --- /dev/null +++ b/src/acpi/asf/asf.c @@ -0,0 +1,557 @@ +/* + * 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 + +#define ASF_DUMP (0) /* Set to 1 for more verbose output */ + +static fwts_acpi_table_info *table; + +static int asf_init(fwts_framework *fw) +{ + + if (fwts_acpi_find_table(fw, "ASF!", 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 ASF! table does not exist, skipping test"); + return FWTS_SKIP; + } + + return FWTS_OK; +} + +/* + * 4.1.2.1 ASF_INFO + */ +static void asf_check_info( + fwts_framework *fw, + ssize_t length, + uint8_t *data, + bool *passed, + bool *abort) +{ + fwts_acpi_table_asf_info *info = (fwts_acpi_table_asf_info *)data; + + if (length < (ssize_t)sizeof(fwts_acpi_table_asf_info)) { + fwts_failed(fw, LOG_LEVEL_HIGH, + "ASF!InfoRecordTooShort", + "ASF! ASF_INFO Record too short, " + "expecting %zu bytes, instead got %zu bytes", + sizeof(fwts_acpi_table_asf_info), length); + *passed = false; + *abort = true; + return; + } + +#if ASF_DUMP + fwts_log_info_verbatum(fw, "ASF! ASF_INFO Record:"); + fwts_log_info_verbatum(fw, " Min Watchdog Reset Value: 0x%2.2" PRIx8, info->watchdog_reset_value); + fwts_log_info_verbatum(fw, " Min Poll Wait Time: 0x%2.2" PRIx8, info->min_sensor_poll_wait_time); + fwts_log_info_verbatum(fw, " System ID: 0x%2.2" PRIx8, info->id); + fwts_log_info_verbatum(fw, " IANA Manufacturer ID: 0x%2.2" PRIx8, info->iana_id); + fwts_log_info_verbatum(fw, " Feature Flags: 0x%2.2" PRIx8, info->flags); + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, info->reserved1); + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, info->reserved2); + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, info->reserved3); +#endif + + if (info->watchdog_reset_value == 0) { + *passed = false; + fwts_failed(fw, LOG_LEVEL_HIGH, + "ASF!InfoMinWatchDogInvalid", + "ASF! ASF_INFO Minimum Watchdog Reset Value is 0x00 and " + "must be in the range 0x01..0xff"); + } + if (info->min_sensor_poll_wait_time < 2) { + *passed = false; + fwts_failed(fw, LOG_LEVEL_HIGH, + "ASF!InfoMinPollWaitTimeInvalid", + "ASF! ASF_INFO Minimum Poll Wait Time is 0x%" PRIx8 + " and must be in the range 0x02..0xff", + info->min_sensor_poll_wait_time); + } + if (info->flags & ~0x01) { + *passed = false; + fwts_failed(fw, LOG_LEVEL_HIGH, + "ASF!InfoFeatureFlagsReserved", + "ASF! ASF_INFO Feature Flags is 0x%" PRIx8 + ", however reserved bits [7:1] must be zero", + info->flags); + } + if (info->reserved1 | info->reserved2 | info->reserved3) { + *passed = false; + fwts_failed(fw, LOG_LEVEL_HIGH, + "ASF!InfoReservedNonZero", + "ASF! ASF_INFO Reserved fields must be zero, " + "however one or more of them are non-zero"); + } + if (*passed) + fwts_passed(fw, "No issues found in ASF! ASF_INFO record."); +} + + +/* + * 4.1.2.2 ASF_ALRT + */ +static void asf_check_alrt( + fwts_framework *fw, + ssize_t record_length, + ssize_t length, + uint8_t *data, + bool *passed, + bool *abort) +{ + fwts_acpi_table_asf_alrt *alrt = (fwts_acpi_table_asf_alrt *)data; + uint8_t i; + ssize_t total_length; + + if (length < (ssize_t)sizeof(fwts_acpi_table_asf_alrt)) { + fwts_failed(fw, LOG_LEVEL_HIGH, + "ASF!AlrtRecordTooShort", + "ASF! ASF_ALRT Record too short, " + "expecting %zu bytes, instead got %zu bytes", + sizeof(fwts_acpi_table_asf_alrt), length); + *passed = false; + *abort = true; + return; + } + +#if ASF_DUMP + fwts_log_info_verbatum(fw, "ASF! ASF_ALRT Record:"); + fwts_log_info_verbatum(fw, " Assertion Event Mask: 0x%2.2" PRIx8, alrt->assertion_mask); + fwts_log_info_verbatum(fw, " De-Assertion Event Mask: 0x%2.2" PRIx8, alrt->deassertion_mask); + fwts_log_info_verbatum(fw, " Number of Alerts: 0x%2.2" PRIx8, alrt->number_of_alerts); + fwts_log_info_verbatum(fw, " Array Element Length: 0x%2.2" PRIx8, alrt->array_length); +#endif + + if ((alrt->number_of_alerts < 1) || + (alrt->number_of_alerts > 8)) { + *passed = false; + fwts_failed(fw, LOG_LEVEL_HIGH, + "ASF!AlrtNumOfAlertsInvalid", + "ASF! ASF_ALRT Number of Alerts field is 0x%" PRIx8 + " and must be in the range 0x01..0x08", + alrt->number_of_alerts); + /* Don't trust the ALRT data, so abort */ + return; + } + if (alrt->array_length != sizeof(fwts_acpi_table_asf_alrt_element)) { + *passed = false; + fwts_failed(fw, LOG_LEVEL_HIGH, + "ASF!AlrtArrayElementLengthInvalid", + "ASF! ASF_ALRT Array Element Length is 0x%" PRIx8 + " and must be instead 0x%" PRIx8, + alrt->array_length, + (uint8_t)sizeof(fwts_acpi_table_asf_alrt_element)); + } + + total_length = sizeof(fwts_acpi_table_asf_alrt) + + (alrt->number_of_alerts * sizeof(fwts_acpi_table_asf_alrt_element)); + if (total_length > record_length) { + *passed = false; + fwts_failed(fw, LOG_LEVEL_HIGH, + "ASF!AlrtArrayElementLengthInvalid", + "ASF! ASF_ALRT Array Element Length makes the " + "total ASF_ALRT record size to be %zu bytes, however the " + "table is only %zu bytes long", + total_length, record_length); + *passed = false; + *abort = true; + return; + } + + data += sizeof(fwts_acpi_table_asf_alrt); + for (i = 0; i < alrt->number_of_alerts; i++) { + fwts_acpi_table_asf_alrt_element *element = + (fwts_acpi_table_asf_alrt_element *)data; + +#if ASF_DUMP + fwts_log_info_verbatum(fw, "ASF! ASF_ALRT Element %" PRIu8 ":", i); + fwts_log_info_verbatum(fw, " Device Address: 0x%2.2" PRIx8, element->device_addr); + fwts_log_info_verbatum(fw, " Alert Command: 0x%2.2" PRIx8, element->command); + fwts_log_info_verbatum(fw, " Alert Data Mask: 0x%2.2" PRIx8, element->data_mask); + fwts_log_info_verbatum(fw, " Alert Compare Value: 0x%2.2" PRIx8, element->compare_value); + fwts_log_info_verbatum(fw, " Alert Event Sensor Type: 0x%2.2" PRIx8, element->sensor_type); + fwts_log_info_verbatum(fw, " Alert Event Type: 0x%2.2" PRIx8, element->event_type); + fwts_log_info_verbatum(fw, " Alert Event Offset: 0x%2.2" PRIx8, element->event_offset); + fwts_log_info_verbatum(fw, " Alert Source Type: 0x%2.2" PRIx8, element->event_source_type); + fwts_log_info_verbatum(fw, " Alert Event Severity: 0x%2.2" PRIx8, element->event_severity); + fwts_log_info_verbatum(fw, " Alert Sensor Number: 0x%2.2" PRIx8, element->sensor_number); + fwts_log_info_verbatum(fw, " Alert Entity: 0x%2.2" PRIx8, element->entity); + fwts_log_info_verbatum(fw, " Alert Entity Instance: 0x%2.2" PRIx8, element->entity_instance); +#endif + + if (element->event_offset & 0x80) { + *passed = false; + fwts_failed(fw, LOG_LEVEL_HIGH, + "ASF!AlrtEventOffsetBit7Set", + "ASF! ASF_ALRT Array Element %" PRIu8 " Event Offset Bit 7 is 1, " + " and should be 0", i); + } + data += sizeof(fwts_acpi_table_asf_alrt_element); + } + if (*passed) + fwts_passed(fw, "No issues found in ASF! ASF_ALRT record."); +} + +/* + * 4.1.2.4 ASF_RCTL + */ +static void asf_check_rctl( + fwts_framework *fw, + ssize_t record_length, + ssize_t length, + uint8_t *data, + bool *passed, + bool *abort) +{ + fwts_acpi_table_asf_rctl *rctl = (fwts_acpi_table_asf_rctl *)data; + uint8_t i; + ssize_t total_length; + + if (length < (ssize_t)sizeof(fwts_acpi_table_asf_rctl)) { + fwts_failed(fw, LOG_LEVEL_HIGH, + "ASF!RctlRecordTooShort", + "ASF! ASF_RCTL Record too short, " + "expecting %zu bytes, instead got %zu bytes", + sizeof(fwts_acpi_table_asf_rctl), length); + *passed = false; + *abort = true; + return; + } +#if ASF_DUMP + fwts_log_info_verbatum(fw, "ASF! ASF_RCTL Record:"); + fwts_log_info_verbatum(fw, " Number of Controls: 0x%2.2" PRIx8, rctl->number_of_controls); + fwts_log_info_verbatum(fw, " Array Element Length: 0x%2.2" PRIx8, rctl->array_element_length); + fwts_log_info_verbatum(fw, " Reserved: 0x%4.4" PRIx16, rctl->array_element_length); +#endif + if (rctl->array_element_length != sizeof(fwts_acpi_table_asf_rctl_element)) { + *passed = false; + fwts_failed(fw, LOG_LEVEL_HIGH, + "ASF!RctlArrayElementLengthInvalid", + "ASF! ASF_RCTL Array Element Length is 0x%" PRIx8 + " and must be instead 0x%" PRIx8, + rctl->array_element_length, + (uint8_t)sizeof(fwts_acpi_table_asf_rctl_element)); + } + + total_length = sizeof(fwts_acpi_table_asf_rctl) + + (rctl->number_of_controls * sizeof(fwts_acpi_table_asf_rctl_element)); + if (total_length > record_length) { + *passed = false; + fwts_failed(fw, LOG_LEVEL_HIGH, + "ASF!RctlArrayElementLengthInvalid", + "ASF! ASF_RCTL Array Element Length makes the " + "total ASF_RCTL record size to be %zu bytes, however the " + "table is only %zu bytes long", + total_length, record_length); + *passed = false; + *abort = true; + return; + } + + data += sizeof(fwts_acpi_table_asf_rctl); + for (i = 0; i < rctl->number_of_controls; i++) { + fwts_acpi_table_asf_rctl_element *element = + (fwts_acpi_table_asf_rctl_element *)data; +#if ASF_DUMP + fwts_log_info_verbatum(fw, "ASF! ASF_RCTL Element %" PRIu8 ":", i); + fwts_log_info_verbatum(fw, " Control Function: 0x%2.2" PRIx8, element->control_function); + fwts_log_info_verbatum(fw, " Control Device Address: 0x%2.2" PRIx8, element->control_device_addr); + fwts_log_info_verbatum(fw, " Control Command: 0x%2.2" PRIx8, element->control_command); + fwts_log_info_verbatum(fw, " Control Value: 0x%2.2" PRIx8, element->control_value); +#endif + + if (element->control_function > 0x03) { + *passed = false; + fwts_failed(fw, LOG_LEVEL_HIGH, + "ASF!RctlCtrlFuncInvalid", + "ASF! ASF_RCTL Control Function is 0x%" PRIx8 + " and must be in the range 0x00..0x03", + element->control_function); + } + data += sizeof(fwts_acpi_table_asf_rctl_element); + } + if (*passed) + fwts_passed(fw, "No issues found in ASF! ASF_RCTL record."); +} + + + +/* + * 4.1.2.6 ASF_RMCP + */ +static void asf_check_rmcp( + fwts_framework *fw, + ssize_t length, + uint8_t *data, + bool *passed, + bool *abort) +{ + fwts_acpi_table_asf_rmcp *rmcp = (fwts_acpi_table_asf_rmcp *)data; + + if (length < (ssize_t)sizeof(fwts_acpi_table_asf_rmcp)) { + fwts_failed(fw, LOG_LEVEL_HIGH, + "ASF!RmcpRecordTooShort", + "ASF! ASF_RMCP Record too short, " + "expecting %zu bytes, instead got %zu bytes", + sizeof(fwts_acpi_table_asf_rmcp), length); + *passed = false; + *abort = true; + return; + } +#if ASF_DUMP + fwts_log_info_verbatum(fw, "ASF! ASF_RMCP Record:"); + fwts_log_info_verbatum(fw, " Remote Control Cap.: " + "0x%2.2" PRIx8 " 0x%2.2" PRIx8 " 0x%2.2" PRIx8 " 0x%2.2" PRIx8 " " + "0x%2.2" PRIx8 " 0x%2.2" PRIx8 " 0x%2.2" PRIx8, + rmcp->remote_control_capabilities[0], + rmcp->remote_control_capabilities[1], + rmcp->remote_control_capabilities[2], + rmcp->remote_control_capabilities[3], + rmcp->remote_control_capabilities[4], + rmcp->remote_control_capabilities[5], + rmcp->remote_control_capabilities[6]); + fwts_log_info_verbatum(fw, " Boot Opt. Completion Code:0x%2.2" PRIx8, rmcp->completion_code); + fwts_log_info_verbatum(fw, " IANA Enterprise ID: 0x%8.8" PRIx32, rmcp->iana); + fwts_log_info_verbatum(fw, " Special Command: 0x%2.2" PRIx8, rmcp->special_command); + fwts_log_info_verbatum(fw, " Special Command Parameter:0x%4.4" PRIx16, rmcp->special_command_param); + fwts_log_info_verbatum(fw, " Boot Options: 0x%2.2" PRIx8 " 0x%2.2" PRIx8, + rmcp->boot_options[0], rmcp->boot_options[1]); + fwts_log_info_verbatum(fw, " OEM Parameters: 0x%4.4" PRIx16, rmcp->oem_parameters); +#endif + + /* Specification, page 33-34 */ + if (rmcp->iana == 0x4542) { + /* Values 0x00..0x05 and 0xc0..0xff are allowed */ + if ((rmcp->special_command > 0x05) && + (rmcp->special_command < 0xc0)) { + *passed = false; + fwts_failed(fw, LOG_LEVEL_HIGH, + "ASF!RmcpSpecialCommandInvalid", + "ASF! ASF_RMCP Special Command is 0x%" PRIx8 + "and should be 0x00..0x05 or 0xc0..0xff", + rmcp->special_command); + } + } + if (*passed) + fwts_passed(fw, "No issues found in ASF! ASF_RMCP record."); +} + +/* + * 4.1.2.7 ASF_ADDR + */ +static void asf_check_addr( + fwts_framework *fw, + ssize_t record_length, + ssize_t length, + uint8_t *data, + bool *passed, + bool *abort) +{ + ssize_t total_length; + fwts_acpi_table_asf_addr *addr = (fwts_acpi_table_asf_addr *)data; +#if ASF_DUMP + uint8_t i; +#else + (void)data; +#endif + if (length < (ssize_t)sizeof(fwts_acpi_table_asf_addr)) { + fwts_failed(fw, LOG_LEVEL_HIGH, + "ASF!AddrRecordTooShort", + "ASF! ASF_ADDR Record too short, " + "expecting %zu bytes, instead got %zu bytes", + sizeof(fwts_acpi_table_asf_addr), length); + *passed = false; + *abort = true; + return; + } +#if ASF_DUMP + fwts_log_info_verbatum(fw, "ASF! ASF_ADDR Record:"); + fwts_log_info_verbatum(fw, " SEEPROM Address: 0x%2.2" PRIx8, addr->seeprom_addr); + fwts_log_info_verbatum(fw, " Number of Devices: 0x%2.2" PRIx8, addr->number_of_devices); +#endif + total_length = sizeof(fwts_acpi_table_asf_addr) + + (addr->number_of_devices * sizeof(fwts_acpi_table_asf_addr_element)); + if (total_length > record_length) { + *passed = false; + fwts_failed(fw, LOG_LEVEL_HIGH, + "ASF!AddrArrayElementLengthInvalid", + "ASF! ASF_ADDR Number of Devices makes the " + "total ASF_ADDR record size to be %zu bytes, however the " + "table is only %zu bytes long", + total_length, record_length); + *passed = false; + *abort = true; + return; + } + +#if ASF_DUMP + data += sizeof(fwts_acpi_table_asf_addr); + for (i = 0; i < addr->number_of_devices; i++) { + fwts_acpi_table_asf_addr_element *element = + (fwts_acpi_table_asf_addr_element *)data; + fwts_log_info_verbatum(fw, " Fixed SMBus Address 0x%2.2" PRIx8, element->fixed_smbus_addr); + data += sizeof(fwts_acpi_table_asf_addr_element); + } +#endif + if (*passed) + fwts_passed(fw, "No issues found in ASF! ASF_ADDR record."); +} + + +/* + * ASF! Hardware Error Source Table test + * http://www.dmtf.org/sites/default/files/standards/documents/DSP0136.pdf + */ +static int asf_test1(fwts_framework *fw) +{ + bool passed = true; + bool abort = false; + fwts_acpi_table_header *hdr = (fwts_acpi_table_header *)table->data; + uint8_t *data = (uint8_t *)table->data; + ssize_t length = (ssize_t)hdr->length; + + fwts_log_info_verbatum(fw, "ASF! Hardware Error Source Table"); + + data += sizeof(fwts_acpi_table_header); + length -= sizeof(fwts_acpi_table_header); + + while (!abort && (length > 0)) { + bool asf_passed = true; + + fwts_acpi_table_asf_header *asf_hdr = + (fwts_acpi_table_asf_header *)data; + + /* Must have enough for a info header */ + if (length < (ssize_t)sizeof(fwts_acpi_table_asf_header)) { + passed = false; + fwts_failed(fw, LOG_LEVEL_HIGH, + "ASF!TooShort", + "ASF! table too short, expecting at least %zu bytes " + "for an ASF! information record header, " + "instead got %zu bytes", + sizeof(fwts_acpi_table_asf_header), table->length); + break; + } + +#if ASF_DUMP + fwts_log_info_verbatum(fw, "Type: 0x%2.2" PRIx8, asf_hdr->type); + fwts_log_info_verbatum(fw, "Reserved: 0x%2.2" PRIx8, asf_hdr->reserved); + fwts_log_info_verbatum(fw, "Length: 0x%4.4" PRIx16, asf_hdr->length); +#endif + + if (asf_hdr->reserved) { + passed = false; + fwts_failed(fw, LOG_LEVEL_HIGH, + "ASF!InfoRecordReservedNonZero", + "ASF! Information Record Reserved field is 0x%" PRIx8 + " and should be zero", asf_hdr->reserved); + } + if (asf_hdr->length > (uint32_t)length) { + passed = false; + fwts_failed(fw, LOG_LEVEL_HIGH, + "ASF!InfoRecordLengthTooLong", + "ASF! Information Record Reserved length is %" PRIu32 + " and this is too long for the size given by " + "the ASF! table. Expected at most %zu bytes.", + asf_hdr->length, length); + /* Since we can't trust the table, abort */ + break; + } + + switch (asf_hdr->type) { + case 0x00: + case 0x80: + asf_check_info(fw, length - sizeof(*asf_hdr), data + sizeof(*asf_hdr), &asf_passed, &abort); + data += asf_hdr->length; + length -= asf_hdr->length; + break; + case 0x01: + case 0x81: + asf_check_alrt(fw, asf_hdr->length, + length - sizeof(*asf_hdr), data + sizeof(*asf_hdr), &asf_passed, &abort); + data += asf_hdr->length; + length -= asf_hdr->length; + break; + case 0x02: + case 0x82: + asf_check_rctl(fw, asf_hdr->length, + length - sizeof(*asf_hdr), data + sizeof(*asf_hdr), &asf_passed, &abort); + data += asf_hdr->length; + length -= asf_hdr->length; + break; + case 0x03: + case 0x83: + asf_check_rmcp(fw, length - sizeof(*asf_hdr), data + sizeof(*asf_hdr), &asf_passed, &abort); + data += asf_hdr->length; + length -= asf_hdr->length; + break; + case 0x04: + case 0x84: + asf_check_addr(fw, asf_hdr->length, + length - sizeof(*asf_hdr), data + sizeof(*asf_hdr), &asf_passed, &abort); + data += asf_hdr->length; + length -= asf_hdr->length; + break; + default: + fwts_failed(fw, LOG_LEVEL_HIGH, + "ASF!InvalidType", + "ASF! Information Record Type 0x%4.4" PRIx16 " is invalid, aborting check", + asf_hdr->type); + passed = false; + length = 0; + break; + } + passed &= asf_passed; +#if ASF_DUMP + fwts_log_nl(fw); +#endif + } +#if ASF_DUMP + fwts_log_nl(fw); +#endif + + if (passed) + fwts_passed(fw, "No issues found in ASF! table."); + + return FWTS_OK; +} + +static fwts_framework_minor_test asf_tests[] = { + { asf_test1, "ASF! Alert Standard Format Table test." }, + { NULL, NULL } +}; + +static fwts_framework_ops asf_ops = { + .description = "ASF! Alert Standard Format Table test.", + .init = asf_init, + .minor_tests = asf_tests +}; + +FWTS_REGISTER("asf", &asf_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_BATCH | FWTS_FLAG_TEST_ACPI)