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