xref: /openbmc/qemu/tests/qtest/bios-tables-test.c (revision 0ce46ab5)
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 /*
14  * How to add or update the tests:
15  * Contributor:
16  * 1. add empty files for new tables, if any, under tests/data/acpi
17  * 2. list any changed files in tests/bios-tables-test-allowed-diff.h
18  * 3. commit the above *before* making changes that affect the tables
19  * Maintainer:
20  * After 1-3 above tests will pass but ignore differences with the expected files.
21  * You will also notice that tests/bios-tables-test-allowed-diff.h lists
22  * a bunch of files. This is your hint that you need to do the below:
23  * 4. Run
24  *      make check V=1
25  * this will produce a bunch of warnings about differences
26  * beween actual and expected ACPI tables. If you have IASL installed,
27  * they will also be disassembled so you can look at the disassembled
28  * output. If not - disassemble them yourself in any way you like.
29  * Look at the differences - make sure they make sense and match what the
30  * changes you are merging are supposed to do.
31  *
32  * 5. From build directory, run:
33  *      $(SRC_PATH)/tests/data/acpi/rebuild-expected-aml.sh
34  * 6. Now commit any changes.
35  * 7. Before doing a pull request, make sure tests/bios-tables-test-allowed-diff.h
36  *    is empty - this will ensure following changes to ACPI tables will
37  *    be noticed.
38  */
39 
40 #include "qemu/osdep.h"
41 #include <glib/gstdio.h>
42 #include "qemu-common.h"
43 #include "hw/firmware/smbios.h"
44 #include "qemu/bitmap.h"
45 #include "acpi-utils.h"
46 #include "boot-sector.h"
47 
48 #define MACHINE_PC "pc"
49 #define MACHINE_Q35 "q35"
50 
51 #define ACPI_REBUILD_EXPECTED_AML "TEST_ACPI_REBUILD_AML"
52 
53 typedef struct {
54     bool tcg_only;
55     const char *machine;
56     const char *variant;
57     const char *uefi_fl1;
58     const char *uefi_fl2;
59     const char *cd;
60     const uint64_t ram_start;
61     const uint64_t scan_len;
62     uint64_t rsdp_addr;
63     uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */];
64     GArray *tables;
65     uint32_t smbios_ep_addr;
66     struct smbios_21_entry_point smbios_ep_table;
67     uint8_t *required_struct_types;
68     int required_struct_types_len;
69     QTestState *qts;
70 } test_data;
71 
72 static char disk[] = "tests/acpi-test-disk-XXXXXX";
73 static const char *data_dir = "tests/data/acpi";
74 #ifdef CONFIG_IASL
75 static const char *iasl = stringify(CONFIG_IASL);
76 #else
77 static const char *iasl;
78 #endif
79 
80 static bool compare_signature(const AcpiSdtTable *sdt, const char *signature)
81 {
82    return !memcmp(sdt->aml, signature, 4);
83 }
84 
85 static void cleanup_table_descriptor(AcpiSdtTable *table)
86 {
87     g_free(table->aml);
88     if (table->aml_file &&
89         !table->tmp_files_retain &&
90         g_strstr_len(table->aml_file, -1, "aml-")) {
91         unlink(table->aml_file);
92     }
93     g_free(table->aml_file);
94     g_free(table->asl);
95     if (table->asl_file &&
96         !table->tmp_files_retain) {
97         unlink(table->asl_file);
98     }
99     g_free(table->asl_file);
100 }
101 
102 static void free_test_data(test_data *data)
103 {
104     int i;
105 
106     for (i = 0; i < data->tables->len; ++i) {
107         cleanup_table_descriptor(&g_array_index(data->tables, AcpiSdtTable, i));
108     }
109 
110     g_array_free(data->tables, true);
111 }
112 
113 static void test_acpi_rsdp_table(test_data *data)
114 {
115     uint8_t *rsdp_table = data->rsdp_table;
116 
117     acpi_fetch_rsdp_table(data->qts, data->rsdp_addr, rsdp_table);
118 
119     switch (rsdp_table[15 /* Revision offset */]) {
120     case 0: /* ACPI 1.0 RSDP */
121         /* With rev 1, checksum is only for the first 20 bytes */
122         g_assert(!acpi_calc_checksum(rsdp_table,  20));
123         break;
124     case 2: /* ACPI 2.0+ RSDP */
125         /* With revision 2, we have 2 checksums */
126         g_assert(!acpi_calc_checksum(rsdp_table, 20));
127         g_assert(!acpi_calc_checksum(rsdp_table, 36));
128         break;
129     default:
130         g_assert_not_reached();
131     }
132 }
133 
134 static void test_acpi_rxsdt_table(test_data *data)
135 {
136     const char *sig = "RSDT";
137     AcpiSdtTable rsdt = {};
138     int entry_size = 4;
139     int addr_off = 16 /* RsdtAddress */;
140     uint8_t *ent;
141 
142     if (data->rsdp_table[15 /* Revision offset */] != 0) {
143         addr_off = 24 /* XsdtAddress */;
144         entry_size = 8;
145         sig = "XSDT";
146     }
147     /* read [RX]SDT table */
148     acpi_fetch_table(data->qts, &rsdt.aml, &rsdt.aml_len,
149                      &data->rsdp_table[addr_off], entry_size, sig, true);
150 
151     /* Load all tables and add to test list directly RSDT referenced tables */
152     ACPI_FOREACH_RSDT_ENTRY(rsdt.aml, rsdt.aml_len, ent, entry_size) {
153         AcpiSdtTable ssdt_table = {};
154 
155         acpi_fetch_table(data->qts, &ssdt_table.aml, &ssdt_table.aml_len, ent,
156                          entry_size, NULL, true);
157         /* Add table to ASL test tables list */
158         g_array_append_val(data->tables, ssdt_table);
159     }
160     cleanup_table_descriptor(&rsdt);
161 }
162 
163 static void test_acpi_fadt_table(test_data *data)
164 {
165     /* FADT table is 1st */
166     AcpiSdtTable table = g_array_index(data->tables, typeof(table), 0);
167     uint8_t *fadt_aml = table.aml;
168     uint32_t fadt_len = table.aml_len;
169     uint32_t val;
170     int dsdt_offset = 40 /* DSDT */;
171     int dsdt_entry_size = 4;
172 
173     g_assert(compare_signature(&table, "FACP"));
174 
175     /* Since DSDT/FACS isn't in RSDT, add them to ASL test list manually */
176     memcpy(&val, fadt_aml + 112 /* Flags */, 4);
177     val = le32_to_cpu(val);
178     if (!(val & 1UL << 20 /* HW_REDUCED_ACPI */)) {
179         acpi_fetch_table(data->qts, &table.aml, &table.aml_len,
180                          fadt_aml + 36 /* FIRMWARE_CTRL */, 4, "FACS", false);
181         g_array_append_val(data->tables, table);
182     }
183 
184     memcpy(&val, fadt_aml + dsdt_offset, 4);
185     val = le32_to_cpu(val);
186     if (!val) {
187         dsdt_offset = 140 /* X_DSDT */;
188         dsdt_entry_size = 8;
189     }
190     acpi_fetch_table(data->qts, &table.aml, &table.aml_len,
191                      fadt_aml + dsdt_offset, dsdt_entry_size, "DSDT", true);
192     g_array_append_val(data->tables, table);
193 
194     memset(fadt_aml + 36, 0, 4); /* sanitize FIRMWARE_CTRL ptr */
195     memset(fadt_aml + 40, 0, 4); /* sanitize DSDT ptr */
196     if (fadt_aml[8 /* FADT Major Version */] >= 3) {
197         memset(fadt_aml + 132, 0, 8); /* sanitize X_FIRMWARE_CTRL ptr */
198         memset(fadt_aml + 140, 0, 8); /* sanitize X_DSDT ptr */
199     }
200 
201     /* update checksum */
202     fadt_aml[9 /* Checksum */] = 0;
203     fadt_aml[9 /* Checksum */] -= acpi_calc_checksum(fadt_aml, fadt_len);
204 }
205 
206 static void dump_aml_files(test_data *data, bool rebuild)
207 {
208     AcpiSdtTable *sdt;
209     GError *error = NULL;
210     gchar *aml_file = NULL;
211     gint fd;
212     ssize_t ret;
213     int i;
214 
215     for (i = 0; i < data->tables->len; ++i) {
216         const char *ext = data->variant ? data->variant : "";
217         sdt = &g_array_index(data->tables, AcpiSdtTable, i);
218         g_assert(sdt->aml);
219 
220         if (rebuild) {
221             aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine,
222                                        sdt->aml, ext);
223             fd = g_open(aml_file, O_WRONLY|O_TRUNC|O_CREAT,
224                         S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
225             if (fd < 0) {
226                 perror(aml_file);
227             }
228             g_assert(fd >= 0);
229         } else {
230             fd = g_file_open_tmp("aml-XXXXXX", &sdt->aml_file, &error);
231             g_assert_no_error(error);
232         }
233 
234         ret = qemu_write_full(fd, sdt->aml, sdt->aml_len);
235         g_assert(ret == sdt->aml_len);
236 
237         close(fd);
238 
239         g_free(aml_file);
240     }
241 }
242 
243 static bool load_asl(GArray *sdts, AcpiSdtTable *sdt)
244 {
245     AcpiSdtTable *temp;
246     GError *error = NULL;
247     GString *command_line = g_string_new(iasl);
248     gint fd;
249     gchar *out, *out_err;
250     gboolean ret;
251     int i;
252 
253     fd = g_file_open_tmp("asl-XXXXXX.dsl", &sdt->asl_file, &error);
254     g_assert_no_error(error);
255     close(fd);
256 
257     /* build command line */
258     g_string_append_printf(command_line, " -p %s ", sdt->asl_file);
259     if (compare_signature(sdt, "DSDT") ||
260         compare_signature(sdt, "SSDT")) {
261         for (i = 0; i < sdts->len; ++i) {
262             temp = &g_array_index(sdts, AcpiSdtTable, i);
263             if (compare_signature(temp, "DSDT") ||
264                 compare_signature(temp, "SSDT")) {
265                 g_string_append_printf(command_line, "-e %s ", temp->aml_file);
266             }
267         }
268     }
269     g_string_append_printf(command_line, "-d %s", sdt->aml_file);
270 
271     /* pass 'out' and 'out_err' in order to be redirected */
272     ret = g_spawn_command_line_sync(command_line->str, &out, &out_err, NULL, &error);
273     g_assert_no_error(error);
274     if (ret) {
275         ret = g_file_get_contents(sdt->asl_file, &sdt->asl,
276                                   &sdt->asl_len, &error);
277         g_assert(ret);
278         g_assert_no_error(error);
279         ret = (sdt->asl_len > 0);
280     }
281 
282     g_free(out);
283     g_free(out_err);
284     g_string_free(command_line, true);
285 
286     return !ret;
287 }
288 
289 #define COMMENT_END "*/"
290 #define DEF_BLOCK "DefinitionBlock ("
291 #define BLOCK_NAME_END ","
292 
293 static GString *normalize_asl(gchar *asl_code)
294 {
295     GString *asl = g_string_new(asl_code);
296     gchar *comment, *block_name;
297 
298     /* strip comments (different generation days) */
299     comment = g_strstr_len(asl->str, asl->len, COMMENT_END);
300     if (comment) {
301         comment += strlen(COMMENT_END);
302         while (*comment == '\n') {
303             comment++;
304         }
305         asl = g_string_erase(asl, 0, comment - asl->str);
306     }
307 
308     /* strip def block name (it has file path in it) */
309     if (g_str_has_prefix(asl->str, DEF_BLOCK)) {
310         block_name = g_strstr_len(asl->str, asl->len, BLOCK_NAME_END);
311         g_assert(block_name);
312         asl = g_string_erase(asl, 0,
313                              block_name + sizeof(BLOCK_NAME_END) - asl->str);
314     }
315 
316     return asl;
317 }
318 
319 static GArray *load_expected_aml(test_data *data)
320 {
321     int i;
322     AcpiSdtTable *sdt;
323     GError *error = NULL;
324     gboolean ret;
325     gsize aml_len;
326 
327     GArray *exp_tables = g_array_new(false, true, sizeof(AcpiSdtTable));
328     if (getenv("V")) {
329         fputc('\n', stderr);
330     }
331     for (i = 0; i < data->tables->len; ++i) {
332         AcpiSdtTable exp_sdt;
333         gchar *aml_file = NULL;
334         const char *ext = data->variant ? data->variant : "";
335 
336         sdt = &g_array_index(data->tables, AcpiSdtTable, i);
337 
338         memset(&exp_sdt, 0, sizeof(exp_sdt));
339 
340 try_again:
341         aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine,
342                                    sdt->aml, ext);
343         if (getenv("V")) {
344             fprintf(stderr, "Looking for expected file '%s'\n", aml_file);
345         }
346         if (g_file_test(aml_file, G_FILE_TEST_EXISTS)) {
347             exp_sdt.aml_file = aml_file;
348         } else if (*ext != '\0') {
349             /* try fallback to generic (extension less) expected file */
350             ext = "";
351             g_free(aml_file);
352             goto try_again;
353         }
354         g_assert(exp_sdt.aml_file);
355         if (getenv("V")) {
356             fprintf(stderr, "Using expected file '%s'\n", aml_file);
357         }
358         ret = g_file_get_contents(aml_file, (gchar **)&exp_sdt.aml,
359                                   &aml_len, &error);
360         exp_sdt.aml_len = aml_len;
361         g_assert(ret);
362         g_assert_no_error(error);
363         g_assert(exp_sdt.aml);
364         if (!exp_sdt.aml_len) {
365             fprintf(stderr, "Warning! zero length expected file '%s'\n",
366                     aml_file);
367         }
368 
369         g_array_append_val(exp_tables, exp_sdt);
370     }
371 
372     return exp_tables;
373 }
374 
375 static bool test_acpi_find_diff_allowed(AcpiSdtTable *sdt)
376 {
377     const gchar *allowed_diff_file[] = {
378 #include "bios-tables-test-allowed-diff.h"
379         NULL
380     };
381     const gchar **f;
382 
383     for (f = allowed_diff_file; *f; ++f) {
384         if (!g_strcmp0(sdt->aml_file, *f)) {
385             return true;
386         }
387     }
388     return false;
389 }
390 
391 /* test the list of tables in @data->tables against reference tables */
392 static void test_acpi_asl(test_data *data)
393 {
394     int i;
395     AcpiSdtTable *sdt, *exp_sdt;
396     test_data exp_data;
397     gboolean exp_err, err, all_tables_match = true;
398 
399     memset(&exp_data, 0, sizeof(exp_data));
400     exp_data.tables = load_expected_aml(data);
401     dump_aml_files(data, false);
402     for (i = 0; i < data->tables->len; ++i) {
403         GString *asl, *exp_asl;
404 
405         sdt = &g_array_index(data->tables, AcpiSdtTable, i);
406         exp_sdt = &g_array_index(exp_data.tables, AcpiSdtTable, i);
407 
408         if (sdt->aml_len == exp_sdt->aml_len &&
409             !memcmp(sdt->aml, exp_sdt->aml, sdt->aml_len)) {
410             /* Identical table binaries: no need to disassemble. */
411             continue;
412         }
413 
414         fprintf(stderr,
415                 "acpi-test: Warning! %.4s binary file mismatch. "
416                 "Actual [aml:%s], Expected [aml:%s].\n",
417                 exp_sdt->aml, sdt->aml_file, exp_sdt->aml_file);
418 
419         all_tables_match = all_tables_match &&
420             test_acpi_find_diff_allowed(exp_sdt);
421 
422         /*
423          *  don't try to decompile if IASL isn't present, in this case user
424          * will just 'get binary file mismatch' warnings and test failure
425          */
426         if (!iasl) {
427             continue;
428         }
429 
430         err = load_asl(data->tables, sdt);
431         asl = normalize_asl(sdt->asl);
432 
433         exp_err = load_asl(exp_data.tables, exp_sdt);
434         exp_asl = normalize_asl(exp_sdt->asl);
435 
436         /* TODO: check for warnings */
437         g_assert(!err || exp_err);
438 
439         if (g_strcmp0(asl->str, exp_asl->str)) {
440             sdt->tmp_files_retain = true;
441             if (exp_err) {
442                 fprintf(stderr,
443                         "Warning! iasl couldn't parse the expected aml\n");
444             } else {
445                 exp_sdt->tmp_files_retain = true;
446                 fprintf(stderr,
447                         "acpi-test: Warning! %.4s mismatch. "
448                         "Actual [asl:%s, aml:%s], Expected [asl:%s, aml:%s].\n",
449                         exp_sdt->aml, sdt->asl_file, sdt->aml_file,
450                         exp_sdt->asl_file, exp_sdt->aml_file);
451                 if (getenv("V")) {
452                     const char *diff_cmd = getenv("DIFF");
453                     if (diff_cmd) {
454                         int ret G_GNUC_UNUSED;
455                         char *diff = g_strdup_printf("%s %s %s", diff_cmd,
456                             exp_sdt->asl_file, sdt->asl_file);
457                         ret = system(diff) ;
458                         g_free(diff);
459                     } else {
460                         fprintf(stderr, "acpi-test: Warning. not showing "
461                             "difference since no diff utility is specified. "
462                             "Set 'DIFF' environment variable to a preferred "
463                             "diff utility and run 'make V=1 check' again to "
464                             "see ASL difference.");
465                     }
466                 }
467             }
468         }
469         g_string_free(asl, true);
470         g_string_free(exp_asl, true);
471     }
472     if (!iasl && !all_tables_match) {
473         fprintf(stderr, "to see ASL diff between mismatched files install IASL,"
474                 " rebuild QEMU from scratch and re-run tests with V=1"
475                 " environment variable set");
476     }
477     g_assert(all_tables_match);
478 
479     free_test_data(&exp_data);
480 }
481 
482 static bool smbios_ep_table_ok(test_data *data)
483 {
484     struct smbios_21_entry_point *ep_table = &data->smbios_ep_table;
485     uint32_t addr = data->smbios_ep_addr;
486 
487     qtest_memread(data->qts, addr, ep_table, sizeof(*ep_table));
488     if (memcmp(ep_table->anchor_string, "_SM_", 4)) {
489         return false;
490     }
491     if (memcmp(ep_table->intermediate_anchor_string, "_DMI_", 5)) {
492         return false;
493     }
494     if (ep_table->structure_table_length == 0) {
495         return false;
496     }
497     if (ep_table->number_of_structures == 0) {
498         return false;
499     }
500     if (acpi_calc_checksum((uint8_t *)ep_table, sizeof *ep_table) ||
501         acpi_calc_checksum((uint8_t *)ep_table + 0x10,
502                            sizeof *ep_table - 0x10)) {
503         return false;
504     }
505     return true;
506 }
507 
508 static void test_smbios_entry_point(test_data *data)
509 {
510     uint32_t off;
511 
512     /* find smbios entry point structure */
513     for (off = 0xf0000; off < 0x100000; off += 0x10) {
514         uint8_t sig[] = "_SM_";
515         int i;
516 
517         for (i = 0; i < sizeof sig - 1; ++i) {
518             sig[i] = qtest_readb(data->qts, off + i);
519         }
520 
521         if (!memcmp(sig, "_SM_", sizeof sig)) {
522             /* signature match, but is this a valid entry point? */
523             data->smbios_ep_addr = off;
524             if (smbios_ep_table_ok(data)) {
525                 break;
526             }
527         }
528     }
529 
530     g_assert_cmphex(off, <, 0x100000);
531 }
532 
533 static inline bool smbios_single_instance(uint8_t type)
534 {
535     switch (type) {
536     case 0:
537     case 1:
538     case 2:
539     case 3:
540     case 16:
541     case 32:
542     case 127:
543         return true;
544     default:
545         return false;
546     }
547 }
548 
549 static void test_smbios_structs(test_data *data)
550 {
551     DECLARE_BITMAP(struct_bitmap, SMBIOS_MAX_TYPE+1) = { 0 };
552     struct smbios_21_entry_point *ep_table = &data->smbios_ep_table;
553     uint32_t addr = le32_to_cpu(ep_table->structure_table_address);
554     int i, len, max_len = 0;
555     uint8_t type, prv, crt;
556 
557     /* walk the smbios tables */
558     for (i = 0; i < le16_to_cpu(ep_table->number_of_structures); i++) {
559 
560         /* grab type and formatted area length from struct header */
561         type = qtest_readb(data->qts, addr);
562         g_assert_cmpuint(type, <=, SMBIOS_MAX_TYPE);
563         len = qtest_readb(data->qts, addr + 1);
564 
565         /* single-instance structs must not have been encountered before */
566         if (smbios_single_instance(type)) {
567             g_assert(!test_bit(type, struct_bitmap));
568         }
569         set_bit(type, struct_bitmap);
570 
571         /* seek to end of unformatted string area of this struct ("\0\0") */
572         prv = crt = 1;
573         while (prv || crt) {
574             prv = crt;
575             crt = qtest_readb(data->qts, addr + len);
576             len++;
577         }
578 
579         /* keep track of max. struct size */
580         if (max_len < len) {
581             max_len = len;
582             g_assert_cmpuint(max_len, <=, ep_table->max_structure_size);
583         }
584 
585         /* start of next structure */
586         addr += len;
587     }
588 
589     /* total table length and max struct size must match entry point values */
590     g_assert_cmpuint(le16_to_cpu(ep_table->structure_table_length), ==,
591                      addr - le32_to_cpu(ep_table->structure_table_address));
592     g_assert_cmpuint(le16_to_cpu(ep_table->max_structure_size), ==, max_len);
593 
594     /* required struct types must all be present */
595     for (i = 0; i < data->required_struct_types_len; i++) {
596         g_assert(test_bit(data->required_struct_types[i], struct_bitmap));
597     }
598 }
599 
600 static void test_acpi_one(const char *params, test_data *data)
601 {
602     char *args;
603     bool use_uefi = data->uefi_fl1 && data->uefi_fl2;
604 
605     if (use_uefi) {
606         /*
607          * TODO: convert '-drive if=pflash' to new syntax (see e33763be7cd3)
608          * when arm/virt boad starts to support it.
609          */
610         args = g_strdup_printf("-machine %s %s -accel tcg -nodefaults -nographic "
611             "-drive if=pflash,format=raw,file=%s,readonly "
612             "-drive if=pflash,format=raw,file=%s,snapshot=on -cdrom %s %s",
613             data->machine, data->tcg_only ? "" : "-accel kvm",
614             data->uefi_fl1, data->uefi_fl2, data->cd, params ? params : "");
615 
616     } else {
617         /* Disable kernel irqchip to be able to override apic irq0. */
618         args = g_strdup_printf("-machine %s,kernel-irqchip=off %s -accel tcg "
619             "-net none -display none %s "
620             "-drive id=hd0,if=none,file=%s,format=raw "
621             "-device ide-hd,drive=hd0 ",
622              data->machine, data->tcg_only ? "" : "-accel kvm",
623              params ? params : "", disk);
624     }
625 
626     data->qts = qtest_init(args);
627 
628     if (use_uefi) {
629         g_assert(data->scan_len);
630         data->rsdp_addr = acpi_find_rsdp_address_uefi(data->qts,
631             data->ram_start, data->scan_len);
632     } else {
633         boot_sector_test(data->qts);
634         data->rsdp_addr = acpi_find_rsdp_address(data->qts);
635         g_assert_cmphex(data->rsdp_addr, <, 0x100000);
636     }
637 
638     data->tables = g_array_new(false, true, sizeof(AcpiSdtTable));
639     test_acpi_rsdp_table(data);
640     test_acpi_rxsdt_table(data);
641     test_acpi_fadt_table(data);
642 
643     if (getenv(ACPI_REBUILD_EXPECTED_AML)) {
644         dump_aml_files(data, true);
645     } else {
646         test_acpi_asl(data);
647     }
648 
649     /*
650      * TODO: make SMBIOS tests work with UEFI firmware,
651      * Bug on uefi-test-tools to provide entry point:
652      * https://bugs.launchpad.net/qemu/+bug/1821884
653      */
654     if (!use_uefi) {
655         test_smbios_entry_point(data);
656         test_smbios_structs(data);
657     }
658 
659     qtest_quit(data->qts);
660     g_free(args);
661 }
662 
663 static uint8_t base_required_struct_types[] = {
664     0, 1, 3, 4, 16, 17, 19, 32, 127
665 };
666 
667 static void test_acpi_piix4_tcg(void)
668 {
669     test_data data;
670 
671     /* Supplying -machine accel argument overrides the default (qtest).
672      * This is to make guest actually run.
673      */
674     memset(&data, 0, sizeof(data));
675     data.machine = MACHINE_PC;
676     data.required_struct_types = base_required_struct_types;
677     data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
678     test_acpi_one(NULL, &data);
679     free_test_data(&data);
680 }
681 
682 static void test_acpi_piix4_tcg_bridge(void)
683 {
684     test_data data;
685 
686     memset(&data, 0, sizeof(data));
687     data.machine = MACHINE_PC;
688     data.variant = ".bridge";
689     data.required_struct_types = base_required_struct_types;
690     data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
691     test_acpi_one("-device pci-bridge,chassis_nr=1", &data);
692     free_test_data(&data);
693 }
694 
695 static void test_acpi_q35_tcg(void)
696 {
697     test_data data;
698 
699     memset(&data, 0, sizeof(data));
700     data.machine = MACHINE_Q35;
701     data.required_struct_types = base_required_struct_types;
702     data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
703     test_acpi_one(NULL, &data);
704     free_test_data(&data);
705 }
706 
707 static void test_acpi_q35_tcg_bridge(void)
708 {
709     test_data data;
710 
711     memset(&data, 0, sizeof(data));
712     data.machine = MACHINE_Q35;
713     data.variant = ".bridge";
714     data.required_struct_types = base_required_struct_types;
715     data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
716     test_acpi_one("-device pci-bridge,chassis_nr=1",
717                   &data);
718     free_test_data(&data);
719 }
720 
721 static void test_acpi_q35_tcg_mmio64(void)
722 {
723     test_data data = {
724         .machine = MACHINE_Q35,
725         .variant = ".mmio64",
726         .required_struct_types = base_required_struct_types,
727         .required_struct_types_len = ARRAY_SIZE(base_required_struct_types)
728     };
729 
730     test_acpi_one("-m 128M,slots=1,maxmem=2G "
731                   "-object memory-backend-ram,id=ram0,size=128M "
732                   "-numa node,memdev=ram0 "
733                   "-device pci-testdev,membar=2G",
734                   &data);
735     free_test_data(&data);
736 }
737 
738 static void test_acpi_piix4_tcg_cphp(void)
739 {
740     test_data data;
741 
742     memset(&data, 0, sizeof(data));
743     data.machine = MACHINE_PC;
744     data.variant = ".cphp";
745     test_acpi_one("-smp 2,cores=3,sockets=2,maxcpus=6"
746                   " -object memory-backend-ram,id=ram0,size=64M"
747                   " -object memory-backend-ram,id=ram1,size=64M"
748                   " -numa node,memdev=ram0 -numa node,memdev=ram1"
749                   " -numa dist,src=0,dst=1,val=21",
750                   &data);
751     free_test_data(&data);
752 }
753 
754 static void test_acpi_q35_tcg_cphp(void)
755 {
756     test_data data;
757 
758     memset(&data, 0, sizeof(data));
759     data.machine = MACHINE_Q35;
760     data.variant = ".cphp";
761     test_acpi_one(" -smp 2,cores=3,sockets=2,maxcpus=6"
762                   " -object memory-backend-ram,id=ram0,size=64M"
763                   " -object memory-backend-ram,id=ram1,size=64M"
764                   " -numa node,memdev=ram0 -numa node,memdev=ram1"
765                   " -numa dist,src=0,dst=1,val=21",
766                   &data);
767     free_test_data(&data);
768 }
769 
770 static uint8_t ipmi_required_struct_types[] = {
771     0, 1, 3, 4, 16, 17, 19, 32, 38, 127
772 };
773 
774 static void test_acpi_q35_tcg_ipmi(void)
775 {
776     test_data data;
777 
778     memset(&data, 0, sizeof(data));
779     data.machine = MACHINE_Q35;
780     data.variant = ".ipmibt";
781     data.required_struct_types = ipmi_required_struct_types;
782     data.required_struct_types_len = ARRAY_SIZE(ipmi_required_struct_types);
783     test_acpi_one("-device ipmi-bmc-sim,id=bmc0"
784                   " -device isa-ipmi-bt,bmc=bmc0",
785                   &data);
786     free_test_data(&data);
787 }
788 
789 static void test_acpi_piix4_tcg_ipmi(void)
790 {
791     test_data data;
792 
793     /* Supplying -machine accel argument overrides the default (qtest).
794      * This is to make guest actually run.
795      */
796     memset(&data, 0, sizeof(data));
797     data.machine = MACHINE_PC;
798     data.variant = ".ipmikcs";
799     data.required_struct_types = ipmi_required_struct_types;
800     data.required_struct_types_len = ARRAY_SIZE(ipmi_required_struct_types);
801     test_acpi_one("-device ipmi-bmc-sim,id=bmc0"
802                   " -device isa-ipmi-kcs,irq=0,bmc=bmc0",
803                   &data);
804     free_test_data(&data);
805 }
806 
807 static void test_acpi_q35_tcg_memhp(void)
808 {
809     test_data data;
810 
811     memset(&data, 0, sizeof(data));
812     data.machine = MACHINE_Q35;
813     data.variant = ".memhp";
814     test_acpi_one(" -m 128,slots=3,maxmem=1G"
815                   " -object memory-backend-ram,id=ram0,size=64M"
816                   " -object memory-backend-ram,id=ram1,size=64M"
817                   " -numa node,memdev=ram0 -numa node,memdev=ram1"
818                   " -numa dist,src=0,dst=1,val=21",
819                   &data);
820     free_test_data(&data);
821 }
822 
823 static void test_acpi_piix4_tcg_memhp(void)
824 {
825     test_data data;
826 
827     memset(&data, 0, sizeof(data));
828     data.machine = MACHINE_PC;
829     data.variant = ".memhp";
830     test_acpi_one(" -m 128,slots=3,maxmem=1G"
831                   " -object memory-backend-ram,id=ram0,size=64M"
832                   " -object memory-backend-ram,id=ram1,size=64M"
833                   " -numa node,memdev=ram0 -numa node,memdev=ram1"
834                   " -numa dist,src=0,dst=1,val=21",
835                   &data);
836     free_test_data(&data);
837 }
838 
839 static void test_acpi_q35_tcg_numamem(void)
840 {
841     test_data data;
842 
843     memset(&data, 0, sizeof(data));
844     data.machine = MACHINE_Q35;
845     data.variant = ".numamem";
846     test_acpi_one(" -object memory-backend-ram,id=ram0,size=128M"
847                   " -numa node -numa node,memdev=ram0", &data);
848     free_test_data(&data);
849 }
850 
851 static void test_acpi_piix4_tcg_numamem(void)
852 {
853     test_data data;
854 
855     memset(&data, 0, sizeof(data));
856     data.machine = MACHINE_PC;
857     data.variant = ".numamem";
858     test_acpi_one(" -object memory-backend-ram,id=ram0,size=128M"
859                   " -numa node -numa node,memdev=ram0", &data);
860     free_test_data(&data);
861 }
862 
863 static void test_acpi_tcg_dimm_pxm(const char *machine)
864 {
865     test_data data;
866 
867     memset(&data, 0, sizeof(data));
868     data.machine = machine;
869     data.variant = ".dimmpxm";
870     test_acpi_one(" -machine nvdimm=on,nvdimm-persistence=cpu"
871                   " -smp 4,sockets=4"
872                   " -m 128M,slots=3,maxmem=1G"
873                   " -object memory-backend-ram,id=ram0,size=32M"
874                   " -object memory-backend-ram,id=ram1,size=32M"
875                   " -object memory-backend-ram,id=ram2,size=32M"
876                   " -object memory-backend-ram,id=ram3,size=32M"
877                   " -numa node,memdev=ram0,nodeid=0"
878                   " -numa node,memdev=ram1,nodeid=1"
879                   " -numa node,memdev=ram2,nodeid=2"
880                   " -numa node,memdev=ram3,nodeid=3"
881                   " -numa cpu,node-id=0,socket-id=0"
882                   " -numa cpu,node-id=1,socket-id=1"
883                   " -numa cpu,node-id=2,socket-id=2"
884                   " -numa cpu,node-id=3,socket-id=3"
885                   " -object memory-backend-ram,id=ram4,size=128M"
886                   " -object memory-backend-ram,id=nvm0,size=128M"
887                   " -device pc-dimm,id=dimm0,memdev=ram4,node=1"
888                   " -device nvdimm,id=dimm1,memdev=nvm0,node=2",
889                   &data);
890     free_test_data(&data);
891 }
892 
893 static void test_acpi_q35_tcg_dimm_pxm(void)
894 {
895     test_acpi_tcg_dimm_pxm(MACHINE_Q35);
896 }
897 
898 static void test_acpi_piix4_tcg_dimm_pxm(void)
899 {
900     test_acpi_tcg_dimm_pxm(MACHINE_PC);
901 }
902 
903 static void test_acpi_virt_tcg_memhp(void)
904 {
905     test_data data = {
906         .machine = "virt",
907         .tcg_only = true,
908         .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
909         .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
910         .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2",
911         .ram_start = 0x40000000ULL,
912         .scan_len = 256ULL * 1024 * 1024,
913     };
914 
915     data.variant = ".memhp";
916     test_acpi_one(" -cpu cortex-a57"
917                   " -m 256M,slots=3,maxmem=1G"
918                   " -object memory-backend-ram,id=ram0,size=128M"
919                   " -object memory-backend-ram,id=ram1,size=128M"
920                   " -numa node,memdev=ram0 -numa node,memdev=ram1"
921                   " -numa dist,src=0,dst=1,val=21",
922                   &data);
923 
924     free_test_data(&data);
925 
926 }
927 
928 static void test_acpi_virt_tcg_numamem(void)
929 {
930     test_data data = {
931         .machine = "virt",
932         .tcg_only = true,
933         .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
934         .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
935         .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2",
936         .ram_start = 0x40000000ULL,
937         .scan_len = 128ULL * 1024 * 1024,
938     };
939 
940     data.variant = ".numamem";
941     test_acpi_one(" -cpu cortex-a57"
942                   " -object memory-backend-ram,id=ram0,size=128M"
943                   " -numa node,memdev=ram0",
944                   &data);
945 
946     free_test_data(&data);
947 
948 }
949 
950 static void test_acpi_tcg_acpi_hmat(const char *machine)
951 {
952     test_data data;
953 
954     memset(&data, 0, sizeof(data));
955     data.machine = machine;
956     data.variant = ".acpihmat";
957     test_acpi_one(" -machine hmat=on"
958                   " -smp 2,sockets=2"
959                   " -m 128M,slots=2,maxmem=1G"
960                   " -object memory-backend-ram,size=64M,id=m0"
961                   " -object memory-backend-ram,size=64M,id=m1"
962                   " -numa node,nodeid=0,memdev=m0"
963                   " -numa node,nodeid=1,memdev=m1,initiator=0"
964                   " -numa cpu,node-id=0,socket-id=0"
965                   " -numa cpu,node-id=0,socket-id=1"
966                   " -numa hmat-lb,initiator=0,target=0,hierarchy=memory,"
967                   "data-type=access-latency,latency=1"
968                   " -numa hmat-lb,initiator=0,target=0,hierarchy=memory,"
969                   "data-type=access-bandwidth,bandwidth=65534M"
970                   " -numa hmat-lb,initiator=0,target=1,hierarchy=memory,"
971                   "data-type=access-latency,latency=65534"
972                   " -numa hmat-lb,initiator=0,target=1,hierarchy=memory,"
973                   "data-type=access-bandwidth,bandwidth=32767M"
974                   " -numa hmat-cache,node-id=0,size=10K,level=1,"
975                   "associativity=direct,policy=write-back,line=8"
976                   " -numa hmat-cache,node-id=1,size=10K,level=1,"
977                   "associativity=direct,policy=write-back,line=8",
978                   &data);
979     free_test_data(&data);
980 }
981 
982 static void test_acpi_q35_tcg_acpi_hmat(void)
983 {
984     test_acpi_tcg_acpi_hmat(MACHINE_Q35);
985 }
986 
987 static void test_acpi_piix4_tcg_acpi_hmat(void)
988 {
989     test_acpi_tcg_acpi_hmat(MACHINE_PC);
990 }
991 
992 static void test_acpi_virt_tcg(void)
993 {
994     test_data data = {
995         .machine = "virt",
996         .tcg_only = true,
997         .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
998         .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
999         .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2",
1000         .ram_start = 0x40000000ULL,
1001         .scan_len = 128ULL * 1024 * 1024,
1002     };
1003 
1004     test_acpi_one("-cpu cortex-a57", &data);
1005     free_test_data(&data);
1006 }
1007 
1008 int main(int argc, char *argv[])
1009 {
1010     const char *arch = qtest_get_arch();
1011     int ret;
1012 
1013     g_test_init(&argc, &argv, NULL);
1014 
1015     if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
1016         ret = boot_sector_init(disk);
1017         if (ret) {
1018             return ret;
1019         }
1020 
1021         qtest_add_func("acpi/piix4", test_acpi_piix4_tcg);
1022         qtest_add_func("acpi/piix4/bridge", test_acpi_piix4_tcg_bridge);
1023         qtest_add_func("acpi/q35", test_acpi_q35_tcg);
1024         qtest_add_func("acpi/q35/bridge", test_acpi_q35_tcg_bridge);
1025         qtest_add_func("acpi/q35/mmio64", test_acpi_q35_tcg_mmio64);
1026         qtest_add_func("acpi/piix4/ipmi", test_acpi_piix4_tcg_ipmi);
1027         qtest_add_func("acpi/q35/ipmi", test_acpi_q35_tcg_ipmi);
1028         qtest_add_func("acpi/piix4/cpuhp", test_acpi_piix4_tcg_cphp);
1029         qtest_add_func("acpi/q35/cpuhp", test_acpi_q35_tcg_cphp);
1030         qtest_add_func("acpi/piix4/memhp", test_acpi_piix4_tcg_memhp);
1031         qtest_add_func("acpi/q35/memhp", test_acpi_q35_tcg_memhp);
1032         qtest_add_func("acpi/piix4/numamem", test_acpi_piix4_tcg_numamem);
1033         qtest_add_func("acpi/q35/numamem", test_acpi_q35_tcg_numamem);
1034         qtest_add_func("acpi/piix4/dimmpxm", test_acpi_piix4_tcg_dimm_pxm);
1035         qtest_add_func("acpi/q35/dimmpxm", test_acpi_q35_tcg_dimm_pxm);
1036         qtest_add_func("acpi/piix4/acpihmat", test_acpi_piix4_tcg_acpi_hmat);
1037         qtest_add_func("acpi/q35/acpihmat", test_acpi_q35_tcg_acpi_hmat);
1038     } else if (strcmp(arch, "aarch64") == 0) {
1039         qtest_add_func("acpi/virt", test_acpi_virt_tcg);
1040         qtest_add_func("acpi/virt/numamem", test_acpi_virt_tcg_numamem);
1041         qtest_add_func("acpi/virt/memhp", test_acpi_virt_tcg_memhp);
1042     }
1043     ret = g_test_run();
1044     boot_sector_cleanup(disk);
1045     return ret;
1046 }
1047