]> Git Repo - qemu.git/blob - tests/vmgenid-test.c
tests: Force Python I/O encoding for check-qapi-schema
[qemu.git] / tests / vmgenid-test.c
1 /*
2  * QTest testcase for VM Generation ID
3  *
4  * Copyright (c) 2016 Red Hat, Inc.
5  * Copyright (c) 2017 Skyport Systems
6  *
7  * This work is licensed under the terms of the GNU GPL, version 2 or later.
8  * See the COPYING file in the top-level directory.
9  */
10
11 #include "qemu/osdep.h"
12 #include "qemu/bitmap.h"
13 #include "qemu/uuid.h"
14 #include "hw/acpi/acpi-defs.h"
15 #include "boot-sector.h"
16 #include "acpi-utils.h"
17 #include "libqtest.h"
18 #include "qapi/qmp/qdict.h"
19
20 #define VGID_GUID "324e6eaf-d1d1-4bf6-bf41-b9bb6c91fb87"
21 #define VMGENID_GUID_OFFSET 40   /* allow space for
22                                   * OVMF SDT Header Probe Supressor
23                                   */
24 #define RSDP_ADDR_INVALID 0x100000 /* RSDP must be below this address */
25
26 static uint32_t acpi_find_vgia(QTestState *qts)
27 {
28     uint32_t rsdp_offset;
29     uint32_t guid_offset = 0;
30     uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */];
31     uint32_t rsdt_len, table_length;
32     uint8_t *rsdt, *ent;
33
34     /* Wait for guest firmware to finish and start the payload. */
35     boot_sector_test(qts);
36
37     /* Tables should be initialized now. */
38     rsdp_offset = acpi_find_rsdp_address(qts);
39
40     g_assert_cmphex(rsdp_offset, <, RSDP_ADDR_INVALID);
41
42
43     acpi_parse_rsdp_table(qts, rsdp_offset, rsdp_table);
44     acpi_fetch_table(qts, &rsdt, &rsdt_len, &rsdp_table[16 /* RsdtAddress */],
45                      "RSDT", true);
46
47     ACPI_FOREACH_RSDT_ENTRY(rsdt, rsdt_len, ent, 4 /* Entry size */) {
48         uint8_t *table_aml;
49
50         acpi_fetch_table(qts, &table_aml, &table_length, ent, NULL, true);
51         if (!memcmp(table_aml + 16 /* OEM Table ID */, "VMGENID", 7)) {
52             uint32_t vgia_val;
53             uint8_t *aml = &table_aml[36 /* AML byte-code start */];
54             /* the first entry in the table should be VGIA
55              * That's all we need
56              */
57             g_assert(aml[0 /* name_op*/] == 0x08);
58             g_assert(memcmp(&aml[1 /* name */], "VGIA", 4) == 0);
59             g_assert(aml[5 /* value op */] == 0x0C /* dword */);
60             memcpy(&vgia_val, &aml[6 /* value */], 4);
61
62             /* The GUID is written at a fixed offset into the fw_cfg file
63              * in order to implement the "OVMF SDT Header probe suppressor"
64              * see docs/specs/vmgenid.txt for more details
65              */
66             guid_offset = le32_to_cpu(vgia_val) + VMGENID_GUID_OFFSET;
67             g_free(table_aml);
68             break;
69         }
70         g_free(table_aml);
71     }
72     g_free(rsdt);
73     return guid_offset;
74 }
75
76 static void read_guid_from_memory(QTestState *qts, QemuUUID *guid)
77 {
78     uint32_t vmgenid_addr;
79     int i;
80
81     vmgenid_addr = acpi_find_vgia(qts);
82     g_assert(vmgenid_addr);
83
84     /* Read the GUID directly from guest memory */
85     for (i = 0; i < 16; i++) {
86         guid->data[i] = qtest_readb(qts, vmgenid_addr + i);
87     }
88     /* The GUID is in little-endian format in the guest, while QEMU
89      * uses big-endian.  Swap after reading.
90      */
91     *guid = qemu_uuid_bswap(*guid);
92 }
93
94 static void read_guid_from_monitor(QTestState *qts, QemuUUID *guid)
95 {
96     QDict *rsp, *rsp_ret;
97     const char *guid_str;
98
99     rsp = qtest_qmp(qts, "{ 'execute': 'query-vm-generation-id' }");
100     if (qdict_haskey(rsp, "return")) {
101         rsp_ret = qdict_get_qdict(rsp, "return");
102         g_assert(qdict_haskey(rsp_ret, "guid"));
103         guid_str = qdict_get_str(rsp_ret, "guid");
104         g_assert(qemu_uuid_parse(guid_str, guid) == 0);
105     }
106     qobject_unref(rsp);
107 }
108
109 static char disk[] = "tests/vmgenid-test-disk-XXXXXX";
110
111 #define GUID_CMD(guid)                          \
112     "-machine accel=kvm:tcg "                   \
113     "-device vmgenid,id=testvgid,guid=%s "      \
114     "-drive id=hd0,if=none,file=%s,format=raw " \
115     "-device ide-hd,drive=hd0 ", guid, disk
116
117 static void vmgenid_set_guid_test(void)
118 {
119     QemuUUID expected, measured;
120     QTestState *qts;
121
122     g_assert(qemu_uuid_parse(VGID_GUID, &expected) == 0);
123
124     qts = qtest_initf(GUID_CMD(VGID_GUID));
125
126     /* Read the GUID from accessing guest memory */
127     read_guid_from_memory(qts, &measured);
128     g_assert(memcmp(measured.data, expected.data, sizeof(measured.data)) == 0);
129
130     qtest_quit(qts);
131 }
132
133 static void vmgenid_set_guid_auto_test(void)
134 {
135     QemuUUID measured;
136     QTestState *qts;
137
138     qts = qtest_initf(GUID_CMD("auto"));
139
140     read_guid_from_memory(qts, &measured);
141
142     /* Just check that the GUID is non-null */
143     g_assert(!qemu_uuid_is_null(&measured));
144
145     qtest_quit(qts);
146 }
147
148 static void vmgenid_query_monitor_test(void)
149 {
150     QemuUUID expected, measured;
151     QTestState *qts;
152
153     g_assert(qemu_uuid_parse(VGID_GUID, &expected) == 0);
154
155     qts = qtest_initf(GUID_CMD(VGID_GUID));
156
157     /* Read the GUID via the monitor */
158     read_guid_from_monitor(qts, &measured);
159     g_assert(memcmp(measured.data, expected.data, sizeof(measured.data)) == 0);
160
161     qtest_quit(qts);
162 }
163
164 int main(int argc, char **argv)
165 {
166     int ret;
167
168     ret = boot_sector_init(disk);
169     if (ret) {
170         return ret;
171     }
172
173     g_test_init(&argc, &argv, NULL);
174
175     qtest_add_func("/vmgenid/vmgenid/set-guid",
176                    vmgenid_set_guid_test);
177     qtest_add_func("/vmgenid/vmgenid/set-guid-auto",
178                    vmgenid_set_guid_auto_test);
179     qtest_add_func("/vmgenid/vmgenid/query-monitor",
180                    vmgenid_query_monitor_test);
181     ret = g_test_run();
182     boot_sector_cleanup(disk);
183
184     return ret;
185 }
This page took 0.0342 seconds and 4 git commands to generate.