gic_v3_distributor.cc revision 14231
11689SN/A/*
22329SN/A * Copyright (c) 2019 ARM Limited
31689SN/A * All rights reserved
41689SN/A *
51689SN/A * The license below extends only to copyright in the software and shall
61689SN/A * not be construed as granting a license to any other intellectual
71689SN/A * property including but not limited to intellectual property relating
81689SN/A * to a hardware implementation of the functionality of the software
91689SN/A * licensed hereunder.  You may use the software subject to the license
101689SN/A * terms below provided that you ensure that this notice is replicated
111689SN/A * unmodified and in its entirety in all distributions of the software,
121689SN/A * modified or unmodified, in source code or in binary form.
131689SN/A *
141689SN/A * Copyright (c) 2018 Metempsy Technology Consulting
151689SN/A * All rights reserved.
161689SN/A *
171689SN/A * Redistribution and use in source and binary forms, with or without
181689SN/A * modification, are permitted provided that the following conditions are
191689SN/A * met: redistributions of source code must retain the above copyright
201689SN/A * notice, this list of conditions and the following disclaimer;
211689SN/A * redistributions in binary form must reproduce the above copyright
221689SN/A * notice, this list of conditions and the following disclaimer in the
231689SN/A * documentation and/or other materials provided with the distribution;
241689SN/A * neither the name of the copyright holders nor the names of its
251689SN/A * contributors may be used to endorse or promote products derived from
261689SN/A * this software without specific prior written permission.
272665Ssaidi@eecs.umich.edu *
282665Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
291689SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
301061SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
312292SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
322292SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
331061SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
342292SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
351061SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
361061SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
372292SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
382292SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
391684SN/A *
401061SN/A * Authors: Jairo Balart
411061SN/A */
422292SN/A
432292SN/A#include "dev/arm/gic_v3_distributor.hh"
442292SN/A
452292SN/A#include <algorithm>
462292SN/A
472292SN/A#include "debug/GIC.hh"
482292SN/A#include "dev/arm/gic_v3.hh"
492292SN/A#include "dev/arm/gic_v3_cpu_interface.hh"
502292SN/A#include "dev/arm/gic_v3_redistributor.hh"
515529Snate@binkert.org
525529Snate@binkert.orgconst AddrRange Gicv3Distributor::GICD_IGROUPR   (0x0080, 0x00ff);
532292SN/Aconst AddrRange Gicv3Distributor::GICD_ISENABLER (0x0100, 0x017f);
542292SN/Aconst AddrRange Gicv3Distributor::GICD_ICENABLER (0x0180, 0x01ff);
552292SN/Aconst AddrRange Gicv3Distributor::GICD_ISPENDR   (0x0200, 0x027f);
561061SN/Aconst AddrRange Gicv3Distributor::GICD_ICPENDR   (0x0280, 0x02ff);
571061SN/Aconst AddrRange Gicv3Distributor::GICD_ISACTIVER (0x0300, 0x037f);
581061SN/Aconst AddrRange Gicv3Distributor::GICD_ICACTIVER (0x0380, 0x03ff);
591061SN/Aconst AddrRange Gicv3Distributor::GICD_IPRIORITYR(0x0400, 0x07ff);
601061SN/Aconst AddrRange Gicv3Distributor::GICD_ITARGETSR (0x0800, 0x08ff);
611061SN/Aconst AddrRange Gicv3Distributor::GICD_ICFGR     (0x0c00, 0x0cff);
621061SN/Aconst AddrRange Gicv3Distributor::GICD_IGRPMODR  (0x0d00, 0x0d7f);
631061SN/Aconst AddrRange Gicv3Distributor::GICD_NSACR     (0x0e00, 0x0eff);
641061SN/Aconst AddrRange Gicv3Distributor::GICD_CPENDSGIR (0x0f10, 0x0f1f);
651061SN/Aconst AddrRange Gicv3Distributor::GICD_SPENDSGIR (0x0f20, 0x0f2f);
661061SN/Aconst AddrRange Gicv3Distributor::GICD_IROUTER   (0x6000, 0x7fe0);
671061SN/A
681061SN/AGicv3Distributor::Gicv3Distributor(Gicv3 * gic, uint32_t it_lines)
691061SN/A    : gic(gic),
701061SN/A      itLines(it_lines),
711061SN/A      irqGroup(it_lines),
722292SN/A      irqEnabled(it_lines),
733500Sktlim@umich.edu      irqPending(it_lines),
741061SN/A      irqActive(it_lines),
752292SN/A      irqPriority(it_lines),
765529Snate@binkert.org      irqConfig(it_lines),
772292SN/A      irqGrpmod(it_lines),
782292SN/A      irqNsacr(it_lines),
792292SN/A      irqAffinityRouting(it_lines),
802292SN/A      gicdPidr0(0x92),
812292SN/A      gicdPidr1(0xb4),
822292SN/A      gicdPidr2(0x3b),
832292SN/A      gicdPidr3(0),
842292SN/A      gicdPidr4(0x44)
855529Snate@binkert.org{
862292SN/A    panic_if(it_lines > Gicv3::INTID_SECURE, "Invalid value for it_lines!");
872292SN/A}
881062SN/A
891061SN/Avoid
902348SN/AGicv3Distributor::init()
912307SN/A{
922307SN/A}
932348SN/A
942307SN/Avoid
952307SN/AGicv3Distributor::initState()
962292SN/A{
972292SN/A    reset();
982292SN/A}
992292SN/A
1001061SN/Avoid
1011061SN/AGicv3Distributor::reset()
1022292SN/A{
1031062SN/A    std::fill(irqGroup.begin(), irqGroup.end(), 0);
1041062SN/A    // Imp. defined reset value
1052292SN/A    std::fill(irqEnabled.begin(), irqEnabled.end(), false);
1062292SN/A    std::fill(irqPending.begin(), irqPending.end(), false);
1071684SN/A    std::fill(irqActive.begin(), irqActive.end(), false);
1082292SN/A    // Imp. defined reset value
1091062SN/A    std::fill(irqPriority.begin(), irqPriority.end(), 0xAAAAAAAA);
1101062SN/A    std::fill(irqConfig.begin(), irqConfig.end(),
1112292SN/A              Gicv3::INT_LEVEL_SENSITIVE); // Imp. defined reset value
1121062SN/A    std::fill(irqGrpmod.begin(), irqGrpmod.end(), 0);
1131061SN/A    std::fill(irqNsacr.begin(), irqNsacr.end(), 0);
1142292SN/A    /*
1152292SN/A     * For our implementation affinity routing is always enabled,
1162292SN/A     * no GICv2 legacy
1172292SN/A     */
1182292SN/A    ARE = true;
1192292SN/A
1202292SN/A    if (gic->getSystem()->haveSecurity()) {
1212292SN/A        DS = false;
1222292SN/A    } else {
1232292SN/A        DS = true;
1242292SN/A    }
1252292SN/A
1262292SN/A    EnableGrp0 = 0;
1272292SN/A    EnableGrp1NS = 0;
1282292SN/A    EnableGrp1S = 0;
1292292SN/A}
1302292SN/A
1312292SN/Auint64_t
1322292SN/AGicv3Distributor::read(Addr addr, size_t size, bool is_secure_access)
1332292SN/A{
1342292SN/A    if (GICD_IGROUPR.contains(addr)) { // Interrupt Group Registers
1352292SN/A        uint64_t val = 0x0;
1362292SN/A
1372292SN/A        if (!DS && !is_secure_access) {
1382292SN/A            // RAZ/WI for non-secure accesses
1392292SN/A            return 0;
1401061SN/A        }
1411061SN/A
1422292SN/A        int first_intid = (addr - GICD_IGROUPR.start()) * 8;
1432292SN/A
1441062SN/A        if (isNotSPI(first_intid)) {
1451062SN/A            return 0;
1462292SN/A        }
1471062SN/A
1482292SN/A        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
1491062SN/A             i++, int_id++) {
1502292SN/A            val |= irqGroup[int_id] << i;
1511062SN/A        }
1522292SN/A
1532292SN/A        return val;
1542292SN/A    } else if (GICD_ISENABLER.contains(addr)) {
1552292SN/A        // Interrupt Set-Enable Registers
1562292SN/A        uint64_t val = 0x0;
1572292SN/A        int first_intid = (addr - GICD_ISENABLER.start()) * 8;
1582292SN/A
1592292SN/A        if (isNotSPI(first_intid)) {
1602292SN/A            return 0;
1612292SN/A        }
1622292SN/A
1632348SN/A        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
1642292SN/A             i++, int_id++) {
1651062SN/A
1662292SN/A            if (nsAccessToSecInt(int_id, is_secure_access))
1672292SN/A            {
1682348SN/A                continue;
1692292SN/A            }
1701062SN/A
1712292SN/A            val |= irqEnabled[int_id] << i;
1722292SN/A        }
1732292SN/A
1742292SN/A        return val;
1752292SN/A    } else if (GICD_ICENABLER.contains(addr)) {
1762292SN/A        // Interrupt Clear-Enable Registers
1772348SN/A        uint64_t val = 0x0;
1782292SN/A        int first_intid = (addr - GICD_ICENABLER.start()) * 8;
1792292SN/A
1802292SN/A        if (isNotSPI(first_intid)) {
1812292SN/A            return 0;
1822348SN/A        }
1832292SN/A
1842292SN/A        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
1852292SN/A             i++, int_id++) {
1862292SN/A
1872292SN/A            if (nsAccessToSecInt(int_id, is_secure_access))
1882292SN/A            {
1892292SN/A                continue;
1902292SN/A            }
1912292SN/A
1922292SN/A            val |= (irqEnabled[int_id] << i);
1932292SN/A        }
1942292SN/A
1952292SN/A        return val;
1962292SN/A    } else if (GICD_ISPENDR.contains(addr)) {
1972292SN/A        // Interrupt Set-Pending Registers
1982292SN/A        uint64_t val = 0x0;
1992292SN/A        int first_intid = (addr - GICD_ISPENDR.start()) * 8;
2002292SN/A
2012292SN/A        if (isNotSPI(first_intid)) {
2022292SN/A            return 0;
2032292SN/A        }
2042292SN/A
2052292SN/A        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
2062292SN/A             i++, int_id++) {
2072348SN/A
2082292SN/A            if (nsAccessToSecInt(int_id, is_secure_access))
2092292SN/A            {
2102292SN/A                if (irqNsacr[int_id] == 0) {
2112348SN/A                    // Group 0 or Secure Group 1 interrupts are RAZ/WI
2121062SN/A                    continue;
2131062SN/A                }
2142292SN/A            }
2152292SN/A
2161062SN/A            val |= (irqPending[int_id] << i);
2172292SN/A        }
2182292SN/A
2191062SN/A        return val;
2202292SN/A    } else if (GICD_ICPENDR.contains(addr)) {
2211061SN/A        // Interrupt Clear-Pending Registers
2222292SN/A        uint64_t val = 0x0;
2231061SN/A        int first_intid = (addr - GICD_ICPENDR.start()) * 8;
2242292SN/A
2252292SN/A        if (isNotSPI(first_intid)) {
2261062SN/A            return 0;
2272292SN/A        }
2282292SN/A
2291062SN/A        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
2302292SN/A             i++, int_id++) {
2312292SN/A
2321061SN/A            if (nsAccessToSecInt(int_id, is_secure_access))
2331061SN/A            {
2341061SN/A                if (irqNsacr[int_id] < 2) {
2351061SN/A                    // Group 0 or Secure Group 1 interrupts are RAZ/WI
2361061SN/A                    continue;
2371061SN/A                }
2381061SN/A            }
2391061SN/A
2402348SN/A            val |= (irqPending[int_id] << i);
2412292SN/A        }
2422348SN/A
2432292SN/A        return val;
2442348SN/A    } else if (GICD_ISACTIVER.contains(addr)) {
2452292SN/A        // Interrupt Set-Active Registers
2462348SN/A        int first_intid = (addr - GICD_ISACTIVER.start()) * 8;
2472292SN/A
2482292SN/A        if (isNotSPI(first_intid)) {
2492292SN/A            return 0;
2502292SN/A        }
2512292SN/A
2522292SN/A        uint64_t val = 0x0;
2532292SN/A
2542292SN/A        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
2552292SN/A             i++, int_id++) {
2561062SN/A
2572292SN/A            if (nsAccessToSecInt(int_id, is_secure_access))
2581062SN/A            {
2592292SN/A                // Group 0 or Secure Group 1 interrupts are RAZ/WI
2601062SN/A                if (irqNsacr[int_id] < 2) {
2612292SN/A                    continue;
2621062SN/A                }
2631061SN/A            }
2641061SN/A
2652292SN/A            val |= (irqActive[int_id] << i);
266        }
267
268        return val;
269    } else if (GICD_ICACTIVER.contains(addr)) {
270        // Interrupt Clear-Active Registers
271        int first_intid = (addr - GICD_ICACTIVER.start()) * 8;
272
273        if (isNotSPI(first_intid)) {
274            return 0;
275        }
276
277        uint64_t val = 0x0;
278
279        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
280             i++, int_id++) {
281
282            if (nsAccessToSecInt(int_id, is_secure_access))
283            {
284                if (irqNsacr[int_id] < 2) {
285                    continue;
286                }
287            }
288
289            val |= (irqActive[int_id] << i);
290        }
291
292        return val;
293    } else if (GICD_IPRIORITYR.contains(addr)) {
294        // Interrupt Priority Registers
295        uint64_t val = 0x0;
296        int first_intid = addr - GICD_IPRIORITYR.start();
297
298        if (isNotSPI(first_intid)) {
299            return 0;
300        }
301
302        for (int i = 0, int_id = first_intid; i < size && int_id < itLines;
303             i++, int_id++) {
304
305            uint8_t prio = irqPriority[int_id];
306
307            if (!DS && !is_secure_access) {
308                if (getIntGroup(int_id) != Gicv3::G1NS) {
309                    // RAZ/WI for non-secure accesses for secure interrupts
310                    continue;
311                } else {
312                    // NS view
313                    prio = (prio << 1) & 0xff;
314                }
315            }
316
317            val |= prio << (i * 8);
318        }
319
320        return val;
321    } else if (GICD_ITARGETSR.contains(addr)) {
322        // Interrupt Processor Targets Registers
323        // ARE always on, RAZ/WI
324        warn("Gicv3Distributor::read(): "
325             "GICD_ITARGETSR is RAZ/WI, legacy not supported!\n");
326        return 0;
327    } else if (GICD_ICFGR.contains(addr)) {
328        // Interrupt Configuration Registers
329        int first_intid = (addr - GICD_ICFGR.start()) * 4;
330
331        if (isNotSPI(first_intid)) {
332            return 0;
333        }
334
335        uint64_t val = 0x0;
336
337        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
338             i = i + 2, int_id++) {
339
340            if (nsAccessToSecInt(int_id, is_secure_access))
341            {
342                continue;
343            }
344
345            if (irqConfig[int_id] == Gicv3::INT_EDGE_TRIGGERED) {
346                val |= (0x2 << i);
347            }
348        }
349
350        return val;
351    } else if (GICD_IGRPMODR.contains(addr)) {
352        // Interrupt Group Modifier Registers
353        if (DS) {
354            // RAZ/WI if security disabled
355            return 0;
356        } else {
357            if (!is_secure_access) {
358                // RAZ/WI for non-secure accesses
359                return 0;
360            } else {
361                int first_intid = (addr - GICD_IGRPMODR.start()) * 8;
362
363                if (isNotSPI(first_intid)) {
364                    return 0;
365                }
366
367                uint64_t val = 0x0;
368
369                for (int i = 0, int_id = first_intid;
370                     i < 8 * size && int_id < itLines; i++, int_id++) {
371                    val |= irqGrpmod[int_id] << i;
372                }
373
374                return val;
375            }
376        }
377    } else if (GICD_NSACR.contains(addr)) {
378        // Non-secure Access Control Registers
379        // 2 bits per interrupt
380        int first_intid = (addr - GICD_NSACR.start()) * 4;
381
382        if (isNotSPI(first_intid)) {
383            return 0;
384        }
385
386        if (DS || (!DS && !is_secure_access)) {
387            return 0;
388        }
389
390        uint64_t val = 0x0;
391
392        for (int i = 0, int_id = first_intid;
393             i < 8 * size && int_id < itLines; i = i + 2, int_id++) {
394            val |= irqNsacr[int_id] << i;
395        }
396
397        return val;
398    } else if (GICD_CPENDSGIR.contains(addr)) { // SGI Clear-Pending Registers
399        // ARE always on, RAZ/WI
400        warn("Gicv3Distributor::read(): "
401             "GICD_CPENDSGIR is RAZ/WI, legacy not supported!\n");
402        return 0x0;
403    } else if (GICD_SPENDSGIR.contains(addr)) { // SGI Set-Pending Registers
404        // ARE always on, RAZ/WI
405        warn("Gicv3Distributor::read(): "
406             "GICD_SPENDSGIR is RAZ/WI, legacy not supported!\n");
407        return 0x0;
408    } else if (GICD_IROUTER.contains(addr)) { // Interrupt Routing Registers
409        // 64 bit registers. 2 or 1 access.
410        int int_id = (addr - GICD_IROUTER.start()) / 8;
411
412        if (isNotSPI(int_id)) {
413            return 0;
414        }
415
416        if (nsAccessToSecInt(int_id, is_secure_access))
417        {
418            if (irqNsacr[int_id] < 3) {
419                return 0;
420            }
421        }
422
423        if (size == 4) {
424            if (addr & 7) { // high half of 64 bit register
425                return irqAffinityRouting[int_id] >> 32;
426            } else { // high low of 64 bit register
427                return irqAffinityRouting[int_id] & 0xFFFFFFFF;
428            }
429        } else {
430            return irqAffinityRouting[int_id];
431        }
432    }
433
434    switch (addr) {
435      case GICD_CTLR: // Control Register
436        if (!DS) {
437            if (is_secure_access) {
438                // E1NWF [7] RAZ/WI
439                // DS [6] - Disable Security
440                // ARE_NS [5] RAO/WI
441                // ARE_S [4] RAO/WI
442                // EnableGrp1S [2]
443                // EnableGrp1NS [1]
444                // EnableGrp0 [0]
445                return (EnableGrp0 << 0) |
446                    (EnableGrp1NS << 1) |
447                    (EnableGrp1S << 2) |
448                    (1 << 4) |
449                    (1 << 5) |
450                    (DS << 6);
451            } else {
452                // ARE_NS [4] RAO/WI;
453                // EnableGrp1A [1] is a read-write alias of the Secure
454                // GICD_CTLR.EnableGrp1NS
455                // EnableGrp1 [0] RES0
456                return (1 << 4) | (EnableGrp1NS << 1);
457            }
458        } else {
459            return (DS << 6) | (ARE << 4) |
460                (EnableGrp1NS << 1) | (EnableGrp0 << 0);
461        }
462
463      case GICD_TYPER: // Interrupt Controller Type Register
464        /*
465         * RSS           [26]    == 1
466         * (The implementation does supports targeted SGIs with affinity
467         * level 0 values of 0 - 255)
468         * No1N          [25]    == 1
469         * (1 of N SPI interrupts are not supported)
470         * A3V           [24]    == 1
471         * (Supports nonzero values of Affinity level 3)
472         * IDbits        [23:19] == 0xf
473         * (The number of interrupt identifier bits supported, minus one)
474         * DVIS          [18]    == 0
475         * (The implementation does not support Direct Virtual LPI
476         * injection)
477         * LPIS          [17]    == 1
478         * (The implementation does not support LPIs)
479         * MBIS          [16]    == 0
480         * (The implementation does not support message-based interrupts
481         * by writing to Distributor registers)
482         * SecurityExtn  [10]    == X
483         * (The GIC implementation supports two Security states)
484         * CPUNumber     [7:5]   == 0
485         * (since for us ARE is always 1 [(ARE = 0) == Gicv2 legacy])
486         * ITLinesNumber [4:0]   == N
487         * (MaxSPIIntId = 32 (N + 1) - 1)
488         */
489        {
490            int max_spi_int_id = itLines - 1;
491            int it_lines_number = ceil((max_spi_int_id + 1) / 32.0) - 1;
492            return (1 << 26) | (1 << 25) | (1 << 24) | (IDBITS << 19) |
493                (1 << 17) | (gic->getSystem()->haveSecurity() << 10) |
494                (it_lines_number << 0);
495        }
496
497      case GICD_IIDR: // Implementer Identification Register
498        //return 0x43b; // ARM JEP106 code (r0p0 GIC-500)
499        return 0;
500
501      case GICD_STATUSR: // Error Reporting Status Register
502        // Optional register, RAZ/WI
503        return 0x0;
504
505      case GICD_PIDR0: // Peripheral ID0 Register
506        return gicdPidr0;
507
508      case GICD_PIDR1: // Peripheral ID1 Register
509        return gicdPidr1;
510
511      case GICD_PIDR2: // Peripheral ID2 Register
512        return gicdPidr2;
513
514      case GICD_PIDR3: // Peripheral ID3 Register
515        return gicdPidr3;
516
517      case GICD_PIDR4: // Peripheral ID4 Register
518        return gicdPidr4;
519
520      case GICD_PIDR5: // Peripheral ID5 Register
521      case GICD_PIDR6: // Peripheral ID6 Register
522      case GICD_PIDR7: // Peripheral ID7 Register
523        return 0; // RES0
524
525      default:
526        panic("Gicv3Distributor::read(): invalid offset %#x\n", addr);
527        break;
528    }
529}
530
531void
532Gicv3Distributor::write(Addr addr, uint64_t data, size_t size,
533                        bool is_secure_access)
534{
535    if (GICD_IGROUPR.contains(addr)) { // Interrupt Group Registers
536        if (!DS && !is_secure_access) {
537            // RAZ/WI for non-secure accesses
538            return;
539        }
540
541        int first_intid = (addr - GICD_IGROUPR.start()) * 8;
542
543        if (isNotSPI(first_intid)) {
544            return;
545        }
546
547        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
548             i++, int_id++) {
549            irqGroup[int_id] = data & (1 << i) ? 1 : 0;
550            DPRINTF(GIC, "Gicv3Distributor::write(): int_id %d group %d\n",
551                    int_id, irqGroup[int_id]);
552        }
553
554        return;
555    } else if (GICD_ISENABLER.contains(addr)) {
556        // Interrupt Set-Enable Registers
557        int first_intid = (addr - GICD_ISENABLER.start()) * 8;
558
559        if (isNotSPI(first_intid)) {
560            return;
561        }
562
563        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
564             i++, int_id++) {
565
566            if (nsAccessToSecInt(int_id, is_secure_access))
567            {
568                continue;
569            }
570
571            bool enable = data & (1 << i) ? 1 : 0;
572
573            if (enable) {
574                if (!irqEnabled[int_id]) {
575                    DPRINTF(GIC, "Gicv3Distributor::write(): "
576                            "int_id %d enabled\n", int_id);
577                }
578
579                irqEnabled[int_id] = true;
580            }
581        }
582
583        return;
584    } else if (GICD_ICENABLER.contains(addr)) {
585        // Interrupt Clear-Enable Registers
586        int first_intid = (addr - GICD_ICENABLER.start()) * 8;
587
588        if (isNotSPI(first_intid)) {
589            return;
590        }
591
592        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
593             i++, int_id++) {
594
595            if (nsAccessToSecInt(int_id, is_secure_access))
596            {
597                continue;
598            }
599
600            bool disable = data & (1 << i) ? 1 : 0;
601
602            if (disable) {
603                if (irqEnabled[int_id]) {
604                    DPRINTF(GIC, "Gicv3Distributor::write(): "
605                            "int_id %d disabled\n", int_id);
606                }
607
608                irqEnabled[int_id] = false;
609            }
610        }
611
612        return;
613    } else if (GICD_ISPENDR.contains(addr)) {
614        // Interrupt Set-Pending Registers
615        int first_intid = (addr - GICD_ISPENDR.start()) * 8;
616
617        if (isNotSPI(first_intid)) {
618            return;
619        }
620
621        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
622             i++, int_id++) {
623
624            if (nsAccessToSecInt(int_id, is_secure_access))
625            {
626                if (irqNsacr[int_id] == 0) {
627                    // Group 0 or Secure Group 1 interrupts are RAZ/WI
628                    continue;
629                }
630            }
631
632            bool pending = data & (1 << i) ? 1 : 0;
633
634            if (pending) {
635                DPRINTF(GIC, "Gicv3Distributor::write() (GICD_ISPENDR): "
636                        "int_id %d (SPI) pending bit set\n", int_id);
637                irqPending[int_id] = true;
638            }
639        }
640
641        update();
642        return;
643    } else if (GICD_ICPENDR.contains(addr)) {
644        // Interrupt Clear-Pending Registers
645        int first_intid = (addr - GICD_ICPENDR.start()) * 8;
646
647        if (isNotSPI(first_intid)) {
648            return;
649        }
650
651        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
652             i++, int_id++) {
653
654            if (nsAccessToSecInt(int_id, is_secure_access))
655            {
656                if (irqNsacr[int_id] < 2) {
657                    // Group 0 or Secure Group 1 interrupts are RAZ/WI
658                    continue;
659                }
660            }
661
662            bool clear = data & (1 << i) ? 1 : 0;
663
664            if (clear) {
665                irqPending[int_id] = false;
666                clearIrqCpuInterface(int_id);
667            }
668        }
669
670        update();
671        return;
672    } else if (GICD_ISACTIVER.contains(addr)) {
673        // Interrupt Set-Active Registers
674        int first_intid = (addr - GICD_ISACTIVER.start()) * 8;
675
676        if (isNotSPI(first_intid)) {
677            return;
678        }
679
680        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
681             i++, int_id++) {
682
683            if (nsAccessToSecInt(int_id, is_secure_access))
684            {
685                continue;
686            }
687
688            bool active = data & (1 << i) ? 1 : 0;
689
690            if (active) {
691                irqActive[int_id] = 1;
692            }
693        }
694
695        return;
696    } else if (GICD_ICACTIVER.contains(addr)) {
697        // Interrupt Clear-Active Registers
698        int first_intid = (addr - GICD_ICACTIVER.start()) * 8;
699
700        if (isNotSPI(first_intid)) {
701            return;
702        }
703
704        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
705             i++, int_id++) {
706
707            if (nsAccessToSecInt(int_id, is_secure_access))
708            {
709                continue;
710            }
711
712            bool clear = data & (1 << i) ? 1 : 0;
713
714            if (clear) {
715                if (irqActive[int_id]) {
716                    DPRINTF(GIC, "Gicv3Distributor::write(): "
717                            "int_id %d active cleared\n", int_id);
718                }
719
720                irqActive[int_id] = false;
721            }
722        }
723
724        return;
725    } else if (GICD_IPRIORITYR.contains(addr)) {
726        // Interrupt Priority Registers
727        int first_intid = addr - GICD_IPRIORITYR.start();
728
729        if (isNotSPI(first_intid)) {
730            return;
731        }
732
733        for (int i = 0, int_id = first_intid; i < size && int_id < itLines;
734                i++, int_id++) {
735            uint8_t prio = bits(data, (i + 1) * 8 - 1, (i * 8));
736
737            if (!DS && !is_secure_access) {
738                if (getIntGroup(int_id) != Gicv3::G1NS) {
739                    // RAZ/WI for non-secure accesses to secure interrupts
740                    continue;
741                } else {
742                    prio = 0x80 | (prio >> 1);
743                }
744            }
745
746            irqPriority[int_id] = prio;
747            DPRINTF(GIC, "Gicv3Distributor::write(): int_id %d priority %d\n",
748                    int_id, irqPriority[int_id]);
749        }
750
751        return;
752    } else if (GICD_ITARGETSR.contains(addr)) {
753        // Interrupt Processor Targets Registers
754        // ARE always on, RAZ/WI
755        warn("Gicv3Distributor::write(): "
756             "GICD_ITARGETSR is RAZ/WI, legacy not supported!\n");
757        return;
758    } else if (GICD_ICFGR.contains(addr)) {
759        // Interrupt Configuration Registers
760        // for x = 0 to 15:
761        //   GICD_ICFGR[2x] = RES0
762        //   GICD_ICFGR[2x + 1] =
763        //     0 level-sensitive
764        //     1 edge-triggered
765        int first_intid = (addr - GICD_ICFGR.start()) * 4;
766
767        if (isNotSPI(first_intid)) {
768            return;
769        }
770
771        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
772             i = i + 2, int_id++) {
773            irqConfig[int_id] = data & (0x2 << i) ?
774                                Gicv3::INT_EDGE_TRIGGERED :
775                                Gicv3::INT_LEVEL_SENSITIVE;
776            DPRINTF(GIC, "Gicv3Distributor::write(): int_id %d config %d\n",
777                    int_id, irqConfig[int_id]);
778        }
779
780        return;
781    } else if (GICD_IGRPMODR.contains(addr)) {
782        // Interrupt Group Modifier Registers
783        if (DS) {
784            return;
785        } else {
786            if (!is_secure_access) {
787                // RAZ/WI for non-secure accesses
788                return;
789            } else {
790                int first_intid = (addr - GICD_IGRPMODR.start()) * 8;
791
792                if (isNotSPI(first_intid)) {
793                    return;
794                }
795
796                for (int i = 0, int_id = first_intid;
797                     i < 8 * size && int_id < itLines; i++, int_id++) {
798                    irqGrpmod[int_id] = bits(data, i);
799                }
800
801                return ;
802            }
803        }
804
805    } else if (GICD_NSACR.contains(addr)) {
806        // Non-secure Access Control Registers
807        // 2 bits per interrupt
808        int first_intid = (addr - GICD_NSACR.start()) * 4;
809
810        if (isNotSPI(first_intid)) {
811            return;
812        }
813
814        if (DS || (!DS && !is_secure_access)) {
815            return;
816        }
817
818        for (int i = 0, int_id = first_intid;
819             i < 8 * size && int_id < itLines; i = i + 2, int_id++) {
820            irqNsacr[int_id] = (data >> (2 * int_id)) & 0x3;
821        }
822
823        return;
824    } else if (GICD_IROUTER.contains(addr)) { // Interrupt Routing Registers
825        // 64 bit registers. 2 accesses.
826        int int_id = (addr - GICD_IROUTER.start()) / 8;
827
828        if (isNotSPI(int_id)) {
829            return;
830        }
831
832        if (nsAccessToSecInt(int_id, is_secure_access))
833        {
834            if (irqNsacr[int_id] < 3) {
835                // Group 0 or Secure Group 1 interrupts are RAZ/WI
836                return;
837            }
838        }
839
840        if (size == 4) {
841            if (addr & 7) { // high half of 64 bit register
842                irqAffinityRouting[int_id] =
843                    (irqAffinityRouting[int_id] & 0xffffffff) | (data << 32);
844            } else { // low half of 64 bit register
845                irqAffinityRouting[int_id] =
846                    (irqAffinityRouting[int_id] & 0xffffffff00000000) |
847                    (data & 0xffffffff);
848            }
849        } else {
850            irqAffinityRouting[int_id] = data;
851        }
852
853        DPRINTF(GIC, "Gicv3Distributor::write(): "
854                "int_id %d GICD_IROUTER %#llx\n",
855                int_id, irqAffinityRouting[int_id]);
856        return;
857    }
858
859    switch (addr) {
860      case GICD_CTLR: // Control Register
861        if (DS) {
862            /*
863             * E1NWF [7]
864             * 1 of N wakeup functionality not supported, RAZ/WI
865             * DS [6] - RAO/WI
866             * ARE [4]
867             * affinity routing always on, no GICv2 legacy, RAO/WI
868             * EnableGrp1 [1]
869             * EnableGrp0 [0]
870             */
871            if ((data & (1 << 4)) == 0) {
872                warn("Gicv3Distributor::write(): "
873                        "setting ARE to 0 is not supported!\n");
874            }
875
876            EnableGrp1NS = data & GICD_CTLR_ENABLEGRP1NS;
877            EnableGrp0 = data & GICD_CTLR_ENABLEGRP0;
878            DPRINTF(GIC, "Gicv3Distributor::write(): (DS 1)"
879                    "EnableGrp1NS %d EnableGrp0 %d\n",
880                    EnableGrp1NS, EnableGrp0);
881        } else {
882            if (is_secure_access) {
883                /*
884                 * E1NWF [7]
885                 * 1 of N wakeup functionality not supported, RAZ/WI
886                 * DS [6]
887                 * ARE_NS [5]
888                 * affinity routing always on, no GICv2 legacy, RAO/WI
889                 * ARE_S [4]
890                 * affinity routing always on, no GICv2 legacy, RAO/WI
891                 * EnableGrp1S [2]
892                 * EnableGrp1NS [1]
893                 * EnableGrp0 [0]
894                 */
895                if ((data & (1 << 5)) == 0) {
896                    warn("Gicv3Distributor::write(): "
897                            "setting ARE_NS to 0 is not supported!\n");
898                }
899
900                if ((data & (1 << 4)) == 0) {
901                    warn("Gicv3Distributor::write(): "
902                            "setting ARE_S to 0 is not supported!\n");
903                }
904
905                DS = data & GICD_CTLR_DS;
906                EnableGrp1S = data & GICD_CTLR_ENABLEGRP1S;
907                EnableGrp1NS = data & GICD_CTLR_ENABLEGRP1NS;
908                EnableGrp0 = data & GICD_CTLR_ENABLEGRP0;
909                DPRINTF(GIC, "Gicv3Distributor::write(): (DS 0 secure)"
910                        "DS %d "
911                        "EnableGrp1S %d EnableGrp1NS %d EnableGrp0 %d\n",
912                        DS, EnableGrp1S, EnableGrp1NS, EnableGrp0);
913
914                if (data & GICD_CTLR_DS) {
915                    EnableGrp1S = 0;
916                }
917            } else {
918                /*
919                 * ARE_NS [4] RAO/WI;
920                 * EnableGrp1A [1] is a read-write alias of the Secure
921                 * GICD_CTLR.EnableGrp1NS
922                 * EnableGrp1 [0] RES0
923                 */
924                if ((data & (1 << 4)) == 0) {
925                    warn("Gicv3Distributor::write(): "
926                            "setting ARE_NS to 0 is not supported!\n");
927                }
928
929                EnableGrp1NS = data & GICD_CTLR_ENABLEGRP1A;
930                DPRINTF(GIC, "Gicv3Distributor::write(): (DS 0 non-secure)"
931                        "EnableGrp1NS %d\n", EnableGrp1NS);
932            }
933        }
934
935        break;
936
937      default:
938        panic("Gicv3Distributor::write(): invalid offset %#x\n", addr);
939        break;
940    }
941}
942
943void
944Gicv3Distributor::sendInt(uint32_t int_id)
945{
946    panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
947    panic_if(int_id > itLines, "Invalid SPI!");
948    irqPending[int_id] = true;
949    DPRINTF(GIC, "Gicv3Distributor::sendInt(): "
950            "int_id %d (SPI) pending bit set\n", int_id);
951    update();
952}
953
954void
955Gicv3Distributor::deassertSPI(uint32_t int_id)
956{
957    panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
958    panic_if(int_id > itLines, "Invalid SPI!");
959    irqPending[int_id] = false;
960    clearIrqCpuInterface(int_id);
961
962    update();
963}
964
965Gicv3CPUInterface*
966Gicv3Distributor::route(uint32_t int_id)
967{
968    IROUTER affinity_routing = irqAffinityRouting[int_id];
969    Gicv3Redistributor * target_redistributor = nullptr;
970
971    const Gicv3::GroupId int_group = getIntGroup(int_id);
972
973    if (affinity_routing.IRM) {
974        // Interrupts routed to any PE defined as a participating node
975        for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
976            Gicv3Redistributor * redistributor_i =
977                gic->getRedistributor(i);
978
979            if (redistributor_i->
980                    canBeSelectedFor1toNInterrupt(int_group)) {
981                target_redistributor = redistributor_i;
982                break;
983            }
984        }
985    } else {
986        uint32_t affinity = (affinity_routing.Aff3 << 24) |
987                            (affinity_routing.Aff2 << 16) |
988                            (affinity_routing.Aff1 << 8) |
989                            (affinity_routing.Aff0 << 0);
990        target_redistributor =
991            gic->getRedistributorByAffinity(affinity);
992    }
993
994    if (!target_redistributor) {
995        // Interrrupts targeting not present cpus must remain pending
996        return nullptr;
997    } else {
998        return target_redistributor->getCPUInterface();
999    }
1000}
1001
1002void
1003Gicv3Distributor::clearIrqCpuInterface(uint32_t int_id)
1004{
1005    auto cpu_interface = route(int_id);
1006    if (cpu_interface)
1007        cpu_interface->hppi.prio = 0xff;
1008}
1009
1010void
1011Gicv3Distributor::update()
1012{
1013    // Find the highest priority pending SPI
1014    for (int int_id = Gicv3::SGI_MAX + Gicv3::PPI_MAX; int_id < itLines;
1015         int_id++) {
1016        Gicv3::GroupId int_group = getIntGroup(int_id);
1017        bool group_enabled = groupEnabled(int_group);
1018
1019        if (irqPending[int_id] && irqEnabled[int_id] &&
1020            !irqActive[int_id] && group_enabled) {
1021
1022            // Find the cpu interface where to route the interrupt
1023            Gicv3CPUInterface *target_cpu_interface = route(int_id);
1024
1025            // Invalid routing
1026            if (!target_cpu_interface) continue;
1027
1028            if ((irqPriority[int_id] < target_cpu_interface->hppi.prio) ||
1029                (irqPriority[int_id] == target_cpu_interface->hppi.prio &&
1030                int_id < target_cpu_interface->hppi.intid)) {
1031
1032                target_cpu_interface->hppi.intid = int_id;
1033                target_cpu_interface->hppi.prio = irqPriority[int_id];
1034                target_cpu_interface->hppi.group = int_group;
1035            }
1036        }
1037    }
1038
1039    // Update all redistributors
1040    for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
1041        gic->getRedistributor(i)->update();
1042    }
1043}
1044
1045Gicv3::IntStatus
1046Gicv3Distributor::intStatus(uint32_t int_id) const
1047{
1048    panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
1049    panic_if(int_id > itLines, "Invalid SPI!");
1050
1051    if (irqPending[int_id]) {
1052        if (irqActive[int_id]) {
1053            return Gicv3::INT_ACTIVE_PENDING;
1054        }
1055
1056        return Gicv3::INT_PENDING;
1057    } else if (irqActive[int_id]) {
1058        return Gicv3::INT_ACTIVE;
1059    } else {
1060        return Gicv3::INT_INACTIVE;
1061    }
1062}
1063
1064Gicv3::GroupId
1065Gicv3Distributor::getIntGroup(int int_id) const
1066{
1067    panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
1068    panic_if(int_id > itLines, "Invalid SPI!");
1069
1070    if (DS) {
1071        if (irqGroup[int_id] == 1) {
1072            return Gicv3::G1NS;
1073        } else {
1074            return Gicv3::G0S;
1075        }
1076    } else {
1077        if (irqGrpmod[int_id] == 0 && irqGroup[int_id] == 0) {
1078            return Gicv3::G0S;
1079        } else if (irqGrpmod[int_id] == 0 && irqGroup[int_id] == 1) {
1080            return Gicv3::G1NS;
1081        } else if (irqGrpmod[int_id] == 1 && irqGroup[int_id] == 0) {
1082            return Gicv3::G1S;
1083        } else if (irqGrpmod[int_id] == 1 && irqGroup[int_id] == 1) {
1084            return Gicv3::G1NS;
1085        }
1086    }
1087
1088    M5_UNREACHABLE;
1089}
1090
1091void
1092Gicv3Distributor::activateIRQ(uint32_t int_id)
1093{
1094    irqPending[int_id] = false;
1095    irqActive[int_id] = true;
1096}
1097
1098void
1099Gicv3Distributor::deactivateIRQ(uint32_t int_id)
1100{
1101    irqActive[int_id] = false;
1102}
1103
1104void
1105Gicv3Distributor::serialize(CheckpointOut & cp) const
1106{
1107    SERIALIZE_SCALAR(ARE);
1108    SERIALIZE_SCALAR(DS);
1109    SERIALIZE_SCALAR(EnableGrp1S);
1110    SERIALIZE_SCALAR(EnableGrp1NS);
1111    SERIALIZE_SCALAR(EnableGrp0);
1112    SERIALIZE_CONTAINER(irqGroup);
1113    SERIALIZE_CONTAINER(irqEnabled);
1114    SERIALIZE_CONTAINER(irqPending);
1115    SERIALIZE_CONTAINER(irqActive);
1116    SERIALIZE_CONTAINER(irqPriority);
1117    SERIALIZE_CONTAINER(irqConfig);
1118    SERIALIZE_CONTAINER(irqGrpmod);
1119    SERIALIZE_CONTAINER(irqNsacr);
1120    SERIALIZE_CONTAINER(irqAffinityRouting);
1121}
1122
1123void
1124Gicv3Distributor::unserialize(CheckpointIn & cp)
1125{
1126    UNSERIALIZE_SCALAR(ARE);
1127    UNSERIALIZE_SCALAR(DS);
1128    UNSERIALIZE_SCALAR(EnableGrp1S);
1129    UNSERIALIZE_SCALAR(EnableGrp1NS);
1130    UNSERIALIZE_SCALAR(EnableGrp0);
1131    UNSERIALIZE_CONTAINER(irqGroup);
1132    UNSERIALIZE_CONTAINER(irqEnabled);
1133    UNSERIALIZE_CONTAINER(irqPending);
1134    UNSERIALIZE_CONTAINER(irqActive);
1135    UNSERIALIZE_CONTAINER(irqPriority);
1136    UNSERIALIZE_CONTAINER(irqConfig);
1137    UNSERIALIZE_CONTAINER(irqGrpmod);
1138    UNSERIALIZE_CONTAINER(irqNsacr);
1139    UNSERIALIZE_CONTAINER(irqAffinityRouting);
1140}
1141