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