qemu/tests/bios-tables-test.c
<<
>>
Prefs
   1/*
   2 * Boot order test cases.
   3 *
   4 * Copyright (c) 2013 Red Hat Inc.
   5 *
   6 * Authors:
   7 *  Michael S. Tsirkin <mst@redhat.com>,
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10 * See the COPYING file in the top-level directory.
  11 */
  12
  13#include "qemu/osdep.h"
  14#include <glib/gstdio.h>
  15#include "qemu-common.h"
  16#include "libqtest.h"
  17#include "hw/acpi/acpi-defs.h"
  18#include "hw/smbios/smbios.h"
  19#include "qemu/bitmap.h"
  20#include "boot-sector.h"
  21
  22#define MACHINE_PC "pc"
  23#define MACHINE_Q35 "q35"
  24
  25#define ACPI_REBUILD_EXPECTED_AML "TEST_ACPI_REBUILD_AML"
  26
  27/* DSDT and SSDTs format */
  28typedef struct {
  29    AcpiTableHeader header;
  30    gchar *aml;            /* aml bytecode from guest */
  31    gsize aml_len;
  32    gchar *aml_file;
  33    gchar *asl;            /* asl code generated from aml */
  34    gsize asl_len;
  35    gchar *asl_file;
  36    bool tmp_files_retain;   /* do not delete the temp asl/aml */
  37} QEMU_PACKED AcpiSdtTable;
  38
  39typedef struct {
  40    const char *machine;
  41    const char *variant;
  42    uint32_t rsdp_addr;
  43    AcpiRsdpDescriptor rsdp_table;
  44    AcpiRsdtDescriptorRev1 rsdt_table;
  45    AcpiFadtDescriptorRev1 fadt_table;
  46    AcpiFacsDescriptorRev1 facs_table;
  47    uint32_t *rsdt_tables_addr;
  48    int rsdt_tables_nr;
  49    GArray *tables;
  50    uint32_t smbios_ep_addr;
  51    struct smbios_21_entry_point smbios_ep_table;
  52    uint8_t *required_struct_types;
  53    int required_struct_types_len;
  54} test_data;
  55
  56#define ACPI_READ_FIELD(field, addr)           \
  57    do {                                       \
  58        switch (sizeof(field)) {               \
  59        case 1:                                \
  60            field = readb(addr);               \
  61            break;                             \
  62        case 2:                                \
  63            field = readw(addr);               \
  64            break;                             \
  65        case 4:                                \
  66            field = readl(addr);               \
  67            break;                             \
  68        case 8:                                \
  69            field = readq(addr);               \
  70            break;                             \
  71        default:                               \
  72            g_assert(false);                   \
  73        }                                      \
  74        addr += sizeof(field);                  \
  75    } while (0);
  76
  77#define ACPI_READ_ARRAY_PTR(arr, length, addr)  \
  78    do {                                        \
  79        int idx;                                \
  80        for (idx = 0; idx < length; ++idx) {    \
  81            ACPI_READ_FIELD(arr[idx], addr);    \
  82        }                                       \
  83    } while (0);
  84
  85#define ACPI_READ_ARRAY(arr, addr)                               \
  86    ACPI_READ_ARRAY_PTR(arr, sizeof(arr)/sizeof(arr[0]), addr)
  87
  88#define ACPI_READ_TABLE_HEADER(table, addr)                      \
  89    do {                                                         \
  90        ACPI_READ_FIELD((table)->signature, addr);               \
  91        ACPI_READ_FIELD((table)->length, addr);                  \
  92        ACPI_READ_FIELD((table)->revision, addr);                \
  93        ACPI_READ_FIELD((table)->checksum, addr);                \
  94        ACPI_READ_ARRAY((table)->oem_id, addr);                  \
  95        ACPI_READ_ARRAY((table)->oem_table_id, addr);            \
  96        ACPI_READ_FIELD((table)->oem_revision, addr);            \
  97        ACPI_READ_ARRAY((table)->asl_compiler_id, addr);         \
  98        ACPI_READ_FIELD((table)->asl_compiler_revision, addr);   \
  99    } while (0);
 100
 101#define ACPI_ASSERT_CMP(actual, expected) do { \
 102    uint32_t ACPI_ASSERT_CMP_le = cpu_to_le32(actual); \
 103    char ACPI_ASSERT_CMP_str[5] = {}; \
 104    memcpy(ACPI_ASSERT_CMP_str, &ACPI_ASSERT_CMP_le, 4); \
 105    g_assert_cmpstr(ACPI_ASSERT_CMP_str, ==, expected); \
 106} while (0)
 107
 108#define ACPI_ASSERT_CMP64(actual, expected) do { \
 109    uint64_t ACPI_ASSERT_CMP_le = cpu_to_le64(actual); \
 110    char ACPI_ASSERT_CMP_str[9] = {}; \
 111    memcpy(ACPI_ASSERT_CMP_str, &ACPI_ASSERT_CMP_le, 8); \
 112    g_assert_cmpstr(ACPI_ASSERT_CMP_str, ==, expected); \
 113} while (0)
 114
 115static char disk[] = "tests/acpi-test-disk-XXXXXX";
 116static const char *data_dir = "tests/acpi-test-data";
 117#ifdef CONFIG_IASL
 118static const char *iasl = stringify(CONFIG_IASL);
 119#else
 120static const char *iasl;
 121#endif
 122
 123static void free_test_data(test_data *data)
 124{
 125    AcpiSdtTable *temp;
 126    int i;
 127
 128    g_free(data->rsdt_tables_addr);
 129
 130    for (i = 0; i < data->tables->len; ++i) {
 131        temp = &g_array_index(data->tables, AcpiSdtTable, i);
 132        g_free(temp->aml);
 133        if (temp->aml_file &&
 134            !temp->tmp_files_retain &&
 135            g_strstr_len(temp->aml_file, -1, "aml-")) {
 136            unlink(temp->aml_file);
 137        }
 138        g_free(temp->aml_file);
 139        g_free(temp->asl);
 140        if (temp->asl_file &&
 141            !temp->tmp_files_retain) {
 142            unlink(temp->asl_file);
 143        }
 144        g_free(temp->asl_file);
 145    }
 146
 147    g_array_free(data->tables, false);
 148}
 149
 150static uint8_t acpi_checksum(const uint8_t *data, int len)
 151{
 152    int i;
 153    uint8_t sum = 0;
 154
 155    for (i = 0; i < len; i++) {
 156        sum += data[i];
 157    }
 158
 159    return sum;
 160}
 161
 162static void test_acpi_rsdp_address(test_data *data)
 163{
 164    uint32_t off;
 165
 166    /* OK, now find RSDP */
 167    for (off = 0xf0000; off < 0x100000; off += 0x10) {
 168        uint8_t sig[] = "RSD PTR ";
 169        int i;
 170
 171        for (i = 0; i < sizeof sig - 1; ++i) {
 172            sig[i] = readb(off + i);
 173        }
 174
 175        if (!memcmp(sig, "RSD PTR ", sizeof sig)) {
 176            break;
 177        }
 178    }
 179
 180    g_assert_cmphex(off, <, 0x100000);
 181    data->rsdp_addr = off;
 182}
 183
 184static void test_acpi_rsdp_table(test_data *data)
 185{
 186    AcpiRsdpDescriptor *rsdp_table = &data->rsdp_table;
 187    uint32_t addr = data->rsdp_addr;
 188
 189    ACPI_READ_FIELD(rsdp_table->signature, addr);
 190    ACPI_ASSERT_CMP64(rsdp_table->signature, "RSD PTR ");
 191
 192    ACPI_READ_FIELD(rsdp_table->checksum, addr);
 193    ACPI_READ_ARRAY(rsdp_table->oem_id, addr);
 194    ACPI_READ_FIELD(rsdp_table->revision, addr);
 195    ACPI_READ_FIELD(rsdp_table->rsdt_physical_address, addr);
 196    ACPI_READ_FIELD(rsdp_table->length, addr);
 197
 198    /* rsdp checksum is not for the whole table, but for the first 20 bytes */
 199    g_assert(!acpi_checksum((uint8_t *)rsdp_table, 20));
 200}
 201
 202static void test_acpi_rsdt_table(test_data *data)
 203{
 204    AcpiRsdtDescriptorRev1 *rsdt_table = &data->rsdt_table;
 205    uint32_t addr = data->rsdp_table.rsdt_physical_address;
 206    uint32_t *tables;
 207    int tables_nr;
 208    uint8_t checksum;
 209
 210    /* read the header */
 211    ACPI_READ_TABLE_HEADER(rsdt_table, addr);
 212    ACPI_ASSERT_CMP(rsdt_table->signature, "RSDT");
 213
 214    /* compute the table entries in rsdt */
 215    tables_nr = (rsdt_table->length - sizeof(AcpiRsdtDescriptorRev1)) /
 216                sizeof(uint32_t);
 217    g_assert_cmpint(tables_nr, >, 0);
 218
 219    /* get the addresses of the tables pointed by rsdt */
 220    tables = g_new0(uint32_t, tables_nr);
 221    ACPI_READ_ARRAY_PTR(tables, tables_nr, addr);
 222
 223    checksum = acpi_checksum((uint8_t *)rsdt_table, rsdt_table->length) +
 224               acpi_checksum((uint8_t *)tables, tables_nr * sizeof(uint32_t));
 225    g_assert(!checksum);
 226
 227   /* SSDT tables after FADT */
 228    data->rsdt_tables_addr = tables;
 229    data->rsdt_tables_nr = tables_nr;
 230}
 231
 232static void test_acpi_fadt_table(test_data *data)
 233{
 234    AcpiFadtDescriptorRev1 *fadt_table = &data->fadt_table;
 235    uint32_t addr;
 236
 237    /* FADT table comes first */
 238    addr = data->rsdt_tables_addr[0];
 239    ACPI_READ_TABLE_HEADER(fadt_table, addr);
 240
 241    ACPI_READ_FIELD(fadt_table->firmware_ctrl, addr);
 242    ACPI_READ_FIELD(fadt_table->dsdt, addr);
 243    ACPI_READ_FIELD(fadt_table->model, addr);
 244    ACPI_READ_FIELD(fadt_table->reserved1, addr);
 245    ACPI_READ_FIELD(fadt_table->sci_int, addr);
 246    ACPI_READ_FIELD(fadt_table->smi_cmd, addr);
 247    ACPI_READ_FIELD(fadt_table->acpi_enable, addr);
 248    ACPI_READ_FIELD(fadt_table->acpi_disable, addr);
 249    ACPI_READ_FIELD(fadt_table->S4bios_req, addr);
 250    ACPI_READ_FIELD(fadt_table->reserved2, addr);
 251    ACPI_READ_FIELD(fadt_table->pm1a_evt_blk, addr);
 252    ACPI_READ_FIELD(fadt_table->pm1b_evt_blk, addr);
 253    ACPI_READ_FIELD(fadt_table->pm1a_cnt_blk, addr);
 254    ACPI_READ_FIELD(fadt_table->pm1b_cnt_blk, addr);
 255    ACPI_READ_FIELD(fadt_table->pm2_cnt_blk, addr);
 256    ACPI_READ_FIELD(fadt_table->pm_tmr_blk, addr);
 257    ACPI_READ_FIELD(fadt_table->gpe0_blk, addr);
 258    ACPI_READ_FIELD(fadt_table->gpe1_blk, addr);
 259    ACPI_READ_FIELD(fadt_table->pm1_evt_len, addr);
 260    ACPI_READ_FIELD(fadt_table->pm1_cnt_len, addr);
 261    ACPI_READ_FIELD(fadt_table->pm2_cnt_len, addr);
 262    ACPI_READ_FIELD(fadt_table->pm_tmr_len, addr);
 263    ACPI_READ_FIELD(fadt_table->gpe0_blk_len, addr);
 264    ACPI_READ_FIELD(fadt_table->gpe1_blk_len, addr);
 265    ACPI_READ_FIELD(fadt_table->gpe1_base, addr);
 266    ACPI_READ_FIELD(fadt_table->reserved3, addr);
 267    ACPI_READ_FIELD(fadt_table->plvl2_lat, addr);
 268    ACPI_READ_FIELD(fadt_table->plvl3_lat, addr);
 269    ACPI_READ_FIELD(fadt_table->flush_size, addr);
 270    ACPI_READ_FIELD(fadt_table->flush_stride, addr);
 271    ACPI_READ_FIELD(fadt_table->duty_offset, addr);
 272    ACPI_READ_FIELD(fadt_table->duty_width, addr);
 273    ACPI_READ_FIELD(fadt_table->day_alrm, addr);
 274    ACPI_READ_FIELD(fadt_table->mon_alrm, addr);
 275    ACPI_READ_FIELD(fadt_table->century, addr);
 276    ACPI_READ_FIELD(fadt_table->reserved4, addr);
 277    ACPI_READ_FIELD(fadt_table->reserved4a, addr);
 278    ACPI_READ_FIELD(fadt_table->reserved4b, addr);
 279    ACPI_READ_FIELD(fadt_table->flags, addr);
 280
 281    ACPI_ASSERT_CMP(fadt_table->signature, "FACP");
 282    g_assert(!acpi_checksum((uint8_t *)fadt_table, fadt_table->length));
 283}
 284
 285static void test_acpi_facs_table(test_data *data)
 286{
 287    AcpiFacsDescriptorRev1 *facs_table = &data->facs_table;
 288    uint32_t addr = data->fadt_table.firmware_ctrl;
 289
 290    ACPI_READ_FIELD(facs_table->signature, addr);
 291    ACPI_READ_FIELD(facs_table->length, addr);
 292    ACPI_READ_FIELD(facs_table->hardware_signature, addr);
 293    ACPI_READ_FIELD(facs_table->firmware_waking_vector, addr);
 294    ACPI_READ_FIELD(facs_table->global_lock, addr);
 295    ACPI_READ_FIELD(facs_table->flags, addr);
 296    ACPI_READ_ARRAY(facs_table->resverved3, addr);
 297
 298    ACPI_ASSERT_CMP(facs_table->signature, "FACS");
 299}
 300
 301static void test_dst_table(AcpiSdtTable *sdt_table, uint32_t addr)
 302{
 303    uint8_t checksum;
 304
 305    ACPI_READ_TABLE_HEADER(&sdt_table->header, addr);
 306
 307    sdt_table->aml_len = sdt_table->header.length - sizeof(AcpiTableHeader);
 308    sdt_table->aml = g_malloc0(sdt_table->aml_len);
 309    ACPI_READ_ARRAY_PTR(sdt_table->aml, sdt_table->aml_len, addr);
 310
 311    checksum = acpi_checksum((uint8_t *)sdt_table, sizeof(AcpiTableHeader)) +
 312               acpi_checksum((uint8_t *)sdt_table->aml, sdt_table->aml_len);
 313    g_assert(!checksum);
 314}
 315
 316static void test_acpi_dsdt_table(test_data *data)
 317{
 318    AcpiSdtTable dsdt_table;
 319    uint32_t addr = data->fadt_table.dsdt;
 320
 321    memset(&dsdt_table, 0, sizeof(dsdt_table));
 322    data->tables = g_array_new(false, true, sizeof(AcpiSdtTable));
 323
 324    test_dst_table(&dsdt_table, addr);
 325    ACPI_ASSERT_CMP(dsdt_table.header.signature, "DSDT");
 326
 327    /* Place DSDT first */
 328    g_array_append_val(data->tables, dsdt_table);
 329}
 330
 331static void test_acpi_tables(test_data *data)
 332{
 333    int tables_nr = data->rsdt_tables_nr - 1; /* fadt is first */
 334    int i;
 335
 336    for (i = 0; i < tables_nr; i++) {
 337        AcpiSdtTable ssdt_table;
 338
 339        memset(&ssdt_table, 0, sizeof(ssdt_table));
 340        uint32_t addr = data->rsdt_tables_addr[i + 1]; /* fadt is first */
 341        test_dst_table(&ssdt_table, addr);
 342        g_array_append_val(data->tables, ssdt_table);
 343    }
 344}
 345
 346static void dump_aml_files(test_data *data, bool rebuild)
 347{
 348    AcpiSdtTable *sdt;
 349    GError *error = NULL;
 350    gchar *aml_file = NULL;
 351    gint fd;
 352    ssize_t ret;
 353    int i;
 354
 355    for (i = 0; i < data->tables->len; ++i) {
 356        const char *ext = data->variant ? data->variant : "";
 357        sdt = &g_array_index(data->tables, AcpiSdtTable, i);
 358        g_assert(sdt->aml);
 359
 360        if (rebuild) {
 361            uint32_t signature = cpu_to_le32(sdt->header.signature);
 362            aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine,
 363                                       (gchar *)&signature, ext);
 364            fd = g_open(aml_file, O_WRONLY|O_TRUNC|O_CREAT,
 365                        S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
 366        } else {
 367            fd = g_file_open_tmp("aml-XXXXXX", &sdt->aml_file, &error);
 368            g_assert_no_error(error);
 369        }
 370        g_assert(fd >= 0);
 371
 372        ret = qemu_write_full(fd, sdt, sizeof(AcpiTableHeader));
 373        g_assert(ret == sizeof(AcpiTableHeader));
 374        ret = qemu_write_full(fd, sdt->aml, sdt->aml_len);
 375        g_assert(ret == sdt->aml_len);
 376
 377        close(fd);
 378
 379        g_free(aml_file);
 380    }
 381}
 382
 383static bool compare_signature(AcpiSdtTable *sdt, const char *signature)
 384{
 385   return !memcmp(&sdt->header.signature, signature, 4);
 386}
 387
 388static bool load_asl(GArray *sdts, AcpiSdtTable *sdt)
 389{
 390    AcpiSdtTable *temp;
 391    GError *error = NULL;
 392    GString *command_line = g_string_new(iasl);
 393    gint fd;
 394    gchar *out, *out_err;
 395    gboolean ret;
 396    int i;
 397
 398    fd = g_file_open_tmp("asl-XXXXXX.dsl", &sdt->asl_file, &error);
 399    g_assert_no_error(error);
 400    close(fd);
 401
 402    /* build command line */
 403    g_string_append_printf(command_line, " -p %s ", sdt->asl_file);
 404    if (compare_signature(sdt, "DSDT") ||
 405        compare_signature(sdt, "SSDT")) {
 406        for (i = 0; i < sdts->len; ++i) {
 407            temp = &g_array_index(sdts, AcpiSdtTable, i);
 408            if (compare_signature(temp, "DSDT") ||
 409                compare_signature(temp, "SSDT")) {
 410                g_string_append_printf(command_line, "-e %s ", temp->aml_file);
 411            }
 412        }
 413    }
 414    g_string_append_printf(command_line, "-d %s", sdt->aml_file);
 415
 416    /* pass 'out' and 'out_err' in order to be redirected */
 417    ret = g_spawn_command_line_sync(command_line->str, &out, &out_err, NULL, &error);
 418    g_assert_no_error(error);
 419    if (ret) {
 420        ret = g_file_get_contents(sdt->asl_file, (gchar **)&sdt->asl,
 421                                  &sdt->asl_len, &error);
 422        g_assert(ret);
 423        g_assert_no_error(error);
 424        ret = (sdt->asl_len > 0);
 425    }
 426
 427    g_free(out);
 428    g_free(out_err);
 429    g_string_free(command_line, true);
 430
 431    return !ret;
 432}
 433
 434#define COMMENT_END "*/"
 435#define DEF_BLOCK "DefinitionBlock ("
 436#define BLOCK_NAME_END ","
 437
 438static GString *normalize_asl(gchar *asl_code)
 439{
 440    GString *asl = g_string_new(asl_code);
 441    gchar *comment, *block_name;
 442
 443    /* strip comments (different generation days) */
 444    comment = g_strstr_len(asl->str, asl->len, COMMENT_END);
 445    if (comment) {
 446        comment += strlen(COMMENT_END);
 447        while (*comment == '\n') {
 448            comment++;
 449        }
 450        asl = g_string_erase(asl, 0, comment - asl->str);
 451    }
 452
 453    /* strip def block name (it has file path in it) */
 454    if (g_str_has_prefix(asl->str, DEF_BLOCK)) {
 455        block_name = g_strstr_len(asl->str, asl->len, BLOCK_NAME_END);
 456        g_assert(block_name);
 457        asl = g_string_erase(asl, 0,
 458                             block_name + sizeof(BLOCK_NAME_END) - asl->str);
 459    }
 460
 461    return asl;
 462}
 463
 464static GArray *load_expected_aml(test_data *data)
 465{
 466    int i;
 467    AcpiSdtTable *sdt;
 468    GError *error = NULL;
 469    gboolean ret;
 470
 471    GArray *exp_tables = g_array_new(false, true, sizeof(AcpiSdtTable));
 472    for (i = 0; i < data->tables->len; ++i) {
 473        AcpiSdtTable exp_sdt;
 474        uint32_t signature;
 475        gchar *aml_file = NULL;
 476        const char *ext = data->variant ? data->variant : "";
 477
 478        sdt = &g_array_index(data->tables, AcpiSdtTable, i);
 479
 480        memset(&exp_sdt, 0, sizeof(exp_sdt));
 481        exp_sdt.header.signature = sdt->header.signature;
 482
 483        signature = cpu_to_le32(sdt->header.signature);
 484
 485try_again:
 486        aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine,
 487                                   (gchar *)&signature, ext);
 488        if (getenv("V")) {
 489            fprintf(stderr, "\nLooking for expected file '%s'\n", aml_file);
 490        }
 491        if (g_file_test(aml_file, G_FILE_TEST_EXISTS)) {
 492            exp_sdt.aml_file = aml_file;
 493        } else if (*ext != '\0') {
 494            /* try fallback to generic (extention less) expected file */
 495            ext = "";
 496            g_free(aml_file);
 497            goto try_again;
 498        }
 499        g_assert(exp_sdt.aml_file);
 500        if (getenv("V")) {
 501            fprintf(stderr, "\nUsing expected file '%s'\n", aml_file);
 502        }
 503        ret = g_file_get_contents(aml_file, &exp_sdt.aml,
 504                                  &exp_sdt.aml_len, &error);
 505        g_assert(ret);
 506        g_assert_no_error(error);
 507        g_assert(exp_sdt.aml);
 508        g_assert(exp_sdt.aml_len);
 509
 510        g_array_append_val(exp_tables, exp_sdt);
 511    }
 512
 513    return exp_tables;
 514}
 515
 516static void test_acpi_asl(test_data *data)
 517{
 518    int i;
 519    AcpiSdtTable *sdt, *exp_sdt;
 520    test_data exp_data;
 521    gboolean exp_err, err;
 522
 523    memset(&exp_data, 0, sizeof(exp_data));
 524    exp_data.tables = load_expected_aml(data);
 525    dump_aml_files(data, false);
 526    for (i = 0; i < data->tables->len; ++i) {
 527        GString *asl, *exp_asl;
 528
 529        sdt = &g_array_index(data->tables, AcpiSdtTable, i);
 530        exp_sdt = &g_array_index(exp_data.tables, AcpiSdtTable, i);
 531
 532        err = load_asl(data->tables, sdt);
 533        asl = normalize_asl(sdt->asl);
 534
 535        exp_err = load_asl(exp_data.tables, exp_sdt);
 536        exp_asl = normalize_asl(exp_sdt->asl);
 537
 538        /* TODO: check for warnings */
 539        g_assert(!err || exp_err);
 540
 541        if (g_strcmp0(asl->str, exp_asl->str)) {
 542            if (exp_err) {
 543                fprintf(stderr,
 544                        "Warning! iasl couldn't parse the expected aml\n");
 545            } else {
 546                uint32_t signature = cpu_to_le32(exp_sdt->header.signature);
 547                sdt->tmp_files_retain = true;
 548                exp_sdt->tmp_files_retain = true;
 549                fprintf(stderr,
 550                        "acpi-test: Warning! %.4s mismatch. "
 551                        "Actual [asl:%s, aml:%s], Expected [asl:%s, aml:%s].\n",
 552                        (gchar *)&signature,
 553                        sdt->asl_file, sdt->aml_file,
 554                        exp_sdt->asl_file, exp_sdt->aml_file);
 555                if (getenv("V")) {
 556                    const char *diff_cmd = getenv("DIFF");
 557                    if (diff_cmd) {
 558                        int ret G_GNUC_UNUSED;
 559                        char *diff = g_strdup_printf("%s %s %s", diff_cmd,
 560                            exp_sdt->asl_file, sdt->asl_file);
 561                        ret = system(diff) ;
 562                        g_free(diff);
 563                    } else {
 564                        fprintf(stderr, "acpi-test: Warning. not showing "
 565                            "difference since no diff utility is specified. "
 566                            "Set 'DIFF' environment variable to a preferred "
 567                            "diff utility and run 'make V=1 check' again to "
 568                            "see ASL difference.");
 569                    }
 570                }
 571          }
 572        }
 573        g_string_free(asl, true);
 574        g_string_free(exp_asl, true);
 575    }
 576
 577    free_test_data(&exp_data);
 578}
 579
 580static bool smbios_ep_table_ok(test_data *data)
 581{
 582    struct smbios_21_entry_point *ep_table = &data->smbios_ep_table;
 583    uint32_t addr = data->smbios_ep_addr;
 584
 585    ACPI_READ_ARRAY(ep_table->anchor_string, addr);
 586    if (memcmp(ep_table->anchor_string, "_SM_", 4)) {
 587        return false;
 588    }
 589    ACPI_READ_FIELD(ep_table->checksum, addr);
 590    ACPI_READ_FIELD(ep_table->length, addr);
 591    ACPI_READ_FIELD(ep_table->smbios_major_version, addr);
 592    ACPI_READ_FIELD(ep_table->smbios_minor_version, addr);
 593    ACPI_READ_FIELD(ep_table->max_structure_size, addr);
 594    ACPI_READ_FIELD(ep_table->entry_point_revision, addr);
 595    ACPI_READ_ARRAY(ep_table->formatted_area, addr);
 596    ACPI_READ_ARRAY(ep_table->intermediate_anchor_string, addr);
 597    if (memcmp(ep_table->intermediate_anchor_string, "_DMI_", 5)) {
 598        return false;
 599    }
 600    ACPI_READ_FIELD(ep_table->intermediate_checksum, addr);
 601    ACPI_READ_FIELD(ep_table->structure_table_length, addr);
 602    if (ep_table->structure_table_length == 0) {
 603        return false;
 604    }
 605    ACPI_READ_FIELD(ep_table->structure_table_address, addr);
 606    ACPI_READ_FIELD(ep_table->number_of_structures, addr);
 607    if (ep_table->number_of_structures == 0) {
 608        return false;
 609    }
 610    ACPI_READ_FIELD(ep_table->smbios_bcd_revision, addr);
 611    if (acpi_checksum((uint8_t *)ep_table, sizeof *ep_table) ||
 612        acpi_checksum((uint8_t *)ep_table + 0x10, sizeof *ep_table - 0x10)) {
 613        return false;
 614    }
 615    return true;
 616}
 617
 618static void test_smbios_entry_point(test_data *data)
 619{
 620    uint32_t off;
 621
 622    /* find smbios entry point structure */
 623    for (off = 0xf0000; off < 0x100000; off += 0x10) {
 624        uint8_t sig[] = "_SM_";
 625        int i;
 626
 627        for (i = 0; i < sizeof sig - 1; ++i) {
 628            sig[i] = readb(off + i);
 629        }
 630
 631        if (!memcmp(sig, "_SM_", sizeof sig)) {
 632            /* signature match, but is this a valid entry point? */
 633            data->smbios_ep_addr = off;
 634            if (smbios_ep_table_ok(data)) {
 635                break;
 636            }
 637        }
 638    }
 639
 640    g_assert_cmphex(off, <, 0x100000);
 641}
 642
 643static inline bool smbios_single_instance(uint8_t type)
 644{
 645    switch (type) {
 646    case 0:
 647    case 1:
 648    case 2:
 649    case 3:
 650    case 16:
 651    case 32:
 652    case 127:
 653        return true;
 654    default:
 655        return false;
 656    }
 657}
 658
 659static void test_smbios_structs(test_data *data)
 660{
 661    DECLARE_BITMAP(struct_bitmap, SMBIOS_MAX_TYPE+1) = { 0 };
 662    struct smbios_21_entry_point *ep_table = &data->smbios_ep_table;
 663    uint32_t addr = ep_table->structure_table_address;
 664    int i, len, max_len = 0;
 665    uint8_t type, prv, crt;
 666
 667    /* walk the smbios tables */
 668    for (i = 0; i < ep_table->number_of_structures; i++) {
 669
 670        /* grab type and formatted area length from struct header */
 671        type = readb(addr);
 672        g_assert_cmpuint(type, <=, SMBIOS_MAX_TYPE);
 673        len = readb(addr + 1);
 674
 675        /* single-instance structs must not have been encountered before */
 676        if (smbios_single_instance(type)) {
 677            g_assert(!test_bit(type, struct_bitmap));
 678        }
 679        set_bit(type, struct_bitmap);
 680
 681        /* seek to end of unformatted string area of this struct ("\0\0") */
 682        prv = crt = 1;
 683        while (prv || crt) {
 684            prv = crt;
 685            crt = readb(addr + len);
 686            len++;
 687        }
 688
 689        /* keep track of max. struct size */
 690        if (max_len < len) {
 691            max_len = len;
 692            g_assert_cmpuint(max_len, <=, ep_table->max_structure_size);
 693        }
 694
 695        /* start of next structure */
 696        addr += len;
 697    }
 698
 699    /* total table length and max struct size must match entry point values */
 700    g_assert_cmpuint(ep_table->structure_table_length, ==,
 701                     addr - ep_table->structure_table_address);
 702    g_assert_cmpuint(ep_table->max_structure_size, ==, max_len);
 703
 704    /* required struct types must all be present */
 705    for (i = 0; i < data->required_struct_types_len; i++) {
 706        g_assert(test_bit(data->required_struct_types[i], struct_bitmap));
 707    }
 708}
 709
 710static void test_acpi_one(const char *params, test_data *data)
 711{
 712    char *args;
 713
 714    /* Disable kernel irqchip to be able to override apic irq0. */
 715    args = g_strdup_printf("-machine %s,accel=%s,kernel-irqchip=off "
 716                           "-net none -display none %s "
 717                           "-drive id=hd0,if=none,file=%s,format=raw "
 718                           "-device ide-hd,drive=hd0 ",
 719                           data->machine, "kvm:tcg",
 720                           params ? params : "", disk);
 721
 722    qtest_start(args);
 723
 724    boot_sector_test();
 725
 726    test_acpi_rsdp_address(data);
 727    test_acpi_rsdp_table(data);
 728    test_acpi_rsdt_table(data);
 729    test_acpi_fadt_table(data);
 730    test_acpi_facs_table(data);
 731    test_acpi_dsdt_table(data);
 732    test_acpi_tables(data);
 733
 734    if (iasl) {
 735        if (getenv(ACPI_REBUILD_EXPECTED_AML)) {
 736            dump_aml_files(data, true);
 737        } else {
 738            test_acpi_asl(data);
 739        }
 740    }
 741
 742    test_smbios_entry_point(data);
 743    test_smbios_structs(data);
 744
 745    qtest_quit(global_qtest);
 746    g_free(args);
 747}
 748
 749static uint8_t base_required_struct_types[] = {
 750    0, 1, 3, 4, 16, 17, 19, 32, 127
 751};
 752
 753static void test_acpi_piix4_tcg(void)
 754{
 755    test_data data;
 756
 757    /* Supplying -machine accel argument overrides the default (qtest).
 758     * This is to make guest actually run.
 759     */
 760    memset(&data, 0, sizeof(data));
 761    data.machine = MACHINE_PC;
 762    data.required_struct_types = base_required_struct_types;
 763    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
 764    test_acpi_one(NULL, &data);
 765    free_test_data(&data);
 766}
 767
 768static void test_acpi_piix4_tcg_bridge(void)
 769{
 770    test_data data;
 771
 772    memset(&data, 0, sizeof(data));
 773    data.machine = MACHINE_PC;
 774    data.variant = ".bridge";
 775    data.required_struct_types = base_required_struct_types;
 776    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
 777    test_acpi_one("-device pci-bridge,chassis_nr=1", &data);
 778    free_test_data(&data);
 779}
 780
 781static void test_acpi_q35_tcg(void)
 782{
 783    test_data data;
 784
 785    memset(&data, 0, sizeof(data));
 786    data.machine = MACHINE_Q35;
 787    data.required_struct_types = base_required_struct_types;
 788    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
 789    test_acpi_one(NULL, &data);
 790    free_test_data(&data);
 791}
 792
 793static void test_acpi_q35_tcg_bridge(void)
 794{
 795    test_data data;
 796
 797    memset(&data, 0, sizeof(data));
 798    data.machine = MACHINE_Q35;
 799    data.variant = ".bridge";
 800    data.required_struct_types = base_required_struct_types;
 801    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
 802    test_acpi_one("-device pci-bridge,chassis_nr=1",
 803                  &data);
 804    free_test_data(&data);
 805}
 806
 807static void test_acpi_piix4_tcg_cphp(void)
 808{
 809    test_data data;
 810
 811    memset(&data, 0, sizeof(data));
 812    data.machine = MACHINE_PC;
 813    data.variant = ".cphp";
 814    test_acpi_one("-smp 2,cores=3,sockets=2,maxcpus=6"
 815                  " -numa node -numa node",
 816                  &data);
 817    free_test_data(&data);
 818}
 819
 820static void test_acpi_q35_tcg_cphp(void)
 821{
 822    test_data data;
 823
 824    memset(&data, 0, sizeof(data));
 825    data.machine = MACHINE_Q35;
 826    data.variant = ".cphp";
 827    test_acpi_one(" -smp 2,cores=3,sockets=2,maxcpus=6"
 828                  " -numa node -numa node",
 829                  &data);
 830    free_test_data(&data);
 831}
 832
 833static uint8_t ipmi_required_struct_types[] = {
 834    0, 1, 3, 4, 16, 17, 19, 32, 38, 127
 835};
 836
 837static void test_acpi_q35_tcg_ipmi(void)
 838{
 839    test_data data;
 840
 841    memset(&data, 0, sizeof(data));
 842    data.machine = MACHINE_Q35;
 843    data.variant = ".ipmibt";
 844    data.required_struct_types = ipmi_required_struct_types;
 845    data.required_struct_types_len = ARRAY_SIZE(ipmi_required_struct_types);
 846    test_acpi_one("-device ipmi-bmc-sim,id=bmc0"
 847                  " -device isa-ipmi-bt,bmc=bmc0",
 848                  &data);
 849    free_test_data(&data);
 850}
 851
 852static void test_acpi_piix4_tcg_ipmi(void)
 853{
 854    test_data data;
 855
 856    /* Supplying -machine accel argument overrides the default (qtest).
 857     * This is to make guest actually run.
 858     */
 859    memset(&data, 0, sizeof(data));
 860    data.machine = MACHINE_PC;
 861    data.variant = ".ipmikcs";
 862    data.required_struct_types = ipmi_required_struct_types;
 863    data.required_struct_types_len = ARRAY_SIZE(ipmi_required_struct_types);
 864    test_acpi_one("-device ipmi-bmc-sim,id=bmc0"
 865                  " -device isa-ipmi-kcs,irq=0,bmc=bmc0",
 866                  &data);
 867    free_test_data(&data);
 868}
 869
 870int main(int argc, char *argv[])
 871{
 872    const char *arch = qtest_get_arch();
 873    int ret;
 874
 875    ret = boot_sector_init(disk);
 876    if(ret)
 877        return ret;
 878
 879    g_test_init(&argc, &argv, NULL);
 880
 881    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
 882        qtest_add_func("acpi/piix4", test_acpi_piix4_tcg);
 883        qtest_add_func("acpi/piix4/bridge", test_acpi_piix4_tcg_bridge);
 884        qtest_add_func("acpi/q35", test_acpi_q35_tcg);
 885        qtest_add_func("acpi/q35/bridge", test_acpi_q35_tcg_bridge);
 886        qtest_add_func("acpi/piix4/ipmi", test_acpi_piix4_tcg_ipmi);
 887        qtest_add_func("acpi/q35/ipmi", test_acpi_q35_tcg_ipmi);
 888        qtest_add_func("acpi/piix4/cpuhp", test_acpi_piix4_tcg_cphp);
 889        qtest_add_func("acpi/q35/cpuhp", test_acpi_q35_tcg_cphp);
 890    }
 891    ret = g_test_run();
 892    boot_sector_cleanup(disk);
 893    return ret;
 894}
 895