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