aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/acpi-test-data/pc/APICbin0 -> 120 bytes
-rw-r--r--tests/acpi-test-data/pc/DSDTbin0 -> 4582 bytes
-rw-r--r--tests/acpi-test-data/pc/FACPbin0 -> 116 bytes
-rw-r--r--tests/acpi-test-data/pc/FACSbin0 -> 64 bytes
-rw-r--r--tests/acpi-test-data/pc/HPETbin0 -> 56 bytes
-rw-r--r--tests/acpi-test-data/pc/SSDTbin0 -> 2200 bytes
-rw-r--r--tests/acpi-test-data/q35/APICbin0 -> 120 bytes
-rw-r--r--tests/acpi-test-data/q35/DSDTbin0 -> 7438 bytes
-rw-r--r--tests/acpi-test-data/q35/FACPbin0 -> 116 bytes
-rw-r--r--tests/acpi-test-data/q35/FACSbin0 -> 64 bytes
-rw-r--r--tests/acpi-test-data/q35/HPETbin0 -> 56 bytes
-rw-r--r--tests/acpi-test-data/q35/MCFGbin0 -> 60 bytes
-rw-r--r--tests/acpi-test-data/q35/SSDTbin0 -> 475 bytes
-rwxr-xr-xtests/acpi-test-data/rebuild-expected-aml.sh36
-rw-r--r--tests/acpi-test.c305
15 files changed, 311 insertions, 30 deletions
diff --git a/tests/acpi-test-data/pc/APIC b/tests/acpi-test-data/pc/APIC
new file mode 100644
index 0000000000..84509e0ae4
--- /dev/null
+++ b/tests/acpi-test-data/pc/APIC
Binary files differ
diff --git a/tests/acpi-test-data/pc/DSDT b/tests/acpi-test-data/pc/DSDT
new file mode 100644
index 0000000000..fbf1c3e6e8
--- /dev/null
+++ b/tests/acpi-test-data/pc/DSDT
Binary files differ
diff --git a/tests/acpi-test-data/pc/FACP b/tests/acpi-test-data/pc/FACP
new file mode 100644
index 0000000000..0639999ed1
--- /dev/null
+++ b/tests/acpi-test-data/pc/FACP
Binary files differ
diff --git a/tests/acpi-test-data/pc/FACS b/tests/acpi-test-data/pc/FACS
new file mode 100644
index 0000000000..fc67ecc407
--- /dev/null
+++ b/tests/acpi-test-data/pc/FACS
Binary files differ
diff --git a/tests/acpi-test-data/pc/HPET b/tests/acpi-test-data/pc/HPET
new file mode 100644
index 0000000000..df689b8f99
--- /dev/null
+++ b/tests/acpi-test-data/pc/HPET
Binary files differ
diff --git a/tests/acpi-test-data/pc/SSDT b/tests/acpi-test-data/pc/SSDT
new file mode 100644
index 0000000000..a51c68e21b
--- /dev/null
+++ b/tests/acpi-test-data/pc/SSDT
Binary files differ
diff --git a/tests/acpi-test-data/q35/APIC b/tests/acpi-test-data/q35/APIC
new file mode 100644
index 0000000000..84509e0ae4
--- /dev/null
+++ b/tests/acpi-test-data/q35/APIC
Binary files differ
diff --git a/tests/acpi-test-data/q35/DSDT b/tests/acpi-test-data/q35/DSDT
new file mode 100644
index 0000000000..5086b839a6
--- /dev/null
+++ b/tests/acpi-test-data/q35/DSDT
Binary files differ
diff --git a/tests/acpi-test-data/q35/FACP b/tests/acpi-test-data/q35/FACP
new file mode 100644
index 0000000000..19f3ac3ce6
--- /dev/null
+++ b/tests/acpi-test-data/q35/FACP
Binary files differ
diff --git a/tests/acpi-test-data/q35/FACS b/tests/acpi-test-data/q35/FACS
new file mode 100644
index 0000000000..fc67ecc407
--- /dev/null
+++ b/tests/acpi-test-data/q35/FACS
Binary files differ
diff --git a/tests/acpi-test-data/q35/HPET b/tests/acpi-test-data/q35/HPET
new file mode 100644
index 0000000000..df689b8f99
--- /dev/null
+++ b/tests/acpi-test-data/q35/HPET
Binary files differ
diff --git a/tests/acpi-test-data/q35/MCFG b/tests/acpi-test-data/q35/MCFG
new file mode 100644
index 0000000000..79ceb27a03
--- /dev/null
+++ b/tests/acpi-test-data/q35/MCFG
Binary files differ
diff --git a/tests/acpi-test-data/q35/SSDT b/tests/acpi-test-data/q35/SSDT
new file mode 100644
index 0000000000..9c6cad8b0b
--- /dev/null
+++ b/tests/acpi-test-data/q35/SSDT
Binary files differ
diff --git a/tests/acpi-test-data/rebuild-expected-aml.sh b/tests/acpi-test-data/rebuild-expected-aml.sh
new file mode 100755
index 0000000000..ab98498884
--- /dev/null
+++ b/tests/acpi-test-data/rebuild-expected-aml.sh
@@ -0,0 +1,36 @@
+#! /bin/bash
+
+#
+# Rebuild expected AML files for acpi unit-test
+#
+# Copyright (c) 2013 Red Hat Inc.
+#
+# Authors:
+# Marcel Apfelbaum <marcel.a@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING.LIB file in the top-level directory.
+
+qemu=
+
+if [ -e x86_64-softmmu/qemu-system-x86_64 ]; then
+ qemu="x86_64-softmmu/qemu-system-x86_64"
+elif [ -e i386-softmmu/qemu-system-i386 ]; then
+ qemu="i386-softmmu/qemu-system-i386"
+else
+ echo "Run 'make' to build the qemu exectutable!"
+ echo "Run this script from the build directory."
+ exit 1;
+fi
+
+if [ ! -e "tests/acpi-test" ]; then
+ echo "Test: acpi-test is required! Run make check before this script."
+ echo "Run this script from the build directory."
+ exit 1;
+fi
+
+TEST_ACPI_REBUILD_AML=y QTEST_QEMU_BINARY=$qemu tests/acpi-test
+
+echo "The files were rebuilt and can be added to git."
+echo "However, if new files were created, please copy them manually" \
+ "to tests/acpi-test-data/pc/ or tests/acpi-test-data/q35/ ."
diff --git a/tests/acpi-test.c b/tests/acpi-test.c
index df1af83158..31f5359787 100644
--- a/tests/acpi-test.c
+++ b/tests/acpi-test.c
@@ -13,19 +13,32 @@
#include <string.h>
#include <stdio.h>
#include <glib.h>
+#include <glib/gstdio.h>
#include "qemu-common.h"
#include "libqtest.h"
#include "qemu/compiler.h"
#include "hw/i386/acpi-defs.h"
+#define MACHINE_PC "pc"
+#define MACHINE_Q35 "q35"
+
+#define ACPI_REBUILD_EXPECTED_AML "TEST_ACPI_REBUILD_AML"
+#define ACPI_SSDT_SIGNATURE 0x54445353 /* SSDT */
+
/* DSDT and SSDTs format */
typedef struct {
AcpiTableHeader header;
- uint8_t *aml;
- int aml_len;
-} AcpiSdtTable;
+ gchar *aml; /* aml bytecode from guest */
+ gsize aml_len;
+ gchar *aml_file;
+ gchar *asl; /* asl code generated from aml */
+ gsize asl_len;
+ gchar *asl_file;
+ bool asl_file_retain; /* do not delete the temp asl */
+} QEMU_PACKED AcpiSdtTable;
typedef struct {
+ const char *machine;
uint32_t rsdp_addr;
AcpiRsdpDescriptor rsdp_table;
AcpiRsdtDescriptorRev1 rsdt_table;
@@ -33,8 +46,7 @@ typedef struct {
AcpiFacsDescriptorRev1 facs_table;
uint32_t *rsdt_tables_addr;
int rsdt_tables_nr;
- AcpiSdtTable dsdt_table;
- GArray *ssdt_tables;
+ GArray *tables;
} test_data;
#define LOW(x) ((x) & 0xff)
@@ -51,13 +63,13 @@ typedef struct {
field = readb(addr); \
break; \
case 2: \
- field = le16_to_cpu(readw(addr)); \
+ field = readw(addr); \
break; \
case 4: \
- field = le32_to_cpu(readl(addr)); \
+ field = readl(addr); \
break; \
case 8: \
- field = le64_to_cpu(readq(addr)); \
+ field = readq(addr); \
break; \
default: \
g_assert(false); \
@@ -91,8 +103,10 @@ typedef struct {
/* Boot sector code: write SIGNATURE into memory,
* then halt.
+ * Q35 machine requires a minimum 0x7e000 bytes disk.
+ * (bug or feature?)
*/
-static uint8_t boot_sector[0x200] = {
+static uint8_t boot_sector[0x7e000] = {
/* 7c00: mov $0xdead,%ax */
[0x00] = 0xb8,
[0x01] = LOW(SIGNATURE),
@@ -117,17 +131,45 @@ static uint8_t boot_sector[0x200] = {
};
static const char *disk = "tests/acpi-test-disk.raw";
+static const char *data_dir = "tests/acpi-test-data";
+#ifdef CONFIG_IASL
+static const char *iasl = stringify(CONFIG_IASL);
+#else
+static const char *iasl;
+#endif
static void free_test_data(test_data *data)
{
+ AcpiSdtTable *temp;
int i;
- g_free(data->rsdt_tables_addr);
- for (i = 0; i < data->ssdt_tables->len; ++i) {
- g_free(g_array_index(data->ssdt_tables, AcpiSdtTable, i).aml);
+ if (data->rsdt_tables_addr) {
+ g_free(data->rsdt_tables_addr);
+ }
+
+ for (i = 0; i < data->tables->len; ++i) {
+ temp = &g_array_index(data->tables, AcpiSdtTable, i);
+ if (temp->aml) {
+ g_free(temp->aml);
+ }
+ if (temp->aml_file) {
+ if (g_strstr_len(temp->aml_file, -1, "aml-")) {
+ unlink(temp->aml_file);
+ }
+ g_free(temp->aml_file);
+ }
+ if (temp->asl) {
+ g_free(temp->asl);
+ }
+ if (temp->asl_file) {
+ if (!temp->asl_file_retain) {
+ unlink(temp->asl_file);
+ }
+ g_free(temp->asl_file);
+ }
}
- g_array_free(data->ssdt_tables, false);
- g_free(data->dsdt_table.aml);
+
+ g_array_free(data->tables, false);
}
static uint8_t acpi_checksum(const uint8_t *data, int len)
@@ -292,34 +334,219 @@ static void test_dst_table(AcpiSdtTable *sdt_table, uint32_t addr)
ACPI_READ_ARRAY_PTR(sdt_table->aml, sdt_table->aml_len, addr);
checksum = acpi_checksum((uint8_t *)sdt_table, sizeof(AcpiTableHeader)) +
- acpi_checksum(sdt_table->aml, sdt_table->aml_len);
+ acpi_checksum((uint8_t *)sdt_table->aml, sdt_table->aml_len);
g_assert(!checksum);
}
static void test_acpi_dsdt_table(test_data *data)
{
- AcpiSdtTable *dsdt_table = &data->dsdt_table;
+ AcpiSdtTable dsdt_table;
uint32_t addr = data->fadt_table.dsdt;
- test_dst_table(dsdt_table, addr);
- g_assert_cmphex(dsdt_table->header.signature, ==, ACPI_DSDT_SIGNATURE);
+ memset(&dsdt_table, 0, sizeof(dsdt_table));
+ data->tables = g_array_new(false, true, sizeof(AcpiSdtTable));
+
+ test_dst_table(&dsdt_table, addr);
+ g_assert_cmphex(dsdt_table.header.signature, ==, ACPI_DSDT_SIGNATURE);
+
+ /* Place DSDT first */
+ g_array_append_val(data->tables, dsdt_table);
}
-static void test_acpi_ssdt_tables(test_data *data)
+static void test_acpi_tables(test_data *data)
{
- GArray *ssdt_tables;
- int ssdt_tables_nr = data->rsdt_tables_nr - 1; /* fadt is first */
+ int tables_nr = data->rsdt_tables_nr - 1; /* fadt is first */
int i;
- ssdt_tables = g_array_sized_new(false, true, sizeof(AcpiSdtTable),
- ssdt_tables_nr);
- for (i = 0; i < ssdt_tables_nr; i++) {
+ for (i = 0; i < tables_nr; i++) {
AcpiSdtTable ssdt_table;
+
+ memset(&ssdt_table, 0 , sizeof(ssdt_table));
uint32_t addr = data->rsdt_tables_addr[i + 1]; /* fadt is first */
test_dst_table(&ssdt_table, addr);
- g_array_append_val(ssdt_tables, ssdt_table);
+ g_array_append_val(data->tables, ssdt_table);
+ }
+}
+
+static void dump_aml_files(test_data *data, bool rebuild)
+{
+ AcpiSdtTable *sdt;
+ GError *error = NULL;
+ gchar *aml_file = NULL;
+ gint fd;
+ ssize_t ret;
+ int i;
+
+ for (i = 0; i < data->tables->len; ++i) {
+ sdt = &g_array_index(data->tables, AcpiSdtTable, i);
+ g_assert(sdt->aml);
+
+ if (rebuild) {
+ aml_file = g_strdup_printf("%s/%s/%.4s", data_dir, data->machine,
+ (gchar *)&sdt->header.signature);
+ fd = g_open(aml_file, O_WRONLY|O_TRUNC|O_CREAT,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
+ } else {
+ fd = g_file_open_tmp("aml-XXXXXX", &sdt->aml_file, &error);
+ g_assert_no_error(error);
+ }
+ g_assert(fd >= 0);
+
+ ret = qemu_write_full(fd, sdt, sizeof(AcpiTableHeader));
+ g_assert(ret == sizeof(AcpiTableHeader));
+ ret = qemu_write_full(fd, sdt->aml, sdt->aml_len);
+ g_assert(ret == sdt->aml_len);
+
+ close(fd);
+
+ if (aml_file) {
+ g_free(aml_file);
+ }
+ }
+}
+
+static bool compare_signature(AcpiSdtTable *sdt, uint32_t signature)
+{
+ return sdt->header.signature == signature;
+}
+
+static void load_asl(GArray *sdts, AcpiSdtTable *sdt)
+{
+ AcpiSdtTable *temp;
+ GError *error = NULL;
+ GString *command_line = g_string_new(iasl);
+ gint fd;
+ gchar *out, *out_err;
+ gboolean ret;
+ int i;
+
+ fd = g_file_open_tmp("asl-XXXXXX.dsl", &sdt->asl_file, &error);
+ g_assert_no_error(error);
+ close(fd);
+
+ /* build command line */
+ g_string_append_printf(command_line, " -p %s ", sdt->asl_file);
+ if (compare_signature(sdt, ACPI_DSDT_SIGNATURE) ||
+ compare_signature(sdt, ACPI_SSDT_SIGNATURE)) {
+ for (i = 0; i < sdts->len; ++i) {
+ temp = &g_array_index(sdts, AcpiSdtTable, i);
+ if (compare_signature(temp, ACPI_DSDT_SIGNATURE) ||
+ compare_signature(temp, ACPI_SSDT_SIGNATURE)) {
+ g_string_append_printf(command_line, "-e %s ", temp->aml_file);
+ }
+ }
}
- data->ssdt_tables = ssdt_tables;
+ g_string_append_printf(command_line, "-d %s", sdt->aml_file);
+
+ /* pass 'out' and 'out_err' in order to be redirected */
+ g_spawn_command_line_sync(command_line->str, &out, &out_err, NULL, &error);
+ g_assert_no_error(error);
+
+ ret = g_file_get_contents(sdt->asl_file, (gchar **)&sdt->asl,
+ &sdt->asl_len, &error);
+ g_assert(ret);
+ g_assert_no_error(error);
+ g_assert(sdt->asl_len);
+
+ g_free(out);
+ g_free(out_err);
+ g_string_free(command_line, true);
+}
+
+#define COMMENT_END "*/"
+#define DEF_BLOCK "DefinitionBlock ("
+#define BLOCK_NAME_END ".aml"
+
+static GString *normalize_asl(gchar *asl_code)
+{
+ GString *asl = g_string_new(asl_code);
+ gchar *comment, *block_name;
+
+ /* strip comments (different generation days) */
+ comment = g_strstr_len(asl->str, asl->len, COMMENT_END);
+ if (comment) {
+ asl = g_string_erase(asl, 0, comment + sizeof(COMMENT_END) - asl->str);
+ }
+
+ /* strip def block name (it has file path in it) */
+ if (g_str_has_prefix(asl->str, DEF_BLOCK)) {
+ block_name = g_strstr_len(asl->str, asl->len, BLOCK_NAME_END);
+ g_assert(block_name);
+ asl = g_string_erase(asl, 0,
+ block_name + sizeof(BLOCK_NAME_END) - asl->str);
+ }
+
+ return asl;
+}
+
+static GArray *load_expected_aml(test_data *data)
+{
+ int i;
+ AcpiSdtTable *sdt;
+ gchar *aml_file;
+ GError *error = NULL;
+ gboolean ret;
+
+ GArray *exp_tables = g_array_new(false, true, sizeof(AcpiSdtTable));
+ for (i = 0; i < data->tables->len; ++i) {
+ AcpiSdtTable exp_sdt;
+ sdt = &g_array_index(data->tables, AcpiSdtTable, i);
+
+ memset(&exp_sdt, 0, sizeof(exp_sdt));
+ exp_sdt.header.signature = sdt->header.signature;
+
+ aml_file = g_strdup_printf("%s/%s/%.4s", data_dir, data->machine,
+ (gchar *)&exp_sdt.header.signature);
+ exp_sdt.aml_file = aml_file;
+ g_assert(g_file_test(aml_file, G_FILE_TEST_EXISTS));
+ ret = g_file_get_contents(aml_file, &exp_sdt.aml,
+ &exp_sdt.aml_len, &error);
+ g_assert(ret);
+ g_assert_no_error(error);
+ g_assert(exp_sdt.aml);
+ g_assert(exp_sdt.aml_len);
+
+ g_array_append_val(exp_tables, exp_sdt);
+ }
+
+ return exp_tables;
+}
+
+static void test_acpi_asl(test_data *data)
+{
+ int i;
+ AcpiSdtTable *sdt, *exp_sdt;
+ test_data exp_data;
+
+ memset(&exp_data, 0, sizeof(exp_data));
+ exp_data.tables = load_expected_aml(data);
+ dump_aml_files(data, false);
+ for (i = 0; i < data->tables->len; ++i) {
+ GString *asl, *exp_asl;
+
+ sdt = &g_array_index(data->tables, AcpiSdtTable, i);
+ exp_sdt = &g_array_index(exp_data.tables, AcpiSdtTable, i);
+
+ load_asl(data->tables, sdt);
+ asl = normalize_asl(sdt->asl);
+
+ load_asl(exp_data.tables, exp_sdt);
+ exp_asl = normalize_asl(exp_sdt->asl);
+
+ if (g_strcmp0(asl->str, exp_asl->str)) {
+ sdt->asl_file_retain = true;
+ exp_sdt->asl_file_retain = true;
+ fprintf(stderr,
+ "acpi-test: Warning! %.4s mismatch. "
+ "Orig asl: %s, expected asl %s.\n",
+ (gchar *)&exp_sdt->header.signature,
+ sdt->asl_file, exp_sdt->asl_file);
+ }
+ g_string_free(asl, true);
+ g_string_free(exp_asl, true);
+ }
+
+ free_test_data(&exp_data);
}
static void test_acpi_one(const char *params, test_data *data)
@@ -329,10 +556,14 @@ static void test_acpi_one(const char *params, test_data *data)
uint8_t signature_high;
uint16_t signature;
int i;
+ const char *device = "";
+
+ if (!g_strcmp0(data->machine, MACHINE_Q35)) {
+ device = ",id=hd -device ide-hd,drive=hd";
+ }
- memset(data, 0, sizeof(*data));
- args = g_strdup_printf("-net none -display none %s %s",
- params ? params : "", disk);
+ args = g_strdup_printf("-net none -display none %s -drive file=%s%s,",
+ params ? params : "", disk, device);
qtest_start(args);
/* Wait at most 1 minute */
@@ -360,7 +591,15 @@ static void test_acpi_one(const char *params, test_data *data)
test_acpi_fadt_table(data);
test_acpi_facs_table(data);
test_acpi_dsdt_table(data);
- test_acpi_ssdt_tables(data);
+ test_acpi_tables(data);
+
+ if (iasl) {
+ if (getenv(ACPI_REBUILD_EXPECTED_AML)) {
+ dump_aml_files(data, true);
+ } else {
+ test_acpi_asl(data);
+ }
+ }
qtest_quit(global_qtest);
g_free(args);
@@ -373,8 +612,14 @@ static void test_acpi_tcg(void)
/* Supplying -machine accel argument overrides the default (qtest).
* This is to make guest actually run.
*/
+ memset(&data, 0, sizeof(data));
+ data.machine = MACHINE_PC;
test_acpi_one("-machine accel=tcg", &data);
+ free_test_data(&data);
+ memset(&data, 0, sizeof(data));
+ data.machine = MACHINE_Q35;
+ test_acpi_one("-machine q35,accel=tcg", &data);
free_test_data(&data);
}