1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
|
/*
* QTest testcase for acpi-erst
*
* Copyright (c) 2021 Oracle
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include <glib/gstdio.h>
#include "libqos/libqos-pc.h"
#include "libqos/libqtest.h"
#include "hw/pci/pci.h"
static void save_fn(QPCIDevice *dev, int devfn, void *data)
{
QPCIDevice **pdev = (QPCIDevice **) data;
*pdev = dev;
}
static QPCIDevice *get_erst_device(QPCIBus *pcibus)
{
QPCIDevice *dev;
dev = NULL;
qpci_device_foreach(pcibus,
PCI_VENDOR_ID_REDHAT,
PCI_DEVICE_ID_REDHAT_ACPI_ERST,
save_fn, &dev);
g_assert(dev != NULL);
return dev;
}
typedef struct _ERSTState {
QOSState *qs;
QPCIBar reg_bar, mem_bar;
uint64_t reg_barsize, mem_barsize;
QPCIDevice *dev;
} ERSTState;
#define ACTION 0
#define VALUE 8
static const char *reg2str(unsigned reg)
{
switch (reg) {
case 0:
return "ACTION";
case 8:
return "VALUE";
default:
return NULL;
}
}
static inline uint32_t in_reg32(ERSTState *s, unsigned reg)
{
const char *name = reg2str(reg);
uint32_t res;
res = qpci_io_readl(s->dev, s->reg_bar, reg);
g_test_message("*%s -> %08x", name, res);
return res;
}
static inline uint64_t in_reg64(ERSTState *s, unsigned reg)
{
const char *name = reg2str(reg);
uint64_t res;
res = qpci_io_readq(s->dev, s->reg_bar, reg);
g_test_message("*%s -> %016" PRIx64, name, res);
return res;
}
static inline void out_reg32(ERSTState *s, unsigned reg, uint32_t v)
{
const char *name = reg2str(reg);
g_test_message("%08x -> *%s", v, name);
qpci_io_writel(s->dev, s->reg_bar, reg, v);
}
static void cleanup_vm(ERSTState *s)
{
g_free(s->dev);
qtest_shutdown(s->qs);
}
static void setup_vm_cmd(ERSTState *s, const char *cmd)
{
const char *arch = qtest_get_arch();
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
s->qs = qtest_pc_boot(cmd);
} else {
g_printerr("erst-test tests are only available on x86\n");
exit(EXIT_FAILURE);
}
s->dev = get_erst_device(s->qs->pcibus);
s->reg_bar = qpci_iomap(s->dev, 0, &s->reg_barsize);
g_assert_cmpuint(s->reg_barsize, ==, 16);
s->mem_bar = qpci_iomap(s->dev, 1, &s->mem_barsize);
g_assert_cmpuint(s->mem_barsize, ==, 0x2000);
qpci_device_enable(s->dev);
}
static void test_acpi_erst_basic(void)
{
ERSTState state;
uint64_t log_address_range;
uint64_t log_address_length;
uint32_t log_address_attr;
setup_vm_cmd(&state,
"-object memory-backend-file,"
"mem-path=acpi-erst.XXXXXX,"
"size=64K,"
"share=on,"
"id=nvram "
"-device acpi-erst,"
"memdev=nvram");
out_reg32(&state, ACTION, 0xD);
log_address_range = in_reg64(&state, VALUE);
out_reg32(&state, ACTION, 0xE);
log_address_length = in_reg64(&state, VALUE);
out_reg32(&state, ACTION, 0xF);
log_address_attr = in_reg32(&state, VALUE);
/* Check log_address_range is not 0, ~0 or base */
g_assert_cmpuint(log_address_range, !=, 0ULL);
g_assert_cmpuint(log_address_range, !=, ~0ULL);
g_assert_cmpuint(log_address_range, !=, state.reg_bar.addr);
g_assert_cmpuint(log_address_range, ==, state.mem_bar.addr);
/* Check log_address_length is bar1_size */
g_assert_cmpuint(log_address_length, ==, state.mem_barsize);
/* Check log_address_attr is 0 */
g_assert_cmpuint(log_address_attr, ==, 0);
cleanup_vm(&state);
}
int main(int argc, char **argv)
{
int ret;
g_test_init(&argc, &argv, NULL);
qtest_add_func("/acpi-erst/basic", test_acpi_erst_basic);
ret = g_test_run();
return ret;
}
|