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