On Fri, 19 Jun 2026 19:11:35 +0800 fanhuang <[email protected]> wrote:
> 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 <[email protected]> Acked-by: Igor Mammedov <[email protected]> > --- > tests/qtest/e820-test.c | 95 +++++++++++++++++++++++++++++++++++++++++ > tests/qtest/meson.build | 1 + > 2 files changed, 96 insertions(+) > create mode 100644 tests/qtest/e820-test.c > > diff --git a/tests/qtest/e820-test.c b/tests/qtest/e820-test.c > new file mode 100644 > index 0000000000..1db0744c08 > --- /dev/null > +++ b/tests/qtest/e820-test.c > @@ -0,0 +1,95 @@ > +/* > + * qtest e820 fw_cfg test case > + * > + * Validate the "etc/e820" fw_cfg table that QEMU hands to the firmware. > + * > + * Copyright (c) 2026 Advanced Micro Devices, Inc. > + * > + * Authors: > + * FangSheng Huang <[email protected]> > + * > + * SPDX-License-Identifier: GPL-2.0-or-later > + */ > + > +#include "qemu/osdep.h" > + > +#include "libqtest.h" > +#include "libqos/fw_cfg.h" > +#include "qemu/bswap.h" > + > +/* e820 entry layout and types (cf. hw/i386/e820_memory_layout.h) */ > +#define E820_RAM 1 > +#define E820_SOFT_RESERVED 0xefffffff > + > +struct e820_entry { > + uint64_t address; > + uint64_t length; > + uint32_t type; > +} QEMU_PACKED; > + > +#define E820_MAX_ENTRIES 128 > + > +/* > + * Read and structurally validate "etc/e820": the file is a packed array > + * of struct e820_entry, so its size must be a whole multiple of the entry > + * size and every entry must have a non-zero length. Returns the entry > + * count and fills @table. > + */ > +static size_t get_e820_table(QFWCFG *fw_cfg, struct e820_entry *table) > +{ > + size_t filesize, n, i; > + > + filesize = qfw_cfg_get_file(fw_cfg, "etc/e820", table, > + E820_MAX_ENTRIES * sizeof(*table)); > + g_assert_cmpint(filesize, >, 0); > + g_assert_cmpint(filesize % sizeof(struct e820_entry), ==, 0); > + > + n = filesize / sizeof(struct e820_entry); > + g_assert_cmpint(n, <=, E820_MAX_ENTRIES); > + > + for (i = 0; i < n; i++) { > + g_assert_cmpint(le64_to_cpu(table[i].length), >, 0); > + } > + > + return n; > +} > + > +static void test_e820_basic(void) > +{ > + struct e820_entry table[E820_MAX_ENTRIES]; > + QFWCFG *fw_cfg; > + QTestState *s; > + size_t n, i; > + bool found_ram = false, found_soft_reserved = false; > + > + s = qtest_init("-machine q35 -m 256M"); > + fw_cfg = pc_fw_cfg_init(s); > + > + n = get_e820_table(fw_cfg, table); > + for (i = 0; i < n; i++) { > + switch (le32_to_cpu(table[i].type)) { > + case E820_RAM: > + found_ram = true; > + break; > + case E820_SOFT_RESERVED: > + found_soft_reserved = true; > + break; > + } > + } > + > + /* baseline: RAM present, no SOFT_RESERVED range */ > + g_assert_true(found_ram); > + g_assert_false(found_soft_reserved); > + > + pc_fw_cfg_uninit(fw_cfg); > + qtest_quit(s); > +} > + > +int main(int argc, char **argv) > +{ > + g_test_init(&argc, &argv, NULL); > + > + qtest_add_func("e820/basic", test_e820_basic); > + > + return g_test_run(); > +} > diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build > index 4897325d84..d69ee27fa4 100644 > --- a/tests/qtest/meson.build > +++ b/tests/qtest/meson.build > @@ -58,6 +58,7 @@ qtests_i386 = \ > (config_all_devices.has_key('CONFIG_AHCI_ICH9') ? ['tco-test'] : []) + > \ > (config_all_devices.has_key('CONFIG_FDC_ISA') ? ['fdc-test'] : []) + > \ > (config_all_devices.has_key('CONFIG_I440FX') ? ['fw_cfg-test'] : []) + > \ > + (config_all_devices.has_key('CONFIG_Q35') ? ['e820-test'] : []) + > \ > (config_all_devices.has_key('CONFIG_FW_CFG_DMA') ? ['vmcoreinfo-test'] : > []) + \ > (config_all_devices.has_key('CONFIG_I440FX') ? ['i440fx-test'] : []) + > \ > (config_all_devices.has_key('CONFIG_I440FX') ? ['ide-test'] : []) + > \
