Patchwork acpi: acpiinfo: Complete reworking to bring it up to date.

login
register
mail settings
Submitter Colin King
Date Dec. 3, 2012, 9:43 p.m.
Message ID <1354571006-22365-1-git-send-email-colin.king@canonical.com>
Download mbox | patch
Permalink /patch/203446/
State Accepted
Headers show

Comments

Colin King - Dec. 3, 2012, 9:43 p.m.
From: Colin Ian King <colin.king@canonical.com>

The apciinfo test is a legacy test originally derived from the
Linux firmware developer kit and had a lot of hard-coded kernel
log checks that are now either out of data or nor used.  I've now
moved these kernel log checks into the fwts klog table because it
makes more sense for them to be scanned by the klog tests.  I have
also added the recent kernel versions of these kernel log messages
to keep it in sync with the upstream code.

I was thinking of removing this test, but the acpiinfo name lends
itself to dumping out some ACPI specific information that is useful
to know.  So I've re-written the test to determine the ACPI version
supported by the kernel ACPI driver, the ACPI version in the
machine's firmware and I've completely re-worked the original code
to also determine the version of the ACPI compiler used to generate
the DSDT and SSDT AML.

Signed-off-by: Colin Ian King <colin.king@canonical.com>
---
 data/klog.json               | 104 +++++++++++++++++
 src/acpi/acpiinfo/acpiinfo.c | 268 ++++++++++++++-----------------------------
 2 files changed, 187 insertions(+), 185 deletions(-)
Keng-Yu Lin - Dec. 6, 2012, 7:44 a.m.
On Tue, Dec 4, 2012 at 5:43 AM, Colin King <colin.king@canonical.com> wrote:
> From: Colin Ian King <colin.king@canonical.com>
>
> The apciinfo test is a legacy test originally derived from the
> Linux firmware developer kit and had a lot of hard-coded kernel
> log checks that are now either out of data or nor used.  I've now
> moved these kernel log checks into the fwts klog table because it
> makes more sense for them to be scanned by the klog tests.  I have
> also added the recent kernel versions of these kernel log messages
> to keep it in sync with the upstream code.
>
> I was thinking of removing this test, but the acpiinfo name lends
> itself to dumping out some ACPI specific information that is useful
> to know.  So I've re-written the test to determine the ACPI version
> supported by the kernel ACPI driver, the ACPI version in the
> machine's firmware and I've completely re-worked the original code
> to also determine the version of the ACPI compiler used to generate
> the DSDT and SSDT AML.
>
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
> ---
>  data/klog.json               | 104 +++++++++++++++++
>  src/acpi/acpiinfo/acpiinfo.c | 268 ++++++++++++++-----------------------------
>  2 files changed, 187 insertions(+), 185 deletions(-)
>
> diff --git a/data/klog.json b/data/klog.json
> index 9084fac..c2cc858 100644
> --- a/data/klog.json
> +++ b/data/klog.json
> @@ -77,6 +77,110 @@
>   "firmware_error_warning_patterns":
>   [
>    {
> +   "compare_mode": "regex",
> +   "log_level": "LOG_LEVEL_MEDIUM",
> +   "tag": "FWTS_TAG_BIOS",
> +   "pattern": "device .* has invalid IRQ.*check vendor BIOS",
> +   "advice": "An error occurred probing the PCI-Express port devices. The device has a valid pin but did not have an a valid IRQ.  This is normally due to a misconfiguration in the firmware.",
> +   "label": "KlogBiosIrqInvalid"
> +  },
> +  {
> +   "compare_mode": "regex",
> +   "log_level": "LOG_LEVEL_CRITCAL",
> +   "tag": "FWTS_TAG_ACPI",
> +   "pattern": "Invalid active.* threshold",
> +   "advice": "The ACPI thermal driver has attempted to evaluate an ACPI active threshold control _ALx and this failed to evaluate.  This is normally due to broken or buggy _ALx control. This may lead to sub-optimal thermal control.",
> +   "label": "KlogAcpiAlThresholdInvalid"
> +  },
> +  {
> +   "compare_mode": "string",
> +   "log_level": "LOG_LEVEL_HIGH",
> +   "tag": "FWTS_TAG_CPU",
> +   "pattern": "No sibling found for CPU",
> +   "advice": "Hyperthreading CPU enumeration failed, hyperthreads will be disabled.",
> +   "label": "KlogCpuNoSiblingFound"
> +  },
> +  {
> +   "compare_mode": "string",
> +   "log_level": "LOG_LEVEL_HIGH",
> +   "tag": "FWTS_TAG_BIOS",
> +   "pattern": "OHCI: BIOS handoff failed",
> +   "advice": "An OHCI BIOS handoff failure generally means that the OHCI driver was unable to take control of the USB controller away from the BIOS. Disabling USB legacy mode in the BIOS may help.",
> +   "label": "KlogBiosOhciEmulation"
> +  },
> +  {
> +   "compare_mode": "string",
> +   "log_level": "LOG_LEVEL_HIGH",
> +   "tag": "FWTS_TAG_BIOS",
> +   "pattern": "EHCI: BIOS handoff failed",
> +   "advice": "An EHCI BIOS handoff failure generally means that the EHCI driver was unable to take control of the USB controller away from the BIOS. Disabling USB legacy mode in the BIOS may help.",
> +   "label": "KlogBiosEhciEmulation"
> +  },
> +  {
> +   "compare_mode": "string",
> +   "log_level": "LOG_LEVEL_HIGH",
> +   "tag": "FWTS_TAG_BIOS",
> +   "pattern": "xHCI BIOS handoff failed",
> +   "advice": "An xHCI BIOS handoff failure generally means that the xHCI driver was unable to take control of the USB controller away from the BIOS. Disabling USB legacy mode in the BIOS may help.",
> +   "label": "KlogBiosXhciEmulation"
> +  },
> +  {
> +   "compare_mode": "regex",
> +   "log_level": "LOG_LEVEL_HIGH",
> +   "tag": "FWTS_TAG_ACPI",
> +   "pattern": "MMCONFIG has no entries",
> +   "advice": "The ACPI MCFG has failed to be parsed, it has no entries in it. This is not expected and is most likely an ACPI misconfiguration. The PCI memory mapped configuration space is not known and hence PCI will be not configured.",
> +   "label": "KlogAcpiMcfgNoEntries"
> +  },
> +  {
> +   "compare_mode": "string",
> +   "log_level": "LOG_LEVEL_HIGH",
> +   "tag": "FWTS_TAG_ACPI",
> +   "pattern": "MMCONFIG not in low 4GB of memory",
> +   "advice": "An ACPI MCFG config entry is not in the lower 4GB (32 bit) address space and will be ignored.",
> +   "label": "KlogAcpiMcfgNotIn32BitMemorySpace"
> +  },
> +  {
> +   "compare_mode": "regex",
> +   "log_level": "LOG_LEVEL_HIGH",
> +   "tag": "FWTS_TAG_ACPI",
> +   "pattern": "MCFG region for .* at .* is above 4GB, ignored",
> +   "advice": "An ACPI MCFG config entry is not in the lower 4GB (32 bit) address space and will be ignored.",
> +   "label": "KlogAcpiMcfgNotin32BitMemorySpace"
> +  },
> +  {
> +   "compare_mode": "regex",
> +   "log_level": "LOG_LEVEL_HIGH",
> +   "tag": "FWTS_TAG_BIOS",
> +   "pattern": "MP-BIOS bug.*8254 timer not connected to IO-APIC",
> +   "advice": "The 8254 timer is not connected to an IO-APIC, this is invariably due to a misconfiguration in the BIOS.",
> +   "label": "KlogIoApic8254TimerNotConnected"
> +  },
> +  {
> +   "compare_mode": "string",
> +   "log_level": "LOG_LEVEL_HIGH",
> +   "tag": "FWTS_TAG_ACPI",
> +   "pattern": "disabled and referenced, BIOS bug",
> +   "advice": "A PCI interrupt link could not be enabled when the associated ACPI _STA control was executed. It will be disabled. This is normally a bug in the _STA control for this link.",
> +   "label": "KlogPciLinkDisabled"
> +  },
> +  {
> +   "compare_mode": "regex",
> +   "log_level": "LOG_LEVEL_HIGH",
> +   "tag": "FWTS_TAG_BIOS",
> +   "pattern": "Inconsistent FADT length .* and revision .* using FADT V1.0 portion of table",
> +   "advice": "The ACPI FADT was reporting to be a version 2.0 (or higher) FADT but the length was too short, so the kernel has assumed it was a version 1.0 FADT instead. The machine may have reduced ACPI 1.0 functionality.",
> +   "label": "KlogAcpiFadtInconsistentLength"
> +  },
> +  {
> +   "compare_mode": "string",
> +   "log_level": "LOG_LEVEL_CRITICAL",
> +   "tag": "FWTS_TAG_BIOS_IRQ",
> +   "pattern": "Disabling IRQ#",
> +   "advice": "The kernel had detected a spurious interrupt which is generating tens of thousands of interrupts. This can occur if the interrupt is stuck.  The kernel has taken action and disabled this interrupt.  Look at /proc/interrupts to find the devices serviced by this interrupt as these are most probably no functioning now.",
> +   "label": "KlogIrqDisabled"
> +  },
> +  {
>     "compare_mode": "string",
>     "log_level": "LOG_LEVEL_HIGH",
>     "tag": "FWTS_TAG_ACPI",
> diff --git a/src/acpi/acpiinfo/acpiinfo.c b/src/acpi/acpiinfo/acpiinfo.c
> index d6d3904..a3c9cb7 100644
> --- a/src/acpi/acpiinfo/acpiinfo.c
> +++ b/src/acpi/acpiinfo/acpiinfo.c
> @@ -1,9 +1,6 @@
>  /*
> - * Copyright (C) 2006, Intel Corporation
>   * Copyright (C) 2010-2012 Canonical
>   *
> - * This file was originally part of 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
> @@ -25,231 +22,132 @@
>
>  #include <stdlib.h>
>  #include <stdio.h>
> -#include <sys/types.h>
> -#include <sys/stat.h>
>  #include <unistd.h>
>  #include <string.h>
>
> -static void acpiinfo_check(fwts_framework *fw, char *line,
> -       int repeated, char *prevline, void *private, int *errors)
> +static int acpiinfo_compiled_by(fwts_framework *fw, char *name, int instance)
>  {
> -       FWTS_UNUSED(repeated);
> -       FWTS_UNUSED(private);
> -       FWTS_UNUSED(errors);
> -
> -       if (strstr(line, "ACPI: Subsystem revision") != NULL) {
> -               char *version = strstr(line, "sion ");
> -               if (version) {
> -                       version += 5;
> -                       fwts_log_info(fw, "Linux ACPI interpreter version %s.",
> -                               version);
> -               }
> -       }
> -
> -       if (strstr(line, "ACPI: DSDT") != NULL) {
> -               char *vendor = "Unknown";
> -               if (strstr(line, "MSFT"))
> -                       vendor = "Microsoft";
> -               if (strstr(line, "INTL"))
> -                       vendor = "Intel";
> -               fwts_log_info(fw, "DSDT was compiled by the %s AML compiler.",
> -                       vendor);
> -       }
> -
> -       if (strstr(line, "Disabling IRQ") != NULL && prevline &&
> -           strstr(prevline, "acpi_irq")) {
> -               fwts_failed(fw, LOG_LEVEL_MEDIUM, "ACPIIRQStuck",
> -                       "ACPI interrupt got stuck: level triggered?");
> -               fwts_tag_failed(fw, FWTS_TAG_BIOS_IRQ);
> -               fwts_log_info_verbatum(fw, "%s", line);
> -       }
> -
> -       if (prevline &&
> -           strstr(prevline, "*** Error: Return object type is incorrect")) {
> -               fwts_failed(fw, LOG_LEVEL_HIGH, "BadObjectReturn",
> -                       "Return object type is incorrect: %s.", line);
> -               fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN);
> -               fwts_log_info_verbatum(fw, "%s", line);
> -       }
> -
> -       if (strstr(line, "ACPI: acpi_ec_space_handler: bit_width is 32, "
> -                       "should be")) {
> -               fwts_failed(fw, LOG_LEVEL_LOW, "ECBitWidth",
> -                       "Embedded controller bit_width is incorrect: %s.",
> -                       line);
> -               fwts_tag_failed(fw, FWTS_TAG_EMBEDDED_CONTROLLER);
> -               fwts_log_info_verbatum(fw, "%s", line);
> -       }
> -
> -       if (strstr(line, "acpi_ec_space_handler: bit_width should be")) {
> -               fwts_failed(fw, LOG_LEVEL_LOW, "ECBitWidth2",
> -                       "Embedded controller bit_width is incorrect: %s.",
> -                       line);
> -               fwts_tag_failed(fw, FWTS_TAG_EMBEDDED_CONTROLLER);
> -               fwts_log_info_verbatum(fw, "%s", line);
> -       }
> +       char *compiler;
> +       char tmp[80];
> +       char num[10];
> +       fwts_acpi_table_info *table;
> +       fwts_acpi_table_header *header;
>
> -       if (strstr(line, "Warning: acpi_table_parse(ACPI_SRAT) returned 0!")) {
> -               fwts_failed(fw, LOG_LEVEL_MEDIUM, "NoSRAT",
> -                       "SRAT table cannot be found");
> -               fwts_tag_failed(fw, FWTS_TAG_ACPI);
> -               fwts_log_info_verbatum(fw, "%s", line);
> -       }
> -
> -       if (strstr(line, "Warning: acpi_table_parse(ACPI_SLIT) returned 0!")) {
> -               fwts_failed(fw, LOG_LEVEL_MEDIUM, "NoSLIT",
> -                       "SLIT table cannot be found");
> -               fwts_tag_failed(fw, FWTS_TAG_ACPI);
> -               fwts_log_info_verbatum(fw, "%s", line);
> -       }
> +       if (fwts_acpi_find_table(fw, name, instance < 0 ? 0 : instance, &table) != FWTS_OK)
> +               return FWTS_ERROR;
>
> -       if (strstr(line, "WARNING: No sibling found for CPU")) {
> -               fwts_failed(fw, LOG_LEVEL_MEDIUM, "CPUHyperthreading",
> -                       "Hyperthreading CPU enumeration fails.");
> -               fwts_log_info_verbatum(fw, "%s", line);
> -       }
> +       if (table == NULL || table->data == NULL)
> +               return FWTS_ERROR;
>
> -       if (prevline && strstr(line, ">>> ERROR: Invalid checksum") &&
> -           strlen(prevline) > 11) {
> -               char tmp[4096];
> +       header = (fwts_acpi_table_header *)table->data;
>
> -               strncpy(tmp, prevline, sizeof(tmp));
> -               tmp[11] = '\0';
> -               fwts_failed(fw, LOG_LEVEL_HIGH, "InvalidTableChecksum",
> -                       "ACPI table %s has an invalid checksum.", tmp+6);
> -               fwts_tag_failed(fw, FWTS_TAG_ACPI_TABLE_CHECKSUM);
> -               fwts_log_info_verbatum(fw, "%s", line);
> +       if (strncmp(header->creator_id, "MSFT", 4) == 0) {
> +               compiler = "Microsoft";
> +       } else if (strncmp(header->creator_id, "INTL", 4) == 0) {
> +               compiler = "Intel";
> +       } else {
> +               snprintf(tmp, sizeof(tmp), "Unknown (%4.4s)", header->creator_id);
> +               compiler = tmp;
>         }
>
> -       if (strstr(line, "MP-BIOS bug: 8254 timer not connected to IO-APIC")) {
> -               fwts_failed(fw, LOG_LEVEL_HIGH, "8254NotConnected",
> -                       "8254 timer not connected to IO-APIC: %s.", line);
> -               fwts_tag_failed(fw, FWTS_TAG_ACPI_APIC);
> -               fwts_log_info_verbatum(fw, "%s", line);
> -       }
> -
> -       if (strstr(line, "ACPI: PCI Interrupt Link") &&
> -           strstr(line, " disabled and referenced, BIOS bug.")) {
> -               fwts_failed(fw, LOG_LEVEL_HIGH, "PCIInterruptLink", "%s", line);
> -               fwts_tag_failed(fw, FWTS_TAG_BIOS_IRQ);
> -               fwts_log_info_verbatum(fw, "%s", line);
> -       }
> +       if (instance == -1)
> +               *num = '\0';
> +       else
> +               snprintf(num, sizeof(num), "%d", instance);
>
> -       if (strstr(line, "*** Warning Inconsistent FADT length") &&
> -           strstr(line, "using FADT V1.0 portion of table")) {
> -               fwts_failed(fw, LOG_LEVEL_HIGH, "FADTRevsion",
> -                       "FADT table claims to be of higher revision than it is.");
> -               fwts_tag_failed(fw, FWTS_TAG_ACPI_INVALID_TABLE);
> -               fwts_log_info_verbatum(fw, "%s", line);
> -       }
> +       fwts_log_info(fw,
> +               "Table %4.4s%s, OEM %6.6s, created with %4.4s (%s) compiler.",
> +               header->signature, num, header->oem_id, header->creator_id, compiler);
>
> -       if (strstr(line, "thermal_get_trip_point: Invalid active threshold")) {
> -               fwts_failed(fw, LOG_LEVEL_CRITICAL, "_AC0TripPoint",
> -                       "_AC0 thermal trip point is invalid.");
> -               fwts_tag_failed(fw, FWTS_TAG_ACPI_THERMAL);
> -               fwts_log_info_verbatum(fw, "%s", line);
> -       }
> +       return FWTS_OK;
> +}
>
> -       if (strstr(line, "MMCONFIG has no entries")) {
> -               fwts_failed(fw, LOG_LEVEL_HIGH, "MCFGNoEntries",
> -                       "The MCFG table has no entries!");
> -               fwts_tag_failed(fw, FWTS_TAG_ACPI_INVALID_TABLE);
> -               fwts_log_info_verbatum(fw, "%s", line);
> -       }
> +static int acpiinfo_test1(fwts_framework *fw)
> +{
> +       char *str;
> +
> +       if (((str = fwts_get("/sys/module/acpi/parameters/acpica_version")) == NULL) &&
> +           ((str = fwts_get("/proc/acpi/info")) == NULL))
> +                fwts_log_info(fw,
> +                       "Cannot get ACPI version info from "
> +                       "/sys/module/acpi/parameters/acpica_version or /proc/acpi/info");
> +        else {
> +               int version;
> +               int yearmonth;
> +
> +                fwts_chop_newline(str);
> +
> +               sscanf(str, "%6d", &yearmonth);
> +
> +               if (yearmonth > 201110) {
> +                       version = 5;
> +               } else if (yearmonth > 200906) {
> +                       version = 4;
> +               } else if (yearmonth > 200505) {
> +                       version = 3;
> +               } else {
> +                       version = 2;
> +               }
>
> -       if (strstr(line, "MMCONFIG not in low 4GB of memory")) {
> -               fwts_failed(fw, LOG_LEVEL_MEDIUM, "MCFGEntriesTooHigh",
> -                       "The MCFG table entries are not in the lower 4Gb of RAM.");
> -               fwts_tag_failed(fw, FWTS_TAG_BIOS_MMCONFIG);
> -               fwts_log_info_verbatum(fw, "%s", line);
> -       }
> +                fwts_log_info(fw, "Kernel ACPICA driver version: %s, supports ACPI %d.0", str, version);
> +                free(str);
> +        }
>
> -       if (strstr(line, "pcie_portdrv_probe->Dev") &&
> -           strstr(line, "has invalid IRQ. Check vendor BIOS")) {
> -               fwts_failed(fw, LOG_LEVEL_HIGH, "PCIExpressInvalidIRQ",
> -                       "PCI Express port driver reports an invalid IRQ.");
> -               fwts_tag_failed(fw, FWTS_TAG_BIOS_IRQ);
> -               fwts_log_info_verbatum(fw, "%s", line);
> -       }
> +       fwts_infoonly(fw);
>
> -       if (strstr(line, "OCHI: BIOS handoff failed (BIOS bug")) {
> -               fwts_failed(fw, LOG_LEVEL_MEDIUM, "OHCIEmulation",
> -                       "OHCI BIOS emulation handoff failed.");
> -               fwts_tag_failed(fw, FWTS_TAG_BIOS);
> -               fwts_log_info_verbatum(fw, "%s", line);
> -               fwts_advice(fw,
> -                       "Generally this means that the EHCI driver was unable "
> -                       "to take control of the USB controller away from the "
> -                       "BIOS. Disabling USB legacy mode in the BIOS may help.");
> -       }
> -       if (strstr(line, "EHCI: BIOS handoff failed (BIOS bug")) {
> -               fwts_failed(fw, LOG_LEVEL_MEDIUM, "EHCIEmulation",
> -                       "EHCI BIOS emulation handoff failed.");
> -               fwts_tag_failed(fw, FWTS_TAG_BIOS);
> -               fwts_log_info_verbatum(fw, "%s", line);
> -               fwts_advice(fw,
> -                       "Generally this means that the EHCI driver was unable "
> -                       "to take control of the USB controller away from the "
> -                       "BIOS. Disabling USB legacy mode in the BIOS may help.");
> -       }
> +       return FWTS_OK;
>  }
>
> -static fwts_list *klog;
> -
> -static int acpiinfo_init(fwts_framework *fw)
> +static int acpiinfo_test2(fwts_framework *fw)
>  {
> -       if (fw->klog)
> -               klog = fwts_file_open_and_read(fw->klog);
> -       else
> -               klog = fwts_klog_read();
> +       fwts_acpi_table_info *table;
> +       fwts_acpi_table_header *header;
>
> -       if (klog == NULL) {
> -               fwts_log_error(fw, "Cannot read kernel log.");
> +       if (fwts_acpi_find_table(fw, "FACP", 0, &table) != FWTS_OK)
>                 return FWTS_ERROR;
> -       }
> -       return FWTS_OK;
> -}
>
> -static int acpiinfo_deinit(fwts_framework *fw)
> -{
> -       FWTS_UNUSED(fw);
> +       if (table == NULL || table->data == NULL)
> +               return FWTS_ERROR;
> +
> +       header = (fwts_acpi_table_header *)table->data;
>
> -       fwts_klog_free(klog);
> +       fwts_log_info(fw,
> +               "FACP ACPI Version: %d.0\n", header->revision);
> +
> +       fwts_infoonly(fw);
>
>         return FWTS_OK;
>  }
>
> -static int acpiinfo_test1(fwts_framework *fw)
> +static int acpiinfo_test3(fwts_framework *fw)
>  {
> -       int errors = 0;
> +       int i;
>
>         fwts_log_info(fw,
> -               "This test checks the output of the in-kernel ACPI CA against "
> -               "common error messages that indicate a bad interaction with "
> -               "the bios, including those that point at AML syntax errors.");
> +               "Determine the compiler used to generate the ACPI AML in the DSDT and SSDT.");
>
> -       if (fwts_klog_scan(fw, klog, acpiinfo_check, NULL, NULL, &errors)) {
> -               fwts_log_error(fw, "failed to scan kernel log.");
> -               return FWTS_ERROR;
> +       acpiinfo_compiled_by(fw, "DSDT", -1);
> +
> +       for (i = 0; i < 32 ; i++) {
> +               /* If we can't fetch the Nth SSDT, we've reached the end */
> +               if (acpiinfo_compiled_by(fw, "SSDT", i) != FWTS_OK)
> +                       break;
>         }
>
> -       if (errors > 0)
> -               fwts_log_info(fw, "Found %d errors in kernel log.", errors);
> -       else
> -               fwts_passed(fw, "Found no errors in kernel log.");
> +       fwts_infoonly(fw);
>
>         return FWTS_OK;
>  }
>
>  static fwts_framework_minor_test acpiinfo_tests[] = {
> -       { acpiinfo_test1, "General ACPI information check." },
> +       { acpiinfo_test1, "Determine Kernel ACPI version." },
> +       { acpiinfo_test2, "Determine machines ACPI version." },
> +       { acpiinfo_test3, "Determine AML compiler." },
>         { NULL, NULL }
>  };
>
>  static fwts_framework_ops acpiinfo_ops = {
>         .description = "General ACPI information check.",
> -       .init        = acpiinfo_init,
> -       .deinit      = acpiinfo_deinit,
>         .minor_tests = acpiinfo_tests
>  };
>
> --
> 1.8.0
>

This looks much better. Thanks Colin.

Acked-by: Keng-Yu Lin <kengyu@canonical.com>
Alex Hung - Dec. 13, 2012, 2:09 a.m.
On 12/04/2012 05:43 AM, Colin King wrote:
> From: Colin Ian King <colin.king@canonical.com>
>
> The apciinfo test is a legacy test originally derived from the
> Linux firmware developer kit and had a lot of hard-coded kernel
> log checks that are now either out of data or nor used.  I've now
> moved these kernel log checks into the fwts klog table because it
> makes more sense for them to be scanned by the klog tests.  I have
> also added the recent kernel versions of these kernel log messages
> to keep it in sync with the upstream code.
>
> I was thinking of removing this test, but the acpiinfo name lends
> itself to dumping out some ACPI specific information that is useful
> to know.  So I've re-written the test to determine the ACPI version
> supported by the kernel ACPI driver, the ACPI version in the
> machine's firmware and I've completely re-worked the original code
> to also determine the version of the ACPI compiler used to generate
> the DSDT and SSDT AML.
>
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
> ---
>   data/klog.json               | 104 +++++++++++++++++
>   src/acpi/acpiinfo/acpiinfo.c | 268 ++++++++++++++-----------------------------
>   2 files changed, 187 insertions(+), 185 deletions(-)
>
> diff --git a/data/klog.json b/data/klog.json
> index 9084fac..c2cc858 100644
> --- a/data/klog.json
> +++ b/data/klog.json
> @@ -77,6 +77,110 @@
>    "firmware_error_warning_patterns":
>    [
>     {
> +   "compare_mode": "regex",
> +   "log_level": "LOG_LEVEL_MEDIUM",
> +   "tag": "FWTS_TAG_BIOS",
> +   "pattern": "device .* has invalid IRQ.*check vendor BIOS",
> +   "advice": "An error occurred probing the PCI-Express port devices. The device has a valid pin but did not have an a valid IRQ.  This is normally due to a misconfiguration in the firmware.",
> +   "label": "KlogBiosIrqInvalid"
> +  },
> +  {
> +   "compare_mode": "regex",
> +   "log_level": "LOG_LEVEL_CRITCAL",
> +   "tag": "FWTS_TAG_ACPI",
> +   "pattern": "Invalid active.* threshold",
> +   "advice": "The ACPI thermal driver has attempted to evaluate an ACPI active threshold control _ALx and this failed to evaluate.  This is normally due to broken or buggy _ALx control. This may lead to sub-optimal thermal control.",
> +   "label": "KlogAcpiAlThresholdInvalid"
> +  },
> +  {
> +   "compare_mode": "string",
> +   "log_level": "LOG_LEVEL_HIGH",
> +   "tag": "FWTS_TAG_CPU",
> +   "pattern": "No sibling found for CPU",
> +   "advice": "Hyperthreading CPU enumeration failed, hyperthreads will be disabled.",
> +   "label": "KlogCpuNoSiblingFound"
> +  },
> +  {
> +   "compare_mode": "string",
> +   "log_level": "LOG_LEVEL_HIGH",
> +   "tag": "FWTS_TAG_BIOS",
> +   "pattern": "OHCI: BIOS handoff failed",
> +   "advice": "An OHCI BIOS handoff failure generally means that the OHCI driver was unable to take control of the USB controller away from the BIOS. Disabling USB legacy mode in the BIOS may help.",
> +   "label": "KlogBiosOhciEmulation"
> +  },
> +  {
> +   "compare_mode": "string",
> +   "log_level": "LOG_LEVEL_HIGH",
> +   "tag": "FWTS_TAG_BIOS",
> +   "pattern": "EHCI: BIOS handoff failed",
> +   "advice": "An EHCI BIOS handoff failure generally means that the EHCI driver was unable to take control of the USB controller away from the BIOS. Disabling USB legacy mode in the BIOS may help.",
> +   "label": "KlogBiosEhciEmulation"
> +  },
> +  {
> +   "compare_mode": "string",
> +   "log_level": "LOG_LEVEL_HIGH",
> +   "tag": "FWTS_TAG_BIOS",
> +   "pattern": "xHCI BIOS handoff failed",
> +   "advice": "An xHCI BIOS handoff failure generally means that the xHCI driver was unable to take control of the USB controller away from the BIOS. Disabling USB legacy mode in the BIOS may help.",
> +   "label": "KlogBiosXhciEmulation"
> +  },
> +  {
> +   "compare_mode": "regex",
> +   "log_level": "LOG_LEVEL_HIGH",
> +   "tag": "FWTS_TAG_ACPI",
> +   "pattern": "MMCONFIG has no entries",
> +   "advice": "The ACPI MCFG has failed to be parsed, it has no entries in it. This is not expected and is most likely an ACPI misconfiguration. The PCI memory mapped configuration space is not known and hence PCI will be not configured.",
> +   "label": "KlogAcpiMcfgNoEntries"
> +  },
> +  {
> +   "compare_mode": "string",
> +   "log_level": "LOG_LEVEL_HIGH",
> +   "tag": "FWTS_TAG_ACPI",
> +   "pattern": "MMCONFIG not in low 4GB of memory",
> +   "advice": "An ACPI MCFG config entry is not in the lower 4GB (32 bit) address space and will be ignored.",
> +   "label": "KlogAcpiMcfgNotIn32BitMemorySpace"
> +  },
> +  {
> +   "compare_mode": "regex",
> +   "log_level": "LOG_LEVEL_HIGH",
> +   "tag": "FWTS_TAG_ACPI",
> +   "pattern": "MCFG region for .* at .* is above 4GB, ignored",
> +   "advice": "An ACPI MCFG config entry is not in the lower 4GB (32 bit) address space and will be ignored.",
> +   "label": "KlogAcpiMcfgNotin32BitMemorySpace"
> +  },
> +  {
> +   "compare_mode": "regex",
> +   "log_level": "LOG_LEVEL_HIGH",
> +   "tag": "FWTS_TAG_BIOS",
> +   "pattern": "MP-BIOS bug.*8254 timer not connected to IO-APIC",
> +   "advice": "The 8254 timer is not connected to an IO-APIC, this is invariably due to a misconfiguration in the BIOS.",
> +   "label": "KlogIoApic8254TimerNotConnected"
> +  },
> +  {
> +   "compare_mode": "string",
> +   "log_level": "LOG_LEVEL_HIGH",
> +   "tag": "FWTS_TAG_ACPI",
> +   "pattern": "disabled and referenced, BIOS bug",
> +   "advice": "A PCI interrupt link could not be enabled when the associated ACPI _STA control was executed. It will be disabled. This is normally a bug in the _STA control for this link.",
> +   "label": "KlogPciLinkDisabled"
> +  },
> +  {
> +   "compare_mode": "regex",
> +   "log_level": "LOG_LEVEL_HIGH",
> +   "tag": "FWTS_TAG_BIOS",
> +   "pattern": "Inconsistent FADT length .* and revision .* using FADT V1.0 portion of table",
> +   "advice": "The ACPI FADT was reporting to be a version 2.0 (or higher) FADT but the length was too short, so the kernel has assumed it was a version 1.0 FADT instead. The machine may have reduced ACPI 1.0 functionality.",
> +   "label": "KlogAcpiFadtInconsistentLength"
> +  },
> +  {
> +   "compare_mode": "string",
> +   "log_level": "LOG_LEVEL_CRITICAL",
> +   "tag": "FWTS_TAG_BIOS_IRQ",
> +   "pattern": "Disabling IRQ#",
> +   "advice": "The kernel had detected a spurious interrupt which is generating tens of thousands of interrupts. This can occur if the interrupt is stuck.  The kernel has taken action and disabled this interrupt.  Look at /proc/interrupts to find the devices serviced by this interrupt as these are most probably no functioning now.",
> +   "label": "KlogIrqDisabled"
> +  },
> +  {
>      "compare_mode": "string",
>      "log_level": "LOG_LEVEL_HIGH",
>      "tag": "FWTS_TAG_ACPI",
> diff --git a/src/acpi/acpiinfo/acpiinfo.c b/src/acpi/acpiinfo/acpiinfo.c
> index d6d3904..a3c9cb7 100644
> --- a/src/acpi/acpiinfo/acpiinfo.c
> +++ b/src/acpi/acpiinfo/acpiinfo.c
> @@ -1,9 +1,6 @@
>   /*
> - * Copyright (C) 2006, Intel Corporation
>    * Copyright (C) 2010-2012 Canonical
>    *
> - * This file was originally part of 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
> @@ -25,231 +22,132 @@
>
>   #include <stdlib.h>
>   #include <stdio.h>
> -#include <sys/types.h>
> -#include <sys/stat.h>
>   #include <unistd.h>
>   #include <string.h>
>
> -static void acpiinfo_check(fwts_framework *fw, char *line,
> -	int repeated, char *prevline, void *private, int *errors)
> +static int acpiinfo_compiled_by(fwts_framework *fw, char *name, int instance)
>   {
> -	FWTS_UNUSED(repeated);
> -	FWTS_UNUSED(private);
> -	FWTS_UNUSED(errors);
> -
> -	if (strstr(line, "ACPI: Subsystem revision") != NULL) {
> -		char *version = strstr(line, "sion ");
> -		if (version) {
> -			version += 5;
> -			fwts_log_info(fw, "Linux ACPI interpreter version %s.",
> -				version);
> -		}
> -	}
> -
> -	if (strstr(line, "ACPI: DSDT") != NULL) {
> -		char *vendor = "Unknown";
> -		if (strstr(line, "MSFT"))
> -			vendor = "Microsoft";
> -		if (strstr(line, "INTL"))
> -			vendor = "Intel";
> -		fwts_log_info(fw, "DSDT was compiled by the %s AML compiler.",
> -			vendor);
> -	}
> -
> -	if (strstr(line, "Disabling IRQ") != NULL && prevline &&
> -	    strstr(prevline, "acpi_irq")) {
> -		fwts_failed(fw, LOG_LEVEL_MEDIUM, "ACPIIRQStuck",
> -			"ACPI interrupt got stuck: level triggered?");
> -		fwts_tag_failed(fw, FWTS_TAG_BIOS_IRQ);
> -		fwts_log_info_verbatum(fw, "%s", line);
> -	}
> -
> -	if (prevline &&
> -	    strstr(prevline, "*** Error: Return object type is incorrect")) {
> -		fwts_failed(fw, LOG_LEVEL_HIGH, "BadObjectReturn",
> -			"Return object type is incorrect: %s.", line);
> -		fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN);
> -		fwts_log_info_verbatum(fw, "%s", line);
> -	}
> -
> -	if (strstr(line, "ACPI: acpi_ec_space_handler: bit_width is 32, "
> -			"should be")) {
> -		fwts_failed(fw, LOG_LEVEL_LOW, "ECBitWidth",
> -			"Embedded controller bit_width is incorrect: %s.",
> -			line);
> -		fwts_tag_failed(fw, FWTS_TAG_EMBEDDED_CONTROLLER);
> -		fwts_log_info_verbatum(fw, "%s", line);
> -	}
> -
> -	if (strstr(line, "acpi_ec_space_handler: bit_width should be")) {
> -		fwts_failed(fw, LOG_LEVEL_LOW, "ECBitWidth2",
> -			"Embedded controller bit_width is incorrect: %s.",
> -			line);
> -		fwts_tag_failed(fw, FWTS_TAG_EMBEDDED_CONTROLLER);
> -		fwts_log_info_verbatum(fw, "%s", line);
> -	}
> +	char *compiler;
> +	char tmp[80];
> +	char num[10];
> +	fwts_acpi_table_info *table;
> +	fwts_acpi_table_header *header;
>
> -	if (strstr(line, "Warning: acpi_table_parse(ACPI_SRAT) returned 0!")) {
> -		fwts_failed(fw, LOG_LEVEL_MEDIUM, "NoSRAT",
> -			"SRAT table cannot be found");
> -		fwts_tag_failed(fw, FWTS_TAG_ACPI);
> -		fwts_log_info_verbatum(fw, "%s", line);
> -	}
> -
> -	if (strstr(line, "Warning: acpi_table_parse(ACPI_SLIT) returned 0!")) {
> -		fwts_failed(fw, LOG_LEVEL_MEDIUM, "NoSLIT",
> -			"SLIT table cannot be found");
> -		fwts_tag_failed(fw, FWTS_TAG_ACPI);
> -		fwts_log_info_verbatum(fw, "%s", line);
> -	}
> +	if (fwts_acpi_find_table(fw, name, instance < 0 ? 0 : instance, &table) != FWTS_OK)
> +		return FWTS_ERROR;
>
> -	if (strstr(line, "WARNING: No sibling found for CPU")) {
> -		fwts_failed(fw, LOG_LEVEL_MEDIUM, "CPUHyperthreading",
> -			"Hyperthreading CPU enumeration fails.");
> -		fwts_log_info_verbatum(fw, "%s", line);
> -	}
> +	if (table == NULL || table->data == NULL)
> +		return FWTS_ERROR;
>
> -	if (prevline && strstr(line, ">>> ERROR: Invalid checksum") &&
> -	    strlen(prevline) > 11) {
> -		char tmp[4096];
> +	header = (fwts_acpi_table_header *)table->data;
>
> -		strncpy(tmp, prevline, sizeof(tmp));
> -		tmp[11] = '\0';
> -		fwts_failed(fw, LOG_LEVEL_HIGH, "InvalidTableChecksum",
> -			"ACPI table %s has an invalid checksum.", tmp+6);
> -		fwts_tag_failed(fw, FWTS_TAG_ACPI_TABLE_CHECKSUM);
> -		fwts_log_info_verbatum(fw, "%s", line);
> +	if (strncmp(header->creator_id, "MSFT", 4) == 0) {
> +		compiler = "Microsoft";
> +	} else if (strncmp(header->creator_id, "INTL", 4) == 0) {
> +		compiler = "Intel";
> +	} else {
> +		snprintf(tmp, sizeof(tmp), "Unknown (%4.4s)", header->creator_id);
> +		compiler = tmp;
>   	}
>
> -	if (strstr(line, "MP-BIOS bug: 8254 timer not connected to IO-APIC")) {
> -		fwts_failed(fw, LOG_LEVEL_HIGH, "8254NotConnected",
> -			"8254 timer not connected to IO-APIC: %s.", line);
> -		fwts_tag_failed(fw, FWTS_TAG_ACPI_APIC);
> -		fwts_log_info_verbatum(fw, "%s", line);
> -	}
> -
> -	if (strstr(line, "ACPI: PCI Interrupt Link") &&
> -	    strstr(line, " disabled and referenced, BIOS bug.")) {
> -		fwts_failed(fw, LOG_LEVEL_HIGH, "PCIInterruptLink", "%s", line);
> -		fwts_tag_failed(fw, FWTS_TAG_BIOS_IRQ);
> -		fwts_log_info_verbatum(fw, "%s", line);
> -	}
> +	if (instance == -1)
> +		*num = '\0';
> +	else
> +		snprintf(num, sizeof(num), "%d", instance);
>
> -	if (strstr(line, "*** Warning Inconsistent FADT length") &&
> -	    strstr(line, "using FADT V1.0 portion of table")) {
> -		fwts_failed(fw, LOG_LEVEL_HIGH, "FADTRevsion",
> -			"FADT table claims to be of higher revision than it is.");
> -		fwts_tag_failed(fw, FWTS_TAG_ACPI_INVALID_TABLE);
> -		fwts_log_info_verbatum(fw, "%s", line);
> -	}
> +	fwts_log_info(fw,
> +		"Table %4.4s%s, OEM %6.6s, created with %4.4s (%s) compiler.",
> +		header->signature, num, header->oem_id, header->creator_id, compiler);
>
> -	if (strstr(line, "thermal_get_trip_point: Invalid active threshold")) {
> -		fwts_failed(fw, LOG_LEVEL_CRITICAL, "_AC0TripPoint",
> -			"_AC0 thermal trip point is invalid.");
> -		fwts_tag_failed(fw, FWTS_TAG_ACPI_THERMAL);
> -		fwts_log_info_verbatum(fw, "%s", line);
> -	}
> +	return FWTS_OK;
> +}
>
> -	if (strstr(line, "MMCONFIG has no entries")) {
> -		fwts_failed(fw, LOG_LEVEL_HIGH, "MCFGNoEntries",
> -			"The MCFG table has no entries!");
> -		fwts_tag_failed(fw, FWTS_TAG_ACPI_INVALID_TABLE);
> -		fwts_log_info_verbatum(fw, "%s", line);
> -	}
> +static int acpiinfo_test1(fwts_framework *fw)
> +{
> +	char *str;
> +
> +	if (((str = fwts_get("/sys/module/acpi/parameters/acpica_version")) == NULL) &&
> +	    ((str = fwts_get("/proc/acpi/info")) == NULL))
> +                fwts_log_info(fw,
> +			"Cannot get ACPI version info from "
> +			"/sys/module/acpi/parameters/acpica_version or /proc/acpi/info");
> +        else {
> +		int version;
> +		int yearmonth;
> +
> +                fwts_chop_newline(str);
> +
> +		sscanf(str, "%6d", &yearmonth);
> +
> +		if (yearmonth > 201110) {
> +			version = 5;
> +		} else if (yearmonth > 200906) {
> +			version = 4;
> +		} else if (yearmonth > 200505) {
> +			version = 3;
> +		} else {
> +			version = 2;
> +		}
>
> -	if (strstr(line, "MMCONFIG not in low 4GB of memory")) {
> -		fwts_failed(fw, LOG_LEVEL_MEDIUM, "MCFGEntriesTooHigh",
> -			"The MCFG table entries are not in the lower 4Gb of RAM.");
> -		fwts_tag_failed(fw, FWTS_TAG_BIOS_MMCONFIG);
> -		fwts_log_info_verbatum(fw, "%s", line);
> -	}
> +                fwts_log_info(fw, "Kernel ACPICA driver version: %s, supports ACPI %d.0", str, version);
> +                free(str);
> +        }
>
> -	if (strstr(line, "pcie_portdrv_probe->Dev") &&
> -	    strstr(line, "has invalid IRQ. Check vendor BIOS")) {
> -		fwts_failed(fw, LOG_LEVEL_HIGH, "PCIExpressInvalidIRQ",
> -			"PCI Express port driver reports an invalid IRQ.");
> -		fwts_tag_failed(fw, FWTS_TAG_BIOS_IRQ);
> -		fwts_log_info_verbatum(fw, "%s", line);
> -	}
> +	fwts_infoonly(fw);
>
> -	if (strstr(line, "OCHI: BIOS handoff failed (BIOS bug")) {
> -		fwts_failed(fw, LOG_LEVEL_MEDIUM, "OHCIEmulation",
> -			"OHCI BIOS emulation handoff failed.");
> -		fwts_tag_failed(fw, FWTS_TAG_BIOS);
> -		fwts_log_info_verbatum(fw, "%s", line);
> -		fwts_advice(fw,
> -			"Generally this means that the EHCI driver was unable "
> -			"to take control of the USB controller away from the "
> -			"BIOS. Disabling USB legacy mode in the BIOS may help.");
> -	}
> -	if (strstr(line, "EHCI: BIOS handoff failed (BIOS bug")) {
> -		fwts_failed(fw, LOG_LEVEL_MEDIUM, "EHCIEmulation",
> -			"EHCI BIOS emulation handoff failed.");
> -		fwts_tag_failed(fw, FWTS_TAG_BIOS);
> -		fwts_log_info_verbatum(fw, "%s", line);
> -		fwts_advice(fw,
> -			"Generally this means that the EHCI driver was unable "
> -			"to take control of the USB controller away from the "
> -			"BIOS. Disabling USB legacy mode in the BIOS may help.");
> -	}
> +	return FWTS_OK;
>   }
>
> -static fwts_list *klog;
> -
> -static int acpiinfo_init(fwts_framework *fw)
> +static int acpiinfo_test2(fwts_framework *fw)
>   {
> -	if (fw->klog)
> -		klog = fwts_file_open_and_read(fw->klog);
> -	else
> -		klog = fwts_klog_read();
> +	fwts_acpi_table_info *table;
> +	fwts_acpi_table_header *header;
>
> -	if (klog == NULL) {
> -		fwts_log_error(fw, "Cannot read kernel log.");
> +	if (fwts_acpi_find_table(fw, "FACP", 0, &table) != FWTS_OK)
>   		return FWTS_ERROR;
> -	}
> -	return FWTS_OK;
> -}
>
> -static int acpiinfo_deinit(fwts_framework *fw)
> -{
> -	FWTS_UNUSED(fw);
> +	if (table == NULL || table->data == NULL)
> +		return FWTS_ERROR;
> +
> +	header = (fwts_acpi_table_header *)table->data;
>
> -	fwts_klog_free(klog);
> +	fwts_log_info(fw,
> +		"FACP ACPI Version: %d.0\n", header->revision);
> +
> +	fwts_infoonly(fw);
>
>   	return FWTS_OK;
>   }
>
> -static int acpiinfo_test1(fwts_framework *fw)
> +static int acpiinfo_test3(fwts_framework *fw)
>   {
> -	int errors = 0;
> +	int i;
>
>   	fwts_log_info(fw,
> -		"This test checks the output of the in-kernel ACPI CA against "
> -		"common error messages that indicate a bad interaction with "
> -		"the bios, including those that point at AML syntax errors.");
> +		"Determine the compiler used to generate the ACPI AML in the DSDT and SSDT.");
>
> -	if (fwts_klog_scan(fw, klog, acpiinfo_check, NULL, NULL, &errors)) {
> -		fwts_log_error(fw, "failed to scan kernel log.");
> -		return FWTS_ERROR;
> +	acpiinfo_compiled_by(fw, "DSDT", -1);
> +
> +	for (i = 0; i < 32 ; i++) {
> +		/* If we can't fetch the Nth SSDT, we've reached the end */
> +		if (acpiinfo_compiled_by(fw, "SSDT", i) != FWTS_OK)
> +			break;
>   	}
>
> -	if (errors > 0)
> -		fwts_log_info(fw, "Found %d errors in kernel log.", errors);
> -	else
> -		fwts_passed(fw, "Found no errors in kernel log.");
> +	fwts_infoonly(fw);
>
>   	return FWTS_OK;
>   }
>
>   static fwts_framework_minor_test acpiinfo_tests[] = {
> -	{ acpiinfo_test1, "General ACPI information check." },
> +	{ acpiinfo_test1, "Determine Kernel ACPI version." },
> +	{ acpiinfo_test2, "Determine machines ACPI version." },
> +	{ acpiinfo_test3, "Determine AML compiler." },
>   	{ NULL, NULL }
>   };
>
>   static fwts_framework_ops acpiinfo_ops = {
>   	.description = "General ACPI information check.",
> -	.init        = acpiinfo_init,
> -	.deinit      = acpiinfo_deinit,
>   	.minor_tests = acpiinfo_tests
>   };
>
>
Acked-by: Alex Hung <alex.hung@canonical.com>

Patch

diff --git a/data/klog.json b/data/klog.json
index 9084fac..c2cc858 100644
--- a/data/klog.json
+++ b/data/klog.json
@@ -77,6 +77,110 @@ 
  "firmware_error_warning_patterns":
  [
   {
+   "compare_mode": "regex",
+   "log_level": "LOG_LEVEL_MEDIUM",
+   "tag": "FWTS_TAG_BIOS",
+   "pattern": "device .* has invalid IRQ.*check vendor BIOS",
+   "advice": "An error occurred probing the PCI-Express port devices. The device has a valid pin but did not have an a valid IRQ.  This is normally due to a misconfiguration in the firmware.",
+   "label": "KlogBiosIrqInvalid"
+  },
+  {
+   "compare_mode": "regex",
+   "log_level": "LOG_LEVEL_CRITCAL",
+   "tag": "FWTS_TAG_ACPI",
+   "pattern": "Invalid active.* threshold",
+   "advice": "The ACPI thermal driver has attempted to evaluate an ACPI active threshold control _ALx and this failed to evaluate.  This is normally due to broken or buggy _ALx control. This may lead to sub-optimal thermal control.",
+   "label": "KlogAcpiAlThresholdInvalid"
+  },
+  {
+   "compare_mode": "string",
+   "log_level": "LOG_LEVEL_HIGH",
+   "tag": "FWTS_TAG_CPU",
+   "pattern": "No sibling found for CPU",
+   "advice": "Hyperthreading CPU enumeration failed, hyperthreads will be disabled.",
+   "label": "KlogCpuNoSiblingFound"
+  },
+  {
+   "compare_mode": "string",
+   "log_level": "LOG_LEVEL_HIGH",
+   "tag": "FWTS_TAG_BIOS",
+   "pattern": "OHCI: BIOS handoff failed",
+   "advice": "An OHCI BIOS handoff failure generally means that the OHCI driver was unable to take control of the USB controller away from the BIOS. Disabling USB legacy mode in the BIOS may help.",
+   "label": "KlogBiosOhciEmulation"
+  },
+  {
+   "compare_mode": "string",
+   "log_level": "LOG_LEVEL_HIGH",
+   "tag": "FWTS_TAG_BIOS",
+   "pattern": "EHCI: BIOS handoff failed",
+   "advice": "An EHCI BIOS handoff failure generally means that the EHCI driver was unable to take control of the USB controller away from the BIOS. Disabling USB legacy mode in the BIOS may help.",
+   "label": "KlogBiosEhciEmulation"
+  },
+  {
+   "compare_mode": "string",
+   "log_level": "LOG_LEVEL_HIGH",
+   "tag": "FWTS_TAG_BIOS",
+   "pattern": "xHCI BIOS handoff failed",
+   "advice": "An xHCI BIOS handoff failure generally means that the xHCI driver was unable to take control of the USB controller away from the BIOS. Disabling USB legacy mode in the BIOS may help.",
+   "label": "KlogBiosXhciEmulation"
+  },
+  {
+   "compare_mode": "regex",
+   "log_level": "LOG_LEVEL_HIGH",
+   "tag": "FWTS_TAG_ACPI",
+   "pattern": "MMCONFIG has no entries",
+   "advice": "The ACPI MCFG has failed to be parsed, it has no entries in it. This is not expected and is most likely an ACPI misconfiguration. The PCI memory mapped configuration space is not known and hence PCI will be not configured.",
+   "label": "KlogAcpiMcfgNoEntries"
+  },
+  {
+   "compare_mode": "string",
+   "log_level": "LOG_LEVEL_HIGH",
+   "tag": "FWTS_TAG_ACPI",
+   "pattern": "MMCONFIG not in low 4GB of memory",
+   "advice": "An ACPI MCFG config entry is not in the lower 4GB (32 bit) address space and will be ignored.",
+   "label": "KlogAcpiMcfgNotIn32BitMemorySpace"
+  },
+  {
+   "compare_mode": "regex",
+   "log_level": "LOG_LEVEL_HIGH",
+   "tag": "FWTS_TAG_ACPI",
+   "pattern": "MCFG region for .* at .* is above 4GB, ignored",
+   "advice": "An ACPI MCFG config entry is not in the lower 4GB (32 bit) address space and will be ignored.",
+   "label": "KlogAcpiMcfgNotin32BitMemorySpace"
+  },
+  {
+   "compare_mode": "regex",
+   "log_level": "LOG_LEVEL_HIGH",
+   "tag": "FWTS_TAG_BIOS",
+   "pattern": "MP-BIOS bug.*8254 timer not connected to IO-APIC",
+   "advice": "The 8254 timer is not connected to an IO-APIC, this is invariably due to a misconfiguration in the BIOS.",
+   "label": "KlogIoApic8254TimerNotConnected"
+  },
+  {
+   "compare_mode": "string",
+   "log_level": "LOG_LEVEL_HIGH",
+   "tag": "FWTS_TAG_ACPI",
+   "pattern": "disabled and referenced, BIOS bug",
+   "advice": "A PCI interrupt link could not be enabled when the associated ACPI _STA control was executed. It will be disabled. This is normally a bug in the _STA control for this link.",
+   "label": "KlogPciLinkDisabled"
+  },
+  {
+   "compare_mode": "regex",
+   "log_level": "LOG_LEVEL_HIGH",
+   "tag": "FWTS_TAG_BIOS",
+   "pattern": "Inconsistent FADT length .* and revision .* using FADT V1.0 portion of table",
+   "advice": "The ACPI FADT was reporting to be a version 2.0 (or higher) FADT but the length was too short, so the kernel has assumed it was a version 1.0 FADT instead. The machine may have reduced ACPI 1.0 functionality.",
+   "label": "KlogAcpiFadtInconsistentLength"
+  },
+  {
+   "compare_mode": "string",
+   "log_level": "LOG_LEVEL_CRITICAL",
+   "tag": "FWTS_TAG_BIOS_IRQ",
+   "pattern": "Disabling IRQ#",
+   "advice": "The kernel had detected a spurious interrupt which is generating tens of thousands of interrupts. This can occur if the interrupt is stuck.  The kernel has taken action and disabled this interrupt.  Look at /proc/interrupts to find the devices serviced by this interrupt as these are most probably no functioning now.",
+   "label": "KlogIrqDisabled"
+  },
+  {
    "compare_mode": "string",
    "log_level": "LOG_LEVEL_HIGH",
    "tag": "FWTS_TAG_ACPI",
diff --git a/src/acpi/acpiinfo/acpiinfo.c b/src/acpi/acpiinfo/acpiinfo.c
index d6d3904..a3c9cb7 100644
--- a/src/acpi/acpiinfo/acpiinfo.c
+++ b/src/acpi/acpiinfo/acpiinfo.c
@@ -1,9 +1,6 @@ 
 /*
- * Copyright (C) 2006, Intel Corporation
  * Copyright (C) 2010-2012 Canonical
  *
- * This file was originally part of 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
@@ -25,231 +22,132 @@ 
 
 #include <stdlib.h>
 #include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <unistd.h>
 #include <string.h>
 
-static void acpiinfo_check(fwts_framework *fw, char *line,
-	int repeated, char *prevline, void *private, int *errors)
+static int acpiinfo_compiled_by(fwts_framework *fw, char *name, int instance)
 {
-	FWTS_UNUSED(repeated);
-	FWTS_UNUSED(private);
-	FWTS_UNUSED(errors);
-
-	if (strstr(line, "ACPI: Subsystem revision") != NULL) {
-		char *version = strstr(line, "sion ");
-		if (version) {
-			version += 5;
-			fwts_log_info(fw, "Linux ACPI interpreter version %s.",
-				version);
-		}
-	}
-
-	if (strstr(line, "ACPI: DSDT") != NULL) {
-		char *vendor = "Unknown";
-		if (strstr(line, "MSFT"))
-			vendor = "Microsoft";
-		if (strstr(line, "INTL"))
-			vendor = "Intel";
-		fwts_log_info(fw, "DSDT was compiled by the %s AML compiler.",
-			vendor);
-	}
-
-	if (strstr(line, "Disabling IRQ") != NULL && prevline &&
-	    strstr(prevline, "acpi_irq")) {
-		fwts_failed(fw, LOG_LEVEL_MEDIUM, "ACPIIRQStuck",
-			"ACPI interrupt got stuck: level triggered?");
-		fwts_tag_failed(fw, FWTS_TAG_BIOS_IRQ);
-		fwts_log_info_verbatum(fw, "%s", line);
-	}
-
-	if (prevline &&
-	    strstr(prevline, "*** Error: Return object type is incorrect")) {
-		fwts_failed(fw, LOG_LEVEL_HIGH, "BadObjectReturn",
-			"Return object type is incorrect: %s.", line);
-		fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN);
-		fwts_log_info_verbatum(fw, "%s", line);
-	}
-
-	if (strstr(line, "ACPI: acpi_ec_space_handler: bit_width is 32, "
-			"should be")) {
-		fwts_failed(fw, LOG_LEVEL_LOW, "ECBitWidth",
-			"Embedded controller bit_width is incorrect: %s.",
-			line);
-		fwts_tag_failed(fw, FWTS_TAG_EMBEDDED_CONTROLLER);
-		fwts_log_info_verbatum(fw, "%s", line);
-	}
-
-	if (strstr(line, "acpi_ec_space_handler: bit_width should be")) {
-		fwts_failed(fw, LOG_LEVEL_LOW, "ECBitWidth2",
-			"Embedded controller bit_width is incorrect: %s.",
-			line);
-		fwts_tag_failed(fw, FWTS_TAG_EMBEDDED_CONTROLLER);
-		fwts_log_info_verbatum(fw, "%s", line);
-	}
+	char *compiler;
+	char tmp[80];
+	char num[10];
+	fwts_acpi_table_info *table;
+	fwts_acpi_table_header *header;
 
-	if (strstr(line, "Warning: acpi_table_parse(ACPI_SRAT) returned 0!")) {
-		fwts_failed(fw, LOG_LEVEL_MEDIUM, "NoSRAT",
-			"SRAT table cannot be found");
-		fwts_tag_failed(fw, FWTS_TAG_ACPI);
-		fwts_log_info_verbatum(fw, "%s", line);
-	}
-
-	if (strstr(line, "Warning: acpi_table_parse(ACPI_SLIT) returned 0!")) {
-		fwts_failed(fw, LOG_LEVEL_MEDIUM, "NoSLIT",
-			"SLIT table cannot be found");
-		fwts_tag_failed(fw, FWTS_TAG_ACPI);
-		fwts_log_info_verbatum(fw, "%s", line);
-	}
+	if (fwts_acpi_find_table(fw, name, instance < 0 ? 0 : instance, &table) != FWTS_OK)
+		return FWTS_ERROR;
 
-	if (strstr(line, "WARNING: No sibling found for CPU")) {
-		fwts_failed(fw, LOG_LEVEL_MEDIUM, "CPUHyperthreading",
-			"Hyperthreading CPU enumeration fails.");
-		fwts_log_info_verbatum(fw, "%s", line);
-	}
+	if (table == NULL || table->data == NULL)
+		return FWTS_ERROR;
 
-	if (prevline && strstr(line, ">>> ERROR: Invalid checksum") &&
-	    strlen(prevline) > 11) {
-		char tmp[4096];
+	header = (fwts_acpi_table_header *)table->data;
 
-		strncpy(tmp, prevline, sizeof(tmp));
-		tmp[11] = '\0';
-		fwts_failed(fw, LOG_LEVEL_HIGH, "InvalidTableChecksum",
-			"ACPI table %s has an invalid checksum.", tmp+6);
-		fwts_tag_failed(fw, FWTS_TAG_ACPI_TABLE_CHECKSUM);
-		fwts_log_info_verbatum(fw, "%s", line);
+	if (strncmp(header->creator_id, "MSFT", 4) == 0) {
+		compiler = "Microsoft";
+	} else if (strncmp(header->creator_id, "INTL", 4) == 0) {
+		compiler = "Intel";
+	} else {
+		snprintf(tmp, sizeof(tmp), "Unknown (%4.4s)", header->creator_id);
+		compiler = tmp;
 	}
 
-	if (strstr(line, "MP-BIOS bug: 8254 timer not connected to IO-APIC")) {
-		fwts_failed(fw, LOG_LEVEL_HIGH, "8254NotConnected",
-			"8254 timer not connected to IO-APIC: %s.", line);
-		fwts_tag_failed(fw, FWTS_TAG_ACPI_APIC);
-		fwts_log_info_verbatum(fw, "%s", line);
-	}
-
-	if (strstr(line, "ACPI: PCI Interrupt Link") &&
-	    strstr(line, " disabled and referenced, BIOS bug.")) {
-		fwts_failed(fw, LOG_LEVEL_HIGH, "PCIInterruptLink", "%s", line);
-		fwts_tag_failed(fw, FWTS_TAG_BIOS_IRQ);
-		fwts_log_info_verbatum(fw, "%s", line);
-	}
+	if (instance == -1)
+		*num = '\0';
+	else
+		snprintf(num, sizeof(num), "%d", instance);
 
-	if (strstr(line, "*** Warning Inconsistent FADT length") &&
-	    strstr(line, "using FADT V1.0 portion of table")) {
-		fwts_failed(fw, LOG_LEVEL_HIGH, "FADTRevsion",
-			"FADT table claims to be of higher revision than it is.");
-		fwts_tag_failed(fw, FWTS_TAG_ACPI_INVALID_TABLE);
-		fwts_log_info_verbatum(fw, "%s", line);
-	}
+	fwts_log_info(fw,
+		"Table %4.4s%s, OEM %6.6s, created with %4.4s (%s) compiler.",
+		header->signature, num, header->oem_id, header->creator_id, compiler);
 
-	if (strstr(line, "thermal_get_trip_point: Invalid active threshold")) {
-		fwts_failed(fw, LOG_LEVEL_CRITICAL, "_AC0TripPoint",
-			"_AC0 thermal trip point is invalid.");
-		fwts_tag_failed(fw, FWTS_TAG_ACPI_THERMAL);
-		fwts_log_info_verbatum(fw, "%s", line);
-	}
+	return FWTS_OK;
+}
 
-	if (strstr(line, "MMCONFIG has no entries")) {
-		fwts_failed(fw, LOG_LEVEL_HIGH, "MCFGNoEntries",
-			"The MCFG table has no entries!");
-		fwts_tag_failed(fw, FWTS_TAG_ACPI_INVALID_TABLE);
-		fwts_log_info_verbatum(fw, "%s", line);
-	}
+static int acpiinfo_test1(fwts_framework *fw)
+{
+	char *str;
+
+	if (((str = fwts_get("/sys/module/acpi/parameters/acpica_version")) == NULL) &&
+	    ((str = fwts_get("/proc/acpi/info")) == NULL))
+                fwts_log_info(fw,
+			"Cannot get ACPI version info from "
+			"/sys/module/acpi/parameters/acpica_version or /proc/acpi/info");
+        else {
+		int version;
+		int yearmonth;
+
+                fwts_chop_newline(str);
+
+		sscanf(str, "%6d", &yearmonth);
+
+		if (yearmonth > 201110) {
+			version = 5;
+		} else if (yearmonth > 200906) {
+			version = 4;
+		} else if (yearmonth > 200505) {
+			version = 3;
+		} else {
+			version = 2;
+		}
 
-	if (strstr(line, "MMCONFIG not in low 4GB of memory")) {
-		fwts_failed(fw, LOG_LEVEL_MEDIUM, "MCFGEntriesTooHigh",
-			"The MCFG table entries are not in the lower 4Gb of RAM.");
-		fwts_tag_failed(fw, FWTS_TAG_BIOS_MMCONFIG);
-		fwts_log_info_verbatum(fw, "%s", line);
-	}
+                fwts_log_info(fw, "Kernel ACPICA driver version: %s, supports ACPI %d.0", str, version);
+                free(str);
+        }
 
-	if (strstr(line, "pcie_portdrv_probe->Dev") &&
-	    strstr(line, "has invalid IRQ. Check vendor BIOS")) {
-		fwts_failed(fw, LOG_LEVEL_HIGH, "PCIExpressInvalidIRQ",
-			"PCI Express port driver reports an invalid IRQ.");
-		fwts_tag_failed(fw, FWTS_TAG_BIOS_IRQ);
-		fwts_log_info_verbatum(fw, "%s", line);
-	}
+	fwts_infoonly(fw);
 
-	if (strstr(line, "OCHI: BIOS handoff failed (BIOS bug")) {
-		fwts_failed(fw, LOG_LEVEL_MEDIUM, "OHCIEmulation",
-			"OHCI BIOS emulation handoff failed.");
-		fwts_tag_failed(fw, FWTS_TAG_BIOS);
-		fwts_log_info_verbatum(fw, "%s", line);
-		fwts_advice(fw,
-			"Generally this means that the EHCI driver was unable "
-			"to take control of the USB controller away from the "
-			"BIOS. Disabling USB legacy mode in the BIOS may help.");
-	}
-	if (strstr(line, "EHCI: BIOS handoff failed (BIOS bug")) {
-		fwts_failed(fw, LOG_LEVEL_MEDIUM, "EHCIEmulation",
-			"EHCI BIOS emulation handoff failed.");
-		fwts_tag_failed(fw, FWTS_TAG_BIOS);
-		fwts_log_info_verbatum(fw, "%s", line);
-		fwts_advice(fw,
-			"Generally this means that the EHCI driver was unable "
-			"to take control of the USB controller away from the "
-			"BIOS. Disabling USB legacy mode in the BIOS may help.");
-	}
+	return FWTS_OK;
 }
 
-static fwts_list *klog;
-
-static int acpiinfo_init(fwts_framework *fw)
+static int acpiinfo_test2(fwts_framework *fw)
 {
-	if (fw->klog)
-		klog = fwts_file_open_and_read(fw->klog);
-	else
-		klog = fwts_klog_read();
+	fwts_acpi_table_info *table;
+	fwts_acpi_table_header *header;
 
-	if (klog == NULL) {
-		fwts_log_error(fw, "Cannot read kernel log.");
+	if (fwts_acpi_find_table(fw, "FACP", 0, &table) != FWTS_OK)
 		return FWTS_ERROR;
-	}
-	return FWTS_OK;
-}
 
-static int acpiinfo_deinit(fwts_framework *fw)
-{
-	FWTS_UNUSED(fw);
+	if (table == NULL || table->data == NULL)
+		return FWTS_ERROR;
+
+	header = (fwts_acpi_table_header *)table->data;
 
-	fwts_klog_free(klog);
+	fwts_log_info(fw,
+		"FACP ACPI Version: %d.0\n", header->revision);
+
+	fwts_infoonly(fw);
 
 	return FWTS_OK;
 }
 
-static int acpiinfo_test1(fwts_framework *fw)
+static int acpiinfo_test3(fwts_framework *fw)
 {
-	int errors = 0;
+	int i;
 
 	fwts_log_info(fw,
-		"This test checks the output of the in-kernel ACPI CA against "
-		"common error messages that indicate a bad interaction with "
-		"the bios, including those that point at AML syntax errors.");
+		"Determine the compiler used to generate the ACPI AML in the DSDT and SSDT.");
 
-	if (fwts_klog_scan(fw, klog, acpiinfo_check, NULL, NULL, &errors)) {
-		fwts_log_error(fw, "failed to scan kernel log.");
-		return FWTS_ERROR;
+	acpiinfo_compiled_by(fw, "DSDT", -1);
+
+	for (i = 0; i < 32 ; i++) {
+		/* If we can't fetch the Nth SSDT, we've reached the end */
+		if (acpiinfo_compiled_by(fw, "SSDT", i) != FWTS_OK)
+			break;
 	}
 
-	if (errors > 0)
-		fwts_log_info(fw, "Found %d errors in kernel log.", errors);
-	else
-		fwts_passed(fw, "Found no errors in kernel log.");
+	fwts_infoonly(fw);
 
 	return FWTS_OK;
 }
 
 static fwts_framework_minor_test acpiinfo_tests[] = {
-	{ acpiinfo_test1, "General ACPI information check." },
+	{ acpiinfo_test1, "Determine Kernel ACPI version." },
+	{ acpiinfo_test2, "Determine machines ACPI version." },
+	{ acpiinfo_test3, "Determine AML compiler." },
 	{ NULL, NULL }
 };
 
 static fwts_framework_ops acpiinfo_ops = {
 	.description = "General ACPI information check.",
-	.init        = acpiinfo_init,
-	.deinit      = acpiinfo_deinit,
 	.minor_tests = acpiinfo_tests
 };