master
c 129 lines 3.34 KB
Raw
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 #include "qemu/units.h"
20
21 /* e820 entry layout and types (cf. hw/i386/e820_memory_layout.h) */
22 #define E820_RAM 1
23 #define E820_SOFT_RESERVED 0xefffffff
24
25 struct e820_entry {
26 uint64_t address;
27 uint64_t length;
28 uint32_t type;
29 } QEMU_PACKED;
30
31 #define E820_MAX_ENTRIES 128
32
33 /*
34 * Read and structurally validate "etc/e820": the file is a packed array
35 * of struct e820_entry, so its size must be a whole multiple of the entry
36 * size and every entry must have a non-zero length. Returns the entry
37 * count and fills @table.
38 */
39 static size_t get_e820_table(QFWCFG *fw_cfg, struct e820_entry *table)
40 {
41 size_t filesize, n, i;
42
43 filesize = qfw_cfg_get_file(fw_cfg, "etc/e820", table,
44 E820_MAX_ENTRIES * sizeof(*table));
45 g_assert_cmpint(filesize, >, 0);
46 g_assert_cmpint(filesize % sizeof(struct e820_entry), ==, 0);
47
48 n = filesize / sizeof(struct e820_entry);
49 g_assert_cmpint(n, <=, E820_MAX_ENTRIES);
50
51 for (i = 0; i < n; i++) {
52 g_assert_cmpint(le64_to_cpu(table[i].length), >, 0);
53 }
54
55 return n;
56 }
57
58 static void test_e820_basic(void)
59 {
60 struct e820_entry table[E820_MAX_ENTRIES];
61 QFWCFG *fw_cfg;
62 QTestState *s;
63 size_t n, i;
64 bool found_ram = false, found_soft_reserved = false;
65
66 s = qtest_init("-machine q35 -m 256M");
67 fw_cfg = pc_fw_cfg_init(s);
68
69 n = get_e820_table(fw_cfg, table);
70 for (i = 0; i < n; i++) {
71 switch (le32_to_cpu(table[i].type)) {
72 case E820_RAM:
73 found_ram = true;
74 break;
75 case E820_SOFT_RESERVED:
76 found_soft_reserved = true;
77 break;
78 }
79 }
80
81 /* baseline: RAM present, no SOFT_RESERVED range */
82 g_assert_true(found_ram);
83 g_assert_false(found_soft_reserved);
84
85 pc_fw_cfg_uninit(fw_cfg);
86 qtest_quit(s);
87 }
88
89 static void test_e820_sp_mem(void)
90 {
91 struct e820_entry table[E820_MAX_ENTRIES];
92 QFWCFG *fw_cfg;
93 QTestState *s;
94 size_t n, i;
95 int soft_reserved = 0;
96 uint64_t soft_reserved_len = 0;
97
98 s = qtest_init("-machine q35 -m 256M,slots=2,maxmem=2G "
99 "-object memory-backend-ram,id=ram0,size=256M "
100 "-numa node,nodeid=0,memdev=ram0 "
101 "-object memory-backend-ram,id=spm0,size=128M "
102 "-device sp-mem,id=sp0,memdev=spm0,node=0");
103 fw_cfg = pc_fw_cfg_init(s);
104
105 n = get_e820_table(fw_cfg, table);
106 for (i = 0; i < n; i++) {
107 if (le32_to_cpu(table[i].type) == E820_SOFT_RESERVED) {
108 soft_reserved++;
109 soft_reserved_len = le64_to_cpu(table[i].length);
110 }
111 }
112
113 /* exactly one SOFT_RESERVED range, sized to the backend */
114 g_assert_cmpint(soft_reserved, ==, 1);
115 g_assert_cmpint(soft_reserved_len, ==, 128 * MiB);
116
117 pc_fw_cfg_uninit(fw_cfg);
118 qtest_quit(s);
119 }
120
121 int main(int argc, char **argv)
122 {
123 g_test_init(&argc, &argv, NULL);
124
125 qtest_add_func("e820/basic", test_e820_basic);
126 qtest_add_func("e820/sp-mem", test_e820_sp_mem);
127
128 return g_test_run();
129 }