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'] : []) + \