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