gic_v2.cc revision 13110
1/*
2 * Copyright (c) 2010, 2013, 2015-2018 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Ali Saidi
41 *          Prakash Ramrakhyani
42 */
43
44#include "dev/arm/gic_v2.hh"
45
46#include "base/trace.hh"
47#include "debug/Checkpoint.hh"
48#include "debug/GIC.hh"
49#include "debug/IPI.hh"
50#include "debug/Interrupt.hh"
51#include "mem/packet.hh"
52#include "mem/packet_access.hh"
53
54const AddrRange GicV2::GICD_IGROUPR   (0x080, 0x0ff);
55const AddrRange GicV2::GICD_ISENABLER (0x100, 0x17f);
56const AddrRange GicV2::GICD_ICENABLER (0x180, 0x1ff);
57const AddrRange GicV2::GICD_ISPENDR   (0x200, 0x27f);
58const AddrRange GicV2::GICD_ICPENDR   (0x280, 0x2ff);
59const AddrRange GicV2::GICD_ISACTIVER (0x300, 0x37f);
60const AddrRange GicV2::GICD_ICACTIVER (0x380, 0x3ff);
61const AddrRange GicV2::GICD_IPRIORITYR(0x400, 0x7ff);
62const AddrRange GicV2::GICD_ITARGETSR (0x800, 0xbff);
63const AddrRange GicV2::GICD_ICFGR     (0xc00, 0xcff);
64
65GicV2::GicV2(const Params *p)
66    : BaseGic(p),
67      distRange(RangeSize(p->dist_addr, DIST_SIZE)),
68      cpuRange(RangeSize(p->cpu_addr, p->cpu_size)),
69      addrRanges{distRange, cpuRange},
70      distPioDelay(p->dist_pio_delay),
71      cpuPioDelay(p->cpu_pio_delay), intLatency(p->int_latency),
72      enabled(false), haveGem5Extensions(p->gem5_extensions),
73      itLines(p->it_lines),
74      intEnabled {}, pendingInt {}, activeInt {},
75      intPriority {}, cpuTarget {}, intConfig {},
76      cpuSgiPending {}, cpuSgiActive {},
77      cpuSgiPendingExt {}, cpuSgiActiveExt {},
78      cpuPpiPending {}, cpuPpiActive {},
79      pendingDelayedInterrupts(0)
80{
81    for (int x = 0; x < CPU_MAX; x++) {
82        iccrpr[x] = 0xff;
83        cpuControl[x] = 0;
84        cpuPriority[x] = 0xff;
85        cpuBpr[x] = GICC_BPR_MINIMUM;
86        // Initialize cpu highest int
87        cpuHighestInt[x] = SPURIOUS_INT;
88        postIntEvent[x] =
89            new EventFunctionWrapper([this, x]{ postDelayedInt(x); },
90                                     "Post Interrupt to CPU");
91    }
92    DPRINTF(Interrupt, "cpuEnabled[0]=%d cpuEnabled[1]=%d\n", cpuEnabled(0),
93            cpuEnabled(1));
94
95    gem5ExtensionsEnabled = false;
96}
97
98GicV2::~GicV2()
99{
100    for (int x = 0; x < CPU_MAX; x++)
101        delete postIntEvent[x];
102}
103
104Tick
105GicV2::read(PacketPtr pkt)
106{
107    const Addr addr = pkt->getAddr();
108
109    if (distRange.contains(addr))
110        return readDistributor(pkt);
111    else if (cpuRange.contains(addr))
112        return readCpu(pkt);
113    else
114        panic("Read to unknown address %#x\n", pkt->getAddr());
115}
116
117
118Tick
119GicV2::write(PacketPtr pkt)
120{
121    const Addr addr = pkt->getAddr();
122
123    if (distRange.contains(addr))
124        return writeDistributor(pkt);
125    else if (cpuRange.contains(addr))
126        return writeCpu(pkt);
127    else
128        panic("Write to unknown address %#x\n", pkt->getAddr());
129}
130
131Tick
132GicV2::readDistributor(PacketPtr pkt)
133{
134    const Addr daddr = pkt->getAddr() - distRange.start();
135    const ContextID ctx = pkt->req->contextId();
136
137    DPRINTF(GIC, "gic distributor read register %#x\n", daddr);
138
139    const uint32_t resp = readDistributor(ctx, daddr, pkt->getSize());
140
141    switch (pkt->getSize()) {
142      case 1:
143        pkt->set<uint8_t>(resp);
144        break;
145      case 2:
146        pkt->set<uint16_t>(resp);
147        break;
148      case 4:
149        pkt->set<uint32_t>(resp);
150        break;
151      default:
152        panic("Invalid size while reading Distributor regs in GIC: %d\n",
153               pkt->getSize());
154    }
155
156    pkt->makeAtomicResponse();
157    return distPioDelay;
158}
159
160uint32_t
161GicV2::readDistributor(ContextID ctx, Addr daddr, size_t resp_sz)
162{
163    if (GICD_IGROUPR.contains(daddr)) {
164        uint32_t ix = (daddr - GICD_IGROUPR.start()) >> 2;
165        assert(ix < 32);
166        return getIntGroup(ctx, ix);
167    }
168
169    if (GICD_ISENABLER.contains(daddr)) {
170        uint32_t ix = (daddr - GICD_ISENABLER.start()) >> 2;
171        assert(ix < 32);
172        return getIntEnabled(ctx, ix);
173    }
174
175    if (GICD_ICENABLER.contains(daddr)) {
176        uint32_t ix = (daddr - GICD_ICENABLER.start()) >> 2;
177        assert(ix < 32);
178        return getIntEnabled(ctx, ix);
179    }
180
181    if (GICD_ISPENDR.contains(daddr)) {
182        uint32_t ix = (daddr - GICD_ISPENDR.start()) >> 2;
183        assert(ix < 32);
184        return getPendingInt(ctx, ix);
185    }
186
187    if (GICD_ICPENDR.contains(daddr)) {
188        uint32_t ix = (daddr - GICD_ICPENDR.start()) >> 2;
189        assert(ix < 32);
190        return getPendingInt(ctx, ix);
191    }
192
193    if (GICD_ISACTIVER.contains(daddr)) {
194        uint32_t ix = (daddr - GICD_ISACTIVER.start()) >> 2;
195        assert(ix < 32);
196        return getActiveInt(ctx, ix);
197    }
198
199    if (GICD_ICACTIVER.contains(daddr)) {
200        uint32_t ix = (daddr - GICD_ICACTIVER.start()) >> 2;
201        assert(ix < 32);
202        return getActiveInt(ctx, ix);
203    }
204
205    if (GICD_IPRIORITYR.contains(daddr)) {
206        Addr int_num = daddr - GICD_IPRIORITYR.start();
207        assert(int_num < INT_LINES_MAX);
208        DPRINTF(Interrupt, "Reading interrupt priority at int# %#x \n",
209                int_num);
210
211        switch (resp_sz) {
212          default: // will panic() after return to caller anyway
213          case 1:
214            return getIntPriority(ctx, int_num);
215          case 2:
216            assert((int_num + 1) < INT_LINES_MAX);
217            return (getIntPriority(ctx, int_num) |
218                    getIntPriority(ctx, int_num+1) << 8);
219          case 4:
220            assert((int_num + 3) < INT_LINES_MAX);
221            return (getIntPriority(ctx, int_num) |
222                    getIntPriority(ctx, int_num+1) << 8 |
223                    getIntPriority(ctx, int_num+2) << 16 |
224                    getIntPriority(ctx, int_num+3) << 24);
225        }
226    }
227
228    if (GICD_ITARGETSR.contains(daddr)) {
229        Addr int_num = daddr - GICD_ITARGETSR.start();
230        DPRINTF(GIC, "Reading processor target register for int# %#x \n",
231                 int_num);
232        assert(int_num < INT_LINES_MAX);
233
234        if (resp_sz == 1) {
235            return getCpuTarget(ctx, int_num);
236        } else {
237            assert(resp_sz == 4);
238            int_num = mbits(int_num, 31, 2);
239            return (getCpuTarget(ctx, int_num) |
240                    getCpuTarget(ctx, int_num+1) << 8 |
241                    getCpuTarget(ctx, int_num+2) << 16 |
242                    getCpuTarget(ctx, int_num+3) << 24) ;
243        }
244    }
245
246    if (GICD_ICFGR.contains(daddr)) {
247        uint32_t ix = (daddr - GICD_ICFGR.start()) >> 2;
248        assert(ix < 64);
249        /** @todo software generated interrupts and PPIs
250         * can't be configured in some ways */
251        return intConfig[ix];
252    }
253
254    switch(daddr) {
255      case GICD_CTLR:
256        return enabled;
257      case GICD_TYPER:
258        /* The 0x100 is a made-up flag to show that gem5 extensions
259         * are available,
260         * write 0x200 to this register to enable it.  */
261        return (((sys->numRunningContexts() - 1) << 5) |
262                (itLines/INT_BITS_MAX -1) |
263                (haveGem5Extensions ? 0x100 : 0x0));
264      case GICD_PIDR0:
265        //ARM defined DevID
266        return (GICD_400_PIDR_VALUE & 0xFF);
267      case GICD_PIDR1:
268        return ((GICD_400_PIDR_VALUE >> 8) & 0xFF);
269      case GICD_PIDR2:
270        return ((GICD_400_PIDR_VALUE >> 16) & 0xFF);
271      case GICD_PIDR3:
272        return ((GICD_400_PIDR_VALUE >> 24) & 0xFF);
273      case GICD_IIDR:
274         /* revision id is resorted to 1 and variant to 0*/
275        return GICD_400_IIDR_VALUE;
276      default:
277        panic("Tried to read Gic distributor at offset %#x\n", daddr);
278        break;
279    }
280}
281
282Tick
283GicV2::readCpu(PacketPtr pkt)
284{
285    const Addr daddr = pkt->getAddr() - cpuRange.start();
286
287    assert(pkt->req->hasContextId());
288    const ContextID ctx = pkt->req->contextId();
289    assert(ctx < sys->numRunningContexts());
290
291    DPRINTF(GIC, "gic cpu read register %#x cpu context: %d\n", daddr,
292            ctx);
293
294    pkt->set<uint32_t>(readCpu(ctx, daddr));
295
296    pkt->makeAtomicResponse();
297    return cpuPioDelay;
298}
299
300uint32_t
301GicV2::readCpu(ContextID ctx, Addr daddr)
302{
303    switch(daddr) {
304      case GICC_IIDR:
305        return GICC_400_IIDR_VALUE;
306      case GICC_CTLR:
307        return cpuControl[ctx];
308      case GICC_PMR:
309        return cpuPriority[ctx];
310      case GICC_BPR:
311        return cpuBpr[ctx];
312      case GICC_IAR:
313        if (enabled && cpuEnabled(ctx)) {
314            int active_int = cpuHighestInt[ctx];
315            IAR iar = 0;
316            iar.ack_id = active_int;
317            iar.cpu_id = 0;
318            if (active_int < SGI_MAX) {
319                // this is a software interrupt from another CPU
320                if (!gem5ExtensionsEnabled) {
321                    panic_if(!cpuSgiPending[active_int],
322                            "Interrupt %d active but no CPU generated it?\n",
323                            active_int);
324                    for (int x = 0; x < sys->numRunningContexts(); x++) {
325                        // See which CPU generated the interrupt
326                        uint8_t cpugen =
327                            bits(cpuSgiPending[active_int], 7 + 8 * x, 8 * x);
328                        if (cpugen & (1 << ctx)) {
329                            iar.cpu_id = x;
330                            break;
331                        }
332                    }
333                    uint64_t sgi_num = ULL(1) << (ctx + 8 * iar.cpu_id);
334                    cpuSgiActive[iar.ack_id] |= sgi_num;
335                    cpuSgiPending[iar.ack_id] &= ~sgi_num;
336                } else {
337                    uint64_t sgi_num = ULL(1) << iar.ack_id;
338                    cpuSgiActiveExt[ctx] |= sgi_num;
339                    cpuSgiPendingExt[ctx] &= ~sgi_num;
340                }
341            } else if (active_int < (SGI_MAX + PPI_MAX) ) {
342                uint32_t int_num = 1 << (cpuHighestInt[ctx] - SGI_MAX);
343                cpuPpiActive[ctx] |= int_num;
344                updateRunPri();
345                cpuPpiPending[ctx] &= ~int_num;
346
347            } else {
348                uint32_t int_num = 1 << intNumToBit(cpuHighestInt[ctx]);
349                getActiveInt(ctx, intNumToWord(cpuHighestInt[ctx])) |= int_num;
350                updateRunPri();
351                if (!isLevelSensitive(ctx, active_int)) {
352                    getPendingInt(ctx, intNumToWord(cpuHighestInt[ctx]))
353                      &= ~int_num;
354                }
355            }
356
357            DPRINTF(Interrupt,
358                    "CPU %d reading IAR.id=%d IAR.cpu=%d, iar=0x%x\n",
359                    ctx, iar.ack_id, iar.cpu_id, iar);
360            cpuHighestInt[ctx] = SPURIOUS_INT;
361            updateIntState(-1);
362            platform->intrctrl->clear(ctx, ArmISA::INT_IRQ, 0);
363            return iar;
364        } else {
365             return SPURIOUS_INT;
366        }
367
368        break;
369      case GICC_RPR:
370        return iccrpr[0];
371      case GICC_HPPIR:
372        panic("Need to implement HPIR");
373        break;
374      default:
375        panic("Tried to read Gic cpu at offset %#x\n", daddr);
376        break;
377    }
378}
379
380Tick
381GicV2::writeDistributor(PacketPtr pkt)
382{
383    const Addr daddr = pkt->getAddr() - distRange.start();
384
385    assert(pkt->req->hasContextId());
386    const ContextID ctx = pkt->req->contextId();
387    const size_t data_sz = pkt->getSize();
388
389    uint32_t pkt_data M5_VAR_USED;
390    switch (data_sz)
391    {
392      case 1:
393        pkt_data = pkt->get<uint8_t>();
394        break;
395      case 2:
396        pkt_data = pkt->get<uint16_t>();
397        break;
398      case 4:
399        pkt_data = pkt->get<uint32_t>();
400        break;
401      default:
402        panic("Invalid size when writing to priority regs in Gic: %d\n",
403              data_sz);
404    }
405
406    DPRINTF(GIC, "gic distributor write register %#x size %#x value %#x \n",
407            daddr, data_sz, pkt_data);
408
409    writeDistributor(ctx, daddr, pkt_data, data_sz);
410
411    pkt->makeAtomicResponse();
412    return distPioDelay;
413}
414
415void
416GicV2::writeDistributor(ContextID ctx, Addr daddr, uint32_t data,
417                        size_t data_sz)
418{
419    if (GICD_IGROUPR.contains(daddr)) {
420        uint32_t ix = (daddr - GICD_IGROUPR.start()) >> 2;
421        assert(ix < 32);
422        getIntGroup(ctx, ix) |= data;
423        return;
424    }
425
426    if (GICD_ISENABLER.contains(daddr)) {
427        uint32_t ix = (daddr - GICD_ISENABLER.start()) >> 2;
428        assert(ix < 32);
429        getIntEnabled(ctx, ix) |= data;
430        return;
431    }
432
433    if (GICD_ICENABLER.contains(daddr)) {
434        uint32_t ix = (daddr - GICD_ICENABLER.start()) >> 2;
435        assert(ix < 32);
436        getIntEnabled(ctx, ix) &= ~data;
437        return;
438    }
439
440    if (GICD_ISPENDR.contains(daddr)) {
441        uint32_t ix = (daddr - GICD_ISPENDR.start()) >> 2;
442        auto mask = data;
443        if (ix == 0) mask &= SGI_MASK; // Don't allow SGIs to be changed
444        getPendingInt(ctx, ix) |= mask;
445        updateIntState(ix);
446        return;
447    }
448
449    if (GICD_ICPENDR.contains(daddr)) {
450        uint32_t ix = (daddr - GICD_ICPENDR.start()) >> 2;
451        auto mask = data;
452        if (ix == 0) mask &= SGI_MASK; // Don't allow SGIs to be changed
453        getPendingInt(ctx, ix) &= ~mask;
454        updateIntState(ix);
455        return;
456    }
457
458    if (GICD_ISACTIVER.contains(daddr)) {
459        uint32_t ix = (daddr - GICD_ISACTIVER.start()) >> 2;
460        getActiveInt(ctx, ix) |= data;
461        return;
462    }
463
464    if (GICD_ICACTIVER.contains(daddr)) {
465        uint32_t ix = (daddr - GICD_ICACTIVER.start()) >> 2;
466        getActiveInt(ctx, ix) &= ~data;
467        return;
468    }
469
470    if (GICD_IPRIORITYR.contains(daddr)) {
471        Addr int_num = daddr - GICD_IPRIORITYR.start();
472        switch(data_sz) {
473          case 1:
474            getIntPriority(ctx, int_num) = data;
475            break;
476          case 2: {
477            getIntPriority(ctx, int_num) = bits(data, 7, 0);
478            getIntPriority(ctx, int_num + 1) = bits(data, 15, 8);
479            break;
480          }
481          case 4: {
482            getIntPriority(ctx, int_num) = bits(data, 7, 0);
483            getIntPriority(ctx, int_num + 1) = bits(data, 15, 8);
484            getIntPriority(ctx, int_num + 2) = bits(data, 23, 16);
485            getIntPriority(ctx, int_num + 3) = bits(data, 31, 24);
486            break;
487          }
488          default:
489            panic("Invalid size when writing to priority regs in Gic: %d\n",
490                   data_sz);
491        }
492
493        updateIntState(-1);
494        updateRunPri();
495        return;
496    }
497
498    if (GICD_ITARGETSR.contains(daddr)) {
499        Addr int_num = daddr - GICD_ITARGETSR.start();
500        // Interrupts 0-31 are read only
501        unsigned offset = SGI_MAX + PPI_MAX;
502        if (int_num >= offset) {
503            unsigned ix = int_num - offset; // index into cpuTarget array
504            if (data_sz == 1) {
505                cpuTarget[ix] = data & 0xff;
506            } else {
507                assert (data_sz == 4);
508                cpuTarget[ix]   = bits(data, 7, 0);
509                cpuTarget[ix+1] = bits(data, 15, 8);
510                cpuTarget[ix+2] = bits(data, 23, 16);
511                cpuTarget[ix+3] = bits(data, 31, 24);
512            }
513            updateIntState(int_num >> 2);
514        }
515        return;
516    }
517
518    if (GICD_ICFGR.contains(daddr)) {
519        uint32_t ix = (daddr - GICD_ICFGR.start()) >> 2;
520        assert(ix < INT_BITS_MAX*2);
521        intConfig[ix] = data;
522        if (data & NN_CONFIG_MASK)
523            warn("GIC N:N mode selected and not supported at this time\n");
524        return;
525    }
526
527    switch(daddr) {
528      case GICD_CTLR:
529        enabled = data;
530        DPRINTF(Interrupt, "Distributor enable flag set to = %d\n", enabled);
531        break;
532      case GICD_TYPER:
533        /* 0x200 is a made-up flag to enable gem5 extension functionality.
534         * This reg is not normally written.
535         */
536        gem5ExtensionsEnabled = (data & 0x200) && haveGem5Extensions;
537        DPRINTF(GIC, "gem5 extensions %s\n",
538                gem5ExtensionsEnabled ? "enabled" : "disabled");
539        break;
540      case GICD_SGIR:
541        softInt(ctx, data);
542        break;
543      default:
544        panic("Tried to write Gic distributor at offset %#x\n", daddr);
545        break;
546    }
547}
548
549Tick
550GicV2::writeCpu(PacketPtr pkt)
551{
552    const Addr daddr = pkt->getAddr() - cpuRange.start();
553
554    assert(pkt->req->hasContextId());
555    const ContextID ctx = pkt->req->contextId();
556    const uint32_t data = pkt->get<uint32_t>();
557
558    DPRINTF(GIC, "gic cpu write register cpu:%d %#x val: %#x\n",
559            ctx, daddr, data);
560
561    writeCpu(ctx, daddr, data);
562
563    pkt->makeAtomicResponse();
564    return cpuPioDelay;
565}
566
567void
568GicV2::writeCpu(ContextID ctx, Addr daddr, uint32_t data)
569{
570    switch(daddr) {
571      case GICC_CTLR:
572        cpuControl[ctx] = data;
573        break;
574      case GICC_PMR:
575        cpuPriority[ctx] = data;
576        break;
577      case GICC_BPR: {
578        auto bpr = data & 0x7;
579        if (bpr < GICC_BPR_MINIMUM)
580            bpr = GICC_BPR_MINIMUM;
581        cpuBpr[ctx] = bpr;
582        break;
583      }
584      case GICC_EOIR: {
585        const IAR iar = data;
586        if (iar.ack_id < SGI_MAX) {
587            // Clear out the bit that corresponds to the cleared int
588            uint64_t clr_int = ULL(1) << (ctx + 8 * iar.cpu_id);
589            if (!(cpuSgiActive[iar.ack_id] & clr_int) &&
590                !(cpuSgiActiveExt[ctx] & (1 << iar.ack_id)))
591                panic("Done handling a SGI that isn't active?\n");
592            if (gem5ExtensionsEnabled)
593                cpuSgiActiveExt[ctx] &= ~(1 << iar.ack_id);
594            else
595                cpuSgiActive[iar.ack_id] &= ~clr_int;
596        } else if (iar.ack_id < (SGI_MAX + PPI_MAX) ) {
597            uint32_t int_num = 1 << (iar.ack_id - SGI_MAX);
598            if (!(cpuPpiActive[ctx] & int_num))
599                panic("CPU %d Done handling a PPI interrupt "
600                      "that isn't active?\n", ctx);
601            cpuPpiActive[ctx] &= ~int_num;
602        } else {
603            uint32_t int_num = 1 << intNumToBit(iar.ack_id);
604            if (!(getActiveInt(ctx, intNumToWord(iar.ack_id)) & int_num))
605                warn("Done handling interrupt that isn't active: %d\n",
606                      intNumToBit(iar.ack_id));
607            getActiveInt(ctx, intNumToWord(iar.ack_id)) &= ~int_num;
608        }
609        updateRunPri();
610        DPRINTF(Interrupt, "CPU %d done handling intr IAR = %d from cpu %d\n",
611                ctx, iar.ack_id, iar.cpu_id);
612        break;
613      }
614      case GICC_APR0:
615      case GICC_APR1:
616      case GICC_APR2:
617      case GICC_APR3:
618        warn("GIC APRn write ignored because not implemented: %#x\n", daddr);
619        break;
620      default:
621        panic("Tried to write Gic cpu at offset %#x\n", daddr);
622        break;
623    }
624    if (cpuEnabled(ctx)) updateIntState(-1);
625}
626
627GicV2::BankedRegs&
628GicV2::getBankedRegs(ContextID ctx) {
629    if (bankedRegs.size() <= ctx)
630        bankedRegs.resize(ctx + 1);
631
632    if (!bankedRegs[ctx])
633        bankedRegs[ctx] = new BankedRegs;
634    return *bankedRegs[ctx];
635}
636
637void
638GicV2::softInt(ContextID ctx, SWI swi)
639{
640    if (gem5ExtensionsEnabled) {
641        switch (swi.list_type) {
642          case 0: {
643             // interrupt cpus specified
644             int dest = swi.cpu_list;
645             DPRINTF(IPI, "Generating softIRQ from CPU %d for CPU %d\n",
646                    ctx, dest);
647             if (cpuEnabled(dest)) {
648                 cpuSgiPendingExt[dest] |= (1 << swi.sgi_id);
649                 DPRINTF(IPI, "SGI[%d]=%#x\n", dest,
650                         cpuSgiPendingExt[dest]);
651             }
652          } break;
653          case 1: {
654             // interrupt all
655             for (int i = 0; i < sys->numContexts(); i++) {
656                 DPRINTF(IPI, "Processing CPU %d\n", i);
657                 if (!cpuEnabled(i))
658                     continue;
659                 cpuSgiPendingExt[i] |= 1 << swi.sgi_id;
660                 DPRINTF(IPI, "SGI[%d]=%#x\n", swi.sgi_id,
661                         cpuSgiPendingExt[i]);
662              }
663          } break;
664          case 2: {
665            // Interrupt requesting cpu only
666            DPRINTF(IPI, "Generating softIRQ from CPU %d for CPU %d\n",
667                    ctx, ctx);
668            if (cpuEnabled(ctx)) {
669                cpuSgiPendingExt[ctx] |= (1 << swi.sgi_id);
670                DPRINTF(IPI, "SGI[%d]=%#x\n", ctx,
671                        cpuSgiPendingExt[ctx]);
672            }
673          } break;
674        }
675    } else {
676        switch (swi.list_type) {
677          case 1:
678            // interrupt all
679            uint8_t cpu_list;
680            cpu_list = 0;
681            for (int x = 0; x < sys->numContexts(); x++)
682                cpu_list |= cpuEnabled(x) ? 1 << x : 0;
683            swi.cpu_list = cpu_list;
684            break;
685          case 2:
686            // interrupt requesting cpu only
687            swi.cpu_list = 1 << ctx;
688            break;
689            // else interrupt cpus specified
690        }
691
692        DPRINTF(IPI, "Generating softIRQ from CPU %d for %#x\n", ctx,
693                swi.cpu_list);
694        for (int i = 0; i < sys->numContexts(); i++) {
695            DPRINTF(IPI, "Processing CPU %d\n", i);
696            if (!cpuEnabled(i))
697                continue;
698            if (swi.cpu_list & (1 << i))
699                cpuSgiPending[swi.sgi_id] |= (1 << i) << (8 * ctx);
700            DPRINTF(IPI, "SGI[%d]=%#x\n", swi.sgi_id,
701                    cpuSgiPending[swi.sgi_id]);
702        }
703    }
704    updateIntState(-1);
705}
706
707uint64_t
708GicV2::genSwiMask(int cpu)
709{
710    if (cpu > sys->numContexts())
711        panic("Invalid CPU ID\n");
712    return ULL(0x0101010101010101) << cpu;
713}
714
715uint8_t
716GicV2::getCpuPriority(unsigned cpu)
717{
718    // see Table 3-2 in IHI0048B.b (GICv2)
719    // mask some low-order priority bits per BPR value
720    // NB: the GIC prioritization scheme is upside down:
721    // lower values are higher priority; masking off bits
722    // actually creates a higher priority, not lower.
723    return cpuPriority[cpu] & (0xff00 >> (7 - cpuBpr[cpu]));
724}
725
726void
727GicV2::updateIntState(int hint)
728{
729    for (int cpu = 0; cpu < sys->numContexts(); cpu++) {
730        if (!cpuEnabled(cpu))
731            continue;
732
733        /*@todo use hint to do less work. */
734        int highest_int = SPURIOUS_INT;
735        // Priorities below that set in GICC_PMR can be ignored
736        uint8_t highest_pri = getCpuPriority(cpu);
737
738        // Check SGIs
739        for (int swi = 0; swi < SGI_MAX; swi++) {
740            if (!cpuSgiPending[swi] && !cpuSgiPendingExt[cpu])
741                continue;
742            if ((cpuSgiPending[swi] & genSwiMask(cpu)) ||
743                (cpuSgiPendingExt[cpu] & (1 << swi)))
744                if (highest_pri > getIntPriority(cpu, swi)) {
745                    highest_pri = getIntPriority(cpu, swi);
746                    highest_int = swi;
747                }
748        }
749
750        // Check PPIs
751        if (cpuPpiPending[cpu]) {
752            for (int ppi_idx = 0, int_num = SGI_MAX;
753                 int_num < PPI_MAX + SGI_MAX;
754                 ppi_idx++, int_num++) {
755
756                const bool ppi_pending = bits(cpuPpiPending[cpu], ppi_idx);
757                const bool ppi_enabled = bits(getIntEnabled(cpu, 0), int_num);
758                const bool higher_priority =
759                    highest_pri > getIntPriority(cpu, int_num);
760
761                if (ppi_pending && ppi_enabled && higher_priority) {
762                    highest_pri = getIntPriority(cpu, int_num);
763                    highest_int = int_num;
764                }
765            }
766        }
767
768        bool mp_sys = sys->numRunningContexts() > 1;
769        // Check other ints
770        for (int x = 0; x < (itLines/INT_BITS_MAX); x++) {
771            if (getIntEnabled(cpu, x) & getPendingInt(cpu, x)) {
772                for (int y = 0; y < INT_BITS_MAX; y++) {
773                   uint32_t int_nm = x * INT_BITS_MAX + y;
774                   DPRINTF(GIC, "Checking for interrupt# %d \n",int_nm);
775                    /* Set current pending int as highest int for current cpu
776                       if the interrupt's priority higher than current priority
777                       and if current cpu is the target (for mp configs only)
778                     */
779                    if ((bits(getIntEnabled(cpu, x), y)
780                        &bits(getPendingInt(cpu, x), y)) &&
781                        (getIntPriority(cpu, int_nm) < highest_pri))
782                        if ((!mp_sys) ||
783                            (gem5ExtensionsEnabled
784                               ? (getCpuTarget(cpu, int_nm) == cpu)
785                               : (getCpuTarget(cpu, int_nm) & (1 << cpu)))) {
786                            highest_pri = getIntPriority(cpu, int_nm);
787                            highest_int = int_nm;
788                        }
789                }
790            }
791        }
792
793        uint32_t prev_highest = cpuHighestInt[cpu];
794        cpuHighestInt[cpu] = highest_int;
795
796        if (highest_int == SPURIOUS_INT) {
797            if (isLevelSensitive(cpu, prev_highest)) {
798
799                DPRINTF(Interrupt, "Clear IRQ for cpu%d\n", cpu);
800                platform->intrctrl->clear(cpu, ArmISA::INT_IRQ, 0);
801            }
802            continue;
803        }
804
805        /* @todo make this work for more than one cpu, need to handle 1:N, N:N
806         * models */
807        if (enabled && cpuEnabled(cpu) &&
808            (highest_pri < getCpuPriority(cpu)) &&
809            !(getActiveInt(cpu, intNumToWord(highest_int))
810              & (1 << intNumToBit(highest_int)))) {
811
812            DPRINTF(Interrupt, "Posting interrupt %d to cpu%d\n", highest_int,
813                    cpu);
814            postInt(cpu, curTick() + intLatency);
815        }
816    }
817}
818
819void
820GicV2::updateRunPri()
821{
822    for (int cpu = 0; cpu < sys->numContexts(); cpu++) {
823        if (!cpuEnabled(cpu))
824            continue;
825        uint8_t maxPriority = 0xff;
826        for (int i = 0; i < itLines; i++) {
827            if (i < SGI_MAX) {
828                if (((cpuSgiActive[i] & genSwiMask(cpu)) ||
829                     (cpuSgiActiveExt[cpu] & (1 << i))) &&
830                        (getIntPriority(cpu, i) < maxPriority))
831                    maxPriority = getIntPriority(cpu, i);
832            } else if (i < (SGI_MAX + PPI_MAX)) {
833                if ((cpuPpiActive[cpu] & ( 1 << (i - SGI_MAX))) &&
834                        (getIntPriority(cpu, i) < maxPriority))
835                    maxPriority = getIntPriority(cpu, i);
836
837            } else {
838                if (getActiveInt(cpu, intNumToWord(i))
839                    & (1 << intNumToBit(i)))
840                    if (getIntPriority(cpu, i) < maxPriority)
841                        maxPriority = getIntPriority(cpu, i);
842            }
843        }
844        iccrpr[cpu] = maxPriority;
845    }
846}
847
848void
849GicV2::sendInt(uint32_t num)
850{
851    uint8_t target = getCpuTarget(0, num);
852    DPRINTF(Interrupt, "Received Interrupt number %d,  cpuTarget %#x: \n",
853            num, target);
854    if ((target & (target - 1)) && !gem5ExtensionsEnabled)
855        panic("Multiple targets for peripheral interrupts is not supported\n");
856    panic_if(num < SGI_MAX + PPI_MAX,
857             "sentInt() must only be used for interrupts 32 and higher");
858    getPendingInt(target, intNumToWord(num)) |= 1 << intNumToBit(num);
859    updateIntState(intNumToWord(num));
860}
861
862void
863GicV2::sendPPInt(uint32_t num, uint32_t cpu)
864{
865    DPRINTF(Interrupt, "Received PPI %d, cpuTarget %#x: \n",
866            num, cpu);
867    cpuPpiPending[cpu] |= 1 << (num - SGI_MAX);
868    updateIntState(intNumToWord(num));
869}
870
871void
872GicV2::clearInt(uint32_t num)
873{
874    if (isLevelSensitive(0, num)) {
875        uint8_t target = getCpuTarget(0, num);
876
877        DPRINTF(Interrupt,
878                "Received Clear interrupt number %d, cpuTarget %#x:\n",
879                num, target);
880
881        getPendingInt(target, intNumToWord(num)) &= ~(1 << intNumToBit(num));
882        updateIntState(intNumToWord(num));
883    } else {
884        /* Nothing to do :
885         * Edge-triggered interrupt remain pending until software
886         * writes GICD_ICPENDR or reads GICC_IAR */
887    }
888}
889
890void
891GicV2::clearPPInt(uint32_t num, uint32_t cpu)
892{
893    DPRINTF(Interrupt, "Clearing PPI %d, cpuTarget %#x: \n",
894            num, cpu);
895    cpuPpiPending[cpu] &= ~(1 << (num - SGI_MAX));
896    updateIntState(intNumToWord(num));
897}
898
899void
900GicV2::postInt(uint32_t cpu, Tick when)
901{
902    if (!(postIntEvent[cpu]->scheduled())) {
903        ++pendingDelayedInterrupts;
904        eventq->schedule(postIntEvent[cpu], when);
905    }
906}
907
908void
909GicV2::postDelayedInt(uint32_t cpu)
910{
911    platform->intrctrl->post(cpu, ArmISA::INT_IRQ, 0);
912    --pendingDelayedInterrupts;
913    assert(pendingDelayedInterrupts >= 0);
914    if (pendingDelayedInterrupts == 0)
915        signalDrainDone();
916}
917
918DrainState
919GicV2::drain()
920{
921    if (pendingDelayedInterrupts == 0) {
922        return DrainState::Drained;
923    } else {
924        return DrainState::Draining;
925    }
926}
927
928
929void
930GicV2::drainResume()
931{
932    // There may be pending interrupts if checkpointed from Kvm; post them.
933    updateIntState(-1);
934}
935
936void
937GicV2::serialize(CheckpointOut &cp) const
938{
939    DPRINTF(Checkpoint, "Serializing Arm GIC\n");
940
941    SERIALIZE_SCALAR(enabled);
942    SERIALIZE_SCALAR(itLines);
943    SERIALIZE_ARRAY(intEnabled, INT_BITS_MAX-1);
944    SERIALIZE_ARRAY(pendingInt, INT_BITS_MAX-1);
945    SERIALIZE_ARRAY(activeInt, INT_BITS_MAX-1);
946    SERIALIZE_ARRAY(intGroup, INT_BITS_MAX-1);
947    SERIALIZE_ARRAY(iccrpr, CPU_MAX);
948    SERIALIZE_ARRAY(intPriority, GLOBAL_INT_LINES);
949    SERIALIZE_ARRAY(cpuTarget, GLOBAL_INT_LINES);
950    SERIALIZE_ARRAY(intConfig, INT_BITS_MAX * 2);
951    SERIALIZE_ARRAY(cpuControl, CPU_MAX);
952    SERIALIZE_ARRAY(cpuPriority, CPU_MAX);
953    SERIALIZE_ARRAY(cpuBpr, CPU_MAX);
954    SERIALIZE_ARRAY(cpuHighestInt, CPU_MAX);
955    SERIALIZE_ARRAY(cpuSgiActive, SGI_MAX);
956    SERIALIZE_ARRAY(cpuSgiPending, SGI_MAX);
957    SERIALIZE_ARRAY(cpuSgiActiveExt, CPU_MAX);
958    SERIALIZE_ARRAY(cpuSgiPendingExt, CPU_MAX);
959    SERIALIZE_ARRAY(cpuPpiActive, CPU_MAX);
960    SERIALIZE_ARRAY(cpuPpiPending, CPU_MAX);
961    SERIALIZE_SCALAR(gem5ExtensionsEnabled);
962
963    for (uint32_t i=0; i < bankedRegs.size(); ++i) {
964        if (!bankedRegs[i])
965            continue;
966        bankedRegs[i]->serializeSection(cp, csprintf("bankedRegs%i", i));
967    }
968}
969
970void
971GicV2::BankedRegs::serialize(CheckpointOut &cp) const
972{
973    SERIALIZE_SCALAR(intEnabled);
974    SERIALIZE_SCALAR(pendingInt);
975    SERIALIZE_SCALAR(activeInt);
976    SERIALIZE_SCALAR(intGroup);
977    SERIALIZE_ARRAY(intPriority, SGI_MAX + PPI_MAX);
978}
979
980void
981GicV2::unserialize(CheckpointIn &cp)
982{
983    DPRINTF(Checkpoint, "Unserializing Arm GIC\n");
984
985    UNSERIALIZE_SCALAR(enabled);
986    UNSERIALIZE_SCALAR(itLines);
987    UNSERIALIZE_ARRAY(intEnabled, INT_BITS_MAX-1);
988    UNSERIALIZE_ARRAY(pendingInt, INT_BITS_MAX-1);
989    UNSERIALIZE_ARRAY(activeInt, INT_BITS_MAX-1);
990    UNSERIALIZE_ARRAY(intGroup, INT_BITS_MAX-1);
991    UNSERIALIZE_ARRAY(iccrpr, CPU_MAX);
992    UNSERIALIZE_ARRAY(intPriority, GLOBAL_INT_LINES);
993    UNSERIALIZE_ARRAY(cpuTarget, GLOBAL_INT_LINES);
994    UNSERIALIZE_ARRAY(intConfig, INT_BITS_MAX * 2);
995    UNSERIALIZE_ARRAY(cpuControl, CPU_MAX);
996    UNSERIALIZE_ARRAY(cpuPriority, CPU_MAX);
997    UNSERIALIZE_ARRAY(cpuBpr, CPU_MAX);
998    UNSERIALIZE_ARRAY(cpuHighestInt, CPU_MAX);
999    UNSERIALIZE_ARRAY(cpuSgiActive, SGI_MAX);
1000    UNSERIALIZE_ARRAY(cpuSgiPending, SGI_MAX);
1001    UNSERIALIZE_ARRAY(cpuSgiActiveExt, CPU_MAX);
1002    UNSERIALIZE_ARRAY(cpuSgiPendingExt, CPU_MAX);
1003    UNSERIALIZE_ARRAY(cpuPpiActive, CPU_MAX);
1004    UNSERIALIZE_ARRAY(cpuPpiPending, CPU_MAX);
1005
1006    // Handle checkpoints from before we drained the GIC to prevent
1007    // in-flight interrupts.
1008    if (cp.entryExists(Serializable::currentSection(), "interrupt_time")) {
1009        Tick interrupt_time[CPU_MAX];
1010        UNSERIALIZE_ARRAY(interrupt_time, CPU_MAX);
1011
1012        for (uint32_t cpu = 0; cpu < CPU_MAX; cpu++) {
1013            if (interrupt_time[cpu])
1014                schedule(postIntEvent[cpu], interrupt_time[cpu]);
1015        }
1016    }
1017
1018    if (!UNSERIALIZE_OPT_SCALAR(gem5ExtensionsEnabled))
1019        gem5ExtensionsEnabled = false;
1020
1021    for (uint32_t i=0; i < CPU_MAX; ++i) {
1022        ScopedCheckpointSection sec(cp, csprintf("bankedRegs%i", i));
1023        if (cp.sectionExists(Serializable::currentSection())) {
1024            getBankedRegs(i).unserialize(cp);
1025        }
1026    }
1027}
1028
1029void
1030GicV2::BankedRegs::unserialize(CheckpointIn &cp)
1031{
1032    UNSERIALIZE_SCALAR(intEnabled);
1033    UNSERIALIZE_SCALAR(pendingInt);
1034    UNSERIALIZE_SCALAR(activeInt);
1035    UNSERIALIZE_SCALAR(intGroup);
1036    UNSERIALIZE_ARRAY(intPriority, SGI_MAX + PPI_MAX);
1037}
1038
1039GicV2 *
1040GicV2Params::create()
1041{
1042    return new GicV2(this);
1043}
1044