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