ACK: [PATCH 2/3] add ACPI HEST table sanity checking (LP: #1465379)
ivanhu
ivan.hu at canonical.com
Thu Jun 18 06:57:50 UTC 2015
On 2015年06月16日 03:00, Colin King wrote:
> From: Colin Ian King <colin.king at canonical.com>
>
> Add HEST (Hardware Error Source Table) test. This has been sanity
> checked against 110 HEST tables in my ACPI collection.
>
> Signed-off-by: Colin Ian King <colin.king at canonical.com>
> ---
> src/Makefile.am | 1 +
> src/acpi/hest/hest.c | 785 +++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 786 insertions(+)
> create mode 100644 src/acpi/hest/hest.c
>
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 42ecac7..3a0e547 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -43,6 +43,7 @@ fwts_SOURCES = main.c \
> acpi/fadt/fadt.c \
> acpi/fan/fan.c \
> acpi/gpedump/gpedump.c \
> + acpi/hest/hest.c \
> acpi/lid/lid.c \
> acpi/mcfg/mcfg.c \
> acpi/method/method.c \
> diff --git a/src/acpi/hest/hest.c b/src/acpi/hest/hest.c
> new file mode 100644
> index 0000000..f1724e5
> --- /dev/null
> +++ b/src/acpi/hest/hest.c
> @@ -0,0 +1,785 @@
> +/*
> + * 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 <stdlib.h>
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <inttypes.h>
> +#include <string.h>
> +
> +static fwts_acpi_table_info *table;
> +
> +static int hest_init(fwts_framework *fw)
> +{
> +
> + if (fwts_acpi_find_table(fw, "HEST", 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 HEST table does not exist, skipping test");
> + return FWTS_SKIP;
> + }
> +
> + return FWTS_OK;
> +}
> +
> +/*
> + * ACPI Section 18.3.2.1 IA-32 Architecture Machine Check Exception
> + */
> +static void hest_check_ia32_arch_machine_check_exception(
> + fwts_framework *fw,
> + ssize_t *length,
> + uint8_t **data,
> + bool *passed)
> +{
> + ssize_t i, total_size;
> +
> + fwts_acpi_table_hest_ia32_machine_check_exception *exception =
> + (fwts_acpi_table_hest_ia32_machine_check_exception *)*data;
> +
> + if (*length < (ssize_t)sizeof(fwts_acpi_table_hest_ia32_machine_check_exception)) {
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTIA32MachineCheckTooShort",
> + "HEST IA-32 Architecture Machine Check Exception "
> + "too short, expecting %zu bytes, "
> + "instead got %zu bytes",
> + sizeof(fwts_acpi_table_hest_ia32_machine_check_exception), *length);
> + *passed = false;
> + *length = 0; /* Forces an early abort */
> + return;
> + }
> +
> + total_size = sizeof(fwts_acpi_table_hest_ia32_machine_check_exception) +
> + (exception->number_of_hardware_banks *
> + sizeof(fwts_acpi_table_hest_machine_check_bank));
> +
> + if (*length < total_size) {
> + *passed = false;
> + *length = 0; /* Forces an early abort */
> + return;
> + }
> +
> + fwts_log_info_verbatum(fw, "HEST IA-32 Architecture Machine Check Exception:");
> + fwts_log_info_verbatum(fw, " Type: 0x%2.2" PRIx8, exception->type);
> + fwts_log_info_verbatum(fw, " Source ID: 0x%4.4" PRIx16, exception->source_id);
> + fwts_log_info_verbatum(fw, " Reserved: 0x%4.4" PRIx16, exception->reserved1);
> + fwts_log_info_verbatum(fw, " Flags: 0x%2.2" PRIx8, exception->flags);
> + fwts_log_info_verbatum(fw, " Enabled: 0x%2.2" PRIx8, exception->enabled);
> + fwts_log_info_verbatum(fw, " Number of Records: 0x%8.8" PRIx32, exception->number_of_records_to_preallocate);
> + fwts_log_info_verbatum(fw, " Max Sections Per Record: 0x%8.8" PRIx32, exception->max_sections_per_record);
> + fwts_log_info_verbatum(fw, " Global Capability Data: 0x%16.16" PRIx64, exception->global_capability_init_data);
> + fwts_log_info_verbatum(fw, " Global Control Data: 0x%16.16" PRIx64, exception->global_control_init_data);
> + fwts_log_info_verbatum(fw, " Number of Hardware Banks: 0x%8.8" PRIx32, exception->number_of_hardware_banks);
> + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, exception->reserved2[0]);
> + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, exception->reserved2[1]);
> + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, exception->reserved2[2]);
> + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, exception->reserved2[3]);
> + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, exception->reserved2[4]);
> + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, exception->reserved2[5]);
> + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, exception->reserved2[6]);
> + fwts_log_nl(fw);
> +
> + for (i = 0; i < exception->number_of_hardware_banks; i++) {
> + fwts_acpi_table_hest_machine_check_bank *bank = &exception->bank[i];
> +
> + fwts_log_info_verbatum(fw, " HEST IA-32 Architecture Machine Check Exception Bank %zd", i);
> + fwts_log_info_verbatum(fw, " Bank Number: 0x%2.2" PRIx8, bank->bank_number);
> + fwts_log_info_verbatum(fw, " Clear Status On Init.: 0x%2.2" PRIx8, bank->clear_status_on_initialization);
> + fwts_log_info_verbatum(fw, " Status Data Format: 0x%2.2" PRIx8, bank->status_data_format);
> + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, bank->reserved);
> + fwts_log_info_verbatum(fw, " Control Reg. MSR Addr: 0x%8.8" PRIx32, bank->control_register_msr_address);
> + fwts_log_info_verbatum(fw, " Control Init Data: 0x%16.16" PRIx64, bank->control_init_data);
> + fwts_log_info_verbatum(fw, " Status Reg. MSR Addr: 0x%8.8" PRIx32, bank->status_register_msr_address);
> + fwts_log_info_verbatum(fw, " Addr Reg. MSR Addr: 0x%8.8" PRIx32, bank->address_register_msr_address);
> + fwts_log_info_verbatum(fw, " Misc Reg. MSR Addr: 0x%8.8" PRIx32, bank->misc_register_msr_address);
> + fwts_log_nl(fw);
> +
> + if (bank->clear_status_on_initialization > 1) {
> + *passed = false;
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTIA32InvalidClearStatusOnInit",
> + "HEST Machine Check Exception Bank Clear Status On Initialization "
> + "has value 0x%" PRIx8 " and only valid values are "
> + "0x00 (Clear) or 0x01 (Don't Clear)",
> + bank->clear_status_on_initialization);
> + }
> + if (bank->status_data_format > 2) {
> + *passed = false;
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTIA32InvalidBankStatusDataFormat",
> + "HEST Machine Check Exception Bank Status Data Format "
> + "has value 0x%" PRIx8 " and only valid values are "
> + "0x00 (IA-32 MCA), 0x01 (Intel 64 MCA) or "
> + "0x02 (AMD64 MCA).",
> + bank->status_data_format);
> + }
> + }
> +
> + *length -= total_size;
> + *data += total_size;
> +}
> +
> +/*
> + * ACPI Section 18.3.2.2 IA-32 Architecture Corrected Machine Check
> + */
> +static void hest_check_ia32_arch_corrected_machine_check(
> + fwts_framework *fw,
> + ssize_t *length,
> + uint8_t **data,
> + bool *passed)
> +{
> + ssize_t i, total_size;
> +
> + fwts_acpi_table_hest_ia32_corrected_machine_check *check =
> + (fwts_acpi_table_hest_ia32_corrected_machine_check *)*data;
> +
> + if (*length < (ssize_t)sizeof(fwts_acpi_table_hest_ia32_corrected_machine_check)) {
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTIA32CorrectedMachineCheckTooShort",
> + "HEST IA-32 Architecture Corrected Machine Check "
> + "too short, expecting %zu bytes, "
> + "instead got %zu bytes",
> + sizeof(fwts_acpi_table_hest_ia32_corrected_machine_check), *length);
> + *passed = false;
> + *length = 0; /* Forces an early abort */
> + return;
> + }
> +
> + total_size = sizeof(fwts_acpi_table_hest_ia32_corrected_machine_check) +
> + (check->number_of_hardware_banks *
> + sizeof(fwts_acpi_table_hest_machine_check_bank));
> +
> + if (*length < total_size) {
> + *passed = false;
> + *length = 0; /* Forces an early abort */
> + return;
> + }
> +
> + fwts_log_info_verbatum(fw, "HEST IA-32 Architecture Machine Check:");
> + fwts_log_info_verbatum(fw, " Type: 0x%2.2" PRIx8, check->type);
> + fwts_log_info_verbatum(fw, " Source ID: 0x%4.4" PRIx16, check->source_id);
> + fwts_log_info_verbatum(fw, " Reserved: 0x%4.4" PRIx16, check->reserved1);
> + fwts_log_info_verbatum(fw, " Flags: 0x%2.2" PRIx8, check->flags);
> + fwts_log_info_verbatum(fw, " Enabled: 0x%2.2" PRIx8, check->enabled);
> + fwts_log_info_verbatum(fw, " Number of Records: 0x%8.8" PRIx32, check->number_of_records_to_preallocate);
> + fwts_log_info_verbatum(fw, " Max Sections Per Record: 0x%8.8" PRIx32, check->max_sections_per_record);
> + fwts_log_info_verbatum(fw, " Hardware Error Notification:");
> + fwts_log_info_verbatum(fw, " Type: 0x%2.2" PRIx8, check->notification.type);
> + fwts_log_info_verbatum(fw, " Length: 0x%2.2" PRIx8, check->notification.length);
> + fwts_log_info_verbatum(fw, " Config. Write. Enable: 0x%4.4" PRIx16,
> + check->notification.configuration_write_enable);
> + fwts_log_info_verbatum(fw, " Poll Interval: 0x%4.4" PRIx16,
> + check->notification.poll_interval);
> + fwts_log_info_verbatum(fw, " Interrupt Vector: 0x%4.4" PRIx16,
> + check->notification.vector);
> + fwts_log_info_verbatum(fw, " Sw. to Polling Value: 0x%4.4" PRIx16,
> + check->notification.switch_to_polling_threshold_value);
> + fwts_log_info_verbatum(fw, " Sw. to Polling Window: 0x%4.4" PRIx16,
> + check->notification.switch_to_polling_threshold_window);
> + fwts_log_info_verbatum(fw, " Error: Thresh. Value: 0x%4.4" PRIx16,
> + check->notification.error_threshold_value);
> + fwts_log_info_verbatum(fw, " Error: Thresh. Window: 0x%4.4" PRIx16,
> + check->notification.error_threshold_window);
> + fwts_log_info_verbatum(fw, " Number of Hardware Banks: 0x%8.8" PRIx32, check->number_of_hardware_banks);
> + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, check->reserved2[0]);
> + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, check->reserved2[1]);
> + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, check->reserved2[2]);
> + fwts_log_nl(fw);
> +
> + for (i = 0; i < check->number_of_hardware_banks; i++) {
> + fwts_acpi_table_hest_machine_check_bank *bank = &check->bank[i];
> +
> + fwts_log_info_verbatum(fw, " HEST IA-32 Architecture Machine Check Bank %zd", i);
> + fwts_log_info_verbatum(fw, " Bank Number: 0x%2.2" PRIx8, bank->bank_number);
> + fwts_log_info_verbatum(fw, " Clear Status On Init.: 0x%2.2" PRIx8, bank->clear_status_on_initialization);
> + fwts_log_info_verbatum(fw, " Status Data Format: 0x%2.2" PRIx8, bank->status_data_format);
> + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, bank->reserved);
> + fwts_log_info_verbatum(fw, " Control Reg. MSR Addr: 0x%8.8" PRIx32, bank->control_register_msr_address);
> + fwts_log_info_verbatum(fw, " Control Init Data: 0x%16.16" PRIx64, bank->control_init_data);
> + fwts_log_info_verbatum(fw, " Status Reg. MSR Addr: 0x%8.8" PRIx32, bank->status_register_msr_address);
> + fwts_log_info_verbatum(fw, " Addr Reg. MSR Addr: 0x%8.8" PRIx32, bank->address_register_msr_address);
> + fwts_log_info_verbatum(fw, " Misc Reg. MSR Addr: 0x%8.8" PRIx32, bank->misc_register_msr_address);
> + fwts_log_nl(fw);
> +
> + if (bank->clear_status_on_initialization > 1) {
> + *passed = false;
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTIA32InvalidClearStatusOnInit",
> + "HEST IA-32 Architecture Machine Check Bank Clear Status On Initialization "
> + "has value 0x%" PRIx8 " and only valid values are "
> + "0x00 (Clear) or 0x01 (Don't Clear)",
> + bank->clear_status_on_initialization);
> + }
> + if (bank->status_data_format > 2) {
> + *passed = false;
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTIA32InvalidBankStatusDataFormat",
> + "HEST IA-32 Architecture Machine Check Bank Status Data Format "
> + "has value 0x%" PRIx8 " and only valid values are "
> + "0x00 (IA-32 MCA), 0x01 (Intel 64 MCA) or "
> + "0x02 (AMD64 MCA).",
> + bank->status_data_format);
> + }
> + }
> +
> + *length -= total_size;
> + *data += total_size;
> +}
> +
> +/*
> + * ACPI Section 18.3.2.2.1, IA-32 Architecture Non-Maskable Interrupt
> + * - note, this should be a higher section number, the ACPI 6.0
> + * specification seems to have numbered this incorrectly.
> + */
> +static void hest_check_fwts_acpi_table_hest_nmi_error(
> + fwts_framework *fw,
> + ssize_t *length,
> + uint8_t **data,
> + bool *passed)
> +{
> + fwts_acpi_table_hest_nmi_error *err =
> + (fwts_acpi_table_hest_nmi_error *)*data;
> +
> + if (*length < (ssize_t)sizeof(fwts_acpi_table_hest_nmi_error)) {
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTIA-32ArchitectureNmiTooShort",
> + "HEST IA-32 Architecture Non-Mastable Interrupt "
> + "too short, expecting %zu bytes, "
> + "instead got %zu bytes",
> + sizeof(fwts_acpi_table_hest_nmi_error), *length);
> + *passed = false;
> + *length = 0; /* Forces an early abort */
> + return;
> + }
> +
> + fwts_log_info_verbatum(fw, "HEST IA-32 Architecture Non-Maskable Interrupt:");
> + fwts_log_info_verbatum(fw, " Type: 0x%2.2" PRIx8, err->type);
> + fwts_log_info_verbatum(fw, " Source ID: 0x%4.4" PRIx16, err->source_id);
> + fwts_log_info_verbatum(fw, " Reserved: 0x%4.4" PRIx16, err->reserved1);
> + fwts_log_info_verbatum(fw, " Number of Records: 0x%8.8" PRIx32, err->number_of_records_to_preallocate);
> + fwts_log_info_verbatum(fw, " Max Sections Per Record: 0x%8.8" PRIx32, err->max_sections_per_record);
> + fwts_log_info_verbatum(fw, " Max Raw Data Length: 0x%8.8" PRIx32, err->max_raw_data_length);
> + fwts_log_nl(fw);
> +
> + if (err->reserved1) {
> + *passed = false;
> + fwts_failed(fw, LOG_LEVEL_LOW,
> + "HESTInvalidRecordsToPreallocate",
> + "HEST IA-32 Architecture NMI Reserved field "
> + "at offset 4 must be zero, instead got 0x%" PRIx16,
> + err->reserved1);
> + }
> + if (err->number_of_records_to_preallocate < 1) {
> + *passed = false;
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTInvalidRecordsToPreallocate",
> + "HEST IA-32 Architecture NMI Number of Records "
> + "to Preallocate is 0x%" PRIx16 " and must be "
> + "more than zero.",
> + err->number_of_records_to_preallocate);
> + }
> + if (err->max_sections_per_record < 1) {
> + *passed = false;
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTInvalidMaxSectionsPerRecord",
> + "HEST A-32 Architecture NMI Max Sections Per "
> + "Record is 0x%" PRIx16 " and must be "
> + "more than zero.",
> + err->max_sections_per_record);
> + }
> +
> + *length -= sizeof(fwts_acpi_table_hest_nmi_error);
> + *data += sizeof(fwts_acpi_table_hest_nmi_error);
> +}
> +
> +/*
> + * ACPI Section 18.3.2.3 PCI Express Root Port AER Structure
> + */
> +static void hest_check_pci_express_root_port_aer(
> + fwts_framework *fw,
> + ssize_t *length,
> + uint8_t **data,
> + bool *passed)
> +{
> + fwts_acpi_table_hest_pci_express_root_port_aer *aer =
> + (fwts_acpi_table_hest_pci_express_root_port_aer *)*data;
> +
> + if (*length < (ssize_t)sizeof(fwts_acpi_table_hest_pci_express_root_port_aer)) {
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTPciExpressRootPortAerTooShort",
> + "HEST PCI Express Root Port AER "
> + "too short, expecting %zu bytes, "
> + "instead got %zu bytes",
> + sizeof(fwts_acpi_table_hest_pci_express_root_port_aer), *length);
> + *passed = false;
> + *length = 0; /* Forces an early abort */
> + return;
> + }
> +
> + fwts_log_info_verbatum(fw, "HEST PCI Express Root Port AER:");
> + fwts_log_info_verbatum(fw, " Type: 0x%2.2" PRIx8, aer->type);
> + fwts_log_info_verbatum(fw, " Source ID: 0x%4.4" PRIx16, aer->source_id);
> + fwts_log_info_verbatum(fw, " Reserved: 0x%4.4" PRIx16, aer->reserved1);
> + fwts_log_info_verbatum(fw, " Flags: 0x%2.2" PRIx8, aer->flags);
> + fwts_log_info_verbatum(fw, " Enabled: 0x%2.2" PRIx8, aer->enabled);
> + fwts_log_info_verbatum(fw, " Number of Records: 0x%8.8" PRIx32, aer->number_of_records_to_preallocate);
> + fwts_log_info_verbatum(fw, " Max Sections Per Record: 0x%8.8" PRIx32, aer->max_sections_per_record);
> + fwts_log_info_verbatum(fw, " Bus: 0x%8.8" PRIx32, aer->bus);
> + fwts_log_info_verbatum(fw, " Device: 0x%4.4" PRIx16, aer->device);
> + fwts_log_info_verbatum(fw, " Function: 0x%4.4" PRIx16, aer->function);
> + fwts_log_info_verbatum(fw, " Device Control: 0x%4.4" PRIx16, aer->device_control);
> + fwts_log_info_verbatum(fw, " Reserved: 0x%4.4" PRIx16, aer->reserved2);
> + fwts_log_info_verbatum(fw, " Uncorrectable Mask: 0x%8.8" PRIx32, aer->uncorrectable_error_mask);
> + fwts_log_info_verbatum(fw, " Uncorrectable Severity: 0x%8.8" PRIx32, aer->uncorrectable_error_severity);
> + fwts_log_info_verbatum(fw, " Correctable Error Mask: 0x%8.8" PRIx32, aer->correctable_error_mask);
> + fwts_log_info_verbatum(fw, " Advanced Capabilities: 0x%8.8" PRIx32, aer->advanced_error_capabilities_and_control);
> + fwts_log_info_verbatum(fw, " Root Error Command: 0x%8.8" PRIx32, aer->root_error_command);
> + fwts_log_nl(fw);
> +
> + if (aer->flags & ~0x3) {
> + *passed = false;
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "HESTPciExpressRootPortFlagsReserved",
> + "HEST PCI Express Root Port Flags Reserved bits "
> + "[2:7] must be zero, instead got 0x%" PRIx8,
> + aer->flags);
> + }
> + if (aer->reserved2) {
> + *passed = false;
> + fwts_failed(fw, LOG_LEVEL_LOW,
> + "HESTPciExpressRootPortReservedNonZero",
> + "HEST PCI Express Root Port Reserved field "
> + "at offset 26 must be zero, instead got 0x%" PRIx16,
> + aer->reserved2);
> + }
> + if (aer->number_of_records_to_preallocate < 1) {
> + *passed = false;
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTInvalidRecordsToPreallocate",
> + "HEST PCI Express Root Port Number of Records "
> + "to Preallocate is 0x%" PRIx16 " and must be "
> + "more than zero.",
> + aer->number_of_records_to_preallocate);
> + }
> + if (aer->max_sections_per_record < 1) {
> + *passed = false;
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTInvalidMaxSectionsPerRecord",
> + "HEST PCI Express Root Port Max Sections Per "
> + "Record is 0x%" PRIx16 " and must be "
> + "more than zero.",
> + aer->max_sections_per_record);
> + }
> + *length -= sizeof(fwts_acpi_table_hest_pci_express_root_port_aer);
> + *data += sizeof(fwts_acpi_table_hest_pci_express_root_port_aer);
> +}
> +
> +/*
> + * ACPI Section 18.3.2.4 PCI Express Device AER Structure
> + */
> +static void hest_check_pci_express_device_aer(
> + fwts_framework *fw,
> + ssize_t *length,
> + uint8_t **data,
> + bool *passed)
> +{
> + fwts_acpi_table_hest_pci_express_device_aer *aer =
> + (fwts_acpi_table_hest_pci_express_device_aer *)*data;
> +
> + if (*length < (ssize_t)sizeof(fwts_acpi_table_hest_pci_express_device_aer)) {
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTPciExpressDeviceAerTooShort",
> + "HEST PCI Express Device AER "
> + "too short, expecting %zu bytes, "
> + "instead got %zu bytes",
> + sizeof(fwts_acpi_table_hest_pci_express_device_aer), *length);
> + *passed = false;
> + *length = 0; /* Forces an early abort */
> + return;
> + }
> +
> + fwts_log_info_verbatum(fw, "HEST PCI Express Device AER:");
> + fwts_log_info_verbatum(fw, " Type: 0x%2.2" PRIx8, aer->type);
> + fwts_log_info_verbatum(fw, " Source ID: 0x%4.4" PRIx16, aer->source_id);
> + fwts_log_info_verbatum(fw, " Reserved: 0x%4.4" PRIx16, aer->reserved1);
> + fwts_log_info_verbatum(fw, " Flags: 0x%2.2" PRIx8, aer->flags);
> + fwts_log_info_verbatum(fw, " Enabled: 0x%2.2" PRIx8, aer->enabled);
> + fwts_log_info_verbatum(fw, " Number of Records: 0x%8.8" PRIx32, aer->number_of_records_to_preallocate);
> + fwts_log_info_verbatum(fw, " Max Sections Per Record: 0x%8.8" PRIx32, aer->max_sections_per_record);
> + fwts_log_info_verbatum(fw, " Bus: 0x%8.8" PRIx32, aer->bus);
> + fwts_log_info_verbatum(fw, " Device: 0x%4.4" PRIx16, aer->device);
> + fwts_log_info_verbatum(fw, " Function: 0x%4.4" PRIx16, aer->function);
> + fwts_log_info_verbatum(fw, " Device Control: 0x%4.4" PRIx16, aer->device_control);
> + fwts_log_info_verbatum(fw, " Uncorrectable Mask: 0x%8.8" PRIx32, aer->uncorrectable_error_mask);
> + fwts_log_info_verbatum(fw, " Uncorrectable Severity: 0x%8.8" PRIx32, aer->uncorrectable_error_severity);
> + fwts_log_info_verbatum(fw, " Correctable Error Mask: 0x%8.8" PRIx32, aer->correctable_error_mask);
> + fwts_log_info_verbatum(fw, " Advanced Capabilities: 0x%8.8" PRIx32, aer->advanced_error_capabilities_and_control);
> + fwts_log_nl(fw);
> +
> + if (aer->flags & ~0x3) {
> + *passed = false;
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "HESTPciExpressRootPortFlagsReserved",
> + "HEST PCI Express Root Port Flags Reserved bits "
> + "[2:7] must be zero, instead got 0x%" PRIx8,
> + aer->flags);
> + }
> + if (aer->reserved2) {
> + *passed = false;
> + fwts_failed(fw, LOG_LEVEL_LOW,
> + "HESTPciExpressRootPortReservedNonZero",
> + "HEST PCI Express Root Port Reserved field "
> + "at offset 26 must be zero, instead got 0x%" PRIx16,
> + aer->reserved2);
> + }
> + if (aer->number_of_records_to_preallocate < 1) {
> + *passed = false;
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTInvalidRecordsToPreallocate",
> + "HEST PCI Express Root Port Number of Records "
> + "to Preallocate is 0x%" PRIx16 " and must be "
> + "more than zero.",
> + aer->number_of_records_to_preallocate);
> + }
> + if (aer->max_sections_per_record < 1) {
> + *passed = false;
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTInvalidMaxSectionsPerRecord",
> + "HEST PCI Express Root Port Max Sections Per "
> + "Record is 0x%" PRIx16 " and must be "
> + "more than zero.",
> + aer->max_sections_per_record);
> + }
> + *length -= sizeof(fwts_acpi_table_hest_pci_express_device_aer);
> + *data += sizeof(fwts_acpi_table_hest_pci_express_device_aer);
> +}
> +
> +/*
> + * ACPI Section 18.3.2.5 PCI Express/PCI-X Bridge AER Structure
> + */
> +static void hest_heck_pci_express_bridge_aer(
> + fwts_framework *fw,
> + ssize_t *length,
> + uint8_t **data,
> + bool *passed)
> +{
> + fwts_acpi_table_hest_pci_express_bridge_aer *aer =
> + (fwts_acpi_table_hest_pci_express_bridge_aer *)*data;
> +
> + if (*length < (ssize_t)sizeof(fwts_acpi_table_hest_pci_express_bridge_aer)) {
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTPciExpressBridgeAerTooShort",
> + "HEST PCI Express Bridge AER "
> + "too short, expecting %zu bytes, "
> + "instead got %zu bytes",
> + sizeof(fwts_acpi_table_hest_pci_express_bridge_aer), *length);
> + *passed = false;
> + *length = 0; /* Forces an early abort */
> + return;
> + }
> +
> + fwts_log_info_verbatum(fw, "HEST PCI Express Bridge AER:");
> + fwts_log_info_verbatum(fw, " Type: 0x%2.2" PRIx8, aer->type);
> + fwts_log_info_verbatum(fw, " Source ID: 0x%4.4" PRIx16, aer->source_id);
> + fwts_log_info_verbatum(fw, " Reserved: 0x%4.4" PRIx16, aer->reserved1);
> + fwts_log_info_verbatum(fw, " Flags: 0x%2.2" PRIx8, aer->flags);
> + fwts_log_info_verbatum(fw, " Enabled: 0x%2.2" PRIx8, aer->enabled);
> + fwts_log_info_verbatum(fw, " Number of Records: 0x%8.8" PRIx32, aer->number_of_records_to_preallocate);
> + fwts_log_info_verbatum(fw, " Max Sections Per Record: 0x%8.8" PRIx32, aer->max_sections_per_record);
> + fwts_log_info_verbatum(fw, " Bus: 0x%8.8" PRIx32, aer->bus);
> + fwts_log_info_verbatum(fw, " Device: 0x%4.4" PRIx16, aer->device);
> + fwts_log_info_verbatum(fw, " Function: 0x%4.4" PRIx16, aer->function);
> + fwts_log_info_verbatum(fw, " Device Control: 0x%4.4" PRIx16, aer->device_control);
> + fwts_log_info_verbatum(fw, " Reserved: 0x%4.4" PRIx16, aer->reserved2);
> + fwts_log_info_verbatum(fw, " Uncorrectable Mask: 0x%8.8" PRIx32, aer->uncorrectable_error_mask);
> + fwts_log_info_verbatum(fw, " Uncorrectable Severity: 0x%8.8" PRIx32, aer->uncorrectable_error_severity);
> + fwts_log_info_verbatum(fw, " Correctable Mask: 0x%8.8" PRIx32, aer->correctable_error_mask);
> + fwts_log_info_verbatum(fw, " Advanced Capabilities: 0x%8.8" PRIx32, aer->advanced_error_capabilities_and_control);
> + fwts_log_info_verbatum(fw, " 2nd Uncorrectable Mask: 0x%8.8" PRIx32, aer->secondary_uncorrectable_error_mask);
> + fwts_log_info_verbatum(fw, " 2nd Uncurrectable Svrity: 0x%8.8" PRIx32, aer->secondary_uncorrectable_error_severity);
> + fwts_log_info_verbatum(fw, " 2nd Advanced Capabilities:0x%8.8" PRIx32, aer->secondary_advanced_error_capabilities_and_control);
> + fwts_log_nl(fw);
> +
> + if (aer->flags & ~0x3) {
> + *passed = false;
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "HESTPciExpressBridgeFlagsReserved",
> + "HEST PCI Express Bridge Flags Reserved bits "
> + "[2:7] must be zero, instead got 0x%" PRIx8,
> + aer->flags);
> + }
> + if (aer->reserved2) {
> + *passed = false;
> + fwts_failed(fw, LOG_LEVEL_LOW,
> + "HESTPciExpressBridgeReservedNonZero",
> + "HEST PCI Express Bridge Reserved field "
> + "at offset 26 must be zero, instead got 0x%" PRIx16,
> + aer->reserved2);
> + }
> + if (aer->number_of_records_to_preallocate < 1) {
> + *passed = false;
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTInvalidRecordsToPreallocate",
> + "HEST PCI Express Bridge Number of Records "
> + "to Preallocate is 0x%" PRIx16 " and must be "
> + "more than zero.",
> + aer->number_of_records_to_preallocate);
> + }
> + if (aer->max_sections_per_record < 1) {
> + *passed = false;
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTInvalidMaxSectionsPerRecord",
> + "HEST PCI Express Brdige Max Sections Per "
> + "Record is 0x%" PRIx16 " and must be "
> + "more than zero.",
> + aer->max_sections_per_record);
> + }
> + *length -= sizeof(fwts_acpi_table_hest_pci_express_bridge_aer);
> + *data += sizeof(fwts_acpi_table_hest_pci_express_bridge_aer);
> +}
> +
> +
> +/*
> + * ACPI Section 18.3.2.6 Generic Error Source
> + */
> +static void hest_check_generic_error_source(
> + fwts_framework *fw,
> + ssize_t *length,
> + uint8_t **data,
> + bool *passed)
> +{
> + fwts_acpi_table_hest_generic_hardware_error_source *source =
> + (fwts_acpi_table_hest_generic_hardware_error_source *)*data;
> +
> + /* Enough data for an empty machine check exceptions stucture? */
> + if (*length < (ssize_t)sizeof(fwts_acpi_table_hest_generic_hardware_error_source)) {
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTGenericHardwareErrorSourceTooShort",
> + "HEST Generic Hardware Error Source Too Short "
> + "too short, expecting %zu bytes, "
> + "instead got %zu bytes",
> + sizeof(fwts_acpi_table_hest_generic_hardware_error_source), *length);
> + *passed = false;
> + *length = 0; /* Forces an early abort */
> + return;
> + }
> +
> + fwts_log_info_verbatum(fw, "HEST Generic Hardware Error Source");
> + fwts_log_info_verbatum(fw, " Type: 0x%2.2" PRIx8, source->type);
> + fwts_log_info_verbatum(fw, " Source ID: 0x%4.4" PRIx16, source->source_id);
> + fwts_log_info_verbatum(fw, " Related Source ID: 0x%4.4" PRIx16, source->related_source_id);
> + fwts_log_info_verbatum(fw, " Flags: 0x%2.2" PRIx8, source->flags);
> + fwts_log_info_verbatum(fw, " Enabled: 0x%2.2" PRIx8, source->enabled);
> + fwts_log_info_verbatum(fw, " Num. Records. Prealloc.: 0x%8.8" PRIx32, source->number_of_records_to_preallocate);
> + fwts_log_info_verbatum(fw, " Max. Sections Per Rec.: 0x%8.8" PRIx32, source->max_sections_per_record);
> + fwts_log_info_verbatum(fw, " Max. Raw Data Length: 0x%8.8" PRIx32, source->max_raw_data_length);
> +
> + fwts_log_info_verbatum(fw, " Error Status Address:");
> + fwts_log_info_verbatum(fw, " Address Space ID: 0x%2.2" PRIx8,
> + source->error_status_address.address_space_id);
> + fwts_log_info_verbatum(fw, " Register Bit Width 0x%2.2" PRIx8,
> + source->error_status_address.register_bit_width);
> + fwts_log_info_verbatum(fw, " Register Bit Offset 0x%2.2" PRIx8,
> + source->error_status_address.register_bit_offset);
> + fwts_log_info_verbatum(fw, " Access Size 0x%2.2" PRIx8,
> + source->error_status_address.access_width);
> + fwts_log_info_verbatum(fw, " Address 0x%16.16" PRIx64,
> + source->error_status_address.address);
> + fwts_log_info_verbatum(fw, " Hardware Error Notification:");
> + fwts_log_info_verbatum(fw, " Type: 0x%2.2" PRIx8, source->notification.type);
> + fwts_log_info_verbatum(fw, " Length: 0x%2.2" PRIx8, source->notification.length);
> + fwts_log_info_verbatum(fw, " Config. Write. Enable: 0x%4.4" PRIx16,
> + source->notification.configuration_write_enable);
> + fwts_log_info_verbatum(fw, " Poll Interval: 0x%4.4" PRIx16,
> + source->notification.poll_interval);
> + fwts_log_info_verbatum(fw, " Interrupt Vector: 0x%4.4" PRIx16,
> + source->notification.vector);
> + fwts_log_info_verbatum(fw, " Sw. to Polling Value: 0x%4.4" PRIx16,
> + source->notification.switch_to_polling_threshold_value);
> + fwts_log_info_verbatum(fw, " Sw. to Polling Window: 0x%4.4" PRIx16,
> + source->notification.switch_to_polling_threshold_window);
> + fwts_log_info_verbatum(fw, " Error: Thresh. Value: 0x%4.4" PRIx16,
> + source->notification.error_threshold_value);
> + fwts_log_info_verbatum(fw, " Error: Thresh. Window: 0x%4.4" PRIx16,
> + source->notification.error_threshold_window);
> + fwts_log_info_verbatum(fw, " Error Status Blk. Length: 0x%8.8" PRIx32, source->error_status_block_length);
> + fwts_log_nl(fw);
> +
> + if (source->number_of_records_to_preallocate < 1) {
> + *passed = false;
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTInvalidRecordsToPreallocate",
> + "HEST Hardware Error Source Number of Records "
> + "to Preallocate is 0x%" PRIx16 " and must be "
> + "more than zero.",
> + source->number_of_records_to_preallocate);
> + }
> + if (source->max_sections_per_record < 1) {
> + *passed = false;
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTInvalidMaxSectionsPerRecord",
> + "HEST Hardware Error Source Max Sections Per "
> + "Record is 0x%" PRIx16 " and must be "
> + "more than zero.",
> + source->max_sections_per_record);
> + }
> + if (source->notification.type > 7) {
> + *passed = false;
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTInvalidHardwareErrorNotificationType",
> + "HEST Hardware Error Notification Type is "
> + "an invalid reserved value of 0x%2.2" PRIx8 ","
> + "expecting value 0x00 to 0x07",
> + source->notification.type);
> + }
> + if (source->notification.configuration_write_enable & ~0x3f) {
> + *passed = false;
> + fwts_failed(fw, LOG_LEVEL_LOW,
> + "HESTIA32ConfigWriteEnabledReservedNonZero",
> + "HEST Configuration Write Enabled Reserved bits [6:31] "
> + "are non-zero.");
> + }
> +
> + *length -= sizeof(fwts_acpi_table_hest_generic_hardware_error_source);
> + *data += sizeof(fwts_acpi_table_hest_generic_hardware_error_source);
> +}
> +
> +/*
> + * ACPI Section 18.3.2.8
> + */
> +
> +/*
> + * HEST Hardware Error Source Table test
> + * ACPI section 18.3.2 "ACPI Error Source"
> + */
> +static int hest_test1(fwts_framework *fw)
> +{
> + bool passed = true;
> + fwts_acpi_table_hest *hest = (fwts_acpi_table_hest *)table->data;
> + uint8_t *data = (uint8_t *)table->data;
> + ssize_t length = (ssize_t)hest->header.length;
> + uint32_t hest_type_00_count = 0,
> + hest_type_01_count = 0,
> + hest_type_02_count = 0;
> +
> + if (table->length < sizeof(fwts_acpi_table_hest)) {
> + passed = false;
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTTooShort",
> + "HEST table too short, expecting %zu bytes, "
> + "instead got %zu bytes",
> + sizeof(fwts_acpi_table_hest), table->length);
> + goto done;
> + }
> +
> + fwts_log_info_verbatum(fw, "HEST Hardware Error Source Table test");
> + fwts_log_info_verbatum(fw, " Error Source Count: 0x%2.2" PRIx8, hest->error_source_count);
> + fwts_log_nl(fw);
> +
> + data += sizeof(fwts_acpi_table_hest);
> + length -= sizeof(fwts_acpi_table_hest);
> +
> + while (length > 0) {
> + uint16_t *type = (uint16_t *)data;
> +
> + switch (*type) {
> + case 0x00:
> + hest_check_ia32_arch_machine_check_exception(fw, &length, &data, &passed);
> + hest_type_00_count++;
> + break;
> + case 0x01:
> + hest_check_ia32_arch_corrected_machine_check(fw, &length, &data, &passed);
> + hest_type_01_count++;
> + break;
> + case 0x02:
> + hest_check_fwts_acpi_table_hest_nmi_error(fw, &length, &data, &passed);
> + hest_type_02_count++;
> + break;
> + case 0x06:
> + hest_check_pci_express_root_port_aer(fw, &length, &data, &passed);
> + break;
> + case 0x07:
> + hest_check_pci_express_device_aer(fw, &length, &data, &passed);
> + break;
> + case 0x08:
> + hest_heck_pci_express_bridge_aer(fw, &length, &data, &passed);
> + break;
> + case 0x09:
> + hest_check_generic_error_source(fw, &length, &data, &passed);
> + break;
> + default:
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTInvalidType",
> + "HEST Type 0x%4.4" PRIx16 " is invalid, aborting check",
> + *type);
> + passed = false;
> + length = 0;
> + break;
> + }
> + }
> + if (hest_type_00_count > 1) {
> + passed = false;
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTTooManyIA32ArchMachineCheckExceptions",
> + "HEST Contained %" PRIu32 " IA32 Architecture "
> + "Machine Check Exception Entries, maximum allowed "
> + "per HEST is just 1.",
> + hest_type_00_count);
> + }
> + if (hest_type_01_count > 1) {
> + passed = false;
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTTooManyIA32CorrectedMachineChecks",
> + "HEST Contained %" PRIu32 " IA32 Architecture "
> + "Corrected Machine Check Exception Entries, maximum allowed "
> + "per HEST is just 1.",
> + hest_type_01_count);
> + }
> + if (hest_type_02_count > 1) {
> + passed = false;
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "HESTTooManyNmiErrors",
> + "HEST Contained %" PRIu32 " NMI Error Entries, "
> + "maximum allowed per HEST is just 1.",
> + hest_type_02_count);
> + }
> +
> + if (passed)
> + fwts_passed(fw, "No issues found in HEST table.");
> +
> +done:
> + return FWTS_OK;
> +}
> +
> +static fwts_framework_minor_test hest_tests[] = {
> + { hest_test1, "HEST Hardware Error Source Table test." },
> + { NULL, NULL }
> +};
> +
> +static fwts_framework_ops hest_ops = {
> + .description = "HEST Hardware Error Source Table test.",
> + .init = hest_init,
> + .minor_tests = hest_tests
> +};
> +
> +FWTS_REGISTER("hest", &hest_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_BATCH | FWTS_FLAG_ROOT_PRIV | FWTS_FLAG_TEST_ACPI)
Acked-by: Ivan Hu<ivan.hu at canonical.com>
More information about the fwts-devel
mailing list