Files
qemu/tests/qtest/e820-test.c
fanhuang c31b39063f tests/qtest: cover sp-mem SOFT_RESERVED e820 entry
Boot one sp-mem device and assert the guest's e820 table gains exactly
one E820_SOFT_RESERVED range whose length matches the device's backend
size.

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-11-FangSheng.Huang@amd.com>
2026-07-03 21:21:07 -04:00

130 lines
3.3 KiB
C

/*
* 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 <FangSheng.Huang@amd.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "libqtest.h"
#include "libqos/fw_cfg.h"
#include "qemu/bswap.h"
#include "qemu/units.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);
}
static void test_e820_sp_mem(void)
{
struct e820_entry table[E820_MAX_ENTRIES];
QFWCFG *fw_cfg;
QTestState *s;
size_t n, i;
int soft_reserved = 0;
uint64_t soft_reserved_len = 0;
s = qtest_init("-machine q35 -m 256M,slots=2,maxmem=2G "
"-object memory-backend-ram,id=ram0,size=256M "
"-numa node,nodeid=0,memdev=ram0 "
"-object memory-backend-ram,id=spm0,size=128M "
"-device sp-mem,id=sp0,memdev=spm0,node=0");
fw_cfg = pc_fw_cfg_init(s);
n = get_e820_table(fw_cfg, table);
for (i = 0; i < n; i++) {
if (le32_to_cpu(table[i].type) == E820_SOFT_RESERVED) {
soft_reserved++;
soft_reserved_len = le64_to_cpu(table[i].length);
}
}
/* exactly one SOFT_RESERVED range, sized to the backend */
g_assert_cmpint(soft_reserved, ==, 1);
g_assert_cmpint(soft_reserved_len, ==, 128 * MiB);
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);
qtest_add_func("e820/sp-mem", test_e820_sp_mem);
return g_test_run();
}