gic_v3_distributor.cc revision 14253:4fbbfeaee777
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]    == 1
480         * (The implementation supports 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) | (1 << 16) |
494                (gic->getSystem()->haveSecurity() << 10) |
495                (it_lines_number << 0);
496        }
497
498      case GICD_IIDR: // Implementer Identification Register
499        //return 0x43b; // ARM JEP106 code (r0p0 GIC-500)
500        return 0;
501
502      case GICD_STATUSR: // Error Reporting Status Register
503        // Optional register, RAZ/WI
504        return 0x0;
505
506      case GICD_PIDR0: // Peripheral ID0 Register
507        return gicdPidr0;
508
509      case GICD_PIDR1: // Peripheral ID1 Register
510        return gicdPidr1;
511
512      case GICD_PIDR2: // Peripheral ID2 Register
513        return gicdPidr2;
514
515      case GICD_PIDR3: // Peripheral ID3 Register
516        return gicdPidr3;
517
518      case GICD_PIDR4: // Peripheral ID4 Register
519        return gicdPidr4;
520
521      case GICD_PIDR5: // Peripheral ID5 Register
522      case GICD_PIDR6: // Peripheral ID6 Register
523      case GICD_PIDR7: // Peripheral ID7 Register
524        return 0; // RES0
525
526      default:
527        panic("Gicv3Distributor::read(): invalid offset %#x\n", addr);
528        break;
529    }
530}
531
532void
533Gicv3Distributor::write(Addr addr, uint64_t data, size_t size,
534                        bool is_secure_access)
535{
536    if (GICD_IGROUPR.contains(addr)) { // Interrupt Group Registers
537        if (!DS && !is_secure_access) {
538            // RAZ/WI for non-secure accesses
539            return;
540        }
541
542        int first_intid = (addr - GICD_IGROUPR.start()) * 8;
543
544        if (isNotSPI(first_intid)) {
545            return;
546        }
547
548        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
549             i++, int_id++) {
550            irqGroup[int_id] = data & (1 << i) ? 1 : 0;
551            DPRINTF(GIC, "Gicv3Distributor::write(): int_id %d group %d\n",
552                    int_id, irqGroup[int_id]);
553        }
554
555        return;
556    } else if (GICD_ISENABLER.contains(addr)) {
557        // Interrupt Set-Enable Registers
558        int first_intid = (addr - GICD_ISENABLER.start()) * 8;
559
560        if (isNotSPI(first_intid)) {
561            return;
562        }
563
564        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
565             i++, int_id++) {
566
567            if (nsAccessToSecInt(int_id, is_secure_access))
568            {
569                continue;
570            }
571
572            bool enable = data & (1 << i) ? 1 : 0;
573
574            if (enable) {
575                if (!irqEnabled[int_id]) {
576                    DPRINTF(GIC, "Gicv3Distributor::write(): "
577                            "int_id %d enabled\n", int_id);
578                }
579
580                irqEnabled[int_id] = true;
581            }
582        }
583
584        return;
585    } else if (GICD_ICENABLER.contains(addr)) {
586        // Interrupt Clear-Enable Registers
587        int first_intid = (addr - GICD_ICENABLER.start()) * 8;
588
589        if (isNotSPI(first_intid)) {
590            return;
591        }
592
593        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
594             i++, int_id++) {
595
596            if (nsAccessToSecInt(int_id, is_secure_access))
597            {
598                continue;
599            }
600
601            bool disable = data & (1 << i) ? 1 : 0;
602
603            if (disable) {
604                if (irqEnabled[int_id]) {
605                    DPRINTF(GIC, "Gicv3Distributor::write(): "
606                            "int_id %d disabled\n", int_id);
607                }
608
609                irqEnabled[int_id] = false;
610            }
611        }
612
613        return;
614    } else if (GICD_ISPENDR.contains(addr)) {
615        // Interrupt Set-Pending Registers
616        int first_intid = (addr - GICD_ISPENDR.start()) * 8;
617
618        if (isNotSPI(first_intid)) {
619            return;
620        }
621
622        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
623             i++, int_id++) {
624
625            if (nsAccessToSecInt(int_id, is_secure_access))
626            {
627                if (irqNsacr[int_id] == 0) {
628                    // Group 0 or Secure Group 1 interrupts are RAZ/WI
629                    continue;
630                }
631            }
632
633            bool pending = data & (1 << i) ? 1 : 0;
634
635            if (pending) {
636                DPRINTF(GIC, "Gicv3Distributor::write() (GICD_ISPENDR): "
637                        "int_id %d (SPI) pending bit set\n", int_id);
638                irqPending[int_id] = true;
639            }
640        }
641
642        update();
643        return;
644    } else if (GICD_ICPENDR.contains(addr)) {
645        // Interrupt Clear-Pending Registers
646        int first_intid = (addr - GICD_ICPENDR.start()) * 8;
647
648        if (isNotSPI(first_intid)) {
649            return;
650        }
651
652        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
653             i++, int_id++) {
654
655            if (nsAccessToSecInt(int_id, is_secure_access))
656            {
657                if (irqNsacr[int_id] < 2) {
658                    // Group 0 or Secure Group 1 interrupts are RAZ/WI
659                    continue;
660                }
661            }
662
663            bool clear = data & (1 << i) ? 1 : 0;
664
665            if (clear) {
666                irqPending[int_id] = false;
667                clearIrqCpuInterface(int_id);
668            }
669        }
670
671        update();
672        return;
673    } else if (GICD_ISACTIVER.contains(addr)) {
674        // Interrupt Set-Active Registers
675        int first_intid = (addr - GICD_ISACTIVER.start()) * 8;
676
677        if (isNotSPI(first_intid)) {
678            return;
679        }
680
681        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
682             i++, int_id++) {
683
684            if (nsAccessToSecInt(int_id, is_secure_access))
685            {
686                continue;
687            }
688
689            bool active = data & (1 << i) ? 1 : 0;
690
691            if (active) {
692                irqActive[int_id] = 1;
693            }
694        }
695
696        return;
697    } else if (GICD_ICACTIVER.contains(addr)) {
698        // Interrupt Clear-Active Registers
699        int first_intid = (addr - GICD_ICACTIVER.start()) * 8;
700
701        if (isNotSPI(first_intid)) {
702            return;
703        }
704
705        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
706             i++, int_id++) {
707
708            if (nsAccessToSecInt(int_id, is_secure_access))
709            {
710                continue;
711            }
712
713            bool clear = data & (1 << i) ? 1 : 0;
714
715            if (clear) {
716                if (irqActive[int_id]) {
717                    DPRINTF(GIC, "Gicv3Distributor::write(): "
718                            "int_id %d active cleared\n", int_id);
719                }
720
721                irqActive[int_id] = false;
722            }
723        }
724
725        return;
726    } else if (GICD_IPRIORITYR.contains(addr)) {
727        // Interrupt Priority Registers
728        int first_intid = addr - GICD_IPRIORITYR.start();
729
730        if (isNotSPI(first_intid)) {
731            return;
732        }
733
734        for (int i = 0, int_id = first_intid; i < size && int_id < itLines;
735                i++, int_id++) {
736            uint8_t prio = bits(data, (i + 1) * 8 - 1, (i * 8));
737
738            if (!DS && !is_secure_access) {
739                if (getIntGroup(int_id) != Gicv3::G1NS) {
740                    // RAZ/WI for non-secure accesses to secure interrupts
741                    continue;
742                } else {
743                    prio = 0x80 | (prio >> 1);
744                }
745            }
746
747            irqPriority[int_id] = prio;
748            DPRINTF(GIC, "Gicv3Distributor::write(): int_id %d priority %d\n",
749                    int_id, irqPriority[int_id]);
750        }
751
752        return;
753    } else if (GICD_ITARGETSR.contains(addr)) {
754        // Interrupt Processor Targets Registers
755        // ARE always on, RAZ/WI
756        warn("Gicv3Distributor::write(): "
757             "GICD_ITARGETSR is RAZ/WI, legacy not supported!\n");
758        return;
759    } else if (GICD_ICFGR.contains(addr)) {
760        // Interrupt Configuration Registers
761        // for x = 0 to 15:
762        //   GICD_ICFGR[2x] = RES0
763        //   GICD_ICFGR[2x + 1] =
764        //     0 level-sensitive
765        //     1 edge-triggered
766        int first_intid = (addr - GICD_ICFGR.start()) * 4;
767
768        if (isNotSPI(first_intid)) {
769            return;
770        }
771
772        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
773             i = i + 2, int_id++) {
774            irqConfig[int_id] = data & (0x2 << i) ?
775                                Gicv3::INT_EDGE_TRIGGERED :
776                                Gicv3::INT_LEVEL_SENSITIVE;
777            DPRINTF(GIC, "Gicv3Distributor::write(): int_id %d config %d\n",
778                    int_id, irqConfig[int_id]);
779        }
780
781        return;
782    } else if (GICD_IGRPMODR.contains(addr)) {
783        // Interrupt Group Modifier Registers
784        if (DS) {
785            return;
786        } else {
787            if (!is_secure_access) {
788                // RAZ/WI for non-secure accesses
789                return;
790            } else {
791                int first_intid = (addr - GICD_IGRPMODR.start()) * 8;
792
793                if (isNotSPI(first_intid)) {
794                    return;
795                }
796
797                for (int i = 0, int_id = first_intid;
798                     i < 8 * size && int_id < itLines; i++, int_id++) {
799                    irqGrpmod[int_id] = bits(data, i);
800                }
801
802                return ;
803            }
804        }
805
806    } else if (GICD_NSACR.contains(addr)) {
807        // Non-secure Access Control Registers
808        // 2 bits per interrupt
809        int first_intid = (addr - GICD_NSACR.start()) * 4;
810
811        if (isNotSPI(first_intid)) {
812            return;
813        }
814
815        if (DS || (!DS && !is_secure_access)) {
816            return;
817        }
818
819        for (int i = 0, int_id = first_intid;
820             i < 8 * size && int_id < itLines; i = i + 2, int_id++) {
821            irqNsacr[int_id] = (data >> (2 * int_id)) & 0x3;
822        }
823
824        return;
825    } else if (GICD_IROUTER.contains(addr)) { // Interrupt Routing Registers
826        // 64 bit registers. 2 accesses.
827        int int_id = (addr - GICD_IROUTER.start()) / 8;
828
829        if (isNotSPI(int_id)) {
830            return;
831        }
832
833        if (nsAccessToSecInt(int_id, is_secure_access))
834        {
835            if (irqNsacr[int_id] < 3) {
836                // Group 0 or Secure Group 1 interrupts are RAZ/WI
837                return;
838            }
839        }
840
841        if (size == 4) {
842            if (addr & 7) { // high half of 64 bit register
843                irqAffinityRouting[int_id] =
844                    (irqAffinityRouting[int_id] & 0xffffffff) | (data << 32);
845            } else { // low half of 64 bit register
846                irqAffinityRouting[int_id] =
847                    (irqAffinityRouting[int_id] & 0xffffffff00000000) |
848                    (data & 0xffffffff);
849            }
850        } else {
851            irqAffinityRouting[int_id] = data;
852        }
853
854        DPRINTF(GIC, "Gicv3Distributor::write(): "
855                "int_id %d GICD_IROUTER %#llx\n",
856                int_id, irqAffinityRouting[int_id]);
857        return;
858    }
859
860    switch (addr) {
861      case GICD_CTLR: // Control Register
862        if (DS) {
863            /*
864             * E1NWF [7]
865             * 1 of N wakeup functionality not supported, RAZ/WI
866             * DS [6] - RAO/WI
867             * ARE [4]
868             * affinity routing always on, no GICv2 legacy, RAO/WI
869             * EnableGrp1 [1]
870             * EnableGrp0 [0]
871             */
872            if ((data & (1 << 4)) == 0) {
873                warn("Gicv3Distributor::write(): "
874                        "setting ARE to 0 is not supported!\n");
875            }
876
877            EnableGrp1NS = data & GICD_CTLR_ENABLEGRP1NS;
878            EnableGrp0 = data & GICD_CTLR_ENABLEGRP0;
879            DPRINTF(GIC, "Gicv3Distributor::write(): (DS 1)"
880                    "EnableGrp1NS %d EnableGrp0 %d\n",
881                    EnableGrp1NS, EnableGrp0);
882        } else {
883            if (is_secure_access) {
884                /*
885                 * E1NWF [7]
886                 * 1 of N wakeup functionality not supported, RAZ/WI
887                 * DS [6]
888                 * ARE_NS [5]
889                 * affinity routing always on, no GICv2 legacy, RAO/WI
890                 * ARE_S [4]
891                 * affinity routing always on, no GICv2 legacy, RAO/WI
892                 * EnableGrp1S [2]
893                 * EnableGrp1NS [1]
894                 * EnableGrp0 [0]
895                 */
896                if ((data & (1 << 5)) == 0) {
897                    warn("Gicv3Distributor::write(): "
898                            "setting ARE_NS to 0 is not supported!\n");
899                }
900
901                if ((data & (1 << 4)) == 0) {
902                    warn("Gicv3Distributor::write(): "
903                            "setting ARE_S to 0 is not supported!\n");
904                }
905
906                DS = data & GICD_CTLR_DS;
907                EnableGrp1S = data & GICD_CTLR_ENABLEGRP1S;
908                EnableGrp1NS = data & GICD_CTLR_ENABLEGRP1NS;
909                EnableGrp0 = data & GICD_CTLR_ENABLEGRP0;
910                DPRINTF(GIC, "Gicv3Distributor::write(): (DS 0 secure)"
911                        "DS %d "
912                        "EnableGrp1S %d EnableGrp1NS %d EnableGrp0 %d\n",
913                        DS, EnableGrp1S, EnableGrp1NS, EnableGrp0);
914
915                if (data & GICD_CTLR_DS) {
916                    EnableGrp1S = 0;
917                }
918            } else {
919                /*
920                 * ARE_NS [4] RAO/WI;
921                 * EnableGrp1A [1] is a read-write alias of the Secure
922                 * GICD_CTLR.EnableGrp1NS
923                 * EnableGrp1 [0] RES0
924                 */
925                if ((data & (1 << 4)) == 0) {
926                    warn("Gicv3Distributor::write(): "
927                            "setting ARE_NS to 0 is not supported!\n");
928                }
929
930                EnableGrp1NS = data & GICD_CTLR_ENABLEGRP1A;
931                DPRINTF(GIC, "Gicv3Distributor::write(): (DS 0 non-secure)"
932                        "EnableGrp1NS %d\n", EnableGrp1NS);
933            }
934        }
935
936        update();
937
938        break;
939
940      case GICD_SGIR: // Error Reporting Status Register
941        // Only if affinity routing is disabled, RES0
942        break;
943
944      case GICD_SETSPI_NSR: {
945        // Writes to this register have no effect if:
946        // * The value written specifies an invalid SPI.
947        // * The SPI is already pending.
948        // * The value written specifies a Secure SPI, the value is
949        // written by a Non-secure access, and the value of the
950        // corresponding GICD_NSACR<n> register is 0.
951        const uint32_t intid = bits(data, 9, 0);
952        if (isNotSPI(intid) || irqPending[intid] ||
953            (nsAccessToSecInt(intid, is_secure_access) &&
954             irqNsacr[intid] == 0)) {
955            return;
956        } else {
957            // Valid SPI, set interrupt pending
958            sendInt(intid);
959        }
960        break;
961      }
962
963      case GICD_CLRSPI_NSR: {
964        // Writes to this register have no effect if:
965        // * The value written specifies an invalid SPI.
966        // * The SPI is not pending.
967        // * The value written specifies a Secure SPI, the value is
968        // written by a Non-secure access, and the value of the
969        // corresponding GICD_NSACR<n> register is less than 0b10.
970        const uint32_t intid = bits(data, 9, 0);
971        if (isNotSPI(intid) || !irqPending[intid] ||
972            (nsAccessToSecInt(intid, is_secure_access) &&
973             irqNsacr[intid] < 2)) {
974            return;
975        } else {
976            // Valid SPI, clear interrupt pending
977            deassertSPI(intid);
978        }
979        break;
980      }
981
982      case GICD_SETSPI_SR: {
983        // Writes to this register have no effect if:
984        // * GICD_CTLR.DS = 1 (WI)
985        // * The value written specifies an invalid SPI.
986        // * The SPI is already pending.
987        // * The value is written by a Non-secure access.
988        const uint32_t intid = bits(data, 9, 0);
989        if (DS || isNotSPI(intid) || irqPending[intid] || !is_secure_access) {
990            return;
991        } else {
992            // Valid SPI, set interrupt pending
993            sendInt(intid);
994        }
995        break;
996      }
997
998      case GICD_CLRSPI_SR: {
999        // Writes to this register have no effect if:
1000        // * GICD_CTLR.DS = 1 (WI)
1001        // * The value written specifies an invalid SPI.
1002        // * The SPI is not pending.
1003        // * The value is written by a Non-secure access.
1004        const uint32_t intid = bits(data, 9, 0);
1005        if (DS || isNotSPI(intid) || !irqPending[intid] || !is_secure_access) {
1006            return;
1007        } else {
1008            // Valid SPI, clear interrupt pending
1009            deassertSPI(intid);
1010        }
1011        break;
1012      }
1013
1014      default:
1015        panic("Gicv3Distributor::write(): invalid offset %#x\n", addr);
1016        break;
1017    }
1018}
1019
1020void
1021Gicv3Distributor::sendInt(uint32_t int_id)
1022{
1023    panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
1024    panic_if(int_id > itLines, "Invalid SPI!");
1025    irqPending[int_id] = true;
1026    DPRINTF(GIC, "Gicv3Distributor::sendInt(): "
1027            "int_id %d (SPI) pending bit set\n", int_id);
1028    update();
1029}
1030
1031void
1032Gicv3Distributor::deassertSPI(uint32_t int_id)
1033{
1034    panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
1035    panic_if(int_id > itLines, "Invalid SPI!");
1036    irqPending[int_id] = false;
1037    clearIrqCpuInterface(int_id);
1038
1039    update();
1040}
1041
1042Gicv3CPUInterface*
1043Gicv3Distributor::route(uint32_t int_id)
1044{
1045    IROUTER affinity_routing = irqAffinityRouting[int_id];
1046    Gicv3Redistributor * target_redistributor = nullptr;
1047
1048    const Gicv3::GroupId int_group = getIntGroup(int_id);
1049
1050    if (affinity_routing.IRM) {
1051        // Interrupts routed to any PE defined as a participating node
1052        for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
1053            Gicv3Redistributor * redistributor_i =
1054                gic->getRedistributor(i);
1055
1056            if (redistributor_i->
1057                    canBeSelectedFor1toNInterrupt(int_group)) {
1058                target_redistributor = redistributor_i;
1059                break;
1060            }
1061        }
1062    } else {
1063        uint32_t affinity = (affinity_routing.Aff3 << 24) |
1064                            (affinity_routing.Aff2 << 16) |
1065                            (affinity_routing.Aff1 << 8) |
1066                            (affinity_routing.Aff0 << 0);
1067        target_redistributor =
1068            gic->getRedistributorByAffinity(affinity);
1069    }
1070
1071    if (!target_redistributor) {
1072        // Interrrupts targeting not present cpus must remain pending
1073        return nullptr;
1074    } else {
1075        return target_redistributor->getCPUInterface();
1076    }
1077}
1078
1079void
1080Gicv3Distributor::clearIrqCpuInterface(uint32_t int_id)
1081{
1082    auto cpu_interface = route(int_id);
1083    if (cpu_interface)
1084        cpu_interface->hppi.prio = 0xff;
1085}
1086
1087void
1088Gicv3Distributor::update()
1089{
1090    // Find the highest priority pending SPI
1091    for (int int_id = Gicv3::SGI_MAX + Gicv3::PPI_MAX; int_id < itLines;
1092         int_id++) {
1093        Gicv3::GroupId int_group = getIntGroup(int_id);
1094        bool group_enabled = groupEnabled(int_group);
1095
1096        if (irqPending[int_id] && irqEnabled[int_id] &&
1097            !irqActive[int_id] && group_enabled) {
1098
1099            // Find the cpu interface where to route the interrupt
1100            Gicv3CPUInterface *target_cpu_interface = route(int_id);
1101
1102            // Invalid routing
1103            if (!target_cpu_interface) continue;
1104
1105            if ((irqPriority[int_id] < target_cpu_interface->hppi.prio) ||
1106                (irqPriority[int_id] == target_cpu_interface->hppi.prio &&
1107                int_id < target_cpu_interface->hppi.intid)) {
1108
1109                target_cpu_interface->hppi.intid = int_id;
1110                target_cpu_interface->hppi.prio = irqPriority[int_id];
1111                target_cpu_interface->hppi.group = int_group;
1112            }
1113        }
1114    }
1115
1116    // Update all redistributors
1117    for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
1118        gic->getRedistributor(i)->update();
1119    }
1120}
1121
1122Gicv3::IntStatus
1123Gicv3Distributor::intStatus(uint32_t int_id) const
1124{
1125    panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
1126    panic_if(int_id > itLines, "Invalid SPI!");
1127
1128    if (irqPending[int_id]) {
1129        if (irqActive[int_id]) {
1130            return Gicv3::INT_ACTIVE_PENDING;
1131        }
1132
1133        return Gicv3::INT_PENDING;
1134    } else if (irqActive[int_id]) {
1135        return Gicv3::INT_ACTIVE;
1136    } else {
1137        return Gicv3::INT_INACTIVE;
1138    }
1139}
1140
1141Gicv3::GroupId
1142Gicv3Distributor::getIntGroup(int int_id) const
1143{
1144    panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
1145    panic_if(int_id > itLines, "Invalid SPI!");
1146
1147    if (DS) {
1148        if (irqGroup[int_id] == 1) {
1149            return Gicv3::G1NS;
1150        } else {
1151            return Gicv3::G0S;
1152        }
1153    } else {
1154        if (irqGrpmod[int_id] == 0 && irqGroup[int_id] == 0) {
1155            return Gicv3::G0S;
1156        } else if (irqGrpmod[int_id] == 0 && irqGroup[int_id] == 1) {
1157            return Gicv3::G1NS;
1158        } else if (irqGrpmod[int_id] == 1 && irqGroup[int_id] == 0) {
1159            return Gicv3::G1S;
1160        } else if (irqGrpmod[int_id] == 1 && irqGroup[int_id] == 1) {
1161            return Gicv3::G1NS;
1162        }
1163    }
1164
1165    M5_UNREACHABLE;
1166}
1167
1168void
1169Gicv3Distributor::activateIRQ(uint32_t int_id)
1170{
1171    irqPending[int_id] = false;
1172    irqActive[int_id] = true;
1173}
1174
1175void
1176Gicv3Distributor::deactivateIRQ(uint32_t int_id)
1177{
1178    irqActive[int_id] = false;
1179}
1180
1181void
1182Gicv3Distributor::serialize(CheckpointOut & cp) const
1183{
1184    SERIALIZE_SCALAR(ARE);
1185    SERIALIZE_SCALAR(DS);
1186    SERIALIZE_SCALAR(EnableGrp1S);
1187    SERIALIZE_SCALAR(EnableGrp1NS);
1188    SERIALIZE_SCALAR(EnableGrp0);
1189    SERIALIZE_CONTAINER(irqGroup);
1190    SERIALIZE_CONTAINER(irqEnabled);
1191    SERIALIZE_CONTAINER(irqPending);
1192    SERIALIZE_CONTAINER(irqActive);
1193    SERIALIZE_CONTAINER(irqPriority);
1194    SERIALIZE_CONTAINER(irqConfig);
1195    SERIALIZE_CONTAINER(irqGrpmod);
1196    SERIALIZE_CONTAINER(irqNsacr);
1197    SERIALIZE_CONTAINER(irqAffinityRouting);
1198}
1199
1200void
1201Gicv3Distributor::unserialize(CheckpointIn & cp)
1202{
1203    UNSERIALIZE_SCALAR(ARE);
1204    UNSERIALIZE_SCALAR(DS);
1205    UNSERIALIZE_SCALAR(EnableGrp1S);
1206    UNSERIALIZE_SCALAR(EnableGrp1NS);
1207    UNSERIALIZE_SCALAR(EnableGrp0);
1208    UNSERIALIZE_CONTAINER(irqGroup);
1209    UNSERIALIZE_CONTAINER(irqEnabled);
1210    UNSERIALIZE_CONTAINER(irqPending);
1211    UNSERIALIZE_CONTAINER(irqActive);
1212    UNSERIALIZE_CONTAINER(irqPriority);
1213    UNSERIALIZE_CONTAINER(irqConfig);
1214    UNSERIALIZE_CONTAINER(irqGrpmod);
1215    UNSERIALIZE_CONTAINER(irqNsacr);
1216    UNSERIALIZE_CONTAINER(irqAffinityRouting);
1217}
1218