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