qemu/tests/qtest/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/*
  14 * How to add or update the tests or commit changes that affect ACPI tables:
  15 * Contributor:
  16 * 1. add empty files for new tables, if any, under tests/data/acpi
  17 * 2. list any changed files in tests/qtest/bios-tables-test-allowed-diff.h
  18 * 3. commit the above *before* making changes that affect the tables
  19 *
  20 * Contributor or ACPI Maintainer (steps 4-7 need to be redone to resolve conflicts
  21 * in binary commit created in step 6):
  22 *
  23 * After 1-3 above tests will pass but ignore differences with the expected files.
  24 * You will also notice that tests/qtest/bios-tables-test-allowed-diff.h lists
  25 * a bunch of files. This is your hint that you need to do the below:
  26 * 4. Run
  27 *      make check V=1
  28 * this will produce a bunch of warnings about differences
  29 * beween actual and expected ACPI tables. If you have IASL installed,
  30 * they will also be disassembled so you can look at the disassembled
  31 * output. If not - disassemble them yourself in any way you like.
  32 * Look at the differences - make sure they make sense and match what the
  33 * changes you are merging are supposed to do.
  34 * Save the changes, preferably in form of ASL diff for the commit log in
  35 * step 6.
  36 *
  37 * 5. From build directory, run:
  38 *      $(SRC_PATH)/tests/data/acpi/rebuild-expected-aml.sh
  39 * 6. Now commit any changes to the expected binary, include diff from step 4
  40 *    in commit log.
  41 *    Expected binary updates needs to be a separate patch from the code that
  42 *    introduces changes to ACPI tables. It lets the maintainer drop
  43 *    and regenerate binary updates in case of merge conflicts. Further, a code
  44 *    change is easily reviewable but a binary blob is not (without doing a
  45 *    disassembly).
  46 * 7. Before sending patches to the list (Contributor)
  47 *    or before doing a pull request (Maintainer), make sure
  48 *    tests/qtest/bios-tables-test-allowed-diff.h is empty - this will ensure
  49 *    following changes to ACPI tables will be noticed.
  50 *
  51 * The resulting patchset/pull request then looks like this:
  52 * - patch 1: list changed files in tests/qtest/bios-tables-test-allowed-diff.h.
  53 * - patches 2 - n: real changes, may contain multiple patches.
  54 * - patch n + 1: update golden master binaries and empty
  55 *   tests/qtest/bios-tables-test-allowed-diff.h
  56 */
  57
  58#include "qemu/osdep.h"
  59#include <glib/gstdio.h>
  60#include "qemu-common.h"
  61#include "hw/firmware/smbios.h"
  62#include "qemu/bitmap.h"
  63#include "acpi-utils.h"
  64#include "boot-sector.h"
  65#include "tpm-emu.h"
  66#include "hw/acpi/tpm.h"
  67#include "qemu/cutils.h"
  68
  69#define MACHINE_PC "pc"
  70#define MACHINE_Q35 "q35"
  71
  72#define ACPI_REBUILD_EXPECTED_AML "TEST_ACPI_REBUILD_AML"
  73
  74#define OEM_ID             "TEST"
  75#define OEM_TABLE_ID       "OEM"
  76#define OEM_TEST_ARGS      "-machine x-oem-id="OEM_ID",x-oem-table-id="OEM_TABLE_ID
  77
  78typedef struct {
  79    bool tcg_only;
  80    const char *machine;
  81    const char *variant;
  82    const char *uefi_fl1;
  83    const char *uefi_fl2;
  84    const char *blkdev;
  85    const char *cd;
  86    const uint64_t ram_start;
  87    const uint64_t scan_len;
  88    uint64_t rsdp_addr;
  89    uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */];
  90    GArray *tables;
  91    uint32_t smbios_ep_addr;
  92    struct smbios_21_entry_point smbios_ep_table;
  93    uint16_t smbios_cpu_max_speed;
  94    uint16_t smbios_cpu_curr_speed;
  95    uint8_t *required_struct_types;
  96    int required_struct_types_len;
  97    QTestState *qts;
  98} test_data;
  99
 100static char disk[] = "tests/acpi-test-disk-XXXXXX";
 101static const char *data_dir = "tests/data/acpi";
 102#ifdef CONFIG_IASL
 103static const char *iasl = CONFIG_IASL;
 104#else
 105static const char *iasl;
 106#endif
 107
 108static bool compare_signature(const AcpiSdtTable *sdt, const char *signature)
 109{
 110   return !memcmp(sdt->aml, signature, 4);
 111}
 112
 113static void cleanup_table_descriptor(AcpiSdtTable *table)
 114{
 115    g_free(table->aml);
 116    if (table->aml_file &&
 117        !table->tmp_files_retain &&
 118        g_strstr_len(table->aml_file, -1, "aml-")) {
 119        unlink(table->aml_file);
 120    }
 121    g_free(table->aml_file);
 122    g_free(table->asl);
 123    if (table->asl_file &&
 124        !table->tmp_files_retain) {
 125        unlink(table->asl_file);
 126    }
 127    g_free(table->asl_file);
 128}
 129
 130static void free_test_data(test_data *data)
 131{
 132    int i;
 133
 134    if (!data->tables) {
 135        return;
 136    }
 137    for (i = 0; i < data->tables->len; ++i) {
 138        cleanup_table_descriptor(&g_array_index(data->tables, AcpiSdtTable, i));
 139    }
 140
 141    g_array_free(data->tables, true);
 142}
 143
 144static void test_acpi_rsdp_table(test_data *data)
 145{
 146    uint8_t *rsdp_table = data->rsdp_table;
 147
 148    acpi_fetch_rsdp_table(data->qts, data->rsdp_addr, rsdp_table);
 149
 150    switch (rsdp_table[15 /* Revision offset */]) {
 151    case 0: /* ACPI 1.0 RSDP */
 152        /* With rev 1, checksum is only for the first 20 bytes */
 153        g_assert(!acpi_calc_checksum(rsdp_table,  20));
 154        break;
 155    case 2: /* ACPI 2.0+ RSDP */
 156        /* With revision 2, we have 2 checksums */
 157        g_assert(!acpi_calc_checksum(rsdp_table, 20));
 158        g_assert(!acpi_calc_checksum(rsdp_table, 36));
 159        break;
 160    default:
 161        g_assert_not_reached();
 162    }
 163}
 164
 165static void test_acpi_rxsdt_table(test_data *data)
 166{
 167    const char *sig = "RSDT";
 168    AcpiSdtTable rsdt = {};
 169    int entry_size = 4;
 170    int addr_off = 16 /* RsdtAddress */;
 171    uint8_t *ent;
 172
 173    if (data->rsdp_table[15 /* Revision offset */] != 0) {
 174        addr_off = 24 /* XsdtAddress */;
 175        entry_size = 8;
 176        sig = "XSDT";
 177    }
 178    /* read [RX]SDT table */
 179    acpi_fetch_table(data->qts, &rsdt.aml, &rsdt.aml_len,
 180                     &data->rsdp_table[addr_off], entry_size, sig, true);
 181
 182    /* Load all tables and add to test list directly RSDT referenced tables */
 183    ACPI_FOREACH_RSDT_ENTRY(rsdt.aml, rsdt.aml_len, ent, entry_size) {
 184        AcpiSdtTable ssdt_table = {};
 185
 186        acpi_fetch_table(data->qts, &ssdt_table.aml, &ssdt_table.aml_len, ent,
 187                         entry_size, NULL, true);
 188        /* Add table to ASL test tables list */
 189        g_array_append_val(data->tables, ssdt_table);
 190    }
 191    cleanup_table_descriptor(&rsdt);
 192}
 193
 194static void test_acpi_fadt_table(test_data *data)
 195{
 196    /* FADT table is 1st */
 197    AcpiSdtTable table = g_array_index(data->tables, typeof(table), 0);
 198    uint8_t *fadt_aml = table.aml;
 199    uint32_t fadt_len = table.aml_len;
 200    uint32_t val;
 201    int dsdt_offset = 40 /* DSDT */;
 202    int dsdt_entry_size = 4;
 203
 204    g_assert(compare_signature(&table, "FACP"));
 205
 206    /* Since DSDT/FACS isn't in RSDT, add them to ASL test list manually */
 207    memcpy(&val, fadt_aml + 112 /* Flags */, 4);
 208    val = le32_to_cpu(val);
 209    if (!(val & 1UL << 20 /* HW_REDUCED_ACPI */)) {
 210        acpi_fetch_table(data->qts, &table.aml, &table.aml_len,
 211                         fadt_aml + 36 /* FIRMWARE_CTRL */, 4, "FACS", false);
 212        g_array_append_val(data->tables, table);
 213    }
 214
 215    memcpy(&val, fadt_aml + dsdt_offset, 4);
 216    val = le32_to_cpu(val);
 217    if (!val) {
 218        dsdt_offset = 140 /* X_DSDT */;
 219        dsdt_entry_size = 8;
 220    }
 221    acpi_fetch_table(data->qts, &table.aml, &table.aml_len,
 222                     fadt_aml + dsdt_offset, dsdt_entry_size, "DSDT", true);
 223    g_array_append_val(data->tables, table);
 224
 225    memset(fadt_aml + 36, 0, 4); /* sanitize FIRMWARE_CTRL ptr */
 226    memset(fadt_aml + 40, 0, 4); /* sanitize DSDT ptr */
 227    if (fadt_aml[8 /* FADT Major Version */] >= 3) {
 228        memset(fadt_aml + 132, 0, 8); /* sanitize X_FIRMWARE_CTRL ptr */
 229        memset(fadt_aml + 140, 0, 8); /* sanitize X_DSDT ptr */
 230    }
 231
 232    /* update checksum */
 233    fadt_aml[9 /* Checksum */] = 0;
 234    fadt_aml[9 /* Checksum */] -= acpi_calc_checksum(fadt_aml, fadt_len);
 235}
 236
 237static void dump_aml_files(test_data *data, bool rebuild)
 238{
 239    AcpiSdtTable *sdt;
 240    GError *error = NULL;
 241    gchar *aml_file = NULL;
 242    gint fd;
 243    ssize_t ret;
 244    int i;
 245
 246    for (i = 0; i < data->tables->len; ++i) {
 247        const char *ext = data->variant ? data->variant : "";
 248        sdt = &g_array_index(data->tables, AcpiSdtTable, i);
 249        g_assert(sdt->aml);
 250
 251        if (rebuild) {
 252            aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine,
 253                                       sdt->aml, ext);
 254            fd = g_open(aml_file, O_WRONLY|O_TRUNC|O_CREAT,
 255                        S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
 256            if (fd < 0) {
 257                perror(aml_file);
 258            }
 259            g_assert(fd >= 0);
 260        } else {
 261            fd = g_file_open_tmp("aml-XXXXXX", &sdt->aml_file, &error);
 262            g_assert_no_error(error);
 263        }
 264
 265        ret = qemu_write_full(fd, sdt->aml, sdt->aml_len);
 266        g_assert(ret == sdt->aml_len);
 267
 268        close(fd);
 269
 270        g_free(aml_file);
 271    }
 272}
 273
 274static bool load_asl(GArray *sdts, AcpiSdtTable *sdt)
 275{
 276    AcpiSdtTable *temp;
 277    GError *error = NULL;
 278    GString *command_line = g_string_new(iasl);
 279    gint fd;
 280    gchar *out, *out_err;
 281    gboolean ret;
 282    int i;
 283
 284    fd = g_file_open_tmp("asl-XXXXXX.dsl", &sdt->asl_file, &error);
 285    g_assert_no_error(error);
 286    close(fd);
 287
 288    /* build command line */
 289    g_string_append_printf(command_line, " -p %s ", sdt->asl_file);
 290    if (compare_signature(sdt, "DSDT") ||
 291        compare_signature(sdt, "SSDT")) {
 292        for (i = 0; i < sdts->len; ++i) {
 293            temp = &g_array_index(sdts, AcpiSdtTable, i);
 294            if (compare_signature(temp, "DSDT") ||
 295                compare_signature(temp, "SSDT")) {
 296                g_string_append_printf(command_line, "-e %s ", temp->aml_file);
 297            }
 298        }
 299    }
 300    g_string_append_printf(command_line, "-d %s", sdt->aml_file);
 301
 302    /* pass 'out' and 'out_err' in order to be redirected */
 303    ret = g_spawn_command_line_sync(command_line->str, &out, &out_err, NULL, &error);
 304    g_assert_no_error(error);
 305    if (ret) {
 306        ret = g_file_get_contents(sdt->asl_file, &sdt->asl,
 307                                  &sdt->asl_len, &error);
 308        g_assert(ret);
 309        g_assert_no_error(error);
 310        ret = (sdt->asl_len > 0);
 311    }
 312
 313    g_free(out);
 314    g_free(out_err);
 315    g_string_free(command_line, true);
 316
 317    return !ret;
 318}
 319
 320#define COMMENT_END "*/"
 321#define DEF_BLOCK "DefinitionBlock ("
 322#define BLOCK_NAME_END ","
 323
 324static GString *normalize_asl(gchar *asl_code)
 325{
 326    GString *asl = g_string_new(asl_code);
 327    gchar *comment, *block_name;
 328
 329    /* strip comments (different generation days) */
 330    comment = g_strstr_len(asl->str, asl->len, COMMENT_END);
 331    if (comment) {
 332        comment += strlen(COMMENT_END);
 333        while (*comment == '\n') {
 334            comment++;
 335        }
 336        asl = g_string_erase(asl, 0, comment - asl->str);
 337    }
 338
 339    /* strip def block name (it has file path in it) */
 340    if (g_str_has_prefix(asl->str, DEF_BLOCK)) {
 341        block_name = g_strstr_len(asl->str, asl->len, BLOCK_NAME_END);
 342        g_assert(block_name);
 343        asl = g_string_erase(asl, 0,
 344                             block_name + sizeof(BLOCK_NAME_END) - asl->str);
 345    }
 346
 347    return asl;
 348}
 349
 350static GArray *load_expected_aml(test_data *data)
 351{
 352    int i;
 353    AcpiSdtTable *sdt;
 354    GError *error = NULL;
 355    gboolean ret;
 356    gsize aml_len;
 357
 358    GArray *exp_tables = g_array_new(false, true, sizeof(AcpiSdtTable));
 359    if (getenv("V")) {
 360        fputc('\n', stderr);
 361    }
 362    for (i = 0; i < data->tables->len; ++i) {
 363        AcpiSdtTable exp_sdt;
 364        gchar *aml_file = NULL;
 365        const char *ext = data->variant ? data->variant : "";
 366
 367        sdt = &g_array_index(data->tables, AcpiSdtTable, i);
 368
 369        memset(&exp_sdt, 0, sizeof(exp_sdt));
 370
 371try_again:
 372        aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine,
 373                                   sdt->aml, ext);
 374        if (getenv("V")) {
 375            fprintf(stderr, "Looking for expected file '%s'\n", aml_file);
 376        }
 377        if (g_file_test(aml_file, G_FILE_TEST_EXISTS)) {
 378            exp_sdt.aml_file = aml_file;
 379        } else if (*ext != '\0') {
 380            /* try fallback to generic (extension less) expected file */
 381            ext = "";
 382            g_free(aml_file);
 383            goto try_again;
 384        }
 385        g_assert(exp_sdt.aml_file);
 386        if (getenv("V")) {
 387            fprintf(stderr, "Using expected file '%s'\n", aml_file);
 388        }
 389        ret = g_file_get_contents(aml_file, (gchar **)&exp_sdt.aml,
 390                                  &aml_len, &error);
 391        exp_sdt.aml_len = aml_len;
 392        g_assert(ret);
 393        g_assert_no_error(error);
 394        g_assert(exp_sdt.aml);
 395        if (!exp_sdt.aml_len) {
 396            fprintf(stderr, "Warning! zero length expected file '%s'\n",
 397                    aml_file);
 398        }
 399
 400        g_array_append_val(exp_tables, exp_sdt);
 401    }
 402
 403    return exp_tables;
 404}
 405
 406static bool test_acpi_find_diff_allowed(AcpiSdtTable *sdt)
 407{
 408    const gchar *allowed_diff_file[] = {
 409#include "bios-tables-test-allowed-diff.h"
 410        NULL
 411    };
 412    const gchar **f;
 413
 414    for (f = allowed_diff_file; *f; ++f) {
 415        if (!g_strcmp0(sdt->aml_file, *f)) {
 416            return true;
 417        }
 418    }
 419    return false;
 420}
 421
 422/* test the list of tables in @data->tables against reference tables */
 423static void test_acpi_asl(test_data *data)
 424{
 425    int i;
 426    AcpiSdtTable *sdt, *exp_sdt;
 427    test_data exp_data;
 428    gboolean exp_err, err, all_tables_match = true;
 429
 430    memset(&exp_data, 0, sizeof(exp_data));
 431    exp_data.tables = load_expected_aml(data);
 432    dump_aml_files(data, false);
 433    for (i = 0; i < data->tables->len; ++i) {
 434        GString *asl, *exp_asl;
 435
 436        sdt = &g_array_index(data->tables, AcpiSdtTable, i);
 437        exp_sdt = &g_array_index(exp_data.tables, AcpiSdtTable, i);
 438
 439        if (sdt->aml_len == exp_sdt->aml_len &&
 440            !memcmp(sdt->aml, exp_sdt->aml, sdt->aml_len)) {
 441            /* Identical table binaries: no need to disassemble. */
 442            continue;
 443        }
 444
 445        fprintf(stderr,
 446                "acpi-test: Warning! %.4s binary file mismatch. "
 447                "Actual [aml:%s], Expected [aml:%s].\n"
 448                "See source file tests/qtest/bios-tables-test.c "
 449                "for instructions on how to update expected files.\n",
 450                exp_sdt->aml, sdt->aml_file, exp_sdt->aml_file);
 451
 452        all_tables_match = all_tables_match &&
 453            test_acpi_find_diff_allowed(exp_sdt);
 454
 455        /*
 456         *  don't try to decompile if IASL isn't present, in this case user
 457         * will just 'get binary file mismatch' warnings and test failure
 458         */
 459        if (!iasl) {
 460            continue;
 461        }
 462
 463        err = load_asl(data->tables, sdt);
 464        asl = normalize_asl(sdt->asl);
 465
 466        exp_err = load_asl(exp_data.tables, exp_sdt);
 467        exp_asl = normalize_asl(exp_sdt->asl);
 468
 469        /* TODO: check for warnings */
 470        g_assert(!err || exp_err);
 471
 472        if (g_strcmp0(asl->str, exp_asl->str)) {
 473            sdt->tmp_files_retain = true;
 474            if (exp_err) {
 475                fprintf(stderr,
 476                        "Warning! iasl couldn't parse the expected aml\n");
 477            } else {
 478                exp_sdt->tmp_files_retain = true;
 479                fprintf(stderr,
 480                        "acpi-test: Warning! %.4s mismatch. "
 481                        "Actual [asl:%s, aml:%s], Expected [asl:%s, aml:%s].\n",
 482                        exp_sdt->aml, sdt->asl_file, sdt->aml_file,
 483                        exp_sdt->asl_file, exp_sdt->aml_file);
 484                fflush(stderr);
 485                if (getenv("V")) {
 486                    const char *diff_env = getenv("DIFF");
 487                    const char *diff_cmd = diff_env ? diff_env : "diff -U 16";
 488                    char *diff = g_strdup_printf("%s %s %s", diff_cmd,
 489                                                 exp_sdt->asl_file, sdt->asl_file);
 490                    int out = dup(STDOUT_FILENO);
 491                    int ret G_GNUC_UNUSED;
 492
 493                    dup2(STDERR_FILENO, STDOUT_FILENO);
 494                    ret = system(diff) ;
 495                    dup2(out, STDOUT_FILENO);
 496                    close(out);
 497                    g_free(diff);
 498                }
 499            }
 500        }
 501        g_string_free(asl, true);
 502        g_string_free(exp_asl, true);
 503    }
 504    if (!iasl && !all_tables_match) {
 505        fprintf(stderr, "to see ASL diff between mismatched files install IASL,"
 506                " rebuild QEMU from scratch and re-run tests with V=1"
 507                " environment variable set");
 508    }
 509    g_assert(all_tables_match);
 510
 511    free_test_data(&exp_data);
 512}
 513
 514static bool smbios_ep_table_ok(test_data *data)
 515{
 516    struct smbios_21_entry_point *ep_table = &data->smbios_ep_table;
 517    uint32_t addr = data->smbios_ep_addr;
 518
 519    qtest_memread(data->qts, addr, ep_table, sizeof(*ep_table));
 520    if (memcmp(ep_table->anchor_string, "_SM_", 4)) {
 521        return false;
 522    }
 523    if (memcmp(ep_table->intermediate_anchor_string, "_DMI_", 5)) {
 524        return false;
 525    }
 526    if (ep_table->structure_table_length == 0) {
 527        return false;
 528    }
 529    if (ep_table->number_of_structures == 0) {
 530        return false;
 531    }
 532    if (acpi_calc_checksum((uint8_t *)ep_table, sizeof *ep_table) ||
 533        acpi_calc_checksum((uint8_t *)ep_table + 0x10,
 534                           sizeof *ep_table - 0x10)) {
 535        return false;
 536    }
 537    return true;
 538}
 539
 540static void test_smbios_entry_point(test_data *data)
 541{
 542    uint32_t off;
 543
 544    /* find smbios entry point structure */
 545    for (off = 0xf0000; off < 0x100000; off += 0x10) {
 546        uint8_t sig[] = "_SM_";
 547        int i;
 548
 549        for (i = 0; i < sizeof sig - 1; ++i) {
 550            sig[i] = qtest_readb(data->qts, off + i);
 551        }
 552
 553        if (!memcmp(sig, "_SM_", sizeof sig)) {
 554            /* signature match, but is this a valid entry point? */
 555            data->smbios_ep_addr = off;
 556            if (smbios_ep_table_ok(data)) {
 557                break;
 558            }
 559        }
 560    }
 561
 562    g_assert_cmphex(off, <, 0x100000);
 563}
 564
 565static inline bool smbios_single_instance(uint8_t type)
 566{
 567    switch (type) {
 568    case 0:
 569    case 1:
 570    case 2:
 571    case 3:
 572    case 16:
 573    case 32:
 574    case 127:
 575        return true;
 576    default:
 577        return false;
 578    }
 579}
 580
 581static bool smbios_cpu_test(test_data *data, uint32_t addr)
 582{
 583    uint16_t expect_speed[2];
 584    uint16_t real;
 585    int offset[2];
 586    int i;
 587
 588    /* Check CPU speed for backward compatibility */
 589    offset[0] = offsetof(struct smbios_type_4, max_speed);
 590    offset[1] = offsetof(struct smbios_type_4, current_speed);
 591    expect_speed[0] = data->smbios_cpu_max_speed ? : 2000;
 592    expect_speed[1] = data->smbios_cpu_curr_speed ? : 2000;
 593
 594    for (i = 0; i < 2; i++) {
 595        real = qtest_readw(data->qts, addr + offset[i]);
 596        if (real != expect_speed[i]) {
 597            fprintf(stderr, "Unexpected SMBIOS CPU speed: real %u expect %u\n",
 598                    real, expect_speed[i]);
 599            return false;
 600        }
 601    }
 602
 603    return true;
 604}
 605
 606static void test_smbios_structs(test_data *data)
 607{
 608    DECLARE_BITMAP(struct_bitmap, SMBIOS_MAX_TYPE+1) = { 0 };
 609    struct smbios_21_entry_point *ep_table = &data->smbios_ep_table;
 610    uint32_t addr = le32_to_cpu(ep_table->structure_table_address);
 611    int i, len, max_len = 0;
 612    uint8_t type, prv, crt;
 613
 614    /* walk the smbios tables */
 615    for (i = 0; i < le16_to_cpu(ep_table->number_of_structures); i++) {
 616
 617        /* grab type and formatted area length from struct header */
 618        type = qtest_readb(data->qts, addr);
 619        g_assert_cmpuint(type, <=, SMBIOS_MAX_TYPE);
 620        len = qtest_readb(data->qts, addr + 1);
 621
 622        /* single-instance structs must not have been encountered before */
 623        if (smbios_single_instance(type)) {
 624            g_assert(!test_bit(type, struct_bitmap));
 625        }
 626        set_bit(type, struct_bitmap);
 627
 628        if (type == 4) {
 629            g_assert(smbios_cpu_test(data, addr));
 630        }
 631
 632        /* seek to end of unformatted string area of this struct ("\0\0") */
 633        prv = crt = 1;
 634        while (prv || crt) {
 635            prv = crt;
 636            crt = qtest_readb(data->qts, addr + len);
 637            len++;
 638        }
 639
 640        /* keep track of max. struct size */
 641        if (max_len < len) {
 642            max_len = len;
 643            g_assert_cmpuint(max_len, <=, ep_table->max_structure_size);
 644        }
 645
 646        /* start of next structure */
 647        addr += len;
 648    }
 649
 650    /* total table length and max struct size must match entry point values */
 651    g_assert_cmpuint(le16_to_cpu(ep_table->structure_table_length), ==,
 652                     addr - le32_to_cpu(ep_table->structure_table_address));
 653    g_assert_cmpuint(le16_to_cpu(ep_table->max_structure_size), ==, max_len);
 654
 655    /* required struct types must all be present */
 656    for (i = 0; i < data->required_struct_types_len; i++) {
 657        g_assert(test_bit(data->required_struct_types[i], struct_bitmap));
 658    }
 659}
 660
 661static void test_acpi_load_tables(test_data *data, bool use_uefi)
 662{
 663    if (use_uefi) {
 664        g_assert(data->scan_len);
 665        data->rsdp_addr = acpi_find_rsdp_address_uefi(data->qts,
 666            data->ram_start, data->scan_len);
 667    } else {
 668        boot_sector_test(data->qts);
 669        data->rsdp_addr = acpi_find_rsdp_address(data->qts);
 670        g_assert_cmphex(data->rsdp_addr, <, 0x100000);
 671    }
 672
 673    data->tables = g_array_new(false, true, sizeof(AcpiSdtTable));
 674    test_acpi_rsdp_table(data);
 675    test_acpi_rxsdt_table(data);
 676    test_acpi_fadt_table(data);
 677}
 678
 679static char *test_acpi_create_args(test_data *data, const char *params,
 680                                   bool use_uefi)
 681{
 682    char *args;
 683
 684    if (use_uefi) {
 685        /*
 686         * TODO: convert '-drive if=pflash' to new syntax (see e33763be7cd3)
 687         * when arm/virt boad starts to support it.
 688         */
 689        if (data->cd) {
 690            args = g_strdup_printf("-machine %s %s -accel tcg "
 691                "-nodefaults -nographic "
 692                "-drive if=pflash,format=raw,file=%s,readonly=on "
 693                "-drive if=pflash,format=raw,file=%s,snapshot=on -cdrom %s %s",
 694                data->machine, data->tcg_only ? "" : "-accel kvm",
 695                data->uefi_fl1, data->uefi_fl2, data->cd, params ? params : "");
 696        } else {
 697            args = g_strdup_printf("-machine %s %s -accel tcg "
 698                "-nodefaults -nographic "
 699                "-drive if=pflash,format=raw,file=%s,readonly=on "
 700                "-drive if=pflash,format=raw,file=%s,snapshot=on %s",
 701                data->machine, data->tcg_only ? "" : "-accel kvm",
 702                data->uefi_fl1, data->uefi_fl2, params ? params : "");
 703        }
 704    } else {
 705        args = g_strdup_printf("-machine %s %s -accel tcg "
 706            "-net none -display none %s "
 707            "-drive id=hd0,if=none,file=%s,format=raw "
 708            "-device %s,drive=hd0 ",
 709             data->machine, data->tcg_only ? "" : "-accel kvm",
 710             params ? params : "", disk,
 711             data->blkdev ?: "ide-hd");
 712    }
 713    return args;
 714}
 715
 716static void test_acpi_one(const char *params, test_data *data)
 717{
 718    char *args;
 719    bool use_uefi = data->uefi_fl1 && data->uefi_fl2;
 720
 721#ifndef CONFIG_TCG
 722    if (data->tcg_only) {
 723        g_test_skip("TCG disabled, skipping ACPI tcg_only test");
 724        return;
 725    }
 726#endif /* CONFIG_TCG */
 727
 728    args = test_acpi_create_args(data, params, use_uefi);
 729    data->qts = qtest_init(args);
 730    test_acpi_load_tables(data, use_uefi);
 731
 732    if (getenv(ACPI_REBUILD_EXPECTED_AML)) {
 733        dump_aml_files(data, true);
 734    } else {
 735        test_acpi_asl(data);
 736    }
 737
 738    /*
 739     * TODO: make SMBIOS tests work with UEFI firmware,
 740     * Bug on uefi-test-tools to provide entry point:
 741     * https://bugs.launchpad.net/qemu/+bug/1821884
 742     */
 743    if (!use_uefi) {
 744        test_smbios_entry_point(data);
 745        test_smbios_structs(data);
 746    }
 747
 748    qtest_quit(data->qts);
 749    g_free(args);
 750}
 751
 752static uint8_t base_required_struct_types[] = {
 753    0, 1, 3, 4, 16, 17, 19, 32, 127
 754};
 755
 756static void test_acpi_piix4_tcg(void)
 757{
 758    test_data data;
 759
 760    /* Supplying -machine accel argument overrides the default (qtest).
 761     * This is to make guest actually run.
 762     */
 763    memset(&data, 0, sizeof(data));
 764    data.machine = MACHINE_PC;
 765    data.required_struct_types = base_required_struct_types;
 766    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
 767    test_acpi_one(NULL, &data);
 768    free_test_data(&data);
 769}
 770
 771static void test_acpi_piix4_tcg_bridge(void)
 772{
 773    test_data data;
 774
 775    memset(&data, 0, sizeof(data));
 776    data.machine = MACHINE_PC;
 777    data.variant = ".bridge";
 778    data.required_struct_types = base_required_struct_types;
 779    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
 780    test_acpi_one("-device pci-bridge,chassis_nr=1", &data);
 781    free_test_data(&data);
 782}
 783
 784static void test_acpi_piix4_no_root_hotplug(void)
 785{
 786    test_data data;
 787
 788    memset(&data, 0, sizeof(data));
 789    data.machine = MACHINE_PC;
 790    data.variant = ".roothp";
 791    data.required_struct_types = base_required_struct_types;
 792    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
 793    test_acpi_one("-global PIIX4_PM.acpi-root-pci-hotplug=off "
 794                  "-device pci-bridge,chassis_nr=1", &data);
 795    free_test_data(&data);
 796}
 797
 798static void test_acpi_piix4_no_bridge_hotplug(void)
 799{
 800    test_data data;
 801
 802    memset(&data, 0, sizeof(data));
 803    data.machine = MACHINE_PC;
 804    data.variant = ".hpbridge";
 805    data.required_struct_types = base_required_struct_types;
 806    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
 807    test_acpi_one("-global PIIX4_PM.acpi-pci-hotplug-with-bridge-support=off "
 808                  "-device pci-bridge,chassis_nr=1", &data);
 809    free_test_data(&data);
 810}
 811
 812static void test_acpi_piix4_no_acpi_pci_hotplug(void)
 813{
 814    test_data data;
 815
 816    memset(&data, 0, sizeof(data));
 817    data.machine = MACHINE_PC;
 818    data.variant = ".hpbrroot";
 819    data.required_struct_types = base_required_struct_types;
 820    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
 821    test_acpi_one("-global PIIX4_PM.acpi-root-pci-hotplug=off "
 822                  "-global PIIX4_PM.acpi-pci-hotplug-with-bridge-support=off "
 823                  "-device pci-bridge,chassis_nr=1", &data);
 824    free_test_data(&data);
 825}
 826
 827static void test_acpi_q35_tcg(void)
 828{
 829    test_data data;
 830
 831    memset(&data, 0, sizeof(data));
 832    data.machine = MACHINE_Q35;
 833    data.required_struct_types = base_required_struct_types;
 834    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
 835    test_acpi_one(NULL, &data);
 836    free_test_data(&data);
 837
 838    data.smbios_cpu_max_speed = 3000;
 839    data.smbios_cpu_curr_speed = 2600;
 840    test_acpi_one("-smbios type=4,max-speed=3000,current-speed=2600", &data);
 841    free_test_data(&data);
 842}
 843
 844static void test_acpi_q35_tcg_bridge(void)
 845{
 846    test_data data;
 847
 848    memset(&data, 0, sizeof(data));
 849    data.machine = MACHINE_Q35;
 850    data.variant = ".bridge";
 851    data.required_struct_types = base_required_struct_types;
 852    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
 853    test_acpi_one("-device pci-bridge,chassis_nr=1",
 854                  &data);
 855    free_test_data(&data);
 856}
 857
 858static void test_acpi_q35_tcg_mmio64(void)
 859{
 860    test_data data = {
 861        .machine = MACHINE_Q35,
 862        .variant = ".mmio64",
 863        .required_struct_types = base_required_struct_types,
 864        .required_struct_types_len = ARRAY_SIZE(base_required_struct_types)
 865    };
 866
 867    test_acpi_one("-m 128M,slots=1,maxmem=2G "
 868                  "-object memory-backend-ram,id=ram0,size=128M "
 869                  "-numa node,memdev=ram0 "
 870                  "-device pci-testdev,membar=2G",
 871                  &data);
 872    free_test_data(&data);
 873}
 874
 875static void test_acpi_piix4_tcg_cphp(void)
 876{
 877    test_data data;
 878
 879    memset(&data, 0, sizeof(data));
 880    data.machine = MACHINE_PC;
 881    data.variant = ".cphp";
 882    test_acpi_one("-smp 2,cores=3,sockets=2,maxcpus=6"
 883                  " -object memory-backend-ram,id=ram0,size=64M"
 884                  " -object memory-backend-ram,id=ram1,size=64M"
 885                  " -numa node,memdev=ram0 -numa node,memdev=ram1"
 886                  " -numa dist,src=0,dst=1,val=21",
 887                  &data);
 888    free_test_data(&data);
 889}
 890
 891static void test_acpi_q35_tcg_cphp(void)
 892{
 893    test_data data;
 894
 895    memset(&data, 0, sizeof(data));
 896    data.machine = MACHINE_Q35;
 897    data.variant = ".cphp";
 898    test_acpi_one(" -smp 2,cores=3,sockets=2,maxcpus=6"
 899                  " -object memory-backend-ram,id=ram0,size=64M"
 900                  " -object memory-backend-ram,id=ram1,size=64M"
 901                  " -numa node,memdev=ram0 -numa node,memdev=ram1"
 902                  " -numa dist,src=0,dst=1,val=21",
 903                  &data);
 904    free_test_data(&data);
 905}
 906
 907static uint8_t ipmi_required_struct_types[] = {
 908    0, 1, 3, 4, 16, 17, 19, 32, 38, 127
 909};
 910
 911static void test_acpi_q35_tcg_ipmi(void)
 912{
 913    test_data data;
 914
 915    memset(&data, 0, sizeof(data));
 916    data.machine = MACHINE_Q35;
 917    data.variant = ".ipmibt";
 918    data.required_struct_types = ipmi_required_struct_types;
 919    data.required_struct_types_len = ARRAY_SIZE(ipmi_required_struct_types);
 920    test_acpi_one("-device ipmi-bmc-sim,id=bmc0"
 921                  " -device isa-ipmi-bt,bmc=bmc0",
 922                  &data);
 923    free_test_data(&data);
 924}
 925
 926static void test_acpi_piix4_tcg_ipmi(void)
 927{
 928    test_data data;
 929
 930    /* Supplying -machine accel argument overrides the default (qtest).
 931     * This is to make guest actually run.
 932     */
 933    memset(&data, 0, sizeof(data));
 934    data.machine = MACHINE_PC;
 935    data.variant = ".ipmikcs";
 936    data.required_struct_types = ipmi_required_struct_types;
 937    data.required_struct_types_len = ARRAY_SIZE(ipmi_required_struct_types);
 938    test_acpi_one("-device ipmi-bmc-sim,id=bmc0"
 939                  " -device isa-ipmi-kcs,irq=0,bmc=bmc0",
 940                  &data);
 941    free_test_data(&data);
 942}
 943
 944static void test_acpi_q35_tcg_memhp(void)
 945{
 946    test_data data;
 947
 948    memset(&data, 0, sizeof(data));
 949    data.machine = MACHINE_Q35;
 950    data.variant = ".memhp";
 951    test_acpi_one(" -m 128,slots=3,maxmem=1G"
 952                  " -object memory-backend-ram,id=ram0,size=64M"
 953                  " -object memory-backend-ram,id=ram1,size=64M"
 954                  " -numa node,memdev=ram0 -numa node,memdev=ram1"
 955                  " -numa dist,src=0,dst=1,val=21",
 956                  &data);
 957    free_test_data(&data);
 958}
 959
 960static void test_acpi_piix4_tcg_memhp(void)
 961{
 962    test_data data;
 963
 964    memset(&data, 0, sizeof(data));
 965    data.machine = MACHINE_PC;
 966    data.variant = ".memhp";
 967    test_acpi_one(" -m 128,slots=3,maxmem=1G"
 968                  " -object memory-backend-ram,id=ram0,size=64M"
 969                  " -object memory-backend-ram,id=ram1,size=64M"
 970                  " -numa node,memdev=ram0 -numa node,memdev=ram1"
 971                  " -numa dist,src=0,dst=1,val=21",
 972                  &data);
 973    free_test_data(&data);
 974}
 975
 976static void test_acpi_piix4_tcg_nosmm(void)
 977{
 978    test_data data;
 979
 980    memset(&data, 0, sizeof(data));
 981    data.machine = MACHINE_PC;
 982    data.variant = ".nosmm";
 983    test_acpi_one("-machine smm=off", &data);
 984    free_test_data(&data);
 985}
 986
 987static void test_acpi_piix4_tcg_smm_compat(void)
 988{
 989    test_data data;
 990
 991    memset(&data, 0, sizeof(data));
 992    data.machine = MACHINE_PC;
 993    data.variant = ".smm-compat";
 994    test_acpi_one("-global PIIX4_PM.smm-compat=on", &data);
 995    free_test_data(&data);
 996}
 997
 998static void test_acpi_piix4_tcg_smm_compat_nosmm(void)
 999{
1000    test_data data;
1001
1002    memset(&data, 0, sizeof(data));
1003    data.machine = MACHINE_PC;
1004    data.variant = ".smm-compat-nosmm";
1005    test_acpi_one("-global PIIX4_PM.smm-compat=on -machine smm=off", &data);
1006    free_test_data(&data);
1007}
1008
1009static void test_acpi_piix4_tcg_nohpet(void)
1010{
1011    test_data data;
1012
1013    memset(&data, 0, sizeof(data));
1014    data.machine = MACHINE_PC;
1015    data.variant = ".nohpet";
1016    test_acpi_one("-no-hpet", &data);
1017    free_test_data(&data);
1018}
1019
1020static void test_acpi_q35_tcg_numamem(void)
1021{
1022    test_data data;
1023
1024    memset(&data, 0, sizeof(data));
1025    data.machine = MACHINE_Q35;
1026    data.variant = ".numamem";
1027    test_acpi_one(" -object memory-backend-ram,id=ram0,size=128M"
1028                  " -numa node -numa node,memdev=ram0", &data);
1029    free_test_data(&data);
1030}
1031
1032static void test_acpi_q35_tcg_nosmm(void)
1033{
1034    test_data data;
1035
1036    memset(&data, 0, sizeof(data));
1037    data.machine = MACHINE_Q35;
1038    data.variant = ".nosmm";
1039    test_acpi_one("-machine smm=off", &data);
1040    free_test_data(&data);
1041}
1042
1043static void test_acpi_q35_tcg_smm_compat(void)
1044{
1045    test_data data;
1046
1047    memset(&data, 0, sizeof(data));
1048    data.machine = MACHINE_Q35;
1049    data.variant = ".smm-compat";
1050    test_acpi_one("-global ICH9-LPC.smm-compat=on", &data);
1051    free_test_data(&data);
1052}
1053
1054static void test_acpi_q35_tcg_smm_compat_nosmm(void)
1055{
1056    test_data data;
1057
1058    memset(&data, 0, sizeof(data));
1059    data.machine = MACHINE_Q35;
1060    data.variant = ".smm-compat-nosmm";
1061    test_acpi_one("-global ICH9-LPC.smm-compat=on -machine smm=off", &data);
1062    free_test_data(&data);
1063}
1064
1065static void test_acpi_q35_tcg_nohpet(void)
1066{
1067    test_data data;
1068
1069    memset(&data, 0, sizeof(data));
1070    data.machine = MACHINE_Q35;
1071    data.variant = ".nohpet";
1072    test_acpi_one("-no-hpet", &data);
1073    free_test_data(&data);
1074}
1075
1076static void test_acpi_piix4_tcg_numamem(void)
1077{
1078    test_data data;
1079
1080    memset(&data, 0, sizeof(data));
1081    data.machine = MACHINE_PC;
1082    data.variant = ".numamem";
1083    test_acpi_one(" -object memory-backend-ram,id=ram0,size=128M"
1084                  " -numa node -numa node,memdev=ram0", &data);
1085    free_test_data(&data);
1086}
1087
1088uint64_t tpm_tis_base_addr;
1089
1090static void test_acpi_tcg_tpm(const char *machine, const char *tpm_if,
1091                              uint64_t base)
1092{
1093#ifdef CONFIG_TPM
1094    gchar *tmp_dir_name = g_strdup_printf("qemu-test_acpi_%s_tcg_%s.XXXXXX",
1095                                          machine, tpm_if);
1096    char *tmp_path = g_dir_make_tmp(tmp_dir_name, NULL);
1097    TestState test;
1098    test_data data;
1099    GThread *thread;
1100    char *args, *variant = g_strdup_printf(".%s", tpm_if);
1101
1102    tpm_tis_base_addr = base;
1103
1104    module_call_init(MODULE_INIT_QOM);
1105
1106    test.addr = g_new0(SocketAddress, 1);
1107    test.addr->type = SOCKET_ADDRESS_TYPE_UNIX;
1108    test.addr->u.q_unix.path = g_build_filename(tmp_path, "sock", NULL);
1109    g_mutex_init(&test.data_mutex);
1110    g_cond_init(&test.data_cond);
1111    test.data_cond_signal = false;
1112
1113    thread = g_thread_new(NULL, tpm_emu_ctrl_thread, &test);
1114    tpm_emu_test_wait_cond(&test);
1115
1116    memset(&data, 0, sizeof(data));
1117    data.machine = machine;
1118    data.variant = variant;
1119
1120    args = g_strdup_printf(
1121        " -chardev socket,id=chr,path=%s"
1122        " -tpmdev emulator,id=dev,chardev=chr"
1123        " -device tpm-%s,tpmdev=dev",
1124        test.addr->u.q_unix.path, tpm_if);
1125
1126    test_acpi_one(args, &data);
1127
1128    g_thread_join(thread);
1129    g_unlink(test.addr->u.q_unix.path);
1130    qapi_free_SocketAddress(test.addr);
1131    g_rmdir(tmp_path);
1132    g_free(variant);
1133    g_free(tmp_path);
1134    g_free(tmp_dir_name);
1135    g_free(args);
1136    free_test_data(&data);
1137#else
1138    g_test_skip("TPM disabled");
1139#endif
1140}
1141
1142static void test_acpi_q35_tcg_tpm_tis(void)
1143{
1144    test_acpi_tcg_tpm("q35", "tis", 0xFED40000);
1145}
1146
1147static void test_acpi_tcg_dimm_pxm(const char *machine)
1148{
1149    test_data data;
1150
1151    memset(&data, 0, sizeof(data));
1152    data.machine = machine;
1153    data.variant = ".dimmpxm";
1154    test_acpi_one(" -machine nvdimm=on,nvdimm-persistence=cpu"
1155                  " -smp 4,sockets=4"
1156                  " -m 128M,slots=3,maxmem=1G"
1157                  " -object memory-backend-ram,id=ram0,size=32M"
1158                  " -object memory-backend-ram,id=ram1,size=32M"
1159                  " -object memory-backend-ram,id=ram2,size=32M"
1160                  " -object memory-backend-ram,id=ram3,size=32M"
1161                  " -numa node,memdev=ram0,nodeid=0"
1162                  " -numa node,memdev=ram1,nodeid=1"
1163                  " -numa node,memdev=ram2,nodeid=2"
1164                  " -numa node,memdev=ram3,nodeid=3"
1165                  " -numa cpu,node-id=0,socket-id=0"
1166                  " -numa cpu,node-id=1,socket-id=1"
1167                  " -numa cpu,node-id=2,socket-id=2"
1168                  " -numa cpu,node-id=3,socket-id=3"
1169                  " -object memory-backend-ram,id=ram4,size=128M"
1170                  " -object memory-backend-ram,id=nvm0,size=128M"
1171                  " -device pc-dimm,id=dimm0,memdev=ram4,node=1"
1172                  " -device nvdimm,id=dimm1,memdev=nvm0,node=2",
1173                  &data);
1174    free_test_data(&data);
1175}
1176
1177static void test_acpi_q35_tcg_dimm_pxm(void)
1178{
1179    test_acpi_tcg_dimm_pxm(MACHINE_Q35);
1180}
1181
1182static void test_acpi_piix4_tcg_dimm_pxm(void)
1183{
1184    test_acpi_tcg_dimm_pxm(MACHINE_PC);
1185}
1186
1187static void test_acpi_virt_tcg_memhp(void)
1188{
1189    test_data data = {
1190        .machine = "virt",
1191        .tcg_only = true,
1192        .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
1193        .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
1194        .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2",
1195        .ram_start = 0x40000000ULL,
1196        .scan_len = 256ULL * 1024 * 1024,
1197    };
1198
1199    data.variant = ".memhp";
1200    test_acpi_one(" -machine nvdimm=on"
1201                  " -cpu cortex-a57"
1202                  " -m 256M,slots=3,maxmem=1G"
1203                  " -object memory-backend-ram,id=ram0,size=128M"
1204                  " -object memory-backend-ram,id=ram1,size=128M"
1205                  " -numa node,memdev=ram0 -numa node,memdev=ram1"
1206                  " -numa dist,src=0,dst=1,val=21"
1207                  " -object memory-backend-ram,id=ram2,size=128M"
1208                  " -object memory-backend-ram,id=nvm0,size=128M"
1209                  " -device pc-dimm,id=dimm0,memdev=ram2,node=0"
1210                  " -device nvdimm,id=dimm1,memdev=nvm0,node=1",
1211                  &data);
1212
1213    free_test_data(&data);
1214
1215}
1216
1217static void test_acpi_microvm_prepare(test_data *data)
1218{
1219    memset(data, 0, sizeof(*data));
1220    data->machine = "microvm";
1221    data->required_struct_types = NULL; /* no smbios */
1222    data->required_struct_types_len = 0;
1223    data->blkdev = "virtio-blk-device";
1224}
1225
1226static void test_acpi_microvm_tcg(void)
1227{
1228    test_data data;
1229
1230    test_acpi_microvm_prepare(&data);
1231    test_acpi_one(" -machine microvm,acpi=on,ioapic2=off,rtc=off",
1232                  &data);
1233    free_test_data(&data);
1234}
1235
1236static void test_acpi_microvm_usb_tcg(void)
1237{
1238    test_data data;
1239
1240    test_acpi_microvm_prepare(&data);
1241    data.variant = ".usb";
1242    test_acpi_one(" -machine microvm,acpi=on,ioapic2=off,usb=on,rtc=off",
1243                  &data);
1244    free_test_data(&data);
1245}
1246
1247static void test_acpi_microvm_rtc_tcg(void)
1248{
1249    test_data data;
1250
1251    test_acpi_microvm_prepare(&data);
1252    data.variant = ".rtc";
1253    test_acpi_one(" -machine microvm,acpi=on,ioapic2=off,rtc=on",
1254                  &data);
1255    free_test_data(&data);
1256}
1257
1258static void test_acpi_microvm_pcie_tcg(void)
1259{
1260    test_data data;
1261
1262    test_acpi_microvm_prepare(&data);
1263    data.variant = ".pcie";
1264    data.tcg_only = true; /* need constant host-phys-bits */
1265    test_acpi_one(" -machine microvm,acpi=on,ioapic2=off,rtc=off,pcie=on",
1266                  &data);
1267    free_test_data(&data);
1268}
1269
1270static void test_acpi_microvm_ioapic2_tcg(void)
1271{
1272    test_data data;
1273
1274    test_acpi_microvm_prepare(&data);
1275    data.variant = ".ioapic2";
1276    test_acpi_one(" -machine microvm,acpi=on,ioapic2=on,rtc=off",
1277                  &data);
1278    free_test_data(&data);
1279}
1280
1281static void test_acpi_virt_tcg_numamem(void)
1282{
1283    test_data data = {
1284        .machine = "virt",
1285        .tcg_only = true,
1286        .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
1287        .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
1288        .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2",
1289        .ram_start = 0x40000000ULL,
1290        .scan_len = 128ULL * 1024 * 1024,
1291    };
1292
1293    data.variant = ".numamem";
1294    test_acpi_one(" -cpu cortex-a57"
1295                  " -object memory-backend-ram,id=ram0,size=128M"
1296                  " -numa node,memdev=ram0",
1297                  &data);
1298
1299    free_test_data(&data);
1300
1301}
1302
1303static void test_acpi_virt_tcg_pxb(void)
1304{
1305    test_data data = {
1306        .machine = "virt",
1307        .tcg_only = true,
1308        .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
1309        .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
1310        .ram_start = 0x40000000ULL,
1311        .scan_len = 128ULL * 1024 * 1024,
1312    };
1313    /*
1314     * While using -cdrom, the cdrom would auto plugged into pxb-pcie,
1315     * the reason is the bus of pxb-pcie is also root bus, it would lead
1316     * to the error only PCI/PCIE bridge could plug onto pxb.
1317     * Therefore,thr cdrom is defined and plugged onto the scsi controller
1318     * to solve the conflicts.
1319     */
1320    data.variant = ".pxb";
1321    test_acpi_one(" -device pcie-root-port,chassis=1,id=pci.1"
1322                  " -device virtio-scsi-pci,id=scsi0,bus=pci.1"
1323                  " -drive file="
1324                  "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2,"
1325                  "if=none,media=cdrom,id=drive-scsi0-0-0-1,readonly=on"
1326                  " -device scsi-cd,bus=scsi0.0,scsi-id=0,"
1327                  "drive=drive-scsi0-0-0-1,id=scsi0-0-0-1,bootindex=1"
1328                  " -cpu cortex-a57"
1329                  " -device pxb-pcie,bus_nr=128",
1330                  &data);
1331
1332    free_test_data(&data);
1333}
1334
1335static void test_acpi_tcg_acpi_hmat(const char *machine)
1336{
1337    test_data data;
1338
1339    memset(&data, 0, sizeof(data));
1340    data.machine = machine;
1341    data.variant = ".acpihmat";
1342    test_acpi_one(" -machine hmat=on"
1343                  " -smp 2,sockets=2"
1344                  " -m 128M,slots=2,maxmem=1G"
1345                  " -object memory-backend-ram,size=64M,id=m0"
1346                  " -object memory-backend-ram,size=64M,id=m1"
1347                  " -numa node,nodeid=0,memdev=m0"
1348                  " -numa node,nodeid=1,memdev=m1,initiator=0"
1349                  " -numa cpu,node-id=0,socket-id=0"
1350                  " -numa cpu,node-id=0,socket-id=1"
1351                  " -numa hmat-lb,initiator=0,target=0,hierarchy=memory,"
1352                  "data-type=access-latency,latency=1"
1353                  " -numa hmat-lb,initiator=0,target=0,hierarchy=memory,"
1354                  "data-type=access-bandwidth,bandwidth=65534M"
1355                  " -numa hmat-lb,initiator=0,target=1,hierarchy=memory,"
1356                  "data-type=access-latency,latency=65534"
1357                  " -numa hmat-lb,initiator=0,target=1,hierarchy=memory,"
1358                  "data-type=access-bandwidth,bandwidth=32767M"
1359                  " -numa hmat-cache,node-id=0,size=10K,level=1,"
1360                  "associativity=direct,policy=write-back,line=8"
1361                  " -numa hmat-cache,node-id=1,size=10K,level=1,"
1362                  "associativity=direct,policy=write-back,line=8",
1363                  &data);
1364    free_test_data(&data);
1365}
1366
1367static void test_acpi_q35_tcg_acpi_hmat(void)
1368{
1369    test_acpi_tcg_acpi_hmat(MACHINE_Q35);
1370}
1371
1372static void test_acpi_piix4_tcg_acpi_hmat(void)
1373{
1374    test_acpi_tcg_acpi_hmat(MACHINE_PC);
1375}
1376
1377static void test_acpi_virt_tcg(void)
1378{
1379    test_data data = {
1380        .machine = "virt",
1381        .tcg_only = true,
1382        .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
1383        .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
1384        .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2",
1385        .ram_start = 0x40000000ULL,
1386        .scan_len = 128ULL * 1024 * 1024,
1387    };
1388
1389    test_acpi_one("-cpu cortex-a57", &data);
1390    free_test_data(&data);
1391
1392    data.smbios_cpu_max_speed = 2900;
1393    data.smbios_cpu_curr_speed = 2700;
1394    test_acpi_one("-cpu cortex-a57 "
1395                  "-smbios type=4,max-speed=2900,current-speed=2700", &data);
1396    free_test_data(&data);
1397}
1398
1399static void test_oem_fields(test_data *data)
1400{
1401    int i;
1402    char oem_id[6];
1403    char oem_table_id[8];
1404
1405    strpadcpy(oem_id, sizeof oem_id, OEM_ID, ' ');
1406    strpadcpy(oem_table_id, sizeof oem_table_id, OEM_TABLE_ID, ' ');
1407    for (i = 0; i < data->tables->len; ++i) {
1408        AcpiSdtTable *sdt;
1409
1410        sdt = &g_array_index(data->tables, AcpiSdtTable, i);
1411        /* FACS doesn't have OEMID and OEMTABLEID fields */
1412        if (compare_signature(sdt, "FACS")) {
1413            continue;
1414        }
1415
1416        g_assert(memcmp(sdt->aml + 10, oem_id, 6) == 0);
1417        g_assert(memcmp(sdt->aml + 16, oem_table_id, 8) == 0);
1418    }
1419}
1420
1421static void test_acpi_oem_fields_pc(void)
1422{
1423    test_data data;
1424    char *args;
1425
1426    memset(&data, 0, sizeof(data));
1427    data.machine = MACHINE_PC;
1428    data.required_struct_types = base_required_struct_types;
1429    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
1430
1431    args = test_acpi_create_args(&data,
1432                                 OEM_TEST_ARGS, false);
1433    data.qts = qtest_init(args);
1434    test_acpi_load_tables(&data, false);
1435    test_oem_fields(&data);
1436    qtest_quit(data.qts);
1437    free_test_data(&data);
1438    g_free(args);
1439}
1440
1441static void test_acpi_oem_fields_q35(void)
1442{
1443    test_data data;
1444    char *args;
1445
1446    memset(&data, 0, sizeof(data));
1447    data.machine = MACHINE_Q35;
1448    data.required_struct_types = base_required_struct_types;
1449    data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
1450
1451    args = test_acpi_create_args(&data,
1452                                 OEM_TEST_ARGS, false);
1453    data.qts = qtest_init(args);
1454    test_acpi_load_tables(&data, false);
1455    test_oem_fields(&data);
1456    qtest_quit(data.qts);
1457    free_test_data(&data);
1458    g_free(args);
1459}
1460
1461static void test_acpi_oem_fields_microvm(void)
1462{
1463    test_data data;
1464    char *args;
1465
1466    test_acpi_microvm_prepare(&data);
1467
1468    args = test_acpi_create_args(&data,
1469                                 OEM_TEST_ARGS",acpi=on", false);
1470    data.qts = qtest_init(args);
1471    test_acpi_load_tables(&data, false);
1472    test_oem_fields(&data);
1473    qtest_quit(data.qts);
1474    free_test_data(&data);
1475    g_free(args);
1476}
1477
1478static void test_acpi_oem_fields_virt(void)
1479{
1480    test_data data = {
1481        .machine = "virt",
1482        .tcg_only = true,
1483        .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
1484        .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
1485        .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2",
1486        .ram_start = 0x40000000ULL,
1487        .scan_len = 128ULL * 1024 * 1024,
1488    };
1489    char *args;
1490
1491    args = test_acpi_create_args(&data,
1492                                 "-cpu cortex-a57 "OEM_TEST_ARGS, true);
1493    data.qts = qtest_init(args);
1494    test_acpi_load_tables(&data, true);
1495    test_oem_fields(&data);
1496    qtest_quit(data.qts);
1497    free_test_data(&data);
1498    g_free(args);
1499}
1500
1501
1502int main(int argc, char *argv[])
1503{
1504    const char *arch = qtest_get_arch();
1505    int ret;
1506
1507    g_test_init(&argc, &argv, NULL);
1508
1509    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
1510        ret = boot_sector_init(disk);
1511        if (ret) {
1512            return ret;
1513        }
1514        qtest_add_func("acpi/q35/oem-fields", test_acpi_oem_fields_q35);
1515        qtest_add_func("acpi/q35/tpm-tis", test_acpi_q35_tcg_tpm_tis);
1516        qtest_add_func("acpi/piix4", test_acpi_piix4_tcg);
1517        qtest_add_func("acpi/oem-fields", test_acpi_oem_fields_pc);
1518        qtest_add_func("acpi/piix4/bridge", test_acpi_piix4_tcg_bridge);
1519        qtest_add_func("acpi/piix4/pci-hotplug/no_root_hotplug",
1520                       test_acpi_piix4_no_root_hotplug);
1521        qtest_add_func("acpi/piix4/pci-hotplug/no_bridge_hotplug",
1522                       test_acpi_piix4_no_bridge_hotplug);
1523        qtest_add_func("acpi/piix4/pci-hotplug/off",
1524                       test_acpi_piix4_no_acpi_pci_hotplug);
1525        qtest_add_func("acpi/q35", test_acpi_q35_tcg);
1526        qtest_add_func("acpi/q35/bridge", test_acpi_q35_tcg_bridge);
1527        qtest_add_func("acpi/q35/mmio64", test_acpi_q35_tcg_mmio64);
1528        qtest_add_func("acpi/piix4/ipmi", test_acpi_piix4_tcg_ipmi);
1529        qtest_add_func("acpi/q35/ipmi", test_acpi_q35_tcg_ipmi);
1530        qtest_add_func("acpi/piix4/cpuhp", test_acpi_piix4_tcg_cphp);
1531        qtest_add_func("acpi/q35/cpuhp", test_acpi_q35_tcg_cphp);
1532        qtest_add_func("acpi/piix4/memhp", test_acpi_piix4_tcg_memhp);
1533        qtest_add_func("acpi/q35/memhp", test_acpi_q35_tcg_memhp);
1534        qtest_add_func("acpi/piix4/numamem", test_acpi_piix4_tcg_numamem);
1535        qtest_add_func("acpi/q35/numamem", test_acpi_q35_tcg_numamem);
1536        qtest_add_func("acpi/piix4/nosmm", test_acpi_piix4_tcg_nosmm);
1537        qtest_add_func("acpi/piix4/smm-compat",
1538                       test_acpi_piix4_tcg_smm_compat);
1539        qtest_add_func("acpi/piix4/smm-compat-nosmm",
1540                       test_acpi_piix4_tcg_smm_compat_nosmm);
1541        qtest_add_func("acpi/piix4/nohpet", test_acpi_piix4_tcg_nohpet);
1542        qtest_add_func("acpi/q35/nosmm", test_acpi_q35_tcg_nosmm);
1543        qtest_add_func("acpi/q35/smm-compat",
1544                       test_acpi_q35_tcg_smm_compat);
1545        qtest_add_func("acpi/q35/smm-compat-nosmm",
1546                       test_acpi_q35_tcg_smm_compat_nosmm);
1547        qtest_add_func("acpi/q35/nohpet", test_acpi_q35_tcg_nohpet);
1548        qtest_add_func("acpi/piix4/dimmpxm", test_acpi_piix4_tcg_dimm_pxm);
1549        qtest_add_func("acpi/q35/dimmpxm", test_acpi_q35_tcg_dimm_pxm);
1550        qtest_add_func("acpi/piix4/acpihmat", test_acpi_piix4_tcg_acpi_hmat);
1551        qtest_add_func("acpi/q35/acpihmat", test_acpi_q35_tcg_acpi_hmat);
1552        qtest_add_func("acpi/microvm", test_acpi_microvm_tcg);
1553        qtest_add_func("acpi/microvm/usb", test_acpi_microvm_usb_tcg);
1554        qtest_add_func("acpi/microvm/rtc", test_acpi_microvm_rtc_tcg);
1555        qtest_add_func("acpi/microvm/ioapic2", test_acpi_microvm_ioapic2_tcg);
1556        qtest_add_func("acpi/microvm/oem-fields", test_acpi_oem_fields_microvm);
1557        if (strcmp(arch, "x86_64") == 0) {
1558            qtest_add_func("acpi/microvm/pcie", test_acpi_microvm_pcie_tcg);
1559        }
1560    } else if (strcmp(arch, "aarch64") == 0) {
1561        qtest_add_func("acpi/virt", test_acpi_virt_tcg);
1562        qtest_add_func("acpi/virt/numamem", test_acpi_virt_tcg_numamem);
1563        qtest_add_func("acpi/virt/memhp", test_acpi_virt_tcg_memhp);
1564        qtest_add_func("acpi/virt/pxb", test_acpi_virt_tcg_pxb);
1565        qtest_add_func("acpi/virt/oem-fields", test_acpi_oem_fields_virt);
1566    }
1567    ret = g_test_run();
1568    boot_sector_cleanup(disk);
1569    return ret;
1570}
1571