@samitouri / QOSamiQemu / commits / 0819ca9dbd

tests/qtest: add e820 fw_cfg test

Add a qtest that reads the "etc/e820" fw_cfg table and checks its structural invariants: the file is a whole number of e820 entries and every entry has a non-zero length. The baseline q35 case asserts the guest sees RAM and, with no sp-mem device, no SOFT_RESERVED range. Signed-off-by: FangSheng Huang <FangSheng.Huang@amd.com> Acked-by: Igor Mammedov <imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Message-ID: <20260623075051.3797975-10-FangSheng.Huang@amd.com>

fanhuang committed Jun 23, 2026 at 15:50 UTC 0819ca9dbd882fff0a1cf9a241a444b4bd34ebbd
2 files changed +96
tests/qtest/e820-test.c new
+95
@@ -0,0 +1,95 @@
1 +/*
2 + * qtest e820 fw_cfg test case
3 + *
4 + * Validate the "etc/e820" fw_cfg table that QEMU hands to the firmware.
5 + *
6 + * Copyright (c) 2026 Advanced Micro Devices, Inc.
7 + *
8 + * Authors:
9 + * FangSheng Huang <FangSheng.Huang@amd.com>
10 + *
11 + * SPDX-License-Identifier: GPL-2.0-or-later
12 + */
13 +
14 +#include "qemu/osdep.h"
15 +
16 +#include "libqtest.h"
17 +#include "libqos/fw_cfg.h"
18 +#include "qemu/bswap.h"
19 +
20 +/* e820 entry layout and types (cf. hw/i386/e820_memory_layout.h) */
21 +#define E820_RAM 1
22 +#define E820_SOFT_RESERVED 0xefffffff
23 +
24 +struct e820_entry {
25 + uint64_t address;
26 + uint64_t length;
27 + uint32_t type;
28 +} QEMU_PACKED;
29 +
30 +#define E820_MAX_ENTRIES 128
31 +
32 +/*
33 + * Read and structurally validate "etc/e820": the file is a packed array
34 + * of struct e820_entry, so its size must be a whole multiple of the entry
35 + * size and every entry must have a non-zero length. Returns the entry
36 + * count and fills @table.
37 + */
38 +static size_t get_e820_table(QFWCFG *fw_cfg, struct e820_entry *table)
39 +{
40 + size_t filesize, n, i;
41 +
42 + filesize = qfw_cfg_get_file(fw_cfg, "etc/e820", table,
43 + E820_MAX_ENTRIES * sizeof(*table));
44 + g_assert_cmpint(filesize, >, 0);
45 + g_assert_cmpint(filesize % sizeof(struct e820_entry), ==, 0);
46 +
47 + n = filesize / sizeof(struct e820_entry);
48 + g_assert_cmpint(n, <=, E820_MAX_ENTRIES);
49 +
50 + for (i = 0; i < n; i++) {
51 + g_assert_cmpint(le64_to_cpu(table[i].length), >, 0);
52 + }
53 +
54 + return n;
55 +}
56 +
57 +static void test_e820_basic(void)
58 +{
59 + struct e820_entry table[E820_MAX_ENTRIES];
60 + QFWCFG *fw_cfg;
61 + QTestState *s;
62 + size_t n, i;
63 + bool found_ram = false, found_soft_reserved = false;
64 +
65 + s = qtest_init("-machine q35 -m 256M");
66 + fw_cfg = pc_fw_cfg_init(s);
67 +
68 + n = get_e820_table(fw_cfg, table);
69 + for (i = 0; i < n; i++) {
70 + switch (le32_to_cpu(table[i].type)) {
71 + case E820_RAM:
72 + found_ram = true;
73 + break;
74 + case E820_SOFT_RESERVED:
75 + found_soft_reserved = true;
76 + break;
77 + }
78 + }
79 +
80 + /* baseline: RAM present, no SOFT_RESERVED range */
81 + g_assert_true(found_ram);
82 + g_assert_false(found_soft_reserved);
83 +
84 + pc_fw_cfg_uninit(fw_cfg);
85 + qtest_quit(s);
86 +}
87 +
88 +int main(int argc, char **argv)
89 +{
90 + g_test_init(&argc, &argv, NULL);
91 +
92 + qtest_add_func("e820/basic", test_e820_basic);
93 +
94 + return g_test_run();
95 +}
tests/qtest/meson.build
+1
@@ -58,6 +58,7 @@ qtests_i386 = \
58 (config_all_devices.has_key('CONFIG_AHCI_ICH9') ? ['tco-test'] : []) + \
59 (config_all_devices.has_key('CONFIG_FDC_ISA') ? ['fdc-test'] : []) + \
60 (config_all_devices.has_key('CONFIG_I440FX') ? ['fw_cfg-test'] : []) + \
61 + (config_all_devices.has_key('CONFIG_Q35') ? ['e820-test'] : []) + \
62 (config_all_devices.has_key('CONFIG_FW_CFG_DMA') ? ['vmcoreinfo-test'] : []) + \
63 (config_all_devices.has_key('CONFIG_Q35') ? ['dump-test'] : []) + \
64 (config_all_devices.has_key('CONFIG_I440FX') ? ['i440fx-test'] : []) + \