xref: /qemu/tests/qtest/bios-tables-test.c (revision fe17cca6bd2cdfb9cc7f29da8e71aa1238bcdba7)
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