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