root / tests / acpi-test.c @ feature-archipelago
History | View | Annotate | Download (19.7 kB)
1 |
/*
|
---|---|
2 |
* Boot order test cases.
|
3 |
*
|
4 |
* Copyright (c) 2013 Red Hat Inc.
|
5 |
*
|
6 |
* Authors:
|
7 |
* Michael S. Tsirkin <mst@redhat.com>,
|
8 |
*
|
9 |
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
10 |
* See the COPYING file in the top-level directory.
|
11 |
*/
|
12 |
|
13 |
#include <string.h> |
14 |
#include <stdio.h> |
15 |
#include <glib.h> |
16 |
#include <glib/gstdio.h> |
17 |
#include "qemu-common.h" |
18 |
#include "libqtest.h" |
19 |
#include "qemu/compiler.h" |
20 |
#include "hw/i386/acpi-defs.h" |
21 |
|
22 |
#define MACHINE_PC "pc" |
23 |
#define MACHINE_Q35 "q35" |
24 |
|
25 |
#define ACPI_REBUILD_EXPECTED_AML "TEST_ACPI_REBUILD_AML" |
26 |
#define ACPI_SSDT_SIGNATURE 0x54445353 /* SSDT */ |
27 |
|
28 |
/* DSDT and SSDTs format */
|
29 |
typedef struct { |
30 |
AcpiTableHeader header; |
31 |
gchar *aml; /* aml bytecode from guest */
|
32 |
gsize aml_len; |
33 |
gchar *aml_file; |
34 |
gchar *asl; /* asl code generated from aml */
|
35 |
gsize asl_len; |
36 |
gchar *asl_file; |
37 |
bool asl_file_retain; /* do not delete the temp asl */ |
38 |
} QEMU_PACKED AcpiSdtTable; |
39 |
|
40 |
typedef struct { |
41 |
const char *machine; |
42 |
uint32_t rsdp_addr; |
43 |
AcpiRsdpDescriptor rsdp_table; |
44 |
AcpiRsdtDescriptorRev1 rsdt_table; |
45 |
AcpiFadtDescriptorRev1 fadt_table; |
46 |
AcpiFacsDescriptorRev1 facs_table; |
47 |
uint32_t *rsdt_tables_addr; |
48 |
int rsdt_tables_nr;
|
49 |
GArray *tables; |
50 |
} test_data; |
51 |
|
52 |
#define LOW(x) ((x) & 0xff) |
53 |
#define HIGH(x) ((x) >> 8) |
54 |
|
55 |
#define SIGNATURE 0xdead |
56 |
#define SIGNATURE_OFFSET 0x10 |
57 |
#define BOOT_SECTOR_ADDRESS 0x7c00 |
58 |
|
59 |
#define ACPI_READ_FIELD(field, addr) \
|
60 |
do { \
|
61 |
switch (sizeof(field)) { \ |
62 |
case 1: \ |
63 |
field = readb(addr); \ |
64 |
break; \
|
65 |
case 2: \ |
66 |
field = readw(addr); \ |
67 |
break; \
|
68 |
case 4: \ |
69 |
field = readl(addr); \ |
70 |
break; \
|
71 |
case 8: \ |
72 |
field = readq(addr); \ |
73 |
break; \
|
74 |
default: \
|
75 |
g_assert(false); \
|
76 |
} \ |
77 |
addr += sizeof(field); \
|
78 |
} while (0); |
79 |
|
80 |
#define ACPI_READ_ARRAY_PTR(arr, length, addr) \
|
81 |
do { \
|
82 |
int idx; \
|
83 |
for (idx = 0; idx < length; ++idx) { \ |
84 |
ACPI_READ_FIELD(arr[idx], addr); \ |
85 |
} \ |
86 |
} while (0); |
87 |
|
88 |
#define ACPI_READ_ARRAY(arr, addr) \
|
89 |
ACPI_READ_ARRAY_PTR(arr, sizeof(arr)/sizeof(arr[0]), addr) |
90 |
|
91 |
#define ACPI_READ_TABLE_HEADER(table, addr) \
|
92 |
do { \
|
93 |
ACPI_READ_FIELD((table)->signature, addr); \ |
94 |
ACPI_READ_FIELD((table)->length, addr); \ |
95 |
ACPI_READ_FIELD((table)->revision, addr); \ |
96 |
ACPI_READ_FIELD((table)->checksum, addr); \ |
97 |
ACPI_READ_ARRAY((table)->oem_id, addr); \ |
98 |
ACPI_READ_ARRAY((table)->oem_table_id, addr); \ |
99 |
ACPI_READ_FIELD((table)->oem_revision, addr); \ |
100 |
ACPI_READ_ARRAY((table)->asl_compiler_id, addr); \ |
101 |
ACPI_READ_FIELD((table)->asl_compiler_revision, addr); \ |
102 |
} while (0); |
103 |
|
104 |
/* Boot sector code: write SIGNATURE into memory,
|
105 |
* then halt.
|
106 |
* Q35 machine requires a minimum 0x7e000 bytes disk.
|
107 |
* (bug or feature?)
|
108 |
*/
|
109 |
static uint8_t boot_sector[0x7e000] = { |
110 |
/* 7c00: mov $0xdead,%ax */
|
111 |
[0x00] = 0xb8, |
112 |
[0x01] = LOW(SIGNATURE),
|
113 |
[0x02] = HIGH(SIGNATURE),
|
114 |
/* 7c03: mov %ax,0x7c10 */
|
115 |
[0x03] = 0xa3, |
116 |
[0x04] = LOW(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET),
|
117 |
[0x05] = HIGH(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET),
|
118 |
/* 7c06: cli */
|
119 |
[0x06] = 0xfa, |
120 |
/* 7c07: hlt */
|
121 |
[0x07] = 0xf4, |
122 |
/* 7c08: jmp 0x7c07=0x7c0a-3 */
|
123 |
[0x08] = 0xeb, |
124 |
[0x09] = LOW(-3), |
125 |
/* We mov 0xdead here: set value to make debugging easier */
|
126 |
[SIGNATURE_OFFSET] = LOW(0xface),
|
127 |
[SIGNATURE_OFFSET + 1] = HIGH(0xface), |
128 |
/* End of boot sector marker */
|
129 |
[0x1FE] = 0x55, |
130 |
[0x1FF] = 0xAA, |
131 |
}; |
132 |
|
133 |
static const char *disk = "tests/acpi-test-disk.raw"; |
134 |
static const char *data_dir = "tests/acpi-test-data"; |
135 |
#ifdef CONFIG_IASL
|
136 |
static const char *iasl = stringify(CONFIG_IASL); |
137 |
#else
|
138 |
static const char *iasl; |
139 |
#endif
|
140 |
|
141 |
static void free_test_data(test_data *data) |
142 |
{ |
143 |
AcpiSdtTable *temp; |
144 |
int i;
|
145 |
|
146 |
if (data->rsdt_tables_addr) {
|
147 |
g_free(data->rsdt_tables_addr); |
148 |
} |
149 |
|
150 |
for (i = 0; i < data->tables->len; ++i) { |
151 |
temp = &g_array_index(data->tables, AcpiSdtTable, i); |
152 |
if (temp->aml) {
|
153 |
g_free(temp->aml); |
154 |
} |
155 |
if (temp->aml_file) {
|
156 |
if (g_strstr_len(temp->aml_file, -1, "aml-")) { |
157 |
unlink(temp->aml_file); |
158 |
} |
159 |
g_free(temp->aml_file); |
160 |
} |
161 |
if (temp->asl) {
|
162 |
g_free(temp->asl); |
163 |
} |
164 |
if (temp->asl_file) {
|
165 |
if (!temp->asl_file_retain) {
|
166 |
unlink(temp->asl_file); |
167 |
} |
168 |
g_free(temp->asl_file); |
169 |
} |
170 |
} |
171 |
|
172 |
g_array_free(data->tables, false);
|
173 |
} |
174 |
|
175 |
static uint8_t acpi_checksum(const uint8_t *data, int len) |
176 |
{ |
177 |
int i;
|
178 |
uint8_t sum = 0;
|
179 |
|
180 |
for (i = 0; i < len; i++) { |
181 |
sum += data[i]; |
182 |
} |
183 |
|
184 |
return sum;
|
185 |
} |
186 |
|
187 |
static void test_acpi_rsdp_address(test_data *data) |
188 |
{ |
189 |
uint32_t off; |
190 |
|
191 |
/* OK, now find RSDP */
|
192 |
for (off = 0xf0000; off < 0x100000; off += 0x10) { |
193 |
uint8_t sig[] = "RSD PTR ";
|
194 |
int i;
|
195 |
|
196 |
for (i = 0; i < sizeof sig - 1; ++i) { |
197 |
sig[i] = readb(off + i); |
198 |
} |
199 |
|
200 |
if (!memcmp(sig, "RSD PTR ", sizeof sig)) { |
201 |
break;
|
202 |
} |
203 |
} |
204 |
|
205 |
g_assert_cmphex(off, <, 0x100000);
|
206 |
data->rsdp_addr = off; |
207 |
} |
208 |
|
209 |
static void test_acpi_rsdp_table(test_data *data) |
210 |
{ |
211 |
AcpiRsdpDescriptor *rsdp_table = &data->rsdp_table; |
212 |
uint32_t addr = data->rsdp_addr; |
213 |
|
214 |
ACPI_READ_FIELD(rsdp_table->signature, addr); |
215 |
g_assert_cmphex(rsdp_table->signature, ==, ACPI_RSDP_SIGNATURE); |
216 |
|
217 |
ACPI_READ_FIELD(rsdp_table->checksum, addr); |
218 |
ACPI_READ_ARRAY(rsdp_table->oem_id, addr); |
219 |
ACPI_READ_FIELD(rsdp_table->revision, addr); |
220 |
ACPI_READ_FIELD(rsdp_table->rsdt_physical_address, addr); |
221 |
ACPI_READ_FIELD(rsdp_table->length, addr); |
222 |
|
223 |
/* rsdp checksum is not for the whole table, but for the first 20 bytes */
|
224 |
g_assert(!acpi_checksum((uint8_t *)rsdp_table, 20));
|
225 |
} |
226 |
|
227 |
static void test_acpi_rsdt_table(test_data *data) |
228 |
{ |
229 |
AcpiRsdtDescriptorRev1 *rsdt_table = &data->rsdt_table; |
230 |
uint32_t addr = data->rsdp_table.rsdt_physical_address; |
231 |
uint32_t *tables; |
232 |
int tables_nr;
|
233 |
uint8_t checksum; |
234 |
|
235 |
/* read the header */
|
236 |
ACPI_READ_TABLE_HEADER(rsdt_table, addr); |
237 |
g_assert_cmphex(rsdt_table->signature, ==, ACPI_RSDT_SIGNATURE); |
238 |
|
239 |
/* compute the table entries in rsdt */
|
240 |
tables_nr = (rsdt_table->length - sizeof(AcpiRsdtDescriptorRev1)) /
|
241 |
sizeof(uint32_t);
|
242 |
g_assert_cmpint(tables_nr, >, 0);
|
243 |
|
244 |
/* get the addresses of the tables pointed by rsdt */
|
245 |
tables = g_new0(uint32_t, tables_nr); |
246 |
ACPI_READ_ARRAY_PTR(tables, tables_nr, addr); |
247 |
|
248 |
checksum = acpi_checksum((uint8_t *)rsdt_table, rsdt_table->length) + |
249 |
acpi_checksum((uint8_t *)tables, tables_nr * sizeof(uint32_t));
|
250 |
g_assert(!checksum); |
251 |
|
252 |
/* SSDT tables after FADT */
|
253 |
data->rsdt_tables_addr = tables; |
254 |
data->rsdt_tables_nr = tables_nr; |
255 |
} |
256 |
|
257 |
static void test_acpi_fadt_table(test_data *data) |
258 |
{ |
259 |
AcpiFadtDescriptorRev1 *fadt_table = &data->fadt_table; |
260 |
uint32_t addr; |
261 |
|
262 |
/* FADT table comes first */
|
263 |
addr = data->rsdt_tables_addr[0];
|
264 |
ACPI_READ_TABLE_HEADER(fadt_table, addr); |
265 |
|
266 |
ACPI_READ_FIELD(fadt_table->firmware_ctrl, addr); |
267 |
ACPI_READ_FIELD(fadt_table->dsdt, addr); |
268 |
ACPI_READ_FIELD(fadt_table->model, addr); |
269 |
ACPI_READ_FIELD(fadt_table->reserved1, addr); |
270 |
ACPI_READ_FIELD(fadt_table->sci_int, addr); |
271 |
ACPI_READ_FIELD(fadt_table->smi_cmd, addr); |
272 |
ACPI_READ_FIELD(fadt_table->acpi_enable, addr); |
273 |
ACPI_READ_FIELD(fadt_table->acpi_disable, addr); |
274 |
ACPI_READ_FIELD(fadt_table->S4bios_req, addr); |
275 |
ACPI_READ_FIELD(fadt_table->reserved2, addr); |
276 |
ACPI_READ_FIELD(fadt_table->pm1a_evt_blk, addr); |
277 |
ACPI_READ_FIELD(fadt_table->pm1b_evt_blk, addr); |
278 |
ACPI_READ_FIELD(fadt_table->pm1a_cnt_blk, addr); |
279 |
ACPI_READ_FIELD(fadt_table->pm1b_cnt_blk, addr); |
280 |
ACPI_READ_FIELD(fadt_table->pm2_cnt_blk, addr); |
281 |
ACPI_READ_FIELD(fadt_table->pm_tmr_blk, addr); |
282 |
ACPI_READ_FIELD(fadt_table->gpe0_blk, addr); |
283 |
ACPI_READ_FIELD(fadt_table->gpe1_blk, addr); |
284 |
ACPI_READ_FIELD(fadt_table->pm1_evt_len, addr); |
285 |
ACPI_READ_FIELD(fadt_table->pm1_cnt_len, addr); |
286 |
ACPI_READ_FIELD(fadt_table->pm2_cnt_len, addr); |
287 |
ACPI_READ_FIELD(fadt_table->pm_tmr_len, addr); |
288 |
ACPI_READ_FIELD(fadt_table->gpe0_blk_len, addr); |
289 |
ACPI_READ_FIELD(fadt_table->gpe1_blk_len, addr); |
290 |
ACPI_READ_FIELD(fadt_table->gpe1_base, addr); |
291 |
ACPI_READ_FIELD(fadt_table->reserved3, addr); |
292 |
ACPI_READ_FIELD(fadt_table->plvl2_lat, addr); |
293 |
ACPI_READ_FIELD(fadt_table->plvl3_lat, addr); |
294 |
ACPI_READ_FIELD(fadt_table->flush_size, addr); |
295 |
ACPI_READ_FIELD(fadt_table->flush_stride, addr); |
296 |
ACPI_READ_FIELD(fadt_table->duty_offset, addr); |
297 |
ACPI_READ_FIELD(fadt_table->duty_width, addr); |
298 |
ACPI_READ_FIELD(fadt_table->day_alrm, addr); |
299 |
ACPI_READ_FIELD(fadt_table->mon_alrm, addr); |
300 |
ACPI_READ_FIELD(fadt_table->century, addr); |
301 |
ACPI_READ_FIELD(fadt_table->reserved4, addr); |
302 |
ACPI_READ_FIELD(fadt_table->reserved4a, addr); |
303 |
ACPI_READ_FIELD(fadt_table->reserved4b, addr); |
304 |
ACPI_READ_FIELD(fadt_table->flags, addr); |
305 |
|
306 |
g_assert_cmphex(fadt_table->signature, ==, ACPI_FACP_SIGNATURE); |
307 |
g_assert(!acpi_checksum((uint8_t *)fadt_table, fadt_table->length)); |
308 |
} |
309 |
|
310 |
static void test_acpi_facs_table(test_data *data) |
311 |
{ |
312 |
AcpiFacsDescriptorRev1 *facs_table = &data->facs_table; |
313 |
uint32_t addr = data->fadt_table.firmware_ctrl; |
314 |
|
315 |
ACPI_READ_FIELD(facs_table->signature, addr); |
316 |
ACPI_READ_FIELD(facs_table->length, addr); |
317 |
ACPI_READ_FIELD(facs_table->hardware_signature, addr); |
318 |
ACPI_READ_FIELD(facs_table->firmware_waking_vector, addr); |
319 |
ACPI_READ_FIELD(facs_table->global_lock, addr); |
320 |
ACPI_READ_FIELD(facs_table->flags, addr); |
321 |
ACPI_READ_ARRAY(facs_table->resverved3, addr); |
322 |
|
323 |
g_assert_cmphex(facs_table->signature, ==, ACPI_FACS_SIGNATURE); |
324 |
} |
325 |
|
326 |
static void test_dst_table(AcpiSdtTable *sdt_table, uint32_t addr) |
327 |
{ |
328 |
uint8_t checksum; |
329 |
|
330 |
ACPI_READ_TABLE_HEADER(&sdt_table->header, addr); |
331 |
|
332 |
sdt_table->aml_len = sdt_table->header.length - sizeof(AcpiTableHeader);
|
333 |
sdt_table->aml = g_malloc0(sdt_table->aml_len); |
334 |
ACPI_READ_ARRAY_PTR(sdt_table->aml, sdt_table->aml_len, addr); |
335 |
|
336 |
checksum = acpi_checksum((uint8_t *)sdt_table, sizeof(AcpiTableHeader)) +
|
337 |
acpi_checksum((uint8_t *)sdt_table->aml, sdt_table->aml_len); |
338 |
g_assert(!checksum); |
339 |
} |
340 |
|
341 |
static void test_acpi_dsdt_table(test_data *data) |
342 |
{ |
343 |
AcpiSdtTable dsdt_table; |
344 |
uint32_t addr = data->fadt_table.dsdt; |
345 |
|
346 |
memset(&dsdt_table, 0, sizeof(dsdt_table)); |
347 |
data->tables = g_array_new(false, true, sizeof(AcpiSdtTable)); |
348 |
|
349 |
test_dst_table(&dsdt_table, addr); |
350 |
g_assert_cmphex(dsdt_table.header.signature, ==, ACPI_DSDT_SIGNATURE); |
351 |
|
352 |
/* Place DSDT first */
|
353 |
g_array_append_val(data->tables, dsdt_table); |
354 |
} |
355 |
|
356 |
static void test_acpi_tables(test_data *data) |
357 |
{ |
358 |
int tables_nr = data->rsdt_tables_nr - 1; /* fadt is first */ |
359 |
int i;
|
360 |
|
361 |
for (i = 0; i < tables_nr; i++) { |
362 |
AcpiSdtTable ssdt_table; |
363 |
|
364 |
memset(&ssdt_table, 0 , sizeof(ssdt_table)); |
365 |
uint32_t addr = data->rsdt_tables_addr[i + 1]; /* fadt is first */ |
366 |
test_dst_table(&ssdt_table, addr); |
367 |
g_array_append_val(data->tables, ssdt_table); |
368 |
} |
369 |
} |
370 |
|
371 |
static void dump_aml_files(test_data *data, bool rebuild) |
372 |
{ |
373 |
AcpiSdtTable *sdt; |
374 |
GError *error = NULL;
|
375 |
gchar *aml_file = NULL;
|
376 |
gint fd; |
377 |
ssize_t ret; |
378 |
int i;
|
379 |
|
380 |
for (i = 0; i < data->tables->len; ++i) { |
381 |
sdt = &g_array_index(data->tables, AcpiSdtTable, i); |
382 |
g_assert(sdt->aml); |
383 |
|
384 |
if (rebuild) {
|
385 |
aml_file = g_strdup_printf("%s/%s/%.4s", data_dir, data->machine,
|
386 |
(gchar *)&sdt->header.signature); |
387 |
fd = g_open(aml_file, O_WRONLY|O_TRUNC|O_CREAT, |
388 |
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH); |
389 |
} else {
|
390 |
fd = g_file_open_tmp("aml-XXXXXX", &sdt->aml_file, &error);
|
391 |
g_assert_no_error(error); |
392 |
} |
393 |
g_assert(fd >= 0);
|
394 |
|
395 |
ret = qemu_write_full(fd, sdt, sizeof(AcpiTableHeader));
|
396 |
g_assert(ret == sizeof(AcpiTableHeader));
|
397 |
ret = qemu_write_full(fd, sdt->aml, sdt->aml_len); |
398 |
g_assert(ret == sdt->aml_len); |
399 |
|
400 |
close(fd); |
401 |
|
402 |
if (aml_file) {
|
403 |
g_free(aml_file); |
404 |
} |
405 |
} |
406 |
} |
407 |
|
408 |
static bool compare_signature(AcpiSdtTable *sdt, uint32_t signature) |
409 |
{ |
410 |
return sdt->header.signature == signature;
|
411 |
} |
412 |
|
413 |
static void load_asl(GArray *sdts, AcpiSdtTable *sdt) |
414 |
{ |
415 |
AcpiSdtTable *temp; |
416 |
GError *error = NULL;
|
417 |
GString *command_line = g_string_new(iasl); |
418 |
gint fd; |
419 |
gchar *out, *out_err; |
420 |
gboolean ret; |
421 |
int i;
|
422 |
|
423 |
fd = g_file_open_tmp("asl-XXXXXX.dsl", &sdt->asl_file, &error);
|
424 |
g_assert_no_error(error); |
425 |
close(fd); |
426 |
|
427 |
/* build command line */
|
428 |
g_string_append_printf(command_line, " -p %s ", sdt->asl_file);
|
429 |
if (compare_signature(sdt, ACPI_DSDT_SIGNATURE) ||
|
430 |
compare_signature(sdt, ACPI_SSDT_SIGNATURE)) { |
431 |
for (i = 0; i < sdts->len; ++i) { |
432 |
temp = &g_array_index(sdts, AcpiSdtTable, i); |
433 |
if (compare_signature(temp, ACPI_DSDT_SIGNATURE) ||
|
434 |
compare_signature(temp, ACPI_SSDT_SIGNATURE)) { |
435 |
g_string_append_printf(command_line, "-e %s ", temp->aml_file);
|
436 |
} |
437 |
} |
438 |
} |
439 |
g_string_append_printf(command_line, "-d %s", sdt->aml_file);
|
440 |
|
441 |
/* pass 'out' and 'out_err' in order to be redirected */
|
442 |
g_spawn_command_line_sync(command_line->str, &out, &out_err, NULL, &error);
|
443 |
g_assert_no_error(error); |
444 |
|
445 |
ret = g_file_get_contents(sdt->asl_file, (gchar **)&sdt->asl, |
446 |
&sdt->asl_len, &error); |
447 |
g_assert(ret); |
448 |
g_assert_no_error(error); |
449 |
g_assert(sdt->asl_len); |
450 |
|
451 |
g_free(out); |
452 |
g_free(out_err); |
453 |
g_string_free(command_line, true);
|
454 |
} |
455 |
|
456 |
#define COMMENT_END "*/" |
457 |
#define DEF_BLOCK "DefinitionBlock (" |
458 |
#define BLOCK_NAME_END ".aml" |
459 |
|
460 |
static GString *normalize_asl(gchar *asl_code)
|
461 |
{ |
462 |
GString *asl = g_string_new(asl_code); |
463 |
gchar *comment, *block_name; |
464 |
|
465 |
/* strip comments (different generation days) */
|
466 |
comment = g_strstr_len(asl->str, asl->len, COMMENT_END); |
467 |
if (comment) {
|
468 |
asl = g_string_erase(asl, 0, comment + sizeof(COMMENT_END) - asl->str); |
469 |
} |
470 |
|
471 |
/* strip def block name (it has file path in it) */
|
472 |
if (g_str_has_prefix(asl->str, DEF_BLOCK)) {
|
473 |
block_name = g_strstr_len(asl->str, asl->len, BLOCK_NAME_END); |
474 |
g_assert(block_name); |
475 |
asl = g_string_erase(asl, 0,
|
476 |
block_name + sizeof(BLOCK_NAME_END) - asl->str);
|
477 |
} |
478 |
|
479 |
return asl;
|
480 |
} |
481 |
|
482 |
static GArray *load_expected_aml(test_data *data)
|
483 |
{ |
484 |
int i;
|
485 |
AcpiSdtTable *sdt; |
486 |
gchar *aml_file; |
487 |
GError *error = NULL;
|
488 |
gboolean ret; |
489 |
|
490 |
GArray *exp_tables = g_array_new(false, true, sizeof(AcpiSdtTable)); |
491 |
for (i = 0; i < data->tables->len; ++i) { |
492 |
AcpiSdtTable exp_sdt; |
493 |
sdt = &g_array_index(data->tables, AcpiSdtTable, i); |
494 |
|
495 |
memset(&exp_sdt, 0, sizeof(exp_sdt)); |
496 |
exp_sdt.header.signature = sdt->header.signature; |
497 |
|
498 |
aml_file = g_strdup_printf("%s/%s/%.4s", data_dir, data->machine,
|
499 |
(gchar *)&exp_sdt.header.signature); |
500 |
exp_sdt.aml_file = aml_file; |
501 |
g_assert(g_file_test(aml_file, G_FILE_TEST_EXISTS)); |
502 |
ret = g_file_get_contents(aml_file, &exp_sdt.aml, |
503 |
&exp_sdt.aml_len, &error); |
504 |
g_assert(ret); |
505 |
g_assert_no_error(error); |
506 |
g_assert(exp_sdt.aml); |
507 |
g_assert(exp_sdt.aml_len); |
508 |
|
509 |
g_array_append_val(exp_tables, exp_sdt); |
510 |
} |
511 |
|
512 |
return exp_tables;
|
513 |
} |
514 |
|
515 |
static void test_acpi_asl(test_data *data) |
516 |
{ |
517 |
int i;
|
518 |
AcpiSdtTable *sdt, *exp_sdt; |
519 |
test_data exp_data; |
520 |
|
521 |
memset(&exp_data, 0, sizeof(exp_data)); |
522 |
exp_data.tables = load_expected_aml(data); |
523 |
dump_aml_files(data, false);
|
524 |
for (i = 0; i < data->tables->len; ++i) { |
525 |
GString *asl, *exp_asl; |
526 |
|
527 |
sdt = &g_array_index(data->tables, AcpiSdtTable, i); |
528 |
exp_sdt = &g_array_index(exp_data.tables, AcpiSdtTable, i); |
529 |
|
530 |
load_asl(data->tables, sdt); |
531 |
asl = normalize_asl(sdt->asl); |
532 |
|
533 |
load_asl(exp_data.tables, exp_sdt); |
534 |
exp_asl = normalize_asl(exp_sdt->asl); |
535 |
|
536 |
if (g_strcmp0(asl->str, exp_asl->str)) {
|
537 |
sdt->asl_file_retain = true;
|
538 |
exp_sdt->asl_file_retain = true;
|
539 |
fprintf(stderr, |
540 |
"acpi-test: Warning! %.4s mismatch. "
|
541 |
"Orig asl: %s, expected asl %s.\n",
|
542 |
(gchar *)&exp_sdt->header.signature, |
543 |
sdt->asl_file, exp_sdt->asl_file); |
544 |
} |
545 |
g_string_free(asl, true);
|
546 |
g_string_free(exp_asl, true);
|
547 |
} |
548 |
|
549 |
free_test_data(&exp_data); |
550 |
} |
551 |
|
552 |
static void test_acpi_one(const char *params, test_data *data) |
553 |
{ |
554 |
char *args;
|
555 |
uint8_t signature_low; |
556 |
uint8_t signature_high; |
557 |
uint16_t signature; |
558 |
int i;
|
559 |
const char *device = ""; |
560 |
|
561 |
if (!g_strcmp0(data->machine, MACHINE_Q35)) {
|
562 |
device = ",id=hd -device ide-hd,drive=hd";
|
563 |
} |
564 |
|
565 |
args = g_strdup_printf("-net none -display none %s -drive file=%s%s,",
|
566 |
params ? params : "", disk, device);
|
567 |
qtest_start(args); |
568 |
|
569 |
/* Wait at most 1 minute */
|
570 |
#define TEST_DELAY (1 * G_USEC_PER_SEC / 10) |
571 |
#define TEST_CYCLES MAX((60 * G_USEC_PER_SEC / TEST_DELAY), 1) |
572 |
|
573 |
/* Poll until code has run and modified memory. Once it has we know BIOS
|
574 |
* initialization is done. TODO: check that IP reached the halt
|
575 |
* instruction.
|
576 |
*/
|
577 |
for (i = 0; i < TEST_CYCLES; ++i) { |
578 |
signature_low = readb(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET); |
579 |
signature_high = readb(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET + 1);
|
580 |
signature = (signature_high << 8) | signature_low;
|
581 |
if (signature == SIGNATURE) {
|
582 |
break;
|
583 |
} |
584 |
g_usleep(TEST_DELAY); |
585 |
} |
586 |
g_assert_cmphex(signature, ==, SIGNATURE); |
587 |
|
588 |
test_acpi_rsdp_address(data); |
589 |
test_acpi_rsdp_table(data); |
590 |
test_acpi_rsdt_table(data); |
591 |
test_acpi_fadt_table(data); |
592 |
test_acpi_facs_table(data); |
593 |
test_acpi_dsdt_table(data); |
594 |
test_acpi_tables(data); |
595 |
|
596 |
if (iasl) {
|
597 |
if (getenv(ACPI_REBUILD_EXPECTED_AML)) {
|
598 |
dump_aml_files(data, true);
|
599 |
} else {
|
600 |
test_acpi_asl(data); |
601 |
} |
602 |
} |
603 |
|
604 |
qtest_quit(global_qtest); |
605 |
g_free(args); |
606 |
} |
607 |
|
608 |
static void test_acpi_tcg(void) |
609 |
{ |
610 |
test_data data; |
611 |
|
612 |
/* Supplying -machine accel argument overrides the default (qtest).
|
613 |
* This is to make guest actually run.
|
614 |
*/
|
615 |
memset(&data, 0, sizeof(data)); |
616 |
data.machine = MACHINE_PC; |
617 |
test_acpi_one("-machine accel=tcg", &data);
|
618 |
free_test_data(&data); |
619 |
|
620 |
memset(&data, 0, sizeof(data)); |
621 |
data.machine = MACHINE_Q35; |
622 |
test_acpi_one("-machine q35,accel=tcg", &data);
|
623 |
free_test_data(&data); |
624 |
} |
625 |
|
626 |
int main(int argc, char *argv[]) |
627 |
{ |
628 |
const char *arch = qtest_get_arch(); |
629 |
FILE *f = fopen(disk, "w");
|
630 |
int ret;
|
631 |
fwrite(boot_sector, 1, sizeof boot_sector, f); |
632 |
fclose(f); |
633 |
|
634 |
g_test_init(&argc, &argv, NULL);
|
635 |
|
636 |
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { |
637 |
qtest_add_func("acpi/tcg", test_acpi_tcg);
|
638 |
} |
639 |
ret = g_test_run(); |
640 |
unlink(disk); |
641 |
return ret;
|
642 |
} |