8
9
#include "qemu/osdep.h"
10
#include "hw/intc/arm_gicv5.h"
11
+#include "qapi/error.h"
12
+#include "qemu/log.h"
13
+#include "trace.h"
14
15
OBJECT_DEFINE_TYPE(GICv5, gicv5, ARM_GICV5, ARM_GICV5_COMMON)
16
17
+static const char *domain_name[] = {
18
+ [GICV5_ID_S] = "Secure",
19
+ [GICV5_ID_NS] = "NonSecure",
20
+ [GICV5_ID_EL3] = "EL3",
21
+ [GICV5_ID_REALM] = "Realm",
22
+};
23
+
24
+static bool config_readl(GICv5 *s, GICv5Domain domain, hwaddr offset,
25
+ uint64_t *data, MemTxAttrs attrs)
26
+{
27
+ return false;
28
+}
29
+
30
+static bool config_writel(GICv5 *s, GICv5Domain domain, hwaddr offset,
31
+ uint64_t data, MemTxAttrs attrs)
32
+{
33
+ return false;
34
+}
35
+
36
+static bool config_readll(GICv5 *s, GICv5Domain domain, hwaddr offset,
37
+ uint64_t *data, MemTxAttrs attrs)
38
+{
39
+ return false;
40
+}
41
+
42
+static bool config_writell(GICv5 *s, GICv5Domain domain, hwaddr offset,
43
+ uint64_t data, MemTxAttrs attrs)
44
+{
45
+ return false;
46
+}
47
+
48
+static MemTxResult config_read(void *opaque, GICv5Domain domain, hwaddr offset,
49
+ uint64_t *data, unsigned size,
50
+ MemTxAttrs attrs)
51
+{
52
+ GICv5 *s = ARM_GICV5(opaque);
53
+ bool result;
54
+
55
+ switch (size) {
56
+ case 4:
57
+ result = config_readl(s, domain, offset, data, attrs);
58
+ break;
59
+ case 8:
60
+ result = config_readll(s, domain, offset, data, attrs);
61
+ break;
62
+ default:
63
+ result = false;
64
+ break;
65
+ }
66
+
67
+ if (!result) {
68
+ qemu_log_mask(LOG_GUEST_ERROR,
69
+ "%s: invalid guest read for IRS %s config frame "
70
+ "at offset " HWADDR_FMT_plx
71
+ " size %u\n", __func__, domain_name[domain],
72
+ offset, size);
73
+ trace_gicv5_badread(domain_name[domain], offset, size);
74
+ /*
75
+ * The spec requires that reserved registers are RAZ/WI; so we
76
+ * log the error but return MEMTX_OK so we don't cause a
77
+ * spurious data abort.
78
+ */
79
+ *data = 0;
80
+ } else {
81
+ trace_gicv5_read(domain_name[domain], offset, *data, size);
82
+ }
83
+
84
+ return MEMTX_OK;
85
+}
86
+
87
+static MemTxResult config_write(void *opaque, GICv5Domain domain,
88
+ hwaddr offset, uint64_t data, unsigned size,
89
+ MemTxAttrs attrs)
90
+{
91
+ GICv5 *s = ARM_GICV5(opaque);
92
+ bool result;
93
+
94
+ switch (size) {
95
+ case 4:
96
+ result = config_writel(s, domain, offset, data, attrs);
97
+ break;
98
+ case 8:
99
+ result = config_writell(s, domain, offset, data, attrs);
100
+ break;
101
+ default:
102
+ result = false;
103
+ break;
104
+ }
105
+
106
+ if (!result) {
107
+ qemu_log_mask(LOG_GUEST_ERROR,
108
+ "%s: invalid guest write for IRS %s config frame "
109
+ "at offset " HWADDR_FMT_plx
110
+ " size %u\n", __func__, domain_name[domain],
111
+ offset, size);
112
+ trace_gicv5_badwrite(domain_name[domain], offset, data, size);
113
+ /*
114
+ * The spec requires that reserved registers are RAZ/WI; so we
115
+ * log the error but return MEMTX_OK so we don't cause a
116
+ * spurious data abort.
117
+ */
118
+ } else {
119
+ trace_gicv5_write(domain_name[domain], offset, data, size);
120
+ }
121
+
122
+ return MEMTX_OK;
123
+}
124
+
125
+#define DEFINE_READ_WRITE_WRAPPERS(NAME, DOMAIN) \
126
+ static MemTxResult config_##NAME##_read(void *opaque, hwaddr offset, \
127
+ uint64_t *data, unsigned size, \
128
+ MemTxAttrs attrs) \
129
+ { \
130
+ return config_read(opaque, DOMAIN, offset, data, size, attrs); \
131
+ } \
132
+ static MemTxResult config_##NAME##_write(void *opaque, hwaddr offset, \
133
+ uint64_t data, unsigned size, \
134
+ MemTxAttrs attrs) \
135
+ { \
136
+ return config_write(opaque, DOMAIN, offset, data, size, attrs); \
137
+ }
138
+
139
+DEFINE_READ_WRITE_WRAPPERS(ns, GICV5_ID_NS)
140
+DEFINE_READ_WRITE_WRAPPERS(realm, GICV5_ID_REALM)
141
+DEFINE_READ_WRITE_WRAPPERS(secure, GICV5_ID_S)
142
+DEFINE_READ_WRITE_WRAPPERS(el3, GICV5_ID_EL3)
143
+
144
+#define FRAME_OP_ENTRY(NAME, DOMAIN) \
145
+ [DOMAIN] = { \
146
+ .read_with_attrs = config_##NAME##_read, \
147
+ .write_with_attrs = config_##NAME##_write, \
148
+ .endianness = DEVICE_LITTLE_ENDIAN, \
149
+ .valid.min_access_size = 4, \
150
+ .valid.max_access_size = 8, \
151
+ .impl.min_access_size = 4, \
152
+ .impl.max_access_size = 8, \
153
+ }
154
+
155
+static const MemoryRegionOps config_frame_ops[NUM_GICV5_DOMAINS] = {
156
+ FRAME_OP_ENTRY(ns, GICV5_ID_NS),
157
+ FRAME_OP_ENTRY(realm, GICV5_ID_REALM),
158
+ FRAME_OP_ENTRY(secure, GICV5_ID_S),
159
+ FRAME_OP_ENTRY(el3, GICV5_ID_EL3),
160
+};
161
+
162
static void gicv5_reset_hold(Object *obj, ResetType type)
163
{
164
GICv5 *s = ARM_GICV5(obj);
169
}
170
}
171
172
+static void gicv5_realize(DeviceState *dev, Error **errp)
173
+{
174
+ GICv5Common *cs = ARM_GICV5_COMMON(dev);
175
+ GICv5Class *gc = ARM_GICV5_GET_CLASS(dev);
176
+
177
+ ERRP_GUARD();
178
+
179
+ gc->parent_realize(dev, errp);
180
+ if (*errp) {
181
+ return;
182
+ }
183
+
184
+ /*
185
+ * When we implement support for more than one interrupt domain,
186
+ * we will provide some QOM properties so the board can configure
187
+ * which domains are implemented. For now, we only implement the
188
+ * NS domain.
189
+ */
190
+ cs->implemented_domains = (1 << GICV5_ID_NS);
191
+ gicv5_common_init_irqs_and_mmio(cs, config_frame_ops);
192
+}
193
+
194
static void gicv5_init(Object *obj)
195
{
196
}
202
static void gicv5_class_init(ObjectClass *oc, const void *data)
203
{
204
ResettableClass *rc = RESETTABLE_CLASS(oc);
205
+ DeviceClass *dc = DEVICE_CLASS(oc);
206
GICv5Class *gc = ARM_GICV5_CLASS(oc);
207
208
+ device_class_set_parent_realize(dc, gicv5_realize, &gc->parent_realize);
209
resettable_class_set_parent_phases(rc, NULL, gicv5_reset_hold, NULL,
210
&gc->parent_phases);
211
}