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