gic_v3_distributor.cc revision 14259
16019Shines@cs.fsu.edu/*
213374Sanouk.vanlaer@arm.com * Copyright (c) 2019 ARM Limited
37399SAli.Saidi@ARM.com * All rights reserved
47399SAli.Saidi@ARM.com *
57399SAli.Saidi@ARM.com * The license below extends only to copyright in the software and shall
67399SAli.Saidi@ARM.com * not be construed as granting a license to any other intellectual
77399SAli.Saidi@ARM.com * property including but not limited to intellectual property relating
87399SAli.Saidi@ARM.com * to a hardware implementation of the functionality of the software
97399SAli.Saidi@ARM.com * licensed hereunder.  You may use the software subject to the license
107399SAli.Saidi@ARM.com * terms below provided that you ensure that this notice is replicated
117399SAli.Saidi@ARM.com * unmodified and in its entirety in all distributions of the software,
127399SAli.Saidi@ARM.com * modified or unmodified, in source code or in binary form.
137399SAli.Saidi@ARM.com *
146019Shines@cs.fsu.edu * Copyright (c) 2018 Metempsy Technology Consulting
156019Shines@cs.fsu.edu * All rights reserved.
166019Shines@cs.fsu.edu *
176019Shines@cs.fsu.edu * Redistribution and use in source and binary forms, with or without
186019Shines@cs.fsu.edu * modification, are permitted provided that the following conditions are
196019Shines@cs.fsu.edu * met: redistributions of source code must retain the above copyright
206019Shines@cs.fsu.edu * notice, this list of conditions and the following disclaimer;
216019Shines@cs.fsu.edu * redistributions in binary form must reproduce the above copyright
226019Shines@cs.fsu.edu * notice, this list of conditions and the following disclaimer in the
236019Shines@cs.fsu.edu * documentation and/or other materials provided with the distribution;
246019Shines@cs.fsu.edu * neither the name of the copyright holders nor the names of its
256019Shines@cs.fsu.edu * contributors may be used to endorse or promote products derived from
266019Shines@cs.fsu.edu * this software without specific prior written permission.
276019Shines@cs.fsu.edu *
286019Shines@cs.fsu.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
296019Shines@cs.fsu.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
306019Shines@cs.fsu.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
316019Shines@cs.fsu.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
326019Shines@cs.fsu.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
336019Shines@cs.fsu.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
346019Shines@cs.fsu.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
356019Shines@cs.fsu.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
366019Shines@cs.fsu.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
376019Shines@cs.fsu.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
386019Shines@cs.fsu.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
396019Shines@cs.fsu.edu *
407399SAli.Saidi@ARM.com * Authors: Jairo Balart
416019Shines@cs.fsu.edu */
426019Shines@cs.fsu.edu
436019Shines@cs.fsu.edu#include "dev/arm/gic_v3_distributor.hh"
446019Shines@cs.fsu.edu
456019Shines@cs.fsu.edu#include <algorithm>
466019Shines@cs.fsu.edu
476019Shines@cs.fsu.edu#include "base/intmath.hh"
488229Snate@binkert.org#include "debug/GIC.hh"
496019Shines@cs.fsu.edu#include "dev/arm/gic_v3.hh"
506019Shines@cs.fsu.edu#include "dev/arm/gic_v3_cpu_interface.hh"
5110687SAndreas.Sandberg@ARM.com#include "dev/arm/gic_v3_redistributor.hh"
526019Shines@cs.fsu.edu
536019Shines@cs.fsu.educonst AddrRange Gicv3Distributor::GICD_IGROUPR   (0x0080, 0x00ff);
546116Snate@binkert.orgconst AddrRange Gicv3Distributor::GICD_ISENABLER (0x0100, 0x017f);
5510463SAndreas.Sandberg@ARM.comconst AddrRange Gicv3Distributor::GICD_ICENABLER (0x0180, 0x01ff);
566019Shines@cs.fsu.educonst AddrRange Gicv3Distributor::GICD_ISPENDR   (0x0200, 0x027f);
576019Shines@cs.fsu.educonst AddrRange Gicv3Distributor::GICD_ICPENDR   (0x0280, 0x02ff);
586019Shines@cs.fsu.educonst AddrRange Gicv3Distributor::GICD_ISACTIVER (0x0300, 0x037f);
596019Shines@cs.fsu.educonst AddrRange Gicv3Distributor::GICD_ICACTIVER (0x0380, 0x03ff);
606019Shines@cs.fsu.educonst AddrRange Gicv3Distributor::GICD_IPRIORITYR(0x0400, 0x07ff);
617404SAli.Saidi@ARM.comconst AddrRange Gicv3Distributor::GICD_ITARGETSR (0x0800, 0x08ff);
6210037SARM gem5 Developersconst AddrRange Gicv3Distributor::GICD_ICFGR     (0x0c00, 0x0cff);
6310037SARM gem5 Developersconst AddrRange Gicv3Distributor::GICD_IGRPMODR  (0x0d00, 0x0d7f);
6411395Sandreas.sandberg@arm.comconst AddrRange Gicv3Distributor::GICD_NSACR     (0x0e00, 0x0eff);
6511395Sandreas.sandberg@arm.comconst AddrRange Gicv3Distributor::GICD_CPENDSGIR (0x0f10, 0x0f1f);
6611395Sandreas.sandberg@arm.comconst AddrRange Gicv3Distributor::GICD_SPENDSGIR (0x0f20, 0x0f2f);
6711395Sandreas.sandberg@arm.comconst AddrRange Gicv3Distributor::GICD_IROUTER   (0x6000, 0x7fe0);
6811395Sandreas.sandberg@arm.com
6911395Sandreas.sandberg@arm.comGicv3Distributor::Gicv3Distributor(Gicv3 * gic, uint32_t it_lines)
7011395Sandreas.sandberg@arm.com    : gic(gic),
7111395Sandreas.sandberg@arm.com      itLines(it_lines),
7211395Sandreas.sandberg@arm.com      ARE(true),
7311395Sandreas.sandberg@arm.com      EnableGrp1S(0),
7411395Sandreas.sandberg@arm.com      EnableGrp1NS(0),
7511395Sandreas.sandberg@arm.com      EnableGrp0(0),
7611395Sandreas.sandberg@arm.com      irqGroup(it_lines, 0),
7711395Sandreas.sandberg@arm.com      irqEnabled(it_lines, false),
7811395Sandreas.sandberg@arm.com      irqPending(it_lines, false),
7911395Sandreas.sandberg@arm.com      irqActive(it_lines, false),
8012749Sgiacomo.travaglini@arm.com      irqPriority(it_lines, 0xAA),
8111395Sandreas.sandberg@arm.com      irqConfig(it_lines, Gicv3::INT_LEVEL_SENSITIVE),
8211395Sandreas.sandberg@arm.com      irqGrpmod(it_lines, 0),
8311395Sandreas.sandberg@arm.com      irqNsacr(it_lines, 0),
8411395Sandreas.sandberg@arm.com      irqAffinityRouting(it_lines, 0),
8511395Sandreas.sandberg@arm.com      gicdTyper(0),
8611395Sandreas.sandberg@arm.com      gicdPidr0(0x92),
8711395Sandreas.sandberg@arm.com      gicdPidr1(0xb4),
8811395Sandreas.sandberg@arm.com      gicdPidr2(0x3b),
8911395Sandreas.sandberg@arm.com      gicdPidr3(0),
9011395Sandreas.sandberg@arm.com      gicdPidr4(0x44)
9111395Sandreas.sandberg@arm.com{
9211395Sandreas.sandberg@arm.com    panic_if(it_lines > Gicv3::INTID_SECURE, "Invalid value for it_lines!");
9311395Sandreas.sandberg@arm.com    /*
9411395Sandreas.sandberg@arm.com     * RSS           [26]    == 1
9511395Sandreas.sandberg@arm.com     * (The implementation does supports targeted SGIs with affinity
9611395Sandreas.sandberg@arm.com     * level 0 values of 0 - 255)
9711395Sandreas.sandberg@arm.com     * No1N          [25]    == 1
9811395Sandreas.sandberg@arm.com     * (1 of N SPI interrupts are not supported)
9911395Sandreas.sandberg@arm.com     * A3V           [24]    == 1
10011395Sandreas.sandberg@arm.com     * (Supports nonzero values of Affinity level 3)
1017404SAli.Saidi@ARM.com     * IDbits        [23:19] == 0xf
1026019Shines@cs.fsu.edu     * (The number of interrupt identifier bits supported, minus one)
1036019Shines@cs.fsu.edu     * DVIS          [18]    == 0
1047294Sgblack@eecs.umich.edu     * (The implementation does not support Direct Virtual LPI
1057294Sgblack@eecs.umich.edu     * injection)
10610037SARM gem5 Developers     * LPIS          [17]    == 1
1077294Sgblack@eecs.umich.edu     * (The implementation does not support LPIs)
1087294Sgblack@eecs.umich.edu     * MBIS          [16]    == 1
1097294Sgblack@eecs.umich.edu     * (The implementation supports message-based interrupts
11010037SARM gem5 Developers     * by writing to Distributor registers)
11110037SARM gem5 Developers     * SecurityExtn  [10]    == X
11210037SARM gem5 Developers     * (The GIC implementation supports two Security states)
11310037SARM gem5 Developers     * CPUNumber     [7:5]   == 0
1147294Sgblack@eecs.umich.edu     * (since for us ARE is always 1 [(ARE = 0) == Gicv2 legacy])
11510037SARM gem5 Developers     * ITLinesNumber [4:0]   == N
1167404SAli.Saidi@ARM.com     * (MaxSPIIntId = 32 (N + 1) - 1)
11710037SARM gem5 Developers     */
1187294Sgblack@eecs.umich.edu    int max_spi_int_id = itLines - 1;
1197294Sgblack@eecs.umich.edu    int it_lines_number = divCeil(max_spi_int_id + 1, 32) - 1;
1207294Sgblack@eecs.umich.edu    gicdTyper = (1 << 26) | (1 << 25) | (1 << 24) | (IDBITS << 19) |
12110037SARM gem5 Developers        (1 << 17) | (1 << 16) |
12210037SARM gem5 Developers        ((gic->getSystem()->haveSecurity() ? 1 : 0) << 10) |
12310037SARM gem5 Developers        (it_lines_number << 0);
12410037SARM gem5 Developers
12510037SARM gem5 Developers    if (gic->getSystem()->haveSecurity()) {
12610037SARM gem5 Developers        DS = false;
12710037SARM gem5 Developers    } else {
12810037SARM gem5 Developers        DS = true;
12910037SARM gem5 Developers    }
13011577SDylan.Johnson@ARM.com}
13111577SDylan.Johnson@ARM.com
13211577SDylan.Johnson@ARM.comvoid
13311577SDylan.Johnson@ARM.comGicv3Distributor::init()
13411577SDylan.Johnson@ARM.com{
13511577SDylan.Johnson@ARM.com}
13611577SDylan.Johnson@ARM.com
13711577SDylan.Johnson@ARM.comuint64_t
13811577SDylan.Johnson@ARM.comGicv3Distributor::read(Addr addr, size_t size, bool is_secure_access)
13911577SDylan.Johnson@ARM.com{
14011577SDylan.Johnson@ARM.com    if (GICD_IGROUPR.contains(addr)) { // Interrupt Group Registers
1417294Sgblack@eecs.umich.edu        uint64_t val = 0x0;
14212735Sandreas.sandberg@arm.com
14312735Sandreas.sandberg@arm.com        if (!DS && !is_secure_access) {
14412735Sandreas.sandberg@arm.com            // RAZ/WI for non-secure accesses
14512735Sandreas.sandberg@arm.com            return 0;
14612735Sandreas.sandberg@arm.com        }
14712735Sandreas.sandberg@arm.com
14812735Sandreas.sandberg@arm.com        int first_intid = (addr - GICD_IGROUPR.start()) * 8;
14912735Sandreas.sandberg@arm.com
1506019Shines@cs.fsu.edu        if (isNotSPI(first_intid)) {
15110037SARM gem5 Developers            return 0;
15210037SARM gem5 Developers        }
15310037SARM gem5 Developers
15410037SARM gem5 Developers        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
15513374Sanouk.vanlaer@arm.com             i++, int_id++) {
15613374Sanouk.vanlaer@arm.com            val |= irqGroup[int_id] << i;
15713374Sanouk.vanlaer@arm.com        }
15813374Sanouk.vanlaer@arm.com
15910037SARM gem5 Developers        return val;
16010037SARM gem5 Developers    } else if (GICD_ISENABLER.contains(addr)) {
16110037SARM gem5 Developers        // Interrupt Set-Enable Registers
1627436Sdam.sunwoo@arm.com        uint64_t val = 0x0;
1637404SAli.Saidi@ARM.com        int first_intid = (addr - GICD_ISENABLER.start()) * 8;
16410037SARM gem5 Developers
16510037SARM gem5 Developers        if (isNotSPI(first_intid)) {
1666019Shines@cs.fsu.edu            return 0;
16711395Sandreas.sandberg@arm.com        }
16811395Sandreas.sandberg@arm.com
1697399SAli.Saidi@ARM.com        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
1707734SAli.Saidi@ARM.com             i++, int_id++) {
1717734SAli.Saidi@ARM.com
1727734SAli.Saidi@ARM.com            if (nsAccessToSecInt(int_id, is_secure_access))
1737734SAli.Saidi@ARM.com            {
1747734SAli.Saidi@ARM.com                continue;
1757734SAli.Saidi@ARM.com            }
1767734SAli.Saidi@ARM.com
1777734SAli.Saidi@ARM.com            val |= irqEnabled[int_id] << i;
1787734SAli.Saidi@ARM.com        }
1797734SAli.Saidi@ARM.com
1807734SAli.Saidi@ARM.com        return val;
1817734SAli.Saidi@ARM.com    } else if (GICD_ICENABLER.contains(addr)) {
1827734SAli.Saidi@ARM.com        // Interrupt Clear-Enable Registers
1837734SAli.Saidi@ARM.com        uint64_t val = 0x0;
1847734SAli.Saidi@ARM.com        int first_intid = (addr - GICD_ICENABLER.start()) * 8;
1857734SAli.Saidi@ARM.com
1867734SAli.Saidi@ARM.com        if (isNotSPI(first_intid)) {
1877734SAli.Saidi@ARM.com            return 0;
1887734SAli.Saidi@ARM.com        }
1897734SAli.Saidi@ARM.com
1906019Shines@cs.fsu.edu        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
1916019Shines@cs.fsu.edu             i++, int_id++) {
1926019Shines@cs.fsu.edu
1936019Shines@cs.fsu.edu            if (nsAccessToSecInt(int_id, is_secure_access))
19410463SAndreas.Sandberg@ARM.com            {
19510463SAndreas.Sandberg@ARM.com                continue;
19610463SAndreas.Sandberg@ARM.com            }
1977697SAli.Saidi@ARM.com
1987404SAli.Saidi@ARM.com            val |= (irqEnabled[int_id] << i);
1996019Shines@cs.fsu.edu        }
20010037SARM gem5 Developers
20110037SARM gem5 Developers        return val;
2026019Shines@cs.fsu.edu    } else if (GICD_ISPENDR.contains(addr)) {
2039535Smrinmoy.ghosh@arm.com        // Interrupt Set-Pending Registers
2049535Smrinmoy.ghosh@arm.com        uint64_t val = 0x0;
2059535Smrinmoy.ghosh@arm.com        int first_intid = (addr - GICD_ISPENDR.start()) * 8;
20610037SARM gem5 Developers
20710037SARM gem5 Developers        if (isNotSPI(first_intid)) {
20810037SARM gem5 Developers            return 0;
2099535Smrinmoy.ghosh@arm.com        }
21010037SARM gem5 Developers
21110037SARM gem5 Developers        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
2129535Smrinmoy.ghosh@arm.com             i++, int_id++) {
21310037SARM gem5 Developers
21410037SARM gem5 Developers            if (nsAccessToSecInt(int_id, is_secure_access))
21510037SARM gem5 Developers            {
2169535Smrinmoy.ghosh@arm.com                if (irqNsacr[int_id] == 0) {
2176019Shines@cs.fsu.edu                    // Group 0 or Secure Group 1 interrupts are RAZ/WI
21810037SARM gem5 Developers                    continue;
21911169Sandreas.hansson@arm.com                }
22010194SGeoffrey.Blake@arm.com            }
22110037SARM gem5 Developers
22211169Sandreas.hansson@arm.com            val |= (irqPending[int_id] << i);
22310037SARM gem5 Developers        }
22411395Sandreas.sandberg@arm.com
22511395Sandreas.sandberg@arm.com        return val;
22610717Sandreas.hansson@arm.com    } else if (GICD_ICPENDR.contains(addr)) {
22710717Sandreas.hansson@arm.com        // Interrupt Clear-Pending Registers
22810717Sandreas.hansson@arm.com        uint64_t val = 0x0;
22910037SARM gem5 Developers        int first_intid = (addr - GICD_ICPENDR.start()) * 8;
2306019Shines@cs.fsu.edu
2316019Shines@cs.fsu.edu        if (isNotSPI(first_intid)) {
2327404SAli.Saidi@ARM.com            return 0;
2337404SAli.Saidi@ARM.com        }
23412749Sgiacomo.travaglini@arm.com
23512749Sgiacomo.travaglini@arm.com        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
23610037SARM gem5 Developers             i++, int_id++) {
23710037SARM gem5 Developers
23810037SARM gem5 Developers            if (nsAccessToSecInt(int_id, is_secure_access))
23912749Sgiacomo.travaglini@arm.com            {
24012749Sgiacomo.travaglini@arm.com                if (irqNsacr[int_id] < 2) {
24112749Sgiacomo.travaglini@arm.com                    // Group 0 or Secure Group 1 interrupts are RAZ/WI
24210037SARM gem5 Developers                    continue;
24310037SARM gem5 Developers                }
24412749Sgiacomo.travaglini@arm.com            }
24512749Sgiacomo.travaglini@arm.com
24610037SARM gem5 Developers            val |= (irqPending[int_id] << i);
24710037SARM gem5 Developers        }
24810037SARM gem5 Developers
24910037SARM gem5 Developers        return val;
25010037SARM gem5 Developers    } else if (GICD_ISACTIVER.contains(addr)) {
25110037SARM gem5 Developers        // Interrupt Set-Active Registers
25210037SARM gem5 Developers        int first_intid = (addr - GICD_ISACTIVER.start()) * 8;
25310037SARM gem5 Developers
25410037SARM gem5 Developers        if (isNotSPI(first_intid)) {
25510037SARM gem5 Developers            return 0;
25610037SARM gem5 Developers        }
25710037SARM gem5 Developers
25810037SARM gem5 Developers        uint64_t val = 0x0;
25910037SARM gem5 Developers
26010037SARM gem5 Developers        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
26110037SARM gem5 Developers             i++, int_id++) {
26210037SARM gem5 Developers
26310037SARM gem5 Developers            if (nsAccessToSecInt(int_id, is_secure_access))
26410037SARM gem5 Developers            {
26511169Sandreas.hansson@arm.com                // Group 0 or Secure Group 1 interrupts are RAZ/WI
26610037SARM gem5 Developers                if (irqNsacr[int_id] < 2) {
26710037SARM gem5 Developers                    continue;
26810037SARM gem5 Developers                }
26910037SARM gem5 Developers            }
2707404SAli.Saidi@ARM.com
2717404SAli.Saidi@ARM.com            val |= (irqActive[int_id] << i);
2727404SAli.Saidi@ARM.com        }
2737404SAli.Saidi@ARM.com
27410037SARM gem5 Developers        return val;
2757404SAli.Saidi@ARM.com    } else if (GICD_ICACTIVER.contains(addr)) {
27610037SARM gem5 Developers        // Interrupt Clear-Active Registers
27710037SARM gem5 Developers        int first_intid = (addr - GICD_ICACTIVER.start()) * 8;
2787404SAli.Saidi@ARM.com
2797404SAli.Saidi@ARM.com        if (isNotSPI(first_intid)) {
2807404SAli.Saidi@ARM.com            return 0;
28110037SARM gem5 Developers        }
2827404SAli.Saidi@ARM.com
28310037SARM gem5 Developers        uint64_t val = 0x0;
2847404SAli.Saidi@ARM.com
2857404SAli.Saidi@ARM.com        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
2867404SAli.Saidi@ARM.com             i++, int_id++) {
28710037SARM gem5 Developers
28810037SARM gem5 Developers            if (nsAccessToSecInt(int_id, is_secure_access))
2897404SAli.Saidi@ARM.com            {
29010037SARM gem5 Developers                if (irqNsacr[int_id] < 2) {
2917404SAli.Saidi@ARM.com                    continue;
29211584SDylan.Johnson@ARM.com                }
29311584SDylan.Johnson@ARM.com            }
29411584SDylan.Johnson@ARM.com
29511584SDylan.Johnson@ARM.com            val |= (irqActive[int_id] << i);
29611584SDylan.Johnson@ARM.com        }
29711584SDylan.Johnson@ARM.com
29811584SDylan.Johnson@ARM.com        return val;
29911584SDylan.Johnson@ARM.com    } else if (GICD_IPRIORITYR.contains(addr)) {
30011584SDylan.Johnson@ARM.com        // Interrupt Priority Registers
30112749Sgiacomo.travaglini@arm.com        uint64_t val = 0x0;
30212749Sgiacomo.travaglini@arm.com        int first_intid = addr - GICD_IPRIORITYR.start();
30312749Sgiacomo.travaglini@arm.com
30412749Sgiacomo.travaglini@arm.com        if (isNotSPI(first_intid)) {
30512749Sgiacomo.travaglini@arm.com            return 0;
30612749Sgiacomo.travaglini@arm.com        }
30712749Sgiacomo.travaglini@arm.com
30811584SDylan.Johnson@ARM.com        for (int i = 0, int_id = first_intid; i < size && int_id < itLines;
30910037SARM gem5 Developers             i++, int_id++) {
3107404SAli.Saidi@ARM.com
31111169Sandreas.hansson@arm.com            uint8_t prio = irqPriority[int_id];
3126019Shines@cs.fsu.edu
31310037SARM gem5 Developers            if (!DS && !is_secure_access) {
31410037SARM gem5 Developers                if (getIntGroup(int_id) != Gicv3::G1NS) {
3156019Shines@cs.fsu.edu                    // RAZ/WI for non-secure accesses for secure interrupts
3166019Shines@cs.fsu.edu                    continue;
3177694SAli.Saidi@ARM.com                } else {
3187694SAli.Saidi@ARM.com                    // NS view
3197694SAli.Saidi@ARM.com                    prio = (prio << 1) & 0xff;
3207694SAli.Saidi@ARM.com                }
3217694SAli.Saidi@ARM.com            }
3227694SAli.Saidi@ARM.com
3237694SAli.Saidi@ARM.com            val |= prio << (i * 8);
3247694SAli.Saidi@ARM.com        }
3257694SAli.Saidi@ARM.com
3267694SAli.Saidi@ARM.com        return val;
3278733Sgeoffrey.blake@arm.com    } else if (GICD_ITARGETSR.contains(addr)) {
3288733Sgeoffrey.blake@arm.com        // Interrupt Processor Targets Registers
3298733Sgeoffrey.blake@arm.com        // ARE always on, RAZ/WI
3308733Sgeoffrey.blake@arm.com        warn("Gicv3Distributor::read(): "
33112749Sgiacomo.travaglini@arm.com             "GICD_ITARGETSR is RAZ/WI, legacy not supported!\n");
33212749Sgiacomo.travaglini@arm.com        return 0;
33312419Sgabeblack@google.com    } else if (GICD_ICFGR.contains(addr)) {
33412749Sgiacomo.travaglini@arm.com        // Interrupt Configuration Registers
33512749Sgiacomo.travaglini@arm.com        int first_intid = (addr - GICD_ICFGR.start()) * 4;
33612419Sgabeblack@google.com
33712419Sgabeblack@google.com        if (isNotSPI(first_intid)) {
33812419Sgabeblack@google.com            return 0;
3398733Sgeoffrey.blake@arm.com        }
3407436Sdam.sunwoo@arm.com
3417436Sdam.sunwoo@arm.com        uint64_t val = 0x0;
3427436Sdam.sunwoo@arm.com
34310037SARM gem5 Developers        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
3447436Sdam.sunwoo@arm.com             i = i + 2, int_id++) {
3457436Sdam.sunwoo@arm.com
3467436Sdam.sunwoo@arm.com            if (nsAccessToSecInt(int_id, is_secure_access))
34710037SARM gem5 Developers            {
34810037SARM gem5 Developers                continue;
3497436Sdam.sunwoo@arm.com            }
3507436Sdam.sunwoo@arm.com
3517436Sdam.sunwoo@arm.com            if (irqConfig[int_id] == Gicv3::INT_EDGE_TRIGGERED) {
3527436Sdam.sunwoo@arm.com                val |= (0x2 << i);
3537436Sdam.sunwoo@arm.com            }
35412749Sgiacomo.travaglini@arm.com        }
3558733Sgeoffrey.blake@arm.com
35610037SARM gem5 Developers        return val;
35712749Sgiacomo.travaglini@arm.com    } else if (GICD_IGRPMODR.contains(addr)) {
3587404SAli.Saidi@ARM.com        // Interrupt Group Modifier Registers
35912749Sgiacomo.travaglini@arm.com        if (DS) {
36012406Sgabeblack@google.com            // RAZ/WI if security disabled
36112406Sgabeblack@google.com            return 0;
36212749Sgiacomo.travaglini@arm.com        } else {
36312749Sgiacomo.travaglini@arm.com            if (!is_secure_access) {
36412406Sgabeblack@google.com                // RAZ/WI for non-secure accesses
36512406Sgabeblack@google.com                return 0;
36612406Sgabeblack@google.com            } else {
36712406Sgabeblack@google.com                int first_intid = (addr - GICD_IGRPMODR.start()) * 8;
36812749Sgiacomo.travaglini@arm.com
36910037SARM gem5 Developers                if (isNotSPI(first_intid)) {
37012406Sgabeblack@google.com                    return 0;
37112406Sgabeblack@google.com                }
37212749Sgiacomo.travaglini@arm.com
37312406Sgabeblack@google.com                uint64_t val = 0x0;
37412406Sgabeblack@google.com
37512406Sgabeblack@google.com                for (int i = 0, int_id = first_intid;
37612406Sgabeblack@google.com                     i < 8 * size && int_id < itLines; i++, int_id++) {
37712749Sgiacomo.travaglini@arm.com                    val |= irqGrpmod[int_id] << i;
37810037SARM gem5 Developers                }
37910037SARM gem5 Developers
38012406Sgabeblack@google.com                return val;
38112749Sgiacomo.travaglini@arm.com            }
38212749Sgiacomo.travaglini@arm.com        }
3836116Snate@binkert.org    } else if (GICD_NSACR.contains(addr)) {
38411168Sandreas.hansson@arm.com        // Non-secure Access Control Registers
3859439SAndreas.Sandberg@ARM.com        // 2 bits per interrupt
3866019Shines@cs.fsu.edu        int first_intid = (addr - GICD_NSACR.start()) * 4;
38711168Sandreas.hansson@arm.com
38811168Sandreas.hansson@arm.com        if (isNotSPI(first_intid)) {
3896019Shines@cs.fsu.edu            return 0;
39011169Sandreas.hansson@arm.com        }
3917749SAli.Saidi@ARM.com
39211168Sandreas.hansson@arm.com        if (DS || (!DS && !is_secure_access)) {
39310463SAndreas.Sandberg@ARM.com            return 0;
3948922Swilliam.wang@arm.com        }
3958922Swilliam.wang@arm.com
3968922Swilliam.wang@arm.com        uint64_t val = 0x0;
3978922Swilliam.wang@arm.com
3988922Swilliam.wang@arm.com        for (int i = 0, int_id = first_intid;
3998922Swilliam.wang@arm.com             i < 8 * size && int_id < itLines; i = i + 2, int_id++) {
4008922Swilliam.wang@arm.com            val |= irqNsacr[int_id] << i;
4018922Swilliam.wang@arm.com        }
4028922Swilliam.wang@arm.com
4038922Swilliam.wang@arm.com        return val;
40411169Sandreas.hansson@arm.com    } else if (GICD_CPENDSGIR.contains(addr)) { // SGI Clear-Pending Registers
4057781SAli.Saidi@ARM.com        // ARE always on, RAZ/WI
4067749SAli.Saidi@ARM.com        warn("Gicv3Distributor::read(): "
4077749SAli.Saidi@ARM.com             "GICD_CPENDSGIR is RAZ/WI, legacy not supported!\n");
4087749SAli.Saidi@ARM.com        return 0x0;
4097749SAli.Saidi@ARM.com    } else if (GICD_SPENDSGIR.contains(addr)) { // SGI Set-Pending Registers
4107749SAli.Saidi@ARM.com        // ARE always on, RAZ/WI
41110854SNathanael.Premillieu@arm.com        warn("Gicv3Distributor::read(): "
41210037SARM gem5 Developers             "GICD_SPENDSGIR is RAZ/WI, legacy not supported!\n");
41310037SARM gem5 Developers        return 0x0;
4147749SAli.Saidi@ARM.com    } else if (GICD_IROUTER.contains(addr)) { // Interrupt Routing Registers
41510037SARM gem5 Developers        // 64 bit registers. 2 or 1 access.
4167749SAli.Saidi@ARM.com        int int_id = (addr - GICD_IROUTER.start()) / 8;
41710037SARM gem5 Developers
41810037SARM gem5 Developers        if (isNotSPI(int_id)) {
41910037SARM gem5 Developers            return 0;
42010037SARM gem5 Developers        }
42110037SARM gem5 Developers
4227749SAli.Saidi@ARM.com        if (nsAccessToSecInt(int_id, is_secure_access))
4237749SAli.Saidi@ARM.com        {
42410037SARM gem5 Developers            if (irqNsacr[int_id] < 3) {
4257749SAli.Saidi@ARM.com                return 0;
4267749SAli.Saidi@ARM.com            }
42711152Smitch.hayenga@arm.com        }
42810037SARM gem5 Developers
42910037SARM gem5 Developers        if (size == 4) {
43010037SARM gem5 Developers            if (addr & 7) { // high half of 64 bit register
43110037SARM gem5 Developers                return irqAffinityRouting[int_id] >> 32;
43210037SARM gem5 Developers            } else { // high low of 64 bit register
43310037SARM gem5 Developers                return irqAffinityRouting[int_id] & 0xFFFFFFFF;
43410037SARM gem5 Developers            }
43512005Sandreas.sandberg@arm.com        } else {
43612005Sandreas.sandberg@arm.com            return irqAffinityRouting[int_id];
43710037SARM gem5 Developers        }
43810037SARM gem5 Developers    }
43910037SARM gem5 Developers
4407749SAli.Saidi@ARM.com    switch (addr) {
4418299Schander.sudanthi@arm.com      case GICD_CTLR: // Control Register
4428299Schander.sudanthi@arm.com        if (!DS) {
4438299Schander.sudanthi@arm.com            if (is_secure_access) {
4448299Schander.sudanthi@arm.com                // E1NWF [7] RAZ/WI
4458299Schander.sudanthi@arm.com                // DS [6] - Disable Security
4467749SAli.Saidi@ARM.com                // ARE_NS [5] RAO/WI
44710037SARM gem5 Developers                // ARE_S [4] RAO/WI
44810037SARM gem5 Developers                // EnableGrp1S [2]
44910037SARM gem5 Developers                // EnableGrp1NS [1]
45010037SARM gem5 Developers                // EnableGrp0 [0]
45110037SARM gem5 Developers                return (EnableGrp0 << 0) |
45210037SARM gem5 Developers                    (EnableGrp1NS << 1) |
45310037SARM gem5 Developers                    (EnableGrp1S << 2) |
45410037SARM gem5 Developers                    (1 << 4) |
45510037SARM gem5 Developers                    (1 << 5) |
45610037SARM gem5 Developers                    (DS << 6);
45710037SARM gem5 Developers            } else {
45810037SARM gem5 Developers                // ARE_NS [4] RAO/WI;
45910037SARM gem5 Developers                // EnableGrp1A [1] is a read-write alias of the Secure
46011395Sandreas.sandberg@arm.com                // GICD_CTLR.EnableGrp1NS
46111395Sandreas.sandberg@arm.com                // EnableGrp1 [0] RES0
46212749Sgiacomo.travaglini@arm.com                return (1 << 4) | (EnableGrp1NS << 1);
46311395Sandreas.sandberg@arm.com            }
46411395Sandreas.sandberg@arm.com        } else {
46511395Sandreas.sandberg@arm.com            return (DS << 6) | (ARE << 4) |
46611395Sandreas.sandberg@arm.com                (EnableGrp1NS << 1) | (EnableGrp0 << 0);
4676019Shines@cs.fsu.edu        }
4686019Shines@cs.fsu.edu
46912605Sgiacomo.travaglini@arm.com      case GICD_TYPER: // Interrupt Controller Type Register
47012605Sgiacomo.travaglini@arm.com        return gicdTyper;
47112605Sgiacomo.travaglini@arm.com
47212605Sgiacomo.travaglini@arm.com      case GICD_IIDR: // Implementer Identification Register
47312605Sgiacomo.travaglini@arm.com        //return 0x43b; // ARM JEP106 code (r0p0 GIC-500)
47412605Sgiacomo.travaglini@arm.com        return 0;
47512605Sgiacomo.travaglini@arm.com
47612605Sgiacomo.travaglini@arm.com      case GICD_STATUSR: // Error Reporting Status Register
47712605Sgiacomo.travaglini@arm.com        // Optional register, RAZ/WI
47812605Sgiacomo.travaglini@arm.com        return 0x0;
47912605Sgiacomo.travaglini@arm.com
48012605Sgiacomo.travaglini@arm.com      case GICD_PIDR0: // Peripheral ID0 Register
48112605Sgiacomo.travaglini@arm.com        return gicdPidr0;
48212605Sgiacomo.travaglini@arm.com
48312605Sgiacomo.travaglini@arm.com      case GICD_PIDR1: // Peripheral ID1 Register
48412605Sgiacomo.travaglini@arm.com        return gicdPidr1;
48512605Sgiacomo.travaglini@arm.com
48612605Sgiacomo.travaglini@arm.com      case GICD_PIDR2: // Peripheral ID2 Register
4877811Ssteve.reinhardt@amd.com        return gicdPidr2;
4886019Shines@cs.fsu.edu
4896019Shines@cs.fsu.edu      case GICD_PIDR3: // Peripheral ID3 Register
490        return gicdPidr3;
491
492      case GICD_PIDR4: // Peripheral ID4 Register
493        return gicdPidr4;
494
495      case GICD_PIDR5: // Peripheral ID5 Register
496      case GICD_PIDR6: // Peripheral ID6 Register
497      case GICD_PIDR7: // Peripheral ID7 Register
498        return 0; // RES0
499
500      default:
501        panic("Gicv3Distributor::read(): invalid offset %#x\n", addr);
502        break;
503    }
504}
505
506void
507Gicv3Distributor::write(Addr addr, uint64_t data, size_t size,
508                        bool is_secure_access)
509{
510    if (GICD_IGROUPR.contains(addr)) { // Interrupt Group Registers
511        if (!DS && !is_secure_access) {
512            // RAZ/WI for non-secure accesses
513            return;
514        }
515
516        int first_intid = (addr - GICD_IGROUPR.start()) * 8;
517
518        if (isNotSPI(first_intid)) {
519            return;
520        }
521
522        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
523             i++, int_id++) {
524            irqGroup[int_id] = data & (1 << i) ? 1 : 0;
525            DPRINTF(GIC, "Gicv3Distributor::write(): int_id %d group %d\n",
526                    int_id, irqGroup[int_id]);
527        }
528
529        return;
530    } else if (GICD_ISENABLER.contains(addr)) {
531        // Interrupt Set-Enable Registers
532        int first_intid = (addr - GICD_ISENABLER.start()) * 8;
533
534        if (isNotSPI(first_intid)) {
535            return;
536        }
537
538        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
539             i++, int_id++) {
540
541            if (nsAccessToSecInt(int_id, is_secure_access))
542            {
543                continue;
544            }
545
546            bool enable = data & (1 << i) ? 1 : 0;
547
548            if (enable) {
549                if (!irqEnabled[int_id]) {
550                    DPRINTF(GIC, "Gicv3Distributor::write(): "
551                            "int_id %d enabled\n", int_id);
552                }
553
554                irqEnabled[int_id] = true;
555            }
556        }
557
558        return;
559    } else if (GICD_ICENABLER.contains(addr)) {
560        // Interrupt Clear-Enable Registers
561        int first_intid = (addr - GICD_ICENABLER.start()) * 8;
562
563        if (isNotSPI(first_intid)) {
564            return;
565        }
566
567        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
568             i++, int_id++) {
569
570            if (nsAccessToSecInt(int_id, is_secure_access))
571            {
572                continue;
573            }
574
575            bool disable = data & (1 << i) ? 1 : 0;
576
577            if (disable) {
578                if (irqEnabled[int_id]) {
579                    DPRINTF(GIC, "Gicv3Distributor::write(): "
580                            "int_id %d disabled\n", int_id);
581                }
582
583                irqEnabled[int_id] = false;
584            }
585        }
586
587        return;
588    } else if (GICD_ISPENDR.contains(addr)) {
589        // Interrupt Set-Pending Registers
590        int first_intid = (addr - GICD_ISPENDR.start()) * 8;
591
592        if (isNotSPI(first_intid)) {
593            return;
594        }
595
596        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
597             i++, int_id++) {
598
599            if (nsAccessToSecInt(int_id, is_secure_access))
600            {
601                if (irqNsacr[int_id] == 0) {
602                    // Group 0 or Secure Group 1 interrupts are RAZ/WI
603                    continue;
604                }
605            }
606
607            bool pending = data & (1 << i) ? 1 : 0;
608
609            if (pending) {
610                DPRINTF(GIC, "Gicv3Distributor::write() (GICD_ISPENDR): "
611                        "int_id %d (SPI) pending bit set\n", int_id);
612                irqPending[int_id] = true;
613            }
614        }
615
616        update();
617        return;
618    } else if (GICD_ICPENDR.contains(addr)) {
619        // Interrupt Clear-Pending Registers
620        int first_intid = (addr - GICD_ICPENDR.start()) * 8;
621
622        if (isNotSPI(first_intid)) {
623            return;
624        }
625
626        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
627             i++, int_id++) {
628
629            if (nsAccessToSecInt(int_id, is_secure_access))
630            {
631                if (irqNsacr[int_id] < 2) {
632                    // Group 0 or Secure Group 1 interrupts are RAZ/WI
633                    continue;
634                }
635            }
636
637            bool clear = data & (1 << i) ? 1 : 0;
638
639            if (clear) {
640                irqPending[int_id] = false;
641                clearIrqCpuInterface(int_id);
642            }
643        }
644
645        update();
646        return;
647    } else if (GICD_ISACTIVER.contains(addr)) {
648        // Interrupt Set-Active Registers
649        int first_intid = (addr - GICD_ISACTIVER.start()) * 8;
650
651        if (isNotSPI(first_intid)) {
652            return;
653        }
654
655        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
656             i++, int_id++) {
657
658            if (nsAccessToSecInt(int_id, is_secure_access))
659            {
660                continue;
661            }
662
663            bool active = data & (1 << i) ? 1 : 0;
664
665            if (active) {
666                irqActive[int_id] = 1;
667            }
668        }
669
670        return;
671    } else if (GICD_ICACTIVER.contains(addr)) {
672        // Interrupt Clear-Active Registers
673        int first_intid = (addr - GICD_ICACTIVER.start()) * 8;
674
675        if (isNotSPI(first_intid)) {
676            return;
677        }
678
679        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
680             i++, int_id++) {
681
682            if (nsAccessToSecInt(int_id, is_secure_access))
683            {
684                continue;
685            }
686
687            bool clear = data & (1 << i) ? 1 : 0;
688
689            if (clear) {
690                if (irqActive[int_id]) {
691                    DPRINTF(GIC, "Gicv3Distributor::write(): "
692                            "int_id %d active cleared\n", int_id);
693                }
694
695                irqActive[int_id] = false;
696            }
697        }
698
699        return;
700    } else if (GICD_IPRIORITYR.contains(addr)) {
701        // Interrupt Priority Registers
702        int first_intid = addr - GICD_IPRIORITYR.start();
703
704        if (isNotSPI(first_intid)) {
705            return;
706        }
707
708        for (int i = 0, int_id = first_intid; i < size && int_id < itLines;
709                i++, int_id++) {
710            uint8_t prio = bits(data, (i + 1) * 8 - 1, (i * 8));
711
712            if (!DS && !is_secure_access) {
713                if (getIntGroup(int_id) != Gicv3::G1NS) {
714                    // RAZ/WI for non-secure accesses to secure interrupts
715                    continue;
716                } else {
717                    prio = 0x80 | (prio >> 1);
718                }
719            }
720
721            irqPriority[int_id] = prio;
722            DPRINTF(GIC, "Gicv3Distributor::write(): int_id %d priority %d\n",
723                    int_id, irqPriority[int_id]);
724        }
725
726        return;
727    } else if (GICD_ITARGETSR.contains(addr)) {
728        // Interrupt Processor Targets Registers
729        // ARE always on, RAZ/WI
730        warn("Gicv3Distributor::write(): "
731             "GICD_ITARGETSR is RAZ/WI, legacy not supported!\n");
732        return;
733    } else if (GICD_ICFGR.contains(addr)) {
734        // Interrupt Configuration Registers
735        // for x = 0 to 15:
736        //   GICD_ICFGR[2x] = RES0
737        //   GICD_ICFGR[2x + 1] =
738        //     0 level-sensitive
739        //     1 edge-triggered
740        int first_intid = (addr - GICD_ICFGR.start()) * 4;
741
742        if (isNotSPI(first_intid)) {
743            return;
744        }
745
746        for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
747             i = i + 2, int_id++) {
748            irqConfig[int_id] = data & (0x2 << i) ?
749                                Gicv3::INT_EDGE_TRIGGERED :
750                                Gicv3::INT_LEVEL_SENSITIVE;
751            DPRINTF(GIC, "Gicv3Distributor::write(): int_id %d config %d\n",
752                    int_id, irqConfig[int_id]);
753        }
754
755        return;
756    } else if (GICD_IGRPMODR.contains(addr)) {
757        // Interrupt Group Modifier Registers
758        if (DS) {
759            return;
760        } else {
761            if (!is_secure_access) {
762                // RAZ/WI for non-secure accesses
763                return;
764            } else {
765                int first_intid = (addr - GICD_IGRPMODR.start()) * 8;
766
767                if (isNotSPI(first_intid)) {
768                    return;
769                }
770
771                for (int i = 0, int_id = first_intid;
772                     i < 8 * size && int_id < itLines; i++, int_id++) {
773                    irqGrpmod[int_id] = bits(data, i);
774                }
775
776                return ;
777            }
778        }
779
780    } else if (GICD_NSACR.contains(addr)) {
781        // Non-secure Access Control Registers
782        // 2 bits per interrupt
783        int first_intid = (addr - GICD_NSACR.start()) * 4;
784
785        if (isNotSPI(first_intid)) {
786            return;
787        }
788
789        if (DS || (!DS && !is_secure_access)) {
790            return;
791        }
792
793        for (int i = 0, int_id = first_intid;
794             i < 8 * size && int_id < itLines; i = i + 2, int_id++) {
795            irqNsacr[int_id] = (data >> (2 * int_id)) & 0x3;
796        }
797
798        return;
799    } else if (GICD_IROUTER.contains(addr)) { // Interrupt Routing Registers
800        // 64 bit registers. 2 accesses.
801        int int_id = (addr - GICD_IROUTER.start()) / 8;
802
803        if (isNotSPI(int_id)) {
804            return;
805        }
806
807        if (nsAccessToSecInt(int_id, is_secure_access))
808        {
809            if (irqNsacr[int_id] < 3) {
810                // Group 0 or Secure Group 1 interrupts are RAZ/WI
811                return;
812            }
813        }
814
815        if (size == 4) {
816            if (addr & 7) { // high half of 64 bit register
817                irqAffinityRouting[int_id] =
818                    (irqAffinityRouting[int_id] & 0xffffffff) | (data << 32);
819            } else { // low half of 64 bit register
820                irqAffinityRouting[int_id] =
821                    (irqAffinityRouting[int_id] & 0xffffffff00000000) |
822                    (data & 0xffffffff);
823            }
824        } else {
825            irqAffinityRouting[int_id] = data;
826        }
827
828        DPRINTF(GIC, "Gicv3Distributor::write(): "
829                "int_id %d GICD_IROUTER %#llx\n",
830                int_id, irqAffinityRouting[int_id]);
831        return;
832    }
833
834    switch (addr) {
835      case GICD_CTLR: // Control Register
836        if (DS) {
837            /*
838             * E1NWF [7]
839             * 1 of N wakeup functionality not supported, RAZ/WI
840             * DS [6] - RAO/WI
841             * ARE [4]
842             * affinity routing always on, no GICv2 legacy, RAO/WI
843             * EnableGrp1 [1]
844             * EnableGrp0 [0]
845             */
846            if ((data & (1 << 4)) == 0) {
847                warn("Gicv3Distributor::write(): "
848                        "setting ARE to 0 is not supported!\n");
849            }
850
851            EnableGrp1NS = data & GICD_CTLR_ENABLEGRP1NS;
852            EnableGrp0 = data & GICD_CTLR_ENABLEGRP0;
853            DPRINTF(GIC, "Gicv3Distributor::write(): (DS 1)"
854                    "EnableGrp1NS %d EnableGrp0 %d\n",
855                    EnableGrp1NS, EnableGrp0);
856        } else {
857            if (is_secure_access) {
858                /*
859                 * E1NWF [7]
860                 * 1 of N wakeup functionality not supported, RAZ/WI
861                 * DS [6]
862                 * ARE_NS [5]
863                 * affinity routing always on, no GICv2 legacy, RAO/WI
864                 * ARE_S [4]
865                 * affinity routing always on, no GICv2 legacy, RAO/WI
866                 * EnableGrp1S [2]
867                 * EnableGrp1NS [1]
868                 * EnableGrp0 [0]
869                 */
870                if ((data & (1 << 5)) == 0) {
871                    warn("Gicv3Distributor::write(): "
872                            "setting ARE_NS to 0 is not supported!\n");
873                }
874
875                if ((data & (1 << 4)) == 0) {
876                    warn("Gicv3Distributor::write(): "
877                            "setting ARE_S to 0 is not supported!\n");
878                }
879
880                DS = data & GICD_CTLR_DS;
881                EnableGrp1S = data & GICD_CTLR_ENABLEGRP1S;
882                EnableGrp1NS = data & GICD_CTLR_ENABLEGRP1NS;
883                EnableGrp0 = data & GICD_CTLR_ENABLEGRP0;
884                DPRINTF(GIC, "Gicv3Distributor::write(): (DS 0 secure)"
885                        "DS %d "
886                        "EnableGrp1S %d EnableGrp1NS %d EnableGrp0 %d\n",
887                        DS, EnableGrp1S, EnableGrp1NS, EnableGrp0);
888
889                if (data & GICD_CTLR_DS) {
890                    EnableGrp1S = 0;
891                }
892            } else {
893                /*
894                 * ARE_NS [4] RAO/WI;
895                 * EnableGrp1A [1] is a read-write alias of the Secure
896                 * GICD_CTLR.EnableGrp1NS
897                 * EnableGrp1 [0] RES0
898                 */
899                if ((data & (1 << 4)) == 0) {
900                    warn("Gicv3Distributor::write(): "
901                            "setting ARE_NS to 0 is not supported!\n");
902                }
903
904                EnableGrp1NS = data & GICD_CTLR_ENABLEGRP1A;
905                DPRINTF(GIC, "Gicv3Distributor::write(): (DS 0 non-secure)"
906                        "EnableGrp1NS %d\n", EnableGrp1NS);
907            }
908        }
909
910        update();
911
912        break;
913
914      case GICD_SGIR: // Error Reporting Status Register
915        // Only if affinity routing is disabled, RES0
916        break;
917
918      case GICD_SETSPI_NSR: {
919        // Writes to this register have no effect if:
920        // * The value written specifies an invalid SPI.
921        // * The SPI is already pending.
922        // * The value written specifies a Secure SPI, the value is
923        // written by a Non-secure access, and the value of the
924        // corresponding GICD_NSACR<n> register is 0.
925        const uint32_t intid = bits(data, 9, 0);
926        if (isNotSPI(intid) || irqPending[intid] ||
927            (nsAccessToSecInt(intid, is_secure_access) &&
928             irqNsacr[intid] == 0)) {
929            return;
930        } else {
931            // Valid SPI, set interrupt pending
932            sendInt(intid);
933        }
934        break;
935      }
936
937      case GICD_CLRSPI_NSR: {
938        // Writes to this register have no effect if:
939        // * The value written specifies an invalid SPI.
940        // * The SPI is not pending.
941        // * The value written specifies a Secure SPI, the value is
942        // written by a Non-secure access, and the value of the
943        // corresponding GICD_NSACR<n> register is less than 0b10.
944        const uint32_t intid = bits(data, 9, 0);
945        if (isNotSPI(intid) || !irqPending[intid] ||
946            (nsAccessToSecInt(intid, is_secure_access) &&
947             irqNsacr[intid] < 2)) {
948            return;
949        } else {
950            // Valid SPI, clear interrupt pending
951            deassertSPI(intid);
952        }
953        break;
954      }
955
956      case GICD_SETSPI_SR: {
957        // Writes to this register have no effect if:
958        // * GICD_CTLR.DS = 1 (WI)
959        // * The value written specifies an invalid SPI.
960        // * The SPI is already pending.
961        // * The value is written by a Non-secure access.
962        const uint32_t intid = bits(data, 9, 0);
963        if (DS || isNotSPI(intid) || irqPending[intid] || !is_secure_access) {
964            return;
965        } else {
966            // Valid SPI, set interrupt pending
967            sendInt(intid);
968        }
969        break;
970      }
971
972      case GICD_CLRSPI_SR: {
973        // Writes to this register have no effect if:
974        // * GICD_CTLR.DS = 1 (WI)
975        // * The value written specifies an invalid SPI.
976        // * The SPI is not pending.
977        // * The value is written by a Non-secure access.
978        const uint32_t intid = bits(data, 9, 0);
979        if (DS || isNotSPI(intid) || !irqPending[intid] || !is_secure_access) {
980            return;
981        } else {
982            // Valid SPI, clear interrupt pending
983            deassertSPI(intid);
984        }
985        break;
986      }
987
988      default:
989        panic("Gicv3Distributor::write(): invalid offset %#x\n", addr);
990        break;
991    }
992}
993
994void
995Gicv3Distributor::sendInt(uint32_t int_id)
996{
997    panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
998    panic_if(int_id > itLines, "Invalid SPI!");
999    irqPending[int_id] = true;
1000    DPRINTF(GIC, "Gicv3Distributor::sendInt(): "
1001            "int_id %d (SPI) pending bit set\n", int_id);
1002    update();
1003}
1004
1005void
1006Gicv3Distributor::deassertSPI(uint32_t int_id)
1007{
1008    panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
1009    panic_if(int_id > itLines, "Invalid SPI!");
1010    irqPending[int_id] = false;
1011    clearIrqCpuInterface(int_id);
1012
1013    update();
1014}
1015
1016Gicv3CPUInterface*
1017Gicv3Distributor::route(uint32_t int_id)
1018{
1019    IROUTER affinity_routing = irqAffinityRouting[int_id];
1020    Gicv3Redistributor * target_redistributor = nullptr;
1021
1022    const Gicv3::GroupId int_group = getIntGroup(int_id);
1023
1024    if (affinity_routing.IRM) {
1025        // Interrupts routed to any PE defined as a participating node
1026        for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
1027            Gicv3Redistributor * redistributor_i =
1028                gic->getRedistributor(i);
1029
1030            if (redistributor_i->
1031                    canBeSelectedFor1toNInterrupt(int_group)) {
1032                target_redistributor = redistributor_i;
1033                break;
1034            }
1035        }
1036    } else {
1037        uint32_t affinity = (affinity_routing.Aff3 << 24) |
1038                            (affinity_routing.Aff2 << 16) |
1039                            (affinity_routing.Aff1 << 8) |
1040                            (affinity_routing.Aff0 << 0);
1041        target_redistributor =
1042            gic->getRedistributorByAffinity(affinity);
1043    }
1044
1045    if (!target_redistributor) {
1046        // Interrrupts targeting not present cpus must remain pending
1047        return nullptr;
1048    } else {
1049        return target_redistributor->getCPUInterface();
1050    }
1051}
1052
1053void
1054Gicv3Distributor::clearIrqCpuInterface(uint32_t int_id)
1055{
1056    auto cpu_interface = route(int_id);
1057    if (cpu_interface)
1058        cpu_interface->resetHppi(int_id);
1059}
1060
1061void
1062Gicv3Distributor::update()
1063{
1064    // Find the highest priority pending SPI
1065    for (int int_id = Gicv3::SGI_MAX + Gicv3::PPI_MAX; int_id < itLines;
1066         int_id++) {
1067        Gicv3::GroupId int_group = getIntGroup(int_id);
1068        bool group_enabled = groupEnabled(int_group);
1069
1070        if (irqPending[int_id] && irqEnabled[int_id] &&
1071            !irqActive[int_id] && group_enabled) {
1072
1073            // Find the cpu interface where to route the interrupt
1074            Gicv3CPUInterface *target_cpu_interface = route(int_id);
1075
1076            // Invalid routing
1077            if (!target_cpu_interface) continue;
1078
1079            if ((irqPriority[int_id] < target_cpu_interface->hppi.prio) ||
1080                (irqPriority[int_id] == target_cpu_interface->hppi.prio &&
1081                int_id < target_cpu_interface->hppi.intid)) {
1082
1083                target_cpu_interface->hppi.intid = int_id;
1084                target_cpu_interface->hppi.prio = irqPriority[int_id];
1085                target_cpu_interface->hppi.group = int_group;
1086            }
1087        }
1088    }
1089
1090    // Update all redistributors
1091    for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
1092        gic->getRedistributor(i)->update();
1093    }
1094}
1095
1096Gicv3::IntStatus
1097Gicv3Distributor::intStatus(uint32_t int_id) const
1098{
1099    panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
1100    panic_if(int_id > itLines, "Invalid SPI!");
1101
1102    if (irqPending[int_id]) {
1103        if (irqActive[int_id]) {
1104            return Gicv3::INT_ACTIVE_PENDING;
1105        }
1106
1107        return Gicv3::INT_PENDING;
1108    } else if (irqActive[int_id]) {
1109        return Gicv3::INT_ACTIVE;
1110    } else {
1111        return Gicv3::INT_INACTIVE;
1112    }
1113}
1114
1115Gicv3::GroupId
1116Gicv3Distributor::getIntGroup(int int_id) const
1117{
1118    panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
1119    panic_if(int_id > itLines, "Invalid SPI!");
1120
1121    if (DS) {
1122        if (irqGroup[int_id] == 1) {
1123            return Gicv3::G1NS;
1124        } else {
1125            return Gicv3::G0S;
1126        }
1127    } else {
1128        if (irqGrpmod[int_id] == 0 && irqGroup[int_id] == 0) {
1129            return Gicv3::G0S;
1130        } else if (irqGrpmod[int_id] == 0 && irqGroup[int_id] == 1) {
1131            return Gicv3::G1NS;
1132        } else if (irqGrpmod[int_id] == 1 && irqGroup[int_id] == 0) {
1133            return Gicv3::G1S;
1134        } else if (irqGrpmod[int_id] == 1 && irqGroup[int_id] == 1) {
1135            return Gicv3::G1NS;
1136        }
1137    }
1138
1139    M5_UNREACHABLE;
1140}
1141
1142void
1143Gicv3Distributor::activateIRQ(uint32_t int_id)
1144{
1145    irqPending[int_id] = false;
1146    irqActive[int_id] = true;
1147}
1148
1149void
1150Gicv3Distributor::deactivateIRQ(uint32_t int_id)
1151{
1152    irqActive[int_id] = false;
1153}
1154
1155void
1156Gicv3Distributor::serialize(CheckpointOut & cp) const
1157{
1158    SERIALIZE_SCALAR(ARE);
1159    SERIALIZE_SCALAR(DS);
1160    SERIALIZE_SCALAR(EnableGrp1S);
1161    SERIALIZE_SCALAR(EnableGrp1NS);
1162    SERIALIZE_SCALAR(EnableGrp0);
1163    SERIALIZE_CONTAINER(irqGroup);
1164    SERIALIZE_CONTAINER(irqEnabled);
1165    SERIALIZE_CONTAINER(irqPending);
1166    SERIALIZE_CONTAINER(irqActive);
1167    SERIALIZE_CONTAINER(irqPriority);
1168    SERIALIZE_CONTAINER(irqConfig);
1169    SERIALIZE_CONTAINER(irqGrpmod);
1170    SERIALIZE_CONTAINER(irqNsacr);
1171    SERIALIZE_CONTAINER(irqAffinityRouting);
1172}
1173
1174void
1175Gicv3Distributor::unserialize(CheckpointIn & cp)
1176{
1177    UNSERIALIZE_SCALAR(ARE);
1178    UNSERIALIZE_SCALAR(DS);
1179    UNSERIALIZE_SCALAR(EnableGrp1S);
1180    UNSERIALIZE_SCALAR(EnableGrp1NS);
1181    UNSERIALIZE_SCALAR(EnableGrp0);
1182    UNSERIALIZE_CONTAINER(irqGroup);
1183    UNSERIALIZE_CONTAINER(irqEnabled);
1184    UNSERIALIZE_CONTAINER(irqPending);
1185    UNSERIALIZE_CONTAINER(irqActive);
1186    UNSERIALIZE_CONTAINER(irqPriority);
1187    UNSERIALIZE_CONTAINER(irqConfig);
1188    UNSERIALIZE_CONTAINER(irqGrpmod);
1189    UNSERIALIZE_CONTAINER(irqNsacr);
1190    UNSERIALIZE_CONTAINER(irqAffinityRouting);
1191}
1192