gic_v3_distributor.cc revision 14167
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        updateAndInformCPUInterfaces();
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            }
667        }
668
669        updateAndInformCPUInterfaces();
670        return;
671    } else if (GICD_ISACTIVER.contains(addr)) {
672        // Interrupt Set-Active Registers
673        int first_intid = (addr - GICD_ISACTIVER.start()) * 8;
674
675        if (isNotSPI(first_intid)) {
676            return;
677        }
678
679        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
680             i++, int_id++) {
681
682            if (nsAccessToSecInt(int_id, is_secure_access))
683            {
684                continue;
685            }
686
687            bool active = data & (1 << i) ? 1 : 0;
688
689            if (active) {
690                irqActive[int_id] = 1;
691            }
692        }
693
694        return;
695    } else if (GICD_ICACTIVER.contains(addr)) {
696        // Interrupt Clear-Active Registers
697        int first_intid = (addr - GICD_ICACTIVER.start()) * 8;
698
699        if (isNotSPI(first_intid)) {
700            return;
701        }
702
703        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
704             i++, int_id++) {
705
706            if (nsAccessToSecInt(int_id, is_secure_access))
707            {
708                continue;
709            }
710
711            bool clear = data & (1 << i) ? 1 : 0;
712
713            if (clear) {
714                if (irqActive[int_id]) {
715                    DPRINTF(GIC, "Gicv3Distributor::write(): "
716                            "int_id %d active cleared\n", int_id);
717                }
718
719                irqActive[int_id] = false;
720            }
721        }
722
723        return;
724    } else if (GICD_IPRIORITYR.contains(addr)) {
725        // Interrupt Priority Registers
726        int first_intid = addr - GICD_IPRIORITYR.start();
727
728        if (isNotSPI(first_intid)) {
729            return;
730        }
731
732        for (int i = 0, int_id = first_intid; i < size && int_id < itLines;
733                i++, int_id++) {
734            uint8_t prio = bits(data, (i + 1) * 8 - 1, (i * 8));
735
736            if (!DS && !is_secure_access) {
737                if (getIntGroup(int_id) != Gicv3::G1NS) {
738                    // RAZ/WI for non-secure accesses to secure interrupts
739                    continue;
740                } else {
741                    prio = 0x80 | (prio >> 1);
742                }
743            }
744
745            irqPriority[int_id] = prio;
746            DPRINTF(GIC, "Gicv3Distributor::write(): int_id %d priority %d\n",
747                    int_id, irqPriority[int_id]);
748        }
749
750        return;
751    } else if (GICD_ITARGETSR.contains(addr)) {
752        // Interrupt Processor Targets Registers
753        // ARE always on, RAZ/WI
754        warn("Gicv3Distributor::write(): "
755             "GICD_ITARGETSR is RAZ/WI, legacy not supported!\n");
756        return;
757    } else if (GICD_ICFGR.contains(addr)) {
758        // Interrupt Configuration Registers
759        // for x = 0 to 15:
760        //   GICD_ICFGR[2x] = RES0
761        //   GICD_ICFGR[2x + 1] =
762        //     0 level-sensitive
763        //     1 edge-triggered
764        int first_intid = (addr - GICD_ICFGR.start()) * 4;
765
766        if (isNotSPI(first_intid)) {
767            return;
768        }
769
770        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
771             i = i + 2, int_id++) {
772            irqConfig[int_id] = data & (0x2 << i) ?
773                                Gicv3::INT_EDGE_TRIGGERED :
774                                Gicv3::INT_LEVEL_SENSITIVE;
775            DPRINTF(GIC, "Gicv3Distributor::write(): int_id %d config %d\n",
776                    int_id, irqConfig[int_id]);
777        }
778
779        return;
780    } else if (GICD_IGRPMODR.contains(addr)) {
781        // Interrupt Group Modifier Registers
782        if (DS) {
783            return;
784        } else {
785            if (!is_secure_access) {
786                // RAZ/WI for non-secure accesses
787                return;
788            } else {
789                int first_intid = (addr - GICD_IGRPMODR.start()) * 8;
790
791                if (isNotSPI(first_intid)) {
792                    return;
793                }
794
795                for (int i = 0, int_id = first_intid;
796                     i < 8 * size && int_id < itLines; i++, int_id++) {
797                    irqGrpmod[int_id] = data & (0x1 << i);
798                }
799
800                return ;
801            }
802        }
803
804    } else if (GICD_NSACR.contains(addr)) {
805        // Non-secure Access Control Registers
806        // 2 bits per interrupt
807        int first_intid = (addr - GICD_NSACR.start()) * 4;
808
809        if (isNotSPI(first_intid)) {
810            return;
811        }
812
813        if (DS || (!DS && !is_secure_access)) {
814            return;
815        }
816
817        for (int i = 0, int_id = first_intid;
818             i < 8 * size && int_id < itLines; i = i + 2, int_id++) {
819            irqNsacr[int_id] = (data >> (2 * int_id)) & 0x3;
820        }
821
822        return;
823    } else if (GICD_IROUTER.contains(addr)) { // Interrupt Routing Registers
824        // 64 bit registers. 2 accesses.
825        int int_id = (addr - GICD_IROUTER.start()) / 8;
826
827        if (isNotSPI(int_id)) {
828            return;
829        }
830
831        if (nsAccessToSecInt(int_id, is_secure_access))
832        {
833            if (irqNsacr[int_id] < 3) {
834                // Group 0 or Secure Group 1 interrupts are RAZ/WI
835                return;
836            }
837        }
838
839        if (size == 4) {
840            if (addr & 7) { // high half of 64 bit register
841                irqAffinityRouting[int_id] =
842                    (irqAffinityRouting[int_id] & 0xffffffff) | (data << 32);
843            } else { // low half of 64 bit register
844                irqAffinityRouting[int_id] =
845                    (irqAffinityRouting[int_id] & 0xffffffff00000000) |
846                    (data & 0xffffffff);
847            }
848        } else {
849            irqAffinityRouting[int_id] = data;
850        }
851
852        DPRINTF(GIC, "Gicv3Distributor::write(): "
853                "int_id %d GICD_IROUTER %#llx\n",
854                int_id, irqAffinityRouting[int_id]);
855        return;
856    }
857
858    switch (addr) {
859      case GICD_CTLR: // Control Register
860        if (DS) {
861            /*
862             * E1NWF [7]
863             * 1 of N wakeup functionality not supported, RAZ/WI
864             * DS [6] - RAO/WI
865             * ARE [4]
866             * affinity routing always on, no GICv2 legacy, RAO/WI
867             * EnableGrp1 [1]
868             * EnableGrp0 [0]
869             */
870            if ((data & (1 << 4)) == 0) {
871                warn("Gicv3Distributor::write(): "
872                        "setting ARE to 0 is not supported!\n");
873            }
874
875            EnableGrp1NS = data & GICD_CTLR_ENABLEGRP1NS;
876            EnableGrp0 = data & GICD_CTLR_ENABLEGRP0;
877            DPRINTF(GIC, "Gicv3Distributor::write(): (DS 1)"
878                    "EnableGrp1NS %d EnableGrp0 %d\n",
879                    EnableGrp1NS, EnableGrp0);
880        } else {
881            if (is_secure_access) {
882                /*
883                 * E1NWF [7]
884                 * 1 of N wakeup functionality not supported, RAZ/WI
885                 * DS [6]
886                 * ARE_NS [5]
887                 * affinity routing always on, no GICv2 legacy, RAO/WI
888                 * ARE_S [4]
889                 * affinity routing always on, no GICv2 legacy, RAO/WI
890                 * EnableGrp1S [2]
891                 * EnableGrp1NS [1]
892                 * EnableGrp0 [0]
893                 */
894                if ((data & (1 << 5)) == 0) {
895                    warn("Gicv3Distributor::write(): "
896                            "setting ARE_NS to 0 is not supported!\n");
897                }
898
899                if ((data & (1 << 4)) == 0) {
900                    warn("Gicv3Distributor::write(): "
901                            "setting ARE_S to 0 is not supported!\n");
902                }
903
904                DS = data & GICD_CTLR_DS;
905                EnableGrp1S = data & GICD_CTLR_ENABLEGRP1S;
906                EnableGrp1NS = data & GICD_CTLR_ENABLEGRP1NS;
907                EnableGrp0 = data & GICD_CTLR_ENABLEGRP0;
908                DPRINTF(GIC, "Gicv3Distributor::write(): (DS 0 secure)"
909                        "DS %d "
910                        "EnableGrp1S %d EnableGrp1NS %d EnableGrp0 %d\n",
911                        DS, EnableGrp1S, EnableGrp1NS, EnableGrp0);
912
913                if (data & GICD_CTLR_DS) {
914                    EnableGrp1S = 0;
915                }
916            } else {
917                /*
918                 * ARE_NS [4] RAO/WI;
919                 * EnableGrp1A [1] is a read-write alias of the Secure
920                 * GICD_CTLR.EnableGrp1NS
921                 * EnableGrp1 [0] RES0
922                 */
923                if ((data & (1 << 4)) == 0) {
924                    warn("Gicv3Distributor::write(): "
925                            "setting ARE_NS to 0 is not supported!\n");
926                }
927
928                EnableGrp1NS = data & GICD_CTLR_ENABLEGRP1A;
929                DPRINTF(GIC, "Gicv3Distributor::write(): (DS 0 non-secure)"
930                        "EnableGrp1NS %d\n", EnableGrp1NS);
931            }
932        }
933
934        break;
935
936      default:
937        panic("Gicv3Distributor::write(): invalid offset %#x\n", addr);
938        break;
939    }
940}
941
942void
943Gicv3Distributor::sendInt(uint32_t int_id)
944{
945    panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
946    panic_if(int_id > itLines, "Invalid SPI!");
947    irqPending[int_id] = true;
948    DPRINTF(GIC, "Gicv3Distributor::sendInt(): "
949            "int_id %d (SPI) pending bit set\n", int_id);
950    updateAndInformCPUInterfaces();
951}
952
953void
954Gicv3Distributor::deassertSPI(uint32_t int_id)
955{
956    panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
957    panic_if(int_id > itLines, "Invalid SPI!");
958    irqPending[int_id] = false;
959    updateAndInformCPUInterfaces();
960}
961
962void
963Gicv3Distributor::updateAndInformCPUInterfaces()
964{
965    update();
966
967    for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
968        gic->getCPUInterface(i)->update();
969    }
970}
971
972void
973Gicv3Distributor::fullUpdate()
974{
975    for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
976        Gicv3CPUInterface * cpu_interface_i = gic->getCPUInterface(i);
977        cpu_interface_i->hppi.prio = 0xff;
978    }
979
980    update();
981
982    for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
983        Gicv3Redistributor * redistributor_i = gic->getRedistributor(i);
984        redistributor_i->update();
985    }
986}
987
988void
989Gicv3Distributor::update()
990{
991    std::vector<bool> new_hppi(gic->getSystem()->numContexts(), false);
992
993    // Find the highest priority pending SPI
994    for (int int_id = Gicv3::SGI_MAX + Gicv3::PPI_MAX; int_id < itLines;
995         int_id++) {
996        Gicv3::GroupId int_group = getIntGroup(int_id);
997        bool group_enabled = groupEnabled(int_group);
998
999        if (irqPending[int_id] && irqEnabled[int_id] &&
1000            !irqActive[int_id] && group_enabled) {
1001            IROUTER affinity_routing = irqAffinityRouting[int_id];
1002            Gicv3Redistributor * target_redistributor = nullptr;
1003
1004            if (affinity_routing.IRM) {
1005                // Interrupts routed to any PE defined as a participating node
1006                for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
1007                    Gicv3Redistributor * redistributor_i =
1008                        gic->getRedistributor(i);
1009
1010                    if (redistributor_i->
1011                            canBeSelectedFor1toNInterrupt(int_group)) {
1012                        target_redistributor = redistributor_i;
1013                        break;
1014                    }
1015                }
1016            } else {
1017                uint32_t affinity = (affinity_routing.Aff3 << 24) |
1018                                    (affinity_routing.Aff3 << 16) |
1019                                    (affinity_routing.Aff1 << 8) |
1020                                    (affinity_routing.Aff0 << 0);
1021                target_redistributor =
1022                    gic->getRedistributorByAffinity(affinity);
1023            }
1024
1025            if (!target_redistributor) {
1026                // Interrrupts targeting not present cpus must remain pending
1027                return;
1028            }
1029
1030            Gicv3CPUInterface * target_cpu_interface =
1031                target_redistributor->getCPUInterface();
1032            uint32_t target_cpu = target_redistributor->cpuId;
1033
1034            if ((irqPriority[int_id] < target_cpu_interface->hppi.prio) ||
1035                /*
1036                 * Multiple pending ints with same priority.
1037                 * Implementation choice which one to signal.
1038                 * Our implementation selects the one with the lower id.
1039                 */
1040                (irqPriority[int_id] == target_cpu_interface->hppi.prio &&
1041                int_id < target_cpu_interface->hppi.intid)) {
1042                target_cpu_interface->hppi.intid = int_id;
1043                target_cpu_interface->hppi.prio = irqPriority[int_id];
1044                target_cpu_interface->hppi.group = int_group;
1045                new_hppi[target_cpu] = true;
1046            }
1047        }
1048    }
1049
1050    for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
1051        Gicv3Redistributor * redistributor_i = gic->getRedistributor(i);
1052        Gicv3CPUInterface * cpu_interface_i =
1053            redistributor_i->getCPUInterface();
1054
1055        if (!new_hppi[i] && cpu_interface_i->hppi.prio != 0xff &&
1056            cpu_interface_i->hppi.intid >= (Gicv3::SGI_MAX + Gicv3::PPI_MAX) &&
1057            cpu_interface_i->hppi.intid < Gicv3::INTID_SECURE) {
1058            fullUpdate();
1059        }
1060    }
1061}
1062
1063Gicv3::IntStatus
1064Gicv3Distributor::intStatus(uint32_t int_id) const
1065{
1066    panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
1067    panic_if(int_id > itLines, "Invalid SPI!");
1068
1069    if (irqPending[int_id]) {
1070        if (irqActive[int_id]) {
1071            return Gicv3::INT_ACTIVE_PENDING;
1072        }
1073
1074        return Gicv3::INT_PENDING;
1075    } else if (irqActive[int_id]) {
1076        return Gicv3::INT_ACTIVE;
1077    } else {
1078        return Gicv3::INT_INACTIVE;
1079    }
1080}
1081
1082Gicv3::GroupId
1083Gicv3Distributor::getIntGroup(int int_id) const
1084{
1085    panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
1086    panic_if(int_id > itLines, "Invalid SPI!");
1087
1088    if (DS) {
1089        if (irqGroup[int_id] == 1) {
1090            return Gicv3::G1NS;
1091        } else {
1092            return Gicv3::G0S;
1093        }
1094    } else {
1095        if (irqGrpmod[int_id] == 0 && irqGroup[int_id] == 0) {
1096            return Gicv3::G0S;
1097        } else if (irqGrpmod[int_id] == 0 && irqGroup[int_id] == 1) {
1098            return Gicv3::G1NS;
1099        } else if (irqGrpmod[int_id] == 1 && irqGroup[int_id] == 0) {
1100            return Gicv3::G1S;
1101        } else if (irqGrpmod[int_id] == 1 && irqGroup[int_id] == 1) {
1102            return Gicv3::G1NS;
1103        }
1104    }
1105
1106    M5_UNREACHABLE;
1107}
1108
1109void
1110Gicv3Distributor::activateIRQ(uint32_t int_id)
1111{
1112    irqPending[int_id] = false;
1113    irqActive[int_id] = true;
1114}
1115
1116void
1117Gicv3Distributor::deactivateIRQ(uint32_t int_id)
1118{
1119    irqActive[int_id] = false;
1120}
1121
1122void
1123Gicv3Distributor::serialize(CheckpointOut & cp) const
1124{
1125    SERIALIZE_SCALAR(ARE);
1126    SERIALIZE_SCALAR(DS);
1127    SERIALIZE_SCALAR(EnableGrp1S);
1128    SERIALIZE_SCALAR(EnableGrp1NS);
1129    SERIALIZE_SCALAR(EnableGrp0);
1130    SERIALIZE_CONTAINER(irqGroup);
1131    SERIALIZE_CONTAINER(irqEnabled);
1132    SERIALIZE_CONTAINER(irqPending);
1133    SERIALIZE_CONTAINER(irqActive);
1134    SERIALIZE_CONTAINER(irqPriority);
1135    SERIALIZE_CONTAINER(irqConfig);
1136    SERIALIZE_CONTAINER(irqGrpmod);
1137    SERIALIZE_CONTAINER(irqNsacr);
1138    SERIALIZE_CONTAINER(irqAffinityRouting);
1139}
1140
1141void
1142Gicv3Distributor::unserialize(CheckpointIn & cp)
1143{
1144    UNSERIALIZE_SCALAR(ARE);
1145    UNSERIALIZE_SCALAR(DS);
1146    UNSERIALIZE_SCALAR(EnableGrp1S);
1147    UNSERIALIZE_SCALAR(EnableGrp1NS);
1148    UNSERIALIZE_SCALAR(EnableGrp0);
1149    UNSERIALIZE_CONTAINER(irqGroup);
1150    UNSERIALIZE_CONTAINER(irqEnabled);
1151    UNSERIALIZE_CONTAINER(irqPending);
1152    UNSERIALIZE_CONTAINER(irqActive);
1153    UNSERIALIZE_CONTAINER(irqPriority);
1154    UNSERIALIZE_CONTAINER(irqConfig);
1155    UNSERIALIZE_CONTAINER(irqGrpmod);
1156    UNSERIALIZE_CONTAINER(irqNsacr);
1157    UNSERIALIZE_CONTAINER(irqAffinityRouting);
1158}
1159