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