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