gic_v3_distributor.cc (13531:e6f1bf55d038) gic_v3_distributor.cc (13690:284050bbec68)
1/*
2 * Copyright (c) 2018 Metempsy Technology Consulting
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Jairo Balart
29 */
30#include "dev/arm/gic_v3_distributor.hh"
31
32#include <algorithm>
33
34#include "debug/GIC.hh"
35#include "dev/arm/gic_v3.hh"
36#include "dev/arm/gic_v3_cpu_interface.hh"
37#include "dev/arm/gic_v3_redistributor.hh"
38
39const AddrRange Gicv3Distributor::GICD_IGROUPR(0x0080, 0x00ff);
40const AddrRange Gicv3Distributor::GICD_ISENABLER(0x0100, 0x017f);
41const AddrRange Gicv3Distributor::GICD_ICENABLER(0x0180, 0x01ff);
42const AddrRange Gicv3Distributor::GICD_ISPENDR(0x0200, 0x027f);
43const AddrRange Gicv3Distributor::GICD_ICPENDR(0x0280, 0x02ff);
44const AddrRange Gicv3Distributor::GICD_ISACTIVER(0x0300, 0x037f);
45const AddrRange Gicv3Distributor::GICD_ICACTIVER(0x0380, 0x03ff);
46const AddrRange Gicv3Distributor::GICD_IPRIORITYR(0x0400, 0x07ff);
47const AddrRange Gicv3Distributor::GICD_ITARGETSR(0x0800, 0x08ff);
48const AddrRange Gicv3Distributor::GICD_ICFGR(0x0c00, 0x0cff);
49const AddrRange Gicv3Distributor::GICD_IGRPMODR(0x0d00, 0x0d7f);
50const AddrRange Gicv3Distributor::GICD_NSACR(0x0e00, 0x0eff);
51const AddrRange Gicv3Distributor::GICD_CPENDSGIR(0x0f10, 0x0f1f);
52const AddrRange Gicv3Distributor::GICD_SPENDSGIR(0x0f20, 0x0f2f);
53const AddrRange Gicv3Distributor::GICD_IROUTER(0x6000, 0x7fe0);
54
55Gicv3Distributor::Gicv3Distributor(Gicv3 * gic, uint32_t it_lines)
56 : gic(gic),
57 itLines(it_lines),
58 irqGroup(it_lines),
59 irqEnabled(it_lines),
60 irqPending(it_lines),
61 irqActive(it_lines),
62 irqPriority(it_lines),
63 irqConfig(it_lines),
64 irqGrpmod(it_lines),
65 irqNsacr(it_lines),
66 irqAffinityRouting(it_lines)
67{
68 panic_if(it_lines > Gicv3::INTID_SECURE, "Invalid value for it_lines!");
69}
70
71Gicv3Distributor::~Gicv3Distributor()
72{
73}
74
75void
76Gicv3Distributor::init()
77{
78}
79
80void
81Gicv3Distributor::initState()
82{
83 reset();
84}
85
86void
87Gicv3Distributor::reset()
88{
89 std::fill(irqGroup.begin(), irqGroup.end(), 0);
90 // Imp. defined reset value
91 std::fill(irqEnabled.begin(), irqEnabled.end(), false);
92 std::fill(irqPending.begin(), irqPending.end(), false);
93 std::fill(irqActive.begin(), irqActive.end(), false);
94 // Imp. defined reset value
95 std::fill(irqPriority.begin(), irqPriority.end(), 0xAAAAAAAA);
96 std::fill(irqConfig.begin(), irqConfig.end(),
97 Gicv3::INT_LEVEL_SENSITIVE); // Imp. defined reset value
98 std::fill(irqGrpmod.begin(), irqGrpmod.end(), 0);
99 std::fill(irqNsacr.begin(), irqNsacr.end(), 0);
100 /*
101 * For our implementation affinity routing is always enabled,
102 * no GICv2 legacy
103 */
104 ARE = true;
105
106 if (gic->getSystem()->haveSecurity()) {
107 DS = false;
108 } else {
109 DS = true;
110 }
111
112 EnableGrp0 = 0;
113 EnableGrp1NS = 0;
114 EnableGrp1S = 0;
115}
116
117uint64_t
118Gicv3Distributor::read(Addr addr, size_t size, bool is_secure_access)
119{
120 if (GICD_IGROUPR.contains(addr)) { // Interrupt Group Registers
121 uint64_t val = 0x0;
122
123 if (!DS && !is_secure_access) {
124 // RAZ/WI for non-secure accesses
125 return 0;
126 }
127
128 int first_intid = (addr - GICD_IGROUPR.start()) * 8;
129
130 if (isNotSPI(first_intid)) {
131 return 0;
132 }
133
134 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
135 i++, int_id++) {
136 val |= irqGroup[int_id] << i;
137 }
138
139 return val;
140 // Interrupt Set-Enable Registers
141 } else if (GICD_ISENABLER.contains(addr)) {
142 uint64_t val = 0x0;
143 int first_intid = (addr - GICD_ISENABLER.start()) * 8;
144
145 if (isNotSPI(first_intid)) {
146 return 0;
147 }
148
149 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
150 i++, int_id++) {
151 if (nsAccessToSecInt(int_id, is_secure_access))
152 {
153 continue;
154 }
155
156 val |= irqEnabled[int_id] << i;
157 }
158
159 return val;
160 } else if (GICD_ICENABLER.contains(addr)) {
161 // Interrupt Clear-Enable Registers
162 uint64_t val = 0x0;
163 int first_intid = (addr - GICD_ICENABLER.start()) * 8;
164
165 if (isNotSPI(first_intid)) {
166 return 0;
167 }
168
169 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
170 i++, int_id++) {
171 if (nsAccessToSecInt(int_id, is_secure_access))
172 {
173 continue;
174 }
175
176 val |= (irqEnabled[int_id] << i);
177 }
178
179 return val;
180 } else if (GICD_ISPENDR.contains(addr)) {
181 uint64_t val = 0x0;
182 int first_intid = (addr - GICD_ISPENDR.start()) * 8;
183
184 if (isNotSPI(first_intid)) {
185 return 0;
186 }
187
188 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
189 i++, int_id++) {
190 if (nsAccessToSecInt(int_id, is_secure_access))
191 {
192 if (irqNsacr[int_id] == 0) {
193 // Group 0 or Secure Group 1 interrupts are RAZ/WI
194 continue;
195 }
196 }
197
198 val |= (irqPending[int_id] << i);
199 }
200
201 return val;
202 } else if (GICD_ICPENDR.contains(addr)) {
203 uint64_t val = 0x0;
204 int first_intid = (addr - GICD_ICPENDR.start()) * 8;
205
206 if (isNotSPI(first_intid)) {
207 return 0;
208 }
209
210 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
211 i++, int_id++) {
212 if (nsAccessToSecInt(int_id, is_secure_access))
213 {
214 if (irqNsacr[int_id] < 2) {
215 // Group 0 or Secure Group 1 interrupts are RAZ/WI
216 continue;
217 }
218 }
219
220 val |= (irqPending[int_id] << i);
221 }
222
223 return val;
224 // Interrupt Set-Active Registers
225 } else if (GICD_ISACTIVER.contains(addr)) {
226 int first_intid = (addr - GICD_ISACTIVER.start()) * 8;
227
228 if (isNotSPI(first_intid)) {
229 return 0;
230 }
231
232 uint64_t val = 0x0;
233
234 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
235 i++, int_id++) {
236 if (nsAccessToSecInt(int_id, is_secure_access))
237 {
238 // Group 0 or Secure Group 1 interrupts are RAZ/WI
239 if (irqNsacr[int_id] < 2) {
240 continue;
241 }
242 }
243
244 val |= (irqActive[int_id] << i);
245 }
246
247 return val;
248 // Interrupt Clear-Active Registers
249 } else if (GICD_ICACTIVER.contains(addr)) {
250 int first_intid = (addr - GICD_ICACTIVER.start()) * 8;
251
252 if (isNotSPI(first_intid)) {
253 return 0;
254 }
255
256 uint64_t val = 0x0;
257
258 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
259 i++, int_id++) {
260 if (nsAccessToSecInt(int_id, is_secure_access))
261 {
262 if (irqNsacr[int_id] < 2) {
263 continue;
264 }
265 }
266
267 val |= (irqActive[int_id] << i);
268 }
269
270 return val;
271 // Interrupt Priority Registers
272 } else if (GICD_IPRIORITYR.contains(addr)) {
273 uint64_t val = 0x0;
274 int first_intid = addr - GICD_IPRIORITYR.start();
275
276 if (isNotSPI(first_intid)) {
277 return 0;
278 }
279
280 for (int i = 0, int_id = first_intid; i < size && int_id < itLines;
281 i++, int_id++) {
282 uint8_t prio = irqPriority[int_id];
283
284 if (!DS && !is_secure_access) {
285 if (getIntGroup(int_id) != Gicv3::G1NS) {
286 // RAZ/WI for non-secure accesses for secure interrupts
287 continue;
288 } else {
289 // NS view
290 prio = (prio << 1) & 0xff;
291 }
292 }
293
294 val |= prio << (i * 8);
295 }
296
297 return val;
298 } else if (GICD_ITARGETSR.contains(addr)) {
299 // Interrupt Processor Targets Registers
300 // ARE always on, RAZ/WI
301 warn("Gicv3Distributor::read(): "
302 "GICD_ITARGETSR is RAZ/WI, legacy not supported!\n");
303 return 0;
304 // Interrupt Configuration Registers
305 } else if (GICD_ICFGR.contains(addr)) {
306 int first_intid = (addr - GICD_ICFGR.start()) * 4;
307
308 if (isNotSPI(first_intid)) {
309 return 0;
310 }
311
312 uint64_t val = 0x0;
313
314 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
315 i = i + 2, int_id++) {
316 if (nsAccessToSecInt(int_id, is_secure_access))
317 {
318 continue;
319 }
320
321 if (irqConfig[int_id] == Gicv3::INT_EDGE_TRIGGERED) {
322 val |= (0x2 << i);
323 }
324 }
325
326 return val;
327 } else if (GICD_IGRPMODR.contains(addr)) {
328 // Interrupt Group Modifier Registers
329 if (DS) {
330 // RAZ/WI if security disabled
331 return 0;
332 } else {
333 if (!is_secure_access) {
334 // RAZ/WI for non-secure accesses
335 return 0;
336 } else {
337 int first_intid = (addr - GICD_IGRPMODR.start()) * 8;
338
339 if (isNotSPI(first_intid)) {
340 return 0;
341 }
342
343 uint64_t val = 0x0;
344
345 for (int i = 0, int_id = first_intid;
346 i < 8 * size && int_id < itLines; i++, int_id++) {
347 val |= irqGrpmod[int_id] << i;
348 }
349
350 return val;
351 }
352 }
353
354 // Non-secure Access Control Registers
355 } else if (GICD_NSACR.contains(addr)) {
356 // 2 bits per interrupt
357 int first_intid = (addr - GICD_NSACR.start()) * 4;
358
359 if (isNotSPI(first_intid)) {
360 return 0;
361 }
362
363 if (DS || (!DS && !is_secure_access)) {
364 return 0;
365 }
366
367 uint64_t val = 0x0;
368
369 for (int i = 0, int_id = first_intid;
370 i < 8 * size && int_id < itLines; i = i + 2, int_id++) {
371 val |= irqNsacr[int_id] << i;
372 }
373
374 return val;
375 } else if (GICD_CPENDSGIR.contains(addr)) { // SGI Clear-Pending Registers
376 // ARE always on, RAZ/WI
377 warn("Gicv3Distributor::read(): "
378 "GICD_CPENDSGIR is RAZ/WI, legacy not supported!\n");
379 return 0x0;
380 } else if (GICD_SPENDSGIR.contains(addr)) { // SGI Set-Pending Registers
381 // ARE always on, RAZ/WI
382 warn("Gicv3Distributor::read(): "
383 "GICD_SPENDSGIR is RAZ/WI, legacy not supported!\n");
384 return 0x0;
385 } else if (GICD_IROUTER.contains(addr)) { // Interrupt Routing Registers
386 // 64 bit registers. 2 or 1 access.
387 int int_id = (addr - GICD_IROUTER.start()) / 8;
388
389 if (isNotSPI(int_id)) {
390 return 0;
391 }
392
393 if (nsAccessToSecInt(int_id, is_secure_access))
394 {
395 if (irqNsacr[int_id] < 3) {
396 return 0;
397 }
398 }
399
400 if (size == 4) {
401 if (addr & 7) { // high half of 64 bit register
402 return irqAffinityRouting[int_id] >> 32;
403 } else { // high low of 64 bit register
404 return irqAffinityRouting[int_id] & 0xFFFFFFFF;
405 }
406 } else {
407 return irqAffinityRouting[int_id];
408 }
409 }
410
411 switch (addr) {
412 case GICD_CTLR: // Control Register
413 if (!DS) {
414 if (is_secure_access) {
415 // E1NWF [7] RAZ/WI
416 // DS [6] - Disable Security
417 // ARE_NS [5] RAO/WI
418 // ARE_S [4] RAO/WI
419 // EnableGrp1S [2]
420 // EnableGrp1NS [1]
421 // EnableGrp0 [0]
422 return (EnableGrp0 << 0) |
423 (EnableGrp1NS << 1) |
424 (EnableGrp1S << 2) |
425 (1 << 4) |
426 (1 << 5) |
427 (DS << 6);
428 } else {
429 // ARE_NS [4] RAO/WI;
430 // EnableGrp1A [1] is a read-write alias of the Secure
431 // GICD_CTLR.EnableGrp1NS
432 // EnableGrp1 [0] RES0
433 return (1 << 4) | (EnableGrp1NS << 1);
434 }
435 } else {
436 return (DS << 6) | (ARE << 4) |
437 (EnableGrp1NS << 1) | (EnableGrp0 << 0);
438 }
439
440 case GICD_TYPER: // Interrupt Controller Type Register
441 /*
442 * RSS [26] == 1
443 * (The implementation does supports targeted SGIs with affinity
444 * level 0 values of 0 - 255)
445 * No1N [25] == 1
446 * (1 of N SPI interrupts are not supported)
447 * A3V [24] == 1
448 * (Supports nonzero values of Affinity level 3)
449 * IDbits [23:19] == 0xf
450 * (The number of interrupt identifier bits supported, minus one)
451 * DVIS [18] == 0
452 * (The implementation does not support Direct Virtual LPI
453 * injection)
1/*
2 * Copyright (c) 2018 Metempsy Technology Consulting
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Jairo Balart
29 */
30#include "dev/arm/gic_v3_distributor.hh"
31
32#include <algorithm>
33
34#include "debug/GIC.hh"
35#include "dev/arm/gic_v3.hh"
36#include "dev/arm/gic_v3_cpu_interface.hh"
37#include "dev/arm/gic_v3_redistributor.hh"
38
39const AddrRange Gicv3Distributor::GICD_IGROUPR(0x0080, 0x00ff);
40const AddrRange Gicv3Distributor::GICD_ISENABLER(0x0100, 0x017f);
41const AddrRange Gicv3Distributor::GICD_ICENABLER(0x0180, 0x01ff);
42const AddrRange Gicv3Distributor::GICD_ISPENDR(0x0200, 0x027f);
43const AddrRange Gicv3Distributor::GICD_ICPENDR(0x0280, 0x02ff);
44const AddrRange Gicv3Distributor::GICD_ISACTIVER(0x0300, 0x037f);
45const AddrRange Gicv3Distributor::GICD_ICACTIVER(0x0380, 0x03ff);
46const AddrRange Gicv3Distributor::GICD_IPRIORITYR(0x0400, 0x07ff);
47const AddrRange Gicv3Distributor::GICD_ITARGETSR(0x0800, 0x08ff);
48const AddrRange Gicv3Distributor::GICD_ICFGR(0x0c00, 0x0cff);
49const AddrRange Gicv3Distributor::GICD_IGRPMODR(0x0d00, 0x0d7f);
50const AddrRange Gicv3Distributor::GICD_NSACR(0x0e00, 0x0eff);
51const AddrRange Gicv3Distributor::GICD_CPENDSGIR(0x0f10, 0x0f1f);
52const AddrRange Gicv3Distributor::GICD_SPENDSGIR(0x0f20, 0x0f2f);
53const AddrRange Gicv3Distributor::GICD_IROUTER(0x6000, 0x7fe0);
54
55Gicv3Distributor::Gicv3Distributor(Gicv3 * gic, uint32_t it_lines)
56 : gic(gic),
57 itLines(it_lines),
58 irqGroup(it_lines),
59 irqEnabled(it_lines),
60 irqPending(it_lines),
61 irqActive(it_lines),
62 irqPriority(it_lines),
63 irqConfig(it_lines),
64 irqGrpmod(it_lines),
65 irqNsacr(it_lines),
66 irqAffinityRouting(it_lines)
67{
68 panic_if(it_lines > Gicv3::INTID_SECURE, "Invalid value for it_lines!");
69}
70
71Gicv3Distributor::~Gicv3Distributor()
72{
73}
74
75void
76Gicv3Distributor::init()
77{
78}
79
80void
81Gicv3Distributor::initState()
82{
83 reset();
84}
85
86void
87Gicv3Distributor::reset()
88{
89 std::fill(irqGroup.begin(), irqGroup.end(), 0);
90 // Imp. defined reset value
91 std::fill(irqEnabled.begin(), irqEnabled.end(), false);
92 std::fill(irqPending.begin(), irqPending.end(), false);
93 std::fill(irqActive.begin(), irqActive.end(), false);
94 // Imp. defined reset value
95 std::fill(irqPriority.begin(), irqPriority.end(), 0xAAAAAAAA);
96 std::fill(irqConfig.begin(), irqConfig.end(),
97 Gicv3::INT_LEVEL_SENSITIVE); // Imp. defined reset value
98 std::fill(irqGrpmod.begin(), irqGrpmod.end(), 0);
99 std::fill(irqNsacr.begin(), irqNsacr.end(), 0);
100 /*
101 * For our implementation affinity routing is always enabled,
102 * no GICv2 legacy
103 */
104 ARE = true;
105
106 if (gic->getSystem()->haveSecurity()) {
107 DS = false;
108 } else {
109 DS = true;
110 }
111
112 EnableGrp0 = 0;
113 EnableGrp1NS = 0;
114 EnableGrp1S = 0;
115}
116
117uint64_t
118Gicv3Distributor::read(Addr addr, size_t size, bool is_secure_access)
119{
120 if (GICD_IGROUPR.contains(addr)) { // Interrupt Group Registers
121 uint64_t val = 0x0;
122
123 if (!DS && !is_secure_access) {
124 // RAZ/WI for non-secure accesses
125 return 0;
126 }
127
128 int first_intid = (addr - GICD_IGROUPR.start()) * 8;
129
130 if (isNotSPI(first_intid)) {
131 return 0;
132 }
133
134 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
135 i++, int_id++) {
136 val |= irqGroup[int_id] << i;
137 }
138
139 return val;
140 // Interrupt Set-Enable Registers
141 } else if (GICD_ISENABLER.contains(addr)) {
142 uint64_t val = 0x0;
143 int first_intid = (addr - GICD_ISENABLER.start()) * 8;
144
145 if (isNotSPI(first_intid)) {
146 return 0;
147 }
148
149 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
150 i++, int_id++) {
151 if (nsAccessToSecInt(int_id, is_secure_access))
152 {
153 continue;
154 }
155
156 val |= irqEnabled[int_id] << i;
157 }
158
159 return val;
160 } else if (GICD_ICENABLER.contains(addr)) {
161 // Interrupt Clear-Enable Registers
162 uint64_t val = 0x0;
163 int first_intid = (addr - GICD_ICENABLER.start()) * 8;
164
165 if (isNotSPI(first_intid)) {
166 return 0;
167 }
168
169 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
170 i++, int_id++) {
171 if (nsAccessToSecInt(int_id, is_secure_access))
172 {
173 continue;
174 }
175
176 val |= (irqEnabled[int_id] << i);
177 }
178
179 return val;
180 } else if (GICD_ISPENDR.contains(addr)) {
181 uint64_t val = 0x0;
182 int first_intid = (addr - GICD_ISPENDR.start()) * 8;
183
184 if (isNotSPI(first_intid)) {
185 return 0;
186 }
187
188 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
189 i++, int_id++) {
190 if (nsAccessToSecInt(int_id, is_secure_access))
191 {
192 if (irqNsacr[int_id] == 0) {
193 // Group 0 or Secure Group 1 interrupts are RAZ/WI
194 continue;
195 }
196 }
197
198 val |= (irqPending[int_id] << i);
199 }
200
201 return val;
202 } else if (GICD_ICPENDR.contains(addr)) {
203 uint64_t val = 0x0;
204 int first_intid = (addr - GICD_ICPENDR.start()) * 8;
205
206 if (isNotSPI(first_intid)) {
207 return 0;
208 }
209
210 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
211 i++, int_id++) {
212 if (nsAccessToSecInt(int_id, is_secure_access))
213 {
214 if (irqNsacr[int_id] < 2) {
215 // Group 0 or Secure Group 1 interrupts are RAZ/WI
216 continue;
217 }
218 }
219
220 val |= (irqPending[int_id] << i);
221 }
222
223 return val;
224 // Interrupt Set-Active Registers
225 } else if (GICD_ISACTIVER.contains(addr)) {
226 int first_intid = (addr - GICD_ISACTIVER.start()) * 8;
227
228 if (isNotSPI(first_intid)) {
229 return 0;
230 }
231
232 uint64_t val = 0x0;
233
234 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
235 i++, int_id++) {
236 if (nsAccessToSecInt(int_id, is_secure_access))
237 {
238 // Group 0 or Secure Group 1 interrupts are RAZ/WI
239 if (irqNsacr[int_id] < 2) {
240 continue;
241 }
242 }
243
244 val |= (irqActive[int_id] << i);
245 }
246
247 return val;
248 // Interrupt Clear-Active Registers
249 } else if (GICD_ICACTIVER.contains(addr)) {
250 int first_intid = (addr - GICD_ICACTIVER.start()) * 8;
251
252 if (isNotSPI(first_intid)) {
253 return 0;
254 }
255
256 uint64_t val = 0x0;
257
258 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
259 i++, int_id++) {
260 if (nsAccessToSecInt(int_id, is_secure_access))
261 {
262 if (irqNsacr[int_id] < 2) {
263 continue;
264 }
265 }
266
267 val |= (irqActive[int_id] << i);
268 }
269
270 return val;
271 // Interrupt Priority Registers
272 } else if (GICD_IPRIORITYR.contains(addr)) {
273 uint64_t val = 0x0;
274 int first_intid = addr - GICD_IPRIORITYR.start();
275
276 if (isNotSPI(first_intid)) {
277 return 0;
278 }
279
280 for (int i = 0, int_id = first_intid; i < size && int_id < itLines;
281 i++, int_id++) {
282 uint8_t prio = irqPriority[int_id];
283
284 if (!DS && !is_secure_access) {
285 if (getIntGroup(int_id) != Gicv3::G1NS) {
286 // RAZ/WI for non-secure accesses for secure interrupts
287 continue;
288 } else {
289 // NS view
290 prio = (prio << 1) & 0xff;
291 }
292 }
293
294 val |= prio << (i * 8);
295 }
296
297 return val;
298 } else if (GICD_ITARGETSR.contains(addr)) {
299 // Interrupt Processor Targets Registers
300 // ARE always on, RAZ/WI
301 warn("Gicv3Distributor::read(): "
302 "GICD_ITARGETSR is RAZ/WI, legacy not supported!\n");
303 return 0;
304 // Interrupt Configuration Registers
305 } else if (GICD_ICFGR.contains(addr)) {
306 int first_intid = (addr - GICD_ICFGR.start()) * 4;
307
308 if (isNotSPI(first_intid)) {
309 return 0;
310 }
311
312 uint64_t val = 0x0;
313
314 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
315 i = i + 2, int_id++) {
316 if (nsAccessToSecInt(int_id, is_secure_access))
317 {
318 continue;
319 }
320
321 if (irqConfig[int_id] == Gicv3::INT_EDGE_TRIGGERED) {
322 val |= (0x2 << i);
323 }
324 }
325
326 return val;
327 } else if (GICD_IGRPMODR.contains(addr)) {
328 // Interrupt Group Modifier Registers
329 if (DS) {
330 // RAZ/WI if security disabled
331 return 0;
332 } else {
333 if (!is_secure_access) {
334 // RAZ/WI for non-secure accesses
335 return 0;
336 } else {
337 int first_intid = (addr - GICD_IGRPMODR.start()) * 8;
338
339 if (isNotSPI(first_intid)) {
340 return 0;
341 }
342
343 uint64_t val = 0x0;
344
345 for (int i = 0, int_id = first_intid;
346 i < 8 * size && int_id < itLines; i++, int_id++) {
347 val |= irqGrpmod[int_id] << i;
348 }
349
350 return val;
351 }
352 }
353
354 // Non-secure Access Control Registers
355 } else if (GICD_NSACR.contains(addr)) {
356 // 2 bits per interrupt
357 int first_intid = (addr - GICD_NSACR.start()) * 4;
358
359 if (isNotSPI(first_intid)) {
360 return 0;
361 }
362
363 if (DS || (!DS && !is_secure_access)) {
364 return 0;
365 }
366
367 uint64_t val = 0x0;
368
369 for (int i = 0, int_id = first_intid;
370 i < 8 * size && int_id < itLines; i = i + 2, int_id++) {
371 val |= irqNsacr[int_id] << i;
372 }
373
374 return val;
375 } else if (GICD_CPENDSGIR.contains(addr)) { // SGI Clear-Pending Registers
376 // ARE always on, RAZ/WI
377 warn("Gicv3Distributor::read(): "
378 "GICD_CPENDSGIR is RAZ/WI, legacy not supported!\n");
379 return 0x0;
380 } else if (GICD_SPENDSGIR.contains(addr)) { // SGI Set-Pending Registers
381 // ARE always on, RAZ/WI
382 warn("Gicv3Distributor::read(): "
383 "GICD_SPENDSGIR is RAZ/WI, legacy not supported!\n");
384 return 0x0;
385 } else if (GICD_IROUTER.contains(addr)) { // Interrupt Routing Registers
386 // 64 bit registers. 2 or 1 access.
387 int int_id = (addr - GICD_IROUTER.start()) / 8;
388
389 if (isNotSPI(int_id)) {
390 return 0;
391 }
392
393 if (nsAccessToSecInt(int_id, is_secure_access))
394 {
395 if (irqNsacr[int_id] < 3) {
396 return 0;
397 }
398 }
399
400 if (size == 4) {
401 if (addr & 7) { // high half of 64 bit register
402 return irqAffinityRouting[int_id] >> 32;
403 } else { // high low of 64 bit register
404 return irqAffinityRouting[int_id] & 0xFFFFFFFF;
405 }
406 } else {
407 return irqAffinityRouting[int_id];
408 }
409 }
410
411 switch (addr) {
412 case GICD_CTLR: // Control Register
413 if (!DS) {
414 if (is_secure_access) {
415 // E1NWF [7] RAZ/WI
416 // DS [6] - Disable Security
417 // ARE_NS [5] RAO/WI
418 // ARE_S [4] RAO/WI
419 // EnableGrp1S [2]
420 // EnableGrp1NS [1]
421 // EnableGrp0 [0]
422 return (EnableGrp0 << 0) |
423 (EnableGrp1NS << 1) |
424 (EnableGrp1S << 2) |
425 (1 << 4) |
426 (1 << 5) |
427 (DS << 6);
428 } else {
429 // ARE_NS [4] RAO/WI;
430 // EnableGrp1A [1] is a read-write alias of the Secure
431 // GICD_CTLR.EnableGrp1NS
432 // EnableGrp1 [0] RES0
433 return (1 << 4) | (EnableGrp1NS << 1);
434 }
435 } else {
436 return (DS << 6) | (ARE << 4) |
437 (EnableGrp1NS << 1) | (EnableGrp0 << 0);
438 }
439
440 case GICD_TYPER: // Interrupt Controller Type Register
441 /*
442 * RSS [26] == 1
443 * (The implementation does supports targeted SGIs with affinity
444 * level 0 values of 0 - 255)
445 * No1N [25] == 1
446 * (1 of N SPI interrupts are not supported)
447 * A3V [24] == 1
448 * (Supports nonzero values of Affinity level 3)
449 * IDbits [23:19] == 0xf
450 * (The number of interrupt identifier bits supported, minus one)
451 * DVIS [18] == 0
452 * (The implementation does not support Direct Virtual LPI
453 * injection)
454 * LPIS [17] == 0
454 * LPIS [17] == 1
455 * (The implementation does not support LPIs)
456 * MBIS [16] == 0
457 * (The implementation does not support message-based interrupts
458 * by writing to Distributor registers)
459 * SecurityExtn [10] == X
460 * (The GIC implementation supports two Security states)
461 * CPUNumber [7:5] == 0
462 * (since for us ARE is always 1 [(ARE = 0) == Gicv2 legacy])
463 * ITLinesNumber [4:0] == N
464 * (MaxSPIIntId = 32 (N + 1) - 1)
465 */
466 {
467 int max_spi_int_id = itLines - 1;
468 int it_lines_number = ceil((max_spi_int_id + 1) / 32.0) - 1;
469 return (1 << 26) | (1 << 25) | (1 << 24) | (0xf << 19) |
455 * (The implementation does not support LPIs)
456 * MBIS [16] == 0
457 * (The implementation does not support message-based interrupts
458 * by writing to Distributor registers)
459 * SecurityExtn [10] == X
460 * (The GIC implementation supports two Security states)
461 * CPUNumber [7:5] == 0
462 * (since for us ARE is always 1 [(ARE = 0) == Gicv2 legacy])
463 * ITLinesNumber [4:0] == N
464 * (MaxSPIIntId = 32 (N + 1) - 1)
465 */
466 {
467 int max_spi_int_id = itLines - 1;
468 int it_lines_number = ceil((max_spi_int_id + 1) / 32.0) - 1;
469 return (1 << 26) | (1 << 25) | (1 << 24) | (0xf << 19) |
470 (gic->getSystem()->haveSecurity() << 10) |
470 (1 << 17) | (gic->getSystem()->haveSecurity() << 10) |
471 (it_lines_number << 0);
472 }
473
474 case GICD_IIDR: // Implementer Identification Register
475 //return 0x43b; // ARM JEP106 code (r0p0 GIC-500)
476 return 0;
477
478 case GICD_STATUSR: // Error Reporting Status Register
479 // Optional register, RAZ/WI
480 return 0x0;
481
482 case GICD_PIDR0: { // Peripheral ID0 Register
483 uint8_t part_0 = 0x92; // Part number, bits[7:0]
484 return part_0;
485 }
486
487 case GICD_PIDR1: { // Peripheral ID1 Register
488 uint8_t des_0 = 0xB; // JEP106 identification code, bits[3:0]
489 uint8_t part_1 = 0x4; // Part number, bits[11:8]
490 return (des_0 << 4) | (part_1 << 0);
491 }
492
493 case GICD_PIDR2: { // Peripheral ID2 Register
494 uint8_t arch_rev = 0x3; // 0x3 GICv3
495 uint8_t jdec = 0x1; // JEP code
496 uint8_t des_1 = 0x3; // JEP106 identification code, bits[6:4]
497 return (arch_rev << 4) | (jdec << 3) | (des_1 << 0);
498 }
499
500 case GICD_PIDR3: // Peripheral ID3 Register
501 return 0x0; // Implementation defined
502
503 case GICD_PIDR4: { // Peripheral ID4 Register
504 uint8_t size = 0x4; // 64 KB software visible page
505 uint8_t des_2 = 0x4; // ARM implementation
506 return (size << 4) | (des_2 << 0);
507 }
508
509 case GICD_PIDR5: // Peripheral ID5 Register
510 case GICD_PIDR6: // Peripheral ID6 Register
511 case GICD_PIDR7: // Peripheral ID7 Register
512 return 0; // RES0
513
514 default:
515 panic("Gicv3Distributor::read(): invalid offset %#x\n", addr);
516 break;
517 }
518}
519
520void
521Gicv3Distributor::write(Addr addr, uint64_t data, size_t size,
522 bool is_secure_access)
523{
524 if (GICD_IGROUPR.contains(addr)) { // Interrupt Group Registers
525 if (!DS && !is_secure_access) {
526 // RAZ/WI for non-secure accesses
527 return;
528 }
529
530 int first_intid = (addr - GICD_IGROUPR.start()) * 8;
531
532 if (isNotSPI(first_intid)) {
533 return;
534 }
535
536 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
537 i++, int_id++) {
538 irqGroup[int_id] = data & (1 << i) ? 1 : 0;
539 DPRINTF(GIC, "Gicv3Distributor::write(): int_id %d group %d\n",
540 int_id, irqGroup[int_id]);
541 }
542
543 return;
544 // Interrupt Set-Enable Registers
545 } else if (GICD_ISENABLER.contains(addr)) {
546 int first_intid = (addr - GICD_ISENABLER.start()) * 8;
547
548 if (isNotSPI(first_intid)) {
549 return;
550 }
551
552 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
553 i++, int_id++) {
554 if (nsAccessToSecInt(int_id, is_secure_access))
555 {
556 continue;
557 }
558
559 bool enable = data & (1 << i) ? 1 : 0;
560
561 if (enable) {
562 if (!irqEnabled[int_id]) {
563 DPRINTF(GIC, "Gicv3Distributor::write(): "
564 "int_id %d enabled\n", int_id);
565 }
566
567 irqEnabled[int_id] = true;
568 }
569 }
570
571 return;
572 } else if (GICD_ICENABLER.contains(addr)) {
573 // Interrupt Clear-Enable Registers
574 int first_intid = (addr - GICD_ICENABLER.start()) * 8;
575
576 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
577 i++, int_id++) {
578 if (nsAccessToSecInt(int_id, is_secure_access))
579 {
580 continue;
581 }
582
583 bool disable = data & (1 << i) ? 1 : 0;
584
585 if (disable) {
586 if (irqEnabled[int_id]) {
587 DPRINTF(GIC, "Gicv3Distributor::write(): "
588 "int_id %d disabled\n", int_id);
589 }
590
591 irqEnabled[int_id] = false;
592 }
593 }
594
595 return;
596 } else if (GICD_ISPENDR.contains(addr)) {
597 int first_intid = (addr - GICD_ISPENDR.start()) * 8;
598
599 if (isNotSPI(first_intid)) {
600 return;
601 }
602
603 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
604 i++, int_id++) {
605 if (nsAccessToSecInt(int_id, is_secure_access))
606 {
607 if (irqNsacr[int_id] == 0) {
608 // Group 0 or Secure Group 1 interrupts are RAZ/WI
609 continue;
610 }
611 }
612
613 bool pending = data & (1 << i) ? 1 : 0;
614
615 if (pending) {
616 DPRINTF(GIC, "Gicv3Distributor::write() (GICD_ISPENDR): "
617 "int_id %d (SPI) pending bit set\n", int_id);
618 irqPending[int_id] = true;
619 }
620 }
621
622 updateAndInformCPUInterfaces();
623 return;
624 } else if (GICD_ICPENDR.contains(addr)) {
625 int first_intid = (addr - GICD_ICPENDR.start()) * 8;
626
627 if (isNotSPI(first_intid)) {
628 return;
629 }
630
631 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
632 i++, int_id++) {
633 if (nsAccessToSecInt(int_id, is_secure_access))
634 {
635 if (irqNsacr[int_id] < 2) {
636 // Group 0 or Secure Group 1 interrupts are RAZ/WI
637 continue;
638 }
639 }
640
641 bool clear = data & (1 << i) ? 1 : 0;
642
643 if (clear) {
644 irqPending[int_id] = false;
645 }
646 }
647
648 updateAndInformCPUInterfaces();
649 return;
650 // Interrupt Set-Active Registers
651 } else if (GICD_ISACTIVER.contains(addr)) {
652 int first_intid = (addr - GICD_ISACTIVER.start()) * 8;
653
654 if (isNotSPI(first_intid)) {
655 return;
656 }
657
658 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
659 i++, int_id++) {
660 if (nsAccessToSecInt(int_id, is_secure_access))
661 {
662 continue;
663 }
664
665 bool active = data & (1 << i) ? 1 : 0;
666
667 if (active) {
668 irqActive[int_id] = 1;
669 }
670 }
671
672 return;
673 } else if (GICD_ICACTIVER.contains(addr)) {
674 // Interrupt Clear-Active Registers
675 int first_intid = (addr - GICD_ICACTIVER.start()) * 8;
676
677 if (isNotSPI(first_intid)) {
678 return;
679 }
680
681 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
682 i++, int_id++) {
683 if (nsAccessToSecInt(int_id, is_secure_access))
684 {
685 continue;
686 }
687
688 bool clear = data & (1 << i) ? 1 : 0;
689
690 if (clear) {
691 if (irqActive[int_id]) {
692 DPRINTF(GIC, "Gicv3Distributor::write(): "
693 "int_id %d active cleared\n", int_id);
694 }
695
696 irqActive[int_id] = false;
697 }
698 }
699
700 return;
701 // Interrupt Priority Registers
702 } else if (GICD_IPRIORITYR.contains(addr)) {
703 int first_intid = addr - GICD_IPRIORITYR.start();
704
705 if (isNotSPI(first_intid)) {
706 return;
707 }
708
709 for (int i = 0, int_id = first_intid; i < size && int_id < itLines;
710 i++, int_id++) {
711 uint8_t prio = bits(data, (i + 1) * 8 - 1, (i * 8));
712
713 if (!DS && !is_secure_access) {
714 if (getIntGroup(int_id) != Gicv3::G1NS) {
715 // RAZ/WI for non-secure accesses to secure interrupts
716 continue;
717 } else {
718 prio = 0x80 | (prio >> 1);
719 }
720 }
721
722 irqPriority[int_id] = prio;
723 DPRINTF(GIC, "Gicv3Distributor::write(): int_id %d priority %d\n",
724 int_id, irqPriority[int_id]);
725 }
726
727 return;
728 } else if (GICD_ITARGETSR.contains(addr)) {
729 // Interrupt Processor Targets Registers
730 // ARE always on, RAZ/WI
731 warn("Gicv3Distributor::write(): "
732 "GICD_ITARGETSR is RAZ/WI, legacy not supported!\n");
733 return;
734 // Interrupt Configuration Registers
735 } else if (GICD_ICFGR.contains(addr)) {
736 /* Here only the odd bits are used; even bits are RES0 */
737 int first_intid = (addr - GICD_ICFGR.start()) * 4;
738
739 if (isNotSPI(first_intid)) {
740 return;
741 }
742
743 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
744 i = i + 2, int_id++) {
745 irqConfig[int_id] = data & (0x2 << i) ?
746 Gicv3::INT_EDGE_TRIGGERED :
747 Gicv3::INT_LEVEL_SENSITIVE;
748 DPRINTF(GIC, "Gicv3Distributor::write(): int_id %d config %d\n",
749 int_id, irqConfig[int_id]);
750 }
751
752 return;
753 } else if (GICD_IGRPMODR.contains(addr)) {
754 // Interrupt Group Modifier Registers
755 if (DS) {
756 return;
757 } else {
758 if (!is_secure_access) {
759 // RAZ/WI for non-secure accesses
760 return;
761 } else {
762 int first_intid = (addr - GICD_IGRPMODR.start()) * 8;
763
764 if (isNotSPI(first_intid)) {
765 return;
766 }
767
768 for (int i = 0, int_id = first_intid;
769 i < 8 * size && int_id < itLines; i++, int_id++) {
770 irqGrpmod[int_id] = data & (0x1 << i);
771 }
772
773 return ;
774 }
775 }
776
777 // Non-secure Access Control Registers
778 } else if (GICD_NSACR.contains(addr)) {
779 // 2 bits per interrupt
780 int first_intid = (addr - GICD_NSACR.start()) * 4;
781
782 if (isNotSPI(first_intid)) {
783 return;
784 }
785
786 if (DS || (!DS && !is_secure_access)) {
787 return;
788 }
789
790 for (int i = 0, int_id = first_intid;
791 i < 8 * size && int_id < itLines; i = i + 2, int_id++) {
792 irqNsacr[int_id] = (data >> (2 * int_id)) & 0x3;
793 }
794
795 return;
796 } else if (GICD_IROUTER.contains(addr)) { // Interrupt Routing Registers
797 // 64 bit registers. 2 accesses.
798 int int_id = (addr - GICD_IROUTER.start()) / 8;
799
800 if (isNotSPI(int_id)) {
801 return;
802 }
803
804 if (nsAccessToSecInt(int_id, is_secure_access))
805 {
806 if (irqNsacr[int_id] < 3) {
807 // Group 0 or Secure Group 1 interrupts are RAZ/WI
808 return;
809 }
810 }
811
812 if (size == 4) {
813 if (addr & 7) { // high half of 64 bit register
814 irqAffinityRouting[int_id] =
815 (irqAffinityRouting[int_id] & 0xffffffff) | (data << 32);
816 } else { // low half of 64 bit register
817 irqAffinityRouting[int_id] =
818 (irqAffinityRouting[int_id] & 0xffffffff00000000) |
819 (data & 0xffffffff);
820 }
821 } else {
822 irqAffinityRouting[int_id] = data;
823 }
824
825 DPRINTF(GIC, "Gicv3Distributor::write(): "
826 "int_id %d GICD_IROUTER %#llx\n",
827 int_id, irqAffinityRouting[int_id]);
828 return;
829 }
830
831 switch (addr) {
832 case GICD_CTLR: // Control Register
833 if (DS) {
834 /*
835 * E1NWF [7]
836 * 1 of N wakeup functionality not supported, RAZ/WI
837 * DS [6] - RAO/WI
838 * ARE [4]
839 * affinity routing always on, no GICv2 legacy, RAO/WI
840 * EnableGrp1 [1]
841 * EnableGrp0 [0]
842 */
843 if ((data & (1 << 4)) == 0) {
844 warn("Gicv3Distributor::write(): "
845 "setting ARE to 0 is not supported!\n");
846 }
847
848 EnableGrp1NS = data & GICD_CTLR_ENABLEGRP1NS;
849 EnableGrp0 = data & GICD_CTLR_ENABLEGRP0;
850 DPRINTF(GIC, "Gicv3Distributor::write(): (DS 1)"
851 "EnableGrp1NS %d EnableGrp0 %d\n",
852 EnableGrp1NS, EnableGrp0);
853 } else {
854 if (is_secure_access) {
855 /*
856 * E1NWF [7]
857 * 1 of N wakeup functionality not supported, RAZ/WI
858 * DS [6]
859 * ARE_NS [5]
860 * affinity routing always on, no GICv2 legacy, RAO/WI
861 * ARE_S [4]
862 * affinity routing always on, no GICv2 legacy, RAO/WI
863 * EnableGrp1S [2]
864 * EnableGrp1NS [1]
865 * EnableGrp0 [0]
866 */
867 if ((data & (1 << 5)) == 0) {
868 warn("Gicv3Distributor::write(): "
869 "setting ARE_NS to 0 is not supported!\n");
870 }
871
872 if ((data & (1 << 4)) == 0) {
873 warn("Gicv3Distributor::write(): "
874 "setting ARE_S to 0 is not supported!\n");
875 }
876
877 DS = data & GICD_CTLR_DS;
878 EnableGrp1S = data & GICD_CTLR_ENABLEGRP1S;
879 EnableGrp1NS = data & GICD_CTLR_ENABLEGRP1NS;
880 EnableGrp0 = data & GICD_CTLR_ENABLEGRP0;
881 DPRINTF(GIC, "Gicv3Distributor::write(): (DS 0 secure)"
882 "DS %d "
883 "EnableGrp1S %d EnableGrp1NS %d EnableGrp0 %d\n",
884 DS, EnableGrp1S, EnableGrp1NS, EnableGrp0);
885
886 if (data & GICD_CTLR_DS) {
887 EnableGrp1S = 0;
888 }
889 } else {
890 /*
891 * ARE_NS [4] RAO/WI;
892 * EnableGrp1A [1] is a read-write alias of the Secure
893 * GICD_CTLR.EnableGrp1NS
894 * EnableGrp1 [0] RES0
895 */
896 if ((data & (1 << 4)) == 0) {
897 warn("Gicv3Distributor::write(): "
898 "setting ARE_NS to 0 is not supported!\n");
899 }
900
901 EnableGrp1NS = data & GICD_CTLR_ENABLEGRP1A;
902 DPRINTF(GIC, "Gicv3Distributor::write(): (DS 0 non-secure)"
903 "EnableGrp1NS %d\n", EnableGrp1NS);
904 }
905 }
906
907 break;
908
909 default:
910 panic("Gicv3Distributor::write(): invalid offset %#x\n", addr);
911 break;
912 }
913}
914
915void
916Gicv3Distributor::sendInt(uint32_t int_id)
917{
918 panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
919 panic_if(int_id > itLines, "Invalid SPI!");
920 irqPending[int_id] = true;
921 DPRINTF(GIC, "Gicv3Distributor::sendInt(): "
922 "int_id %d (SPI) pending bit set\n", int_id);
923 updateAndInformCPUInterfaces();
924}
925
926void
927Gicv3Distributor::intDeasserted(uint32_t int_id)
928{
929 panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
930 panic_if(int_id > itLines, "Invalid SPI!");
931 irqPending[int_id] = false;
932 updateAndInformCPUInterfaces();
933}
934
935void
936Gicv3Distributor::updateAndInformCPUInterfaces()
937{
938 update();
939
940 for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
941 gic->getCPUInterface(i)->update();
942 }
943}
944
945void
946Gicv3Distributor::fullUpdate()
947{
948 for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
949 Gicv3CPUInterface * cpu_interface_i = gic->getCPUInterface(i);
950 cpu_interface_i->hppi.prio = 0xff;
951 }
952
953 update();
954
955 for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
956 Gicv3Redistributor * redistributor_i = gic->getRedistributor(i);
957 redistributor_i->update();
958 }
959}
960
961void
962Gicv3Distributor::update()
963{
964 std::vector<bool> new_hppi(gic->getSystem()->numContexts(), false);
965
966 // Find the highest priority pending SPI
967 for (int int_id = Gicv3::SGI_MAX + Gicv3::PPI_MAX; int_id < itLines;
968 int_id++) {
969 Gicv3::GroupId int_group = getIntGroup(int_id);
970 bool group_enabled = groupEnabled(int_group);
971
972 if (irqPending[int_id] && irqEnabled[int_id] &&
973 !irqActive[int_id] && group_enabled) {
974 IROUTER affinity_routing = irqAffinityRouting[int_id];
975 Gicv3Redistributor * target_redistributor = nullptr;
976
977 if (affinity_routing.IRM) {
978 // Interrupts routed to any PE defined as a participating node
979 for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
980 Gicv3Redistributor * redistributor_i =
981 gic->getRedistributor(i);
982
983 if (redistributor_i->
984 canBeSelectedFor1toNInterrupt(int_group)) {
985 target_redistributor = redistributor_i;
986 break;
987 }
988 }
989 } else {
990 uint32_t affinity = (affinity_routing.Aff3 << 24) |
991 (affinity_routing.Aff3 << 16) |
992 (affinity_routing.Aff1 << 8) |
993 (affinity_routing.Aff0 << 0);
994 target_redistributor =
995 gic->getRedistributorByAffinity(affinity);
996 }
997
998 if (!target_redistributor) {
999 // Interrrupts targeting not present cpus must remain pending
1000 return;
1001 }
1002
1003 Gicv3CPUInterface * target_cpu_interface =
1004 target_redistributor->getCPUInterface();
1005 uint32_t target_cpu = target_redistributor->cpuId;
1006
1007 if ((irqPriority[int_id] < target_cpu_interface->hppi.prio) ||
1008 /*
1009 * Multiple pending ints with same priority.
1010 * Implementation choice which one to signal.
1011 * Our implementation selects the one with the lower id.
1012 */
1013 (irqPriority[int_id] == target_cpu_interface->hppi.prio &&
1014 int_id < target_cpu_interface->hppi.intid)) {
1015 target_cpu_interface->hppi.intid = int_id;
1016 target_cpu_interface->hppi.prio = irqPriority[int_id];
1017 target_cpu_interface->hppi.group = int_group;
1018 new_hppi[target_cpu] = true;
1019 }
1020 }
1021 }
1022
1023 for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
1024 Gicv3Redistributor * redistributor_i = gic->getRedistributor(i);
1025 Gicv3CPUInterface * cpu_interface_i =
1026 redistributor_i->getCPUInterface();
1027
1028 if (!new_hppi[i] && cpu_interface_i->hppi.prio != 0xff &&
1029 cpu_interface_i->hppi.intid >=
1030 (Gicv3::SGI_MAX + Gicv3::PPI_MAX) &&
1031 cpu_interface_i->hppi.intid < Gicv3::INTID_SECURE) {
1032 fullUpdate();
1033 }
1034 }
1035}
1036
1037Gicv3::IntStatus
1038Gicv3Distributor::intStatus(uint32_t int_id)
1039{
1040 panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
1041 panic_if(int_id > itLines, "Invalid SPI!");
1042
1043 if (irqPending[int_id]) {
1044 if (irqActive[int_id]) {
1045 return Gicv3::INT_ACTIVE_PENDING;
1046 }
1047
1048 return Gicv3::INT_PENDING;
1049 } else if (irqActive[int_id]) {
1050 return Gicv3::INT_ACTIVE;
1051 } else {
1052 return Gicv3::INT_INACTIVE;
1053 }
1054}
1055
1056Gicv3::GroupId
1057Gicv3Distributor::getIntGroup(int int_id)
1058{
1059 panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
1060 panic_if(int_id > itLines, "Invalid SPI!");
1061
1062 if (DS) {
1063 if (irqGroup[int_id] == 1) {
1064 return Gicv3::G1NS;
1065 } else {
1066 return Gicv3::G0S;
1067 }
1068 } else {
1069 if (irqGrpmod[int_id] == 0 && irqGroup[int_id] == 0) {
1070 return Gicv3::G0S;
1071 } else if (irqGrpmod[int_id] == 0 && irqGroup[int_id] == 1) {
1072 return Gicv3::G1NS;
1073 } else if (irqGrpmod[int_id] == 1 && irqGroup[int_id] == 0) {
1074 return Gicv3::G1S;
1075 } else if (irqGrpmod[int_id] == 1 && irqGroup[int_id] == 1) {
1076 return Gicv3::G1NS;
1077 }
1078 }
1079
1080 M5_UNREACHABLE;
1081}
1082
1083void
1084Gicv3Distributor::activateIRQ(uint32_t int_id)
1085{
1086 irqPending[int_id] = false;
1087 irqActive[int_id] = true;
1088}
1089
1090void
1091Gicv3Distributor::deactivateIRQ(uint32_t int_id)
1092{
1093 irqActive[int_id] = false;
1094}
1095
1096void
1097Gicv3Distributor::serialize(CheckpointOut & cp) const
1098{
1099 SERIALIZE_SCALAR(ARE);
1100 SERIALIZE_SCALAR(DS);
1101 SERIALIZE_SCALAR(EnableGrp1S);
1102 SERIALIZE_SCALAR(EnableGrp1NS);
1103 SERIALIZE_SCALAR(EnableGrp0);
1104 SERIALIZE_CONTAINER(irqGroup);
1105 SERIALIZE_CONTAINER(irqEnabled);
1106 SERIALIZE_CONTAINER(irqPending);
1107 SERIALIZE_CONTAINER(irqActive);
1108 SERIALIZE_CONTAINER(irqPriority);
1109 SERIALIZE_CONTAINER(irqConfig);
1110 SERIALIZE_CONTAINER(irqGrpmod);
1111 SERIALIZE_CONTAINER(irqNsacr);
1112 SERIALIZE_CONTAINER(irqAffinityRouting);
1113}
1114
1115void
1116Gicv3Distributor::unserialize(CheckpointIn & cp)
1117{
1118 UNSERIALIZE_SCALAR(ARE);
1119 UNSERIALIZE_SCALAR(DS);
1120 UNSERIALIZE_SCALAR(EnableGrp1S);
1121 UNSERIALIZE_SCALAR(EnableGrp1NS);
1122 UNSERIALIZE_SCALAR(EnableGrp0);
1123 UNSERIALIZE_CONTAINER(irqGroup);
1124 UNSERIALIZE_CONTAINER(irqEnabled);
1125 UNSERIALIZE_CONTAINER(irqPending);
1126 UNSERIALIZE_CONTAINER(irqActive);
1127 UNSERIALIZE_CONTAINER(irqPriority);
1128 UNSERIALIZE_CONTAINER(irqConfig);
1129 UNSERIALIZE_CONTAINER(irqGrpmod);
1130 UNSERIALIZE_CONTAINER(irqNsacr);
1131 UNSERIALIZE_CONTAINER(irqAffinityRouting);
1132}
471 (it_lines_number << 0);
472 }
473
474 case GICD_IIDR: // Implementer Identification Register
475 //return 0x43b; // ARM JEP106 code (r0p0 GIC-500)
476 return 0;
477
478 case GICD_STATUSR: // Error Reporting Status Register
479 // Optional register, RAZ/WI
480 return 0x0;
481
482 case GICD_PIDR0: { // Peripheral ID0 Register
483 uint8_t part_0 = 0x92; // Part number, bits[7:0]
484 return part_0;
485 }
486
487 case GICD_PIDR1: { // Peripheral ID1 Register
488 uint8_t des_0 = 0xB; // JEP106 identification code, bits[3:0]
489 uint8_t part_1 = 0x4; // Part number, bits[11:8]
490 return (des_0 << 4) | (part_1 << 0);
491 }
492
493 case GICD_PIDR2: { // Peripheral ID2 Register
494 uint8_t arch_rev = 0x3; // 0x3 GICv3
495 uint8_t jdec = 0x1; // JEP code
496 uint8_t des_1 = 0x3; // JEP106 identification code, bits[6:4]
497 return (arch_rev << 4) | (jdec << 3) | (des_1 << 0);
498 }
499
500 case GICD_PIDR3: // Peripheral ID3 Register
501 return 0x0; // Implementation defined
502
503 case GICD_PIDR4: { // Peripheral ID4 Register
504 uint8_t size = 0x4; // 64 KB software visible page
505 uint8_t des_2 = 0x4; // ARM implementation
506 return (size << 4) | (des_2 << 0);
507 }
508
509 case GICD_PIDR5: // Peripheral ID5 Register
510 case GICD_PIDR6: // Peripheral ID6 Register
511 case GICD_PIDR7: // Peripheral ID7 Register
512 return 0; // RES0
513
514 default:
515 panic("Gicv3Distributor::read(): invalid offset %#x\n", addr);
516 break;
517 }
518}
519
520void
521Gicv3Distributor::write(Addr addr, uint64_t data, size_t size,
522 bool is_secure_access)
523{
524 if (GICD_IGROUPR.contains(addr)) { // Interrupt Group Registers
525 if (!DS && !is_secure_access) {
526 // RAZ/WI for non-secure accesses
527 return;
528 }
529
530 int first_intid = (addr - GICD_IGROUPR.start()) * 8;
531
532 if (isNotSPI(first_intid)) {
533 return;
534 }
535
536 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
537 i++, int_id++) {
538 irqGroup[int_id] = data & (1 << i) ? 1 : 0;
539 DPRINTF(GIC, "Gicv3Distributor::write(): int_id %d group %d\n",
540 int_id, irqGroup[int_id]);
541 }
542
543 return;
544 // Interrupt Set-Enable Registers
545 } else if (GICD_ISENABLER.contains(addr)) {
546 int first_intid = (addr - GICD_ISENABLER.start()) * 8;
547
548 if (isNotSPI(first_intid)) {
549 return;
550 }
551
552 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
553 i++, int_id++) {
554 if (nsAccessToSecInt(int_id, is_secure_access))
555 {
556 continue;
557 }
558
559 bool enable = data & (1 << i) ? 1 : 0;
560
561 if (enable) {
562 if (!irqEnabled[int_id]) {
563 DPRINTF(GIC, "Gicv3Distributor::write(): "
564 "int_id %d enabled\n", int_id);
565 }
566
567 irqEnabled[int_id] = true;
568 }
569 }
570
571 return;
572 } else if (GICD_ICENABLER.contains(addr)) {
573 // Interrupt Clear-Enable Registers
574 int first_intid = (addr - GICD_ICENABLER.start()) * 8;
575
576 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
577 i++, int_id++) {
578 if (nsAccessToSecInt(int_id, is_secure_access))
579 {
580 continue;
581 }
582
583 bool disable = data & (1 << i) ? 1 : 0;
584
585 if (disable) {
586 if (irqEnabled[int_id]) {
587 DPRINTF(GIC, "Gicv3Distributor::write(): "
588 "int_id %d disabled\n", int_id);
589 }
590
591 irqEnabled[int_id] = false;
592 }
593 }
594
595 return;
596 } else if (GICD_ISPENDR.contains(addr)) {
597 int first_intid = (addr - GICD_ISPENDR.start()) * 8;
598
599 if (isNotSPI(first_intid)) {
600 return;
601 }
602
603 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
604 i++, int_id++) {
605 if (nsAccessToSecInt(int_id, is_secure_access))
606 {
607 if (irqNsacr[int_id] == 0) {
608 // Group 0 or Secure Group 1 interrupts are RAZ/WI
609 continue;
610 }
611 }
612
613 bool pending = data & (1 << i) ? 1 : 0;
614
615 if (pending) {
616 DPRINTF(GIC, "Gicv3Distributor::write() (GICD_ISPENDR): "
617 "int_id %d (SPI) pending bit set\n", int_id);
618 irqPending[int_id] = true;
619 }
620 }
621
622 updateAndInformCPUInterfaces();
623 return;
624 } else if (GICD_ICPENDR.contains(addr)) {
625 int first_intid = (addr - GICD_ICPENDR.start()) * 8;
626
627 if (isNotSPI(first_intid)) {
628 return;
629 }
630
631 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
632 i++, int_id++) {
633 if (nsAccessToSecInt(int_id, is_secure_access))
634 {
635 if (irqNsacr[int_id] < 2) {
636 // Group 0 or Secure Group 1 interrupts are RAZ/WI
637 continue;
638 }
639 }
640
641 bool clear = data & (1 << i) ? 1 : 0;
642
643 if (clear) {
644 irqPending[int_id] = false;
645 }
646 }
647
648 updateAndInformCPUInterfaces();
649 return;
650 // Interrupt Set-Active Registers
651 } else if (GICD_ISACTIVER.contains(addr)) {
652 int first_intid = (addr - GICD_ISACTIVER.start()) * 8;
653
654 if (isNotSPI(first_intid)) {
655 return;
656 }
657
658 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
659 i++, int_id++) {
660 if (nsAccessToSecInt(int_id, is_secure_access))
661 {
662 continue;
663 }
664
665 bool active = data & (1 << i) ? 1 : 0;
666
667 if (active) {
668 irqActive[int_id] = 1;
669 }
670 }
671
672 return;
673 } else if (GICD_ICACTIVER.contains(addr)) {
674 // Interrupt Clear-Active Registers
675 int first_intid = (addr - GICD_ICACTIVER.start()) * 8;
676
677 if (isNotSPI(first_intid)) {
678 return;
679 }
680
681 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
682 i++, int_id++) {
683 if (nsAccessToSecInt(int_id, is_secure_access))
684 {
685 continue;
686 }
687
688 bool clear = data & (1 << i) ? 1 : 0;
689
690 if (clear) {
691 if (irqActive[int_id]) {
692 DPRINTF(GIC, "Gicv3Distributor::write(): "
693 "int_id %d active cleared\n", int_id);
694 }
695
696 irqActive[int_id] = false;
697 }
698 }
699
700 return;
701 // Interrupt Priority Registers
702 } else if (GICD_IPRIORITYR.contains(addr)) {
703 int first_intid = addr - GICD_IPRIORITYR.start();
704
705 if (isNotSPI(first_intid)) {
706 return;
707 }
708
709 for (int i = 0, int_id = first_intid; i < size && int_id < itLines;
710 i++, int_id++) {
711 uint8_t prio = bits(data, (i + 1) * 8 - 1, (i * 8));
712
713 if (!DS && !is_secure_access) {
714 if (getIntGroup(int_id) != Gicv3::G1NS) {
715 // RAZ/WI for non-secure accesses to secure interrupts
716 continue;
717 } else {
718 prio = 0x80 | (prio >> 1);
719 }
720 }
721
722 irqPriority[int_id] = prio;
723 DPRINTF(GIC, "Gicv3Distributor::write(): int_id %d priority %d\n",
724 int_id, irqPriority[int_id]);
725 }
726
727 return;
728 } else if (GICD_ITARGETSR.contains(addr)) {
729 // Interrupt Processor Targets Registers
730 // ARE always on, RAZ/WI
731 warn("Gicv3Distributor::write(): "
732 "GICD_ITARGETSR is RAZ/WI, legacy not supported!\n");
733 return;
734 // Interrupt Configuration Registers
735 } else if (GICD_ICFGR.contains(addr)) {
736 /* Here only the odd bits are used; even bits are RES0 */
737 int first_intid = (addr - GICD_ICFGR.start()) * 4;
738
739 if (isNotSPI(first_intid)) {
740 return;
741 }
742
743 for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
744 i = i + 2, int_id++) {
745 irqConfig[int_id] = data & (0x2 << i) ?
746 Gicv3::INT_EDGE_TRIGGERED :
747 Gicv3::INT_LEVEL_SENSITIVE;
748 DPRINTF(GIC, "Gicv3Distributor::write(): int_id %d config %d\n",
749 int_id, irqConfig[int_id]);
750 }
751
752 return;
753 } else if (GICD_IGRPMODR.contains(addr)) {
754 // Interrupt Group Modifier Registers
755 if (DS) {
756 return;
757 } else {
758 if (!is_secure_access) {
759 // RAZ/WI for non-secure accesses
760 return;
761 } else {
762 int first_intid = (addr - GICD_IGRPMODR.start()) * 8;
763
764 if (isNotSPI(first_intid)) {
765 return;
766 }
767
768 for (int i = 0, int_id = first_intid;
769 i < 8 * size && int_id < itLines; i++, int_id++) {
770 irqGrpmod[int_id] = data & (0x1 << i);
771 }
772
773 return ;
774 }
775 }
776
777 // Non-secure Access Control Registers
778 } else if (GICD_NSACR.contains(addr)) {
779 // 2 bits per interrupt
780 int first_intid = (addr - GICD_NSACR.start()) * 4;
781
782 if (isNotSPI(first_intid)) {
783 return;
784 }
785
786 if (DS || (!DS && !is_secure_access)) {
787 return;
788 }
789
790 for (int i = 0, int_id = first_intid;
791 i < 8 * size && int_id < itLines; i = i + 2, int_id++) {
792 irqNsacr[int_id] = (data >> (2 * int_id)) & 0x3;
793 }
794
795 return;
796 } else if (GICD_IROUTER.contains(addr)) { // Interrupt Routing Registers
797 // 64 bit registers. 2 accesses.
798 int int_id = (addr - GICD_IROUTER.start()) / 8;
799
800 if (isNotSPI(int_id)) {
801 return;
802 }
803
804 if (nsAccessToSecInt(int_id, is_secure_access))
805 {
806 if (irqNsacr[int_id] < 3) {
807 // Group 0 or Secure Group 1 interrupts are RAZ/WI
808 return;
809 }
810 }
811
812 if (size == 4) {
813 if (addr & 7) { // high half of 64 bit register
814 irqAffinityRouting[int_id] =
815 (irqAffinityRouting[int_id] & 0xffffffff) | (data << 32);
816 } else { // low half of 64 bit register
817 irqAffinityRouting[int_id] =
818 (irqAffinityRouting[int_id] & 0xffffffff00000000) |
819 (data & 0xffffffff);
820 }
821 } else {
822 irqAffinityRouting[int_id] = data;
823 }
824
825 DPRINTF(GIC, "Gicv3Distributor::write(): "
826 "int_id %d GICD_IROUTER %#llx\n",
827 int_id, irqAffinityRouting[int_id]);
828 return;
829 }
830
831 switch (addr) {
832 case GICD_CTLR: // Control Register
833 if (DS) {
834 /*
835 * E1NWF [7]
836 * 1 of N wakeup functionality not supported, RAZ/WI
837 * DS [6] - RAO/WI
838 * ARE [4]
839 * affinity routing always on, no GICv2 legacy, RAO/WI
840 * EnableGrp1 [1]
841 * EnableGrp0 [0]
842 */
843 if ((data & (1 << 4)) == 0) {
844 warn("Gicv3Distributor::write(): "
845 "setting ARE to 0 is not supported!\n");
846 }
847
848 EnableGrp1NS = data & GICD_CTLR_ENABLEGRP1NS;
849 EnableGrp0 = data & GICD_CTLR_ENABLEGRP0;
850 DPRINTF(GIC, "Gicv3Distributor::write(): (DS 1)"
851 "EnableGrp1NS %d EnableGrp0 %d\n",
852 EnableGrp1NS, EnableGrp0);
853 } else {
854 if (is_secure_access) {
855 /*
856 * E1NWF [7]
857 * 1 of N wakeup functionality not supported, RAZ/WI
858 * DS [6]
859 * ARE_NS [5]
860 * affinity routing always on, no GICv2 legacy, RAO/WI
861 * ARE_S [4]
862 * affinity routing always on, no GICv2 legacy, RAO/WI
863 * EnableGrp1S [2]
864 * EnableGrp1NS [1]
865 * EnableGrp0 [0]
866 */
867 if ((data & (1 << 5)) == 0) {
868 warn("Gicv3Distributor::write(): "
869 "setting ARE_NS to 0 is not supported!\n");
870 }
871
872 if ((data & (1 << 4)) == 0) {
873 warn("Gicv3Distributor::write(): "
874 "setting ARE_S to 0 is not supported!\n");
875 }
876
877 DS = data & GICD_CTLR_DS;
878 EnableGrp1S = data & GICD_CTLR_ENABLEGRP1S;
879 EnableGrp1NS = data & GICD_CTLR_ENABLEGRP1NS;
880 EnableGrp0 = data & GICD_CTLR_ENABLEGRP0;
881 DPRINTF(GIC, "Gicv3Distributor::write(): (DS 0 secure)"
882 "DS %d "
883 "EnableGrp1S %d EnableGrp1NS %d EnableGrp0 %d\n",
884 DS, EnableGrp1S, EnableGrp1NS, EnableGrp0);
885
886 if (data & GICD_CTLR_DS) {
887 EnableGrp1S = 0;
888 }
889 } else {
890 /*
891 * ARE_NS [4] RAO/WI;
892 * EnableGrp1A [1] is a read-write alias of the Secure
893 * GICD_CTLR.EnableGrp1NS
894 * EnableGrp1 [0] RES0
895 */
896 if ((data & (1 << 4)) == 0) {
897 warn("Gicv3Distributor::write(): "
898 "setting ARE_NS to 0 is not supported!\n");
899 }
900
901 EnableGrp1NS = data & GICD_CTLR_ENABLEGRP1A;
902 DPRINTF(GIC, "Gicv3Distributor::write(): (DS 0 non-secure)"
903 "EnableGrp1NS %d\n", EnableGrp1NS);
904 }
905 }
906
907 break;
908
909 default:
910 panic("Gicv3Distributor::write(): invalid offset %#x\n", addr);
911 break;
912 }
913}
914
915void
916Gicv3Distributor::sendInt(uint32_t int_id)
917{
918 panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
919 panic_if(int_id > itLines, "Invalid SPI!");
920 irqPending[int_id] = true;
921 DPRINTF(GIC, "Gicv3Distributor::sendInt(): "
922 "int_id %d (SPI) pending bit set\n", int_id);
923 updateAndInformCPUInterfaces();
924}
925
926void
927Gicv3Distributor::intDeasserted(uint32_t int_id)
928{
929 panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
930 panic_if(int_id > itLines, "Invalid SPI!");
931 irqPending[int_id] = false;
932 updateAndInformCPUInterfaces();
933}
934
935void
936Gicv3Distributor::updateAndInformCPUInterfaces()
937{
938 update();
939
940 for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
941 gic->getCPUInterface(i)->update();
942 }
943}
944
945void
946Gicv3Distributor::fullUpdate()
947{
948 for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
949 Gicv3CPUInterface * cpu_interface_i = gic->getCPUInterface(i);
950 cpu_interface_i->hppi.prio = 0xff;
951 }
952
953 update();
954
955 for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
956 Gicv3Redistributor * redistributor_i = gic->getRedistributor(i);
957 redistributor_i->update();
958 }
959}
960
961void
962Gicv3Distributor::update()
963{
964 std::vector<bool> new_hppi(gic->getSystem()->numContexts(), false);
965
966 // Find the highest priority pending SPI
967 for (int int_id = Gicv3::SGI_MAX + Gicv3::PPI_MAX; int_id < itLines;
968 int_id++) {
969 Gicv3::GroupId int_group = getIntGroup(int_id);
970 bool group_enabled = groupEnabled(int_group);
971
972 if (irqPending[int_id] && irqEnabled[int_id] &&
973 !irqActive[int_id] && group_enabled) {
974 IROUTER affinity_routing = irqAffinityRouting[int_id];
975 Gicv3Redistributor * target_redistributor = nullptr;
976
977 if (affinity_routing.IRM) {
978 // Interrupts routed to any PE defined as a participating node
979 for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
980 Gicv3Redistributor * redistributor_i =
981 gic->getRedistributor(i);
982
983 if (redistributor_i->
984 canBeSelectedFor1toNInterrupt(int_group)) {
985 target_redistributor = redistributor_i;
986 break;
987 }
988 }
989 } else {
990 uint32_t affinity = (affinity_routing.Aff3 << 24) |
991 (affinity_routing.Aff3 << 16) |
992 (affinity_routing.Aff1 << 8) |
993 (affinity_routing.Aff0 << 0);
994 target_redistributor =
995 gic->getRedistributorByAffinity(affinity);
996 }
997
998 if (!target_redistributor) {
999 // Interrrupts targeting not present cpus must remain pending
1000 return;
1001 }
1002
1003 Gicv3CPUInterface * target_cpu_interface =
1004 target_redistributor->getCPUInterface();
1005 uint32_t target_cpu = target_redistributor->cpuId;
1006
1007 if ((irqPriority[int_id] < target_cpu_interface->hppi.prio) ||
1008 /*
1009 * Multiple pending ints with same priority.
1010 * Implementation choice which one to signal.
1011 * Our implementation selects the one with the lower id.
1012 */
1013 (irqPriority[int_id] == target_cpu_interface->hppi.prio &&
1014 int_id < target_cpu_interface->hppi.intid)) {
1015 target_cpu_interface->hppi.intid = int_id;
1016 target_cpu_interface->hppi.prio = irqPriority[int_id];
1017 target_cpu_interface->hppi.group = int_group;
1018 new_hppi[target_cpu] = true;
1019 }
1020 }
1021 }
1022
1023 for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
1024 Gicv3Redistributor * redistributor_i = gic->getRedistributor(i);
1025 Gicv3CPUInterface * cpu_interface_i =
1026 redistributor_i->getCPUInterface();
1027
1028 if (!new_hppi[i] && cpu_interface_i->hppi.prio != 0xff &&
1029 cpu_interface_i->hppi.intid >=
1030 (Gicv3::SGI_MAX + Gicv3::PPI_MAX) &&
1031 cpu_interface_i->hppi.intid < Gicv3::INTID_SECURE) {
1032 fullUpdate();
1033 }
1034 }
1035}
1036
1037Gicv3::IntStatus
1038Gicv3Distributor::intStatus(uint32_t int_id)
1039{
1040 panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
1041 panic_if(int_id > itLines, "Invalid SPI!");
1042
1043 if (irqPending[int_id]) {
1044 if (irqActive[int_id]) {
1045 return Gicv3::INT_ACTIVE_PENDING;
1046 }
1047
1048 return Gicv3::INT_PENDING;
1049 } else if (irqActive[int_id]) {
1050 return Gicv3::INT_ACTIVE;
1051 } else {
1052 return Gicv3::INT_INACTIVE;
1053 }
1054}
1055
1056Gicv3::GroupId
1057Gicv3Distributor::getIntGroup(int int_id)
1058{
1059 panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
1060 panic_if(int_id > itLines, "Invalid SPI!");
1061
1062 if (DS) {
1063 if (irqGroup[int_id] == 1) {
1064 return Gicv3::G1NS;
1065 } else {
1066 return Gicv3::G0S;
1067 }
1068 } else {
1069 if (irqGrpmod[int_id] == 0 && irqGroup[int_id] == 0) {
1070 return Gicv3::G0S;
1071 } else if (irqGrpmod[int_id] == 0 && irqGroup[int_id] == 1) {
1072 return Gicv3::G1NS;
1073 } else if (irqGrpmod[int_id] == 1 && irqGroup[int_id] == 0) {
1074 return Gicv3::G1S;
1075 } else if (irqGrpmod[int_id] == 1 && irqGroup[int_id] == 1) {
1076 return Gicv3::G1NS;
1077 }
1078 }
1079
1080 M5_UNREACHABLE;
1081}
1082
1083void
1084Gicv3Distributor::activateIRQ(uint32_t int_id)
1085{
1086 irqPending[int_id] = false;
1087 irqActive[int_id] = true;
1088}
1089
1090void
1091Gicv3Distributor::deactivateIRQ(uint32_t int_id)
1092{
1093 irqActive[int_id] = false;
1094}
1095
1096void
1097Gicv3Distributor::serialize(CheckpointOut & cp) const
1098{
1099 SERIALIZE_SCALAR(ARE);
1100 SERIALIZE_SCALAR(DS);
1101 SERIALIZE_SCALAR(EnableGrp1S);
1102 SERIALIZE_SCALAR(EnableGrp1NS);
1103 SERIALIZE_SCALAR(EnableGrp0);
1104 SERIALIZE_CONTAINER(irqGroup);
1105 SERIALIZE_CONTAINER(irqEnabled);
1106 SERIALIZE_CONTAINER(irqPending);
1107 SERIALIZE_CONTAINER(irqActive);
1108 SERIALIZE_CONTAINER(irqPriority);
1109 SERIALIZE_CONTAINER(irqConfig);
1110 SERIALIZE_CONTAINER(irqGrpmod);
1111 SERIALIZE_CONTAINER(irqNsacr);
1112 SERIALIZE_CONTAINER(irqAffinityRouting);
1113}
1114
1115void
1116Gicv3Distributor::unserialize(CheckpointIn & cp)
1117{
1118 UNSERIALIZE_SCALAR(ARE);
1119 UNSERIALIZE_SCALAR(DS);
1120 UNSERIALIZE_SCALAR(EnableGrp1S);
1121 UNSERIALIZE_SCALAR(EnableGrp1NS);
1122 UNSERIALIZE_SCALAR(EnableGrp0);
1123 UNSERIALIZE_CONTAINER(irqGroup);
1124 UNSERIALIZE_CONTAINER(irqEnabled);
1125 UNSERIALIZE_CONTAINER(irqPending);
1126 UNSERIALIZE_CONTAINER(irqActive);
1127 UNSERIALIZE_CONTAINER(irqPriority);
1128 UNSERIALIZE_CONTAINER(irqConfig);
1129 UNSERIALIZE_CONTAINER(irqGrpmod);
1130 UNSERIALIZE_CONTAINER(irqNsacr);
1131 UNSERIALIZE_CONTAINER(irqAffinityRouting);
1132}