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