gic_v2.cc revision 13108:8e46a4e10f94
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        cpuEnabled[x] = false;
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        return 0; // unimplemented; RAZ (read as zero)
165    }
166
167    if (GICD_ISENABLER.contains(daddr)) {
168        uint32_t ix = (daddr - GICD_ISENABLER.start()) >> 2;
169        assert(ix < 32);
170        return getIntEnabled(ctx, ix);
171    }
172
173    if (GICD_ICENABLER.contains(daddr)) {
174        uint32_t ix = (daddr - GICD_ICENABLER.start()) >> 2;
175        assert(ix < 32);
176        return getIntEnabled(ctx, ix);
177    }
178
179    if (GICD_ISPENDR.contains(daddr)) {
180        uint32_t ix = (daddr - GICD_ISPENDR.start()) >> 2;
181        assert(ix < 32);
182        return getPendingInt(ctx, ix);
183    }
184
185    if (GICD_ICPENDR.contains(daddr)) {
186        uint32_t ix = (daddr - GICD_ICPENDR.start()) >> 2;
187        assert(ix < 32);
188        return getPendingInt(ctx, ix);
189    }
190
191    if (GICD_ISACTIVER.contains(daddr)) {
192        uint32_t ix = (daddr - GICD_ISACTIVER.start()) >> 2;
193        assert(ix < 32);
194        return getActiveInt(ctx, ix);
195    }
196
197    if (GICD_ICACTIVER.contains(daddr)) {
198        uint32_t ix = (daddr - GICD_ICACTIVER.start()) >> 2;
199        assert(ix < 32);
200        return getActiveInt(ctx, ix);
201    }
202
203    if (GICD_IPRIORITYR.contains(daddr)) {
204        Addr int_num = daddr - GICD_IPRIORITYR.start();
205        assert(int_num < INT_LINES_MAX);
206        DPRINTF(Interrupt, "Reading interrupt priority at int# %#x \n",
207                int_num);
208
209        switch (resp_sz) {
210          default: // will panic() after return to caller anyway
211          case 1:
212            return getIntPriority(ctx, int_num);
213          case 2:
214            assert((int_num + 1) < INT_LINES_MAX);
215            return (getIntPriority(ctx, int_num) |
216                    getIntPriority(ctx, int_num+1) << 8);
217          case 4:
218            assert((int_num + 3) < INT_LINES_MAX);
219            return (getIntPriority(ctx, int_num) |
220                    getIntPriority(ctx, int_num+1) << 8 |
221                    getIntPriority(ctx, int_num+2) << 16 |
222                    getIntPriority(ctx, int_num+3) << 24);
223        }
224    }
225
226    if (GICD_ITARGETSR.contains(daddr)) {
227        Addr int_num = daddr - GICD_ITARGETSR.start();
228        DPRINTF(GIC, "Reading processor target register for int# %#x \n",
229                 int_num);
230        assert(int_num < INT_LINES_MAX);
231
232        if (resp_sz == 1) {
233            return getCpuTarget(ctx, int_num);
234        } else {
235            assert(resp_sz == 4);
236            int_num = mbits(int_num, 31, 2);
237            return (getCpuTarget(ctx, int_num) |
238                    getCpuTarget(ctx, int_num+1) << 8 |
239                    getCpuTarget(ctx, int_num+2) << 16 |
240                    getCpuTarget(ctx, int_num+3) << 24) ;
241        }
242    }
243
244    if (GICD_ICFGR.contains(daddr)) {
245        uint32_t ix = (daddr - GICD_ICFGR.start()) >> 2;
246        assert(ix < 64);
247        /** @todo software generated interrupts and PPIs
248         * can't be configured in some ways */
249        return intConfig[ix];
250    }
251
252    switch(daddr) {
253      case GICD_CTLR:
254        return enabled;
255      case GICD_TYPER:
256        /* The 0x100 is a made-up flag to show that gem5 extensions
257         * are available,
258         * write 0x200 to this register to enable it.  */
259        return (((sys->numRunningContexts() - 1) << 5) |
260                (itLines/INT_BITS_MAX -1) |
261                (haveGem5Extensions ? 0x100 : 0x0));
262      case GICD_PIDR0:
263        //ARM defined DevID
264        return (GICD_400_PIDR_VALUE & 0xFF);
265      case GICD_PIDR1:
266        return ((GICD_400_PIDR_VALUE >> 8) & 0xFF);
267      case GICD_PIDR2:
268        return ((GICD_400_PIDR_VALUE >> 16) & 0xFF);
269      case GICD_PIDR3:
270        return ((GICD_400_PIDR_VALUE >> 24) & 0xFF);
271      case GICD_IIDR:
272         /* revision id is resorted to 1 and variant to 0*/
273        return GICD_400_IIDR_VALUE;
274      default:
275        panic("Tried to read Gic distributor at offset %#x\n", daddr);
276        break;
277    }
278}
279
280Tick
281GicV2::readCpu(PacketPtr pkt)
282{
283    const Addr daddr = pkt->getAddr() - cpuRange.start();
284
285    assert(pkt->req->hasContextId());
286    const ContextID ctx = pkt->req->contextId();
287    assert(ctx < sys->numRunningContexts());
288
289    DPRINTF(GIC, "gic cpu read register %#x cpu context: %d\n", daddr,
290            ctx);
291
292    pkt->set<uint32_t>(readCpu(ctx, daddr));
293
294    pkt->makeAtomicResponse();
295    return cpuPioDelay;
296}
297
298uint32_t
299GicV2::readCpu(ContextID ctx, Addr daddr)
300{
301    switch(daddr) {
302      case GICC_IIDR:
303        return GICC_400_IIDR_VALUE;
304      case GICC_CTLR:
305        return cpuEnabled[ctx];
306      case GICC_PMR:
307        return cpuPriority[ctx];
308      case GICC_BPR:
309        return cpuBpr[ctx];
310      case GICC_IAR:
311        if (enabled && cpuEnabled[ctx]) {
312            int active_int = cpuHighestInt[ctx];
313            IAR iar = 0;
314            iar.ack_id = active_int;
315            iar.cpu_id = 0;
316            if (active_int < SGI_MAX) {
317                // this is a software interrupt from another CPU
318                if (!gem5ExtensionsEnabled) {
319                    panic_if(!cpuSgiPending[active_int],
320                            "Interrupt %d active but no CPU generated it?\n",
321                            active_int);
322                    for (int x = 0; x < sys->numRunningContexts(); x++) {
323                        // See which CPU generated the interrupt
324                        uint8_t cpugen =
325                            bits(cpuSgiPending[active_int], 7 + 8 * x, 8 * x);
326                        if (cpugen & (1 << ctx)) {
327                            iar.cpu_id = x;
328                            break;
329                        }
330                    }
331                    uint64_t sgi_num = ULL(1) << (ctx + 8 * iar.cpu_id);
332                    cpuSgiActive[iar.ack_id] |= sgi_num;
333                    cpuSgiPending[iar.ack_id] &= ~sgi_num;
334                } else {
335                    uint64_t sgi_num = ULL(1) << iar.ack_id;
336                    cpuSgiActiveExt[ctx] |= sgi_num;
337                    cpuSgiPendingExt[ctx] &= ~sgi_num;
338                }
339            } else if (active_int < (SGI_MAX + PPI_MAX) ) {
340                uint32_t int_num = 1 << (cpuHighestInt[ctx] - SGI_MAX);
341                cpuPpiActive[ctx] |= int_num;
342                updateRunPri();
343                cpuPpiPending[ctx] &= ~int_num;
344
345            } else {
346                uint32_t int_num = 1 << intNumToBit(cpuHighestInt[ctx]);
347                getActiveInt(ctx, intNumToWord(cpuHighestInt[ctx])) |= int_num;
348                updateRunPri();
349                if (!isLevelSensitive(ctx, active_int)) {
350                    getPendingInt(ctx, intNumToWord(cpuHighestInt[ctx]))
351                      &= ~int_num;
352                }
353            }
354
355            DPRINTF(Interrupt,
356                    "CPU %d reading IAR.id=%d IAR.cpu=%d, iar=0x%x\n",
357                    ctx, iar.ack_id, iar.cpu_id, iar);
358            cpuHighestInt[ctx] = SPURIOUS_INT;
359            updateIntState(-1);
360            platform->intrctrl->clear(ctx, ArmISA::INT_IRQ, 0);
361            return iar;
362        } else {
363             return SPURIOUS_INT;
364        }
365
366        break;
367      case GICC_RPR:
368        return iccrpr[0];
369      case GICC_HPPIR:
370        panic("Need to implement HPIR");
371        break;
372      default:
373        panic("Tried to read Gic cpu at offset %#x\n", daddr);
374        break;
375    }
376}
377
378Tick
379GicV2::writeDistributor(PacketPtr pkt)
380{
381    const Addr daddr = pkt->getAddr() - distRange.start();
382
383    assert(pkt->req->hasContextId());
384    const ContextID ctx = pkt->req->contextId();
385    const size_t data_sz = pkt->getSize();
386
387    uint32_t pkt_data M5_VAR_USED;
388    switch (data_sz)
389    {
390      case 1:
391        pkt_data = pkt->get<uint8_t>();
392        break;
393      case 2:
394        pkt_data = pkt->get<uint16_t>();
395        break;
396      case 4:
397        pkt_data = pkt->get<uint32_t>();
398        break;
399      default:
400        panic("Invalid size when writing to priority regs in Gic: %d\n",
401              data_sz);
402    }
403
404    DPRINTF(GIC, "gic distributor write register %#x size %#x value %#x \n",
405            daddr, data_sz, pkt_data);
406
407    writeDistributor(ctx, daddr, pkt_data, data_sz);
408
409    pkt->makeAtomicResponse();
410    return distPioDelay;
411}
412
413void
414GicV2::writeDistributor(ContextID ctx, Addr daddr, uint32_t data,
415                        size_t data_sz)
416{
417    if (GICD_IGROUPR.contains(daddr)) {
418        return; // unimplemented; WI (writes ignored)
419    }
420
421    if (GICD_ISENABLER.contains(daddr)) {
422        uint32_t ix = (daddr - GICD_ISENABLER.start()) >> 2;
423        assert(ix < 32);
424        getIntEnabled(ctx, ix) |= data;
425        return;
426    }
427
428    if (GICD_ICENABLER.contains(daddr)) {
429        uint32_t ix = (daddr - GICD_ICENABLER.start()) >> 2;
430        assert(ix < 32);
431        getIntEnabled(ctx, ix) &= ~data;
432        return;
433    }
434
435    if (GICD_ISPENDR.contains(daddr)) {
436        uint32_t ix = (daddr - GICD_ISPENDR.start()) >> 2;
437        auto mask = data;
438        if (ix == 0) mask &= SGI_MASK; // Don't allow SGIs to be changed
439        getPendingInt(ctx, ix) |= mask;
440        updateIntState(ix);
441        return;
442    }
443
444    if (GICD_ICPENDR.contains(daddr)) {
445        uint32_t ix = (daddr - GICD_ICPENDR.start()) >> 2;
446        auto mask = data;
447        if (ix == 0) mask &= SGI_MASK; // Don't allow SGIs to be changed
448        getPendingInt(ctx, ix) &= ~mask;
449        updateIntState(ix);
450        return;
451    }
452
453    if (GICD_ISACTIVER.contains(daddr)) {
454        uint32_t ix = (daddr - GICD_ISACTIVER.start()) >> 2;
455        getActiveInt(ctx, ix) |= data;
456        return;
457    }
458
459    if (GICD_ICACTIVER.contains(daddr)) {
460        uint32_t ix = (daddr - GICD_ICACTIVER.start()) >> 2;
461        getActiveInt(ctx, ix) &= ~data;
462        return;
463    }
464
465    if (GICD_IPRIORITYR.contains(daddr)) {
466        Addr int_num = daddr - GICD_IPRIORITYR.start();
467        switch(data_sz) {
468          case 1:
469            getIntPriority(ctx, int_num) = data;
470            break;
471          case 2: {
472            getIntPriority(ctx, int_num) = bits(data, 7, 0);
473            getIntPriority(ctx, int_num + 1) = bits(data, 15, 8);
474            break;
475          }
476          case 4: {
477            getIntPriority(ctx, int_num) = bits(data, 7, 0);
478            getIntPriority(ctx, int_num + 1) = bits(data, 15, 8);
479            getIntPriority(ctx, int_num + 2) = bits(data, 23, 16);
480            getIntPriority(ctx, int_num + 3) = bits(data, 31, 24);
481            break;
482          }
483          default:
484            panic("Invalid size when writing to priority regs in Gic: %d\n",
485                   data_sz);
486        }
487
488        updateIntState(-1);
489        updateRunPri();
490        return;
491    }
492
493    if (GICD_ITARGETSR.contains(daddr)) {
494        Addr int_num = daddr - GICD_ITARGETSR.start();
495        // Interrupts 0-31 are read only
496        unsigned offset = SGI_MAX + PPI_MAX;
497        if (int_num >= offset) {
498            unsigned ix = int_num - offset; // index into cpuTarget array
499            if (data_sz == 1) {
500                cpuTarget[ix] = data & 0xff;
501            } else {
502                assert (data_sz == 4);
503                cpuTarget[ix]   = bits(data, 7, 0);
504                cpuTarget[ix+1] = bits(data, 15, 8);
505                cpuTarget[ix+2] = bits(data, 23, 16);
506                cpuTarget[ix+3] = bits(data, 31, 24);
507            }
508            updateIntState(int_num >> 2);
509        }
510        return;
511    }
512
513    if (GICD_ICFGR.contains(daddr)) {
514        uint32_t ix = (daddr - GICD_ICFGR.start()) >> 2;
515        assert(ix < INT_BITS_MAX*2);
516        intConfig[ix] = data;
517        if (data & NN_CONFIG_MASK)
518            warn("GIC N:N mode selected and not supported at this time\n");
519        return;
520    }
521
522    switch(daddr) {
523      case GICD_CTLR:
524        enabled = data;
525        DPRINTF(Interrupt, "Distributor enable flag set to = %d\n", enabled);
526        break;
527      case GICD_TYPER:
528        /* 0x200 is a made-up flag to enable gem5 extension functionality.
529         * This reg is not normally written.
530         */
531        gem5ExtensionsEnabled = (data & 0x200) && haveGem5Extensions;
532        DPRINTF(GIC, "gem5 extensions %s\n",
533                gem5ExtensionsEnabled ? "enabled" : "disabled");
534        break;
535      case GICD_SGIR:
536        softInt(ctx, data);
537        break;
538      default:
539        panic("Tried to write Gic distributor at offset %#x\n", daddr);
540        break;
541    }
542}
543
544Tick
545GicV2::writeCpu(PacketPtr pkt)
546{
547    const Addr daddr = pkt->getAddr() - cpuRange.start();
548
549    assert(pkt->req->hasContextId());
550    const ContextID ctx = pkt->req->contextId();
551    const uint32_t data = pkt->get<uint32_t>();
552
553    DPRINTF(GIC, "gic cpu write register cpu:%d %#x val: %#x\n",
554            ctx, daddr, data);
555
556    writeCpu(ctx, daddr, data);
557
558    pkt->makeAtomicResponse();
559    return cpuPioDelay;
560}
561
562void
563GicV2::writeCpu(ContextID ctx, Addr daddr, uint32_t data)
564{
565    switch(daddr) {
566      case GICC_CTLR:
567        cpuEnabled[ctx] = data;
568        break;
569      case GICC_PMR:
570        cpuPriority[ctx] = data;
571        break;
572      case GICC_BPR: {
573        auto bpr = data & 0x7;
574        if (bpr < GICC_BPR_MINIMUM)
575            bpr = GICC_BPR_MINIMUM;
576        cpuBpr[ctx] = bpr;
577        break;
578      }
579      case GICC_EOIR: {
580        const IAR iar = data;
581        if (iar.ack_id < SGI_MAX) {
582            // Clear out the bit that corresponds to the cleared int
583            uint64_t clr_int = ULL(1) << (ctx + 8 * iar.cpu_id);
584            if (!(cpuSgiActive[iar.ack_id] & clr_int) &&
585                !(cpuSgiActiveExt[ctx] & (1 << iar.ack_id)))
586                panic("Done handling a SGI that isn't active?\n");
587            if (gem5ExtensionsEnabled)
588                cpuSgiActiveExt[ctx] &= ~(1 << iar.ack_id);
589            else
590                cpuSgiActive[iar.ack_id] &= ~clr_int;
591        } else if (iar.ack_id < (SGI_MAX + PPI_MAX) ) {
592            uint32_t int_num = 1 << (iar.ack_id - SGI_MAX);
593            if (!(cpuPpiActive[ctx] & int_num))
594                panic("CPU %d Done handling a PPI interrupt "
595                      "that isn't active?\n", ctx);
596            cpuPpiActive[ctx] &= ~int_num;
597        } else {
598            uint32_t int_num = 1 << intNumToBit(iar.ack_id);
599            if (!(getActiveInt(ctx, intNumToWord(iar.ack_id)) & int_num))
600                warn("Done handling interrupt that isn't active: %d\n",
601                      intNumToBit(iar.ack_id));
602            getActiveInt(ctx, intNumToWord(iar.ack_id)) &= ~int_num;
603        }
604        updateRunPri();
605        DPRINTF(Interrupt, "CPU %d done handling intr IAR = %d from cpu %d\n",
606                ctx, iar.ack_id, iar.cpu_id);
607        break;
608      }
609      case GICC_APR0:
610      case GICC_APR1:
611      case GICC_APR2:
612      case GICC_APR3:
613        warn("GIC APRn write ignored because not implemented: %#x\n", daddr);
614        break;
615      default:
616        panic("Tried to write Gic cpu at offset %#x\n", daddr);
617        break;
618    }
619    if (cpuEnabled[ctx]) updateIntState(-1);
620}
621
622GicV2::BankedRegs&
623GicV2::getBankedRegs(ContextID ctx) {
624    if (bankedRegs.size() <= ctx)
625        bankedRegs.resize(ctx + 1);
626
627    if (!bankedRegs[ctx])
628        bankedRegs[ctx] = new BankedRegs;
629    return *bankedRegs[ctx];
630}
631
632void
633GicV2::softInt(ContextID ctx, SWI swi)
634{
635    if (gem5ExtensionsEnabled) {
636        switch (swi.list_type) {
637          case 0: {
638             // interrupt cpus specified
639             int dest = swi.cpu_list;
640             DPRINTF(IPI, "Generating softIRQ from CPU %d for CPU %d\n",
641                    ctx, dest);
642             if (cpuEnabled[dest]) {
643                 cpuSgiPendingExt[dest] |= (1 << swi.sgi_id);
644                 DPRINTF(IPI, "SGI[%d]=%#x\n", dest,
645                         cpuSgiPendingExt[dest]);
646             }
647          } break;
648          case 1: {
649             // interrupt all
650             for (int i = 0; i < sys->numContexts(); i++) {
651                 DPRINTF(IPI, "Processing CPU %d\n", i);
652                 if (!cpuEnabled[i])
653                     continue;
654                 cpuSgiPendingExt[i] |= 1 << swi.sgi_id;
655                 DPRINTF(IPI, "SGI[%d]=%#x\n", swi.sgi_id,
656                         cpuSgiPendingExt[i]);
657              }
658          } break;
659          case 2: {
660            // Interrupt requesting cpu only
661            DPRINTF(IPI, "Generating softIRQ from CPU %d for CPU %d\n",
662                    ctx, ctx);
663            if (cpuEnabled[ctx]) {
664                cpuSgiPendingExt[ctx] |= (1 << swi.sgi_id);
665                DPRINTF(IPI, "SGI[%d]=%#x\n", ctx,
666                        cpuSgiPendingExt[ctx]);
667            }
668          } break;
669        }
670    } else {
671        switch (swi.list_type) {
672          case 1:
673            // interrupt all
674            uint8_t cpu_list;
675            cpu_list = 0;
676            for (int x = 0; x < sys->numContexts(); x++)
677                cpu_list |= cpuEnabled[x] ? 1 << x : 0;
678            swi.cpu_list = cpu_list;
679            break;
680          case 2:
681            // interrupt requesting cpu only
682            swi.cpu_list = 1 << ctx;
683            break;
684            // else interrupt cpus specified
685        }
686
687        DPRINTF(IPI, "Generating softIRQ from CPU %d for %#x\n", ctx,
688                swi.cpu_list);
689        for (int i = 0; i < sys->numContexts(); i++) {
690            DPRINTF(IPI, "Processing CPU %d\n", i);
691            if (!cpuEnabled[i])
692                continue;
693            if (swi.cpu_list & (1 << i))
694                cpuSgiPending[swi.sgi_id] |= (1 << i) << (8 * ctx);
695            DPRINTF(IPI, "SGI[%d]=%#x\n", swi.sgi_id,
696                    cpuSgiPending[swi.sgi_id]);
697        }
698    }
699    updateIntState(-1);
700}
701
702uint64_t
703GicV2::genSwiMask(int cpu)
704{
705    if (cpu > sys->numContexts())
706        panic("Invalid CPU ID\n");
707    return ULL(0x0101010101010101) << cpu;
708}
709
710uint8_t
711GicV2::getCpuPriority(unsigned cpu)
712{
713    // see Table 3-2 in IHI0048B.b (GICv2)
714    // mask some low-order priority bits per BPR value
715    // NB: the GIC prioritization scheme is upside down:
716    // lower values are higher priority; masking off bits
717    // actually creates a higher priority, not lower.
718    return cpuPriority[cpu] & (0xff00 >> (7 - cpuBpr[cpu]));
719}
720
721void
722GicV2::updateIntState(int hint)
723{
724    for (int cpu = 0; cpu < sys->numContexts(); cpu++) {
725        if (!cpuEnabled[cpu])
726            continue;
727
728        /*@todo use hint to do less work. */
729        int highest_int = SPURIOUS_INT;
730        // Priorities below that set in GICC_PMR can be ignored
731        uint8_t highest_pri = getCpuPriority(cpu);
732
733        // Check SGIs
734        for (int swi = 0; swi < SGI_MAX; swi++) {
735            if (!cpuSgiPending[swi] && !cpuSgiPendingExt[cpu])
736                continue;
737            if ((cpuSgiPending[swi] & genSwiMask(cpu)) ||
738                (cpuSgiPendingExt[cpu] & (1 << swi)))
739                if (highest_pri > getIntPriority(cpu, swi)) {
740                    highest_pri = getIntPriority(cpu, swi);
741                    highest_int = swi;
742                }
743        }
744
745        // Check PPIs
746        if (cpuPpiPending[cpu]) {
747            for (int ppi_idx = 0, int_num = SGI_MAX;
748                 int_num < PPI_MAX + SGI_MAX;
749                 ppi_idx++, int_num++) {
750
751                const bool ppi_pending = bits(cpuPpiPending[cpu], ppi_idx);
752                const bool ppi_enabled = bits(getIntEnabled(cpu, 0), int_num);
753                const bool higher_priority =
754                    highest_pri > getIntPriority(cpu, int_num);
755
756                if (ppi_pending && ppi_enabled && higher_priority) {
757                    highest_pri = getIntPriority(cpu, int_num);
758                    highest_int = int_num;
759                }
760            }
761        }
762
763        bool mp_sys = sys->numRunningContexts() > 1;
764        // Check other ints
765        for (int x = 0; x < (itLines/INT_BITS_MAX); x++) {
766            if (getIntEnabled(cpu, x) & getPendingInt(cpu, x)) {
767                for (int y = 0; y < INT_BITS_MAX; y++) {
768                   uint32_t int_nm = x * INT_BITS_MAX + y;
769                   DPRINTF(GIC, "Checking for interrupt# %d \n",int_nm);
770                    /* Set current pending int as highest int for current cpu
771                       if the interrupt's priority higher than current priority
772                       and if current cpu is the target (for mp configs only)
773                     */
774                    if ((bits(getIntEnabled(cpu, x), y)
775                        &bits(getPendingInt(cpu, x), y)) &&
776                        (getIntPriority(cpu, int_nm) < highest_pri))
777                        if ((!mp_sys) ||
778                            (gem5ExtensionsEnabled
779                               ? (getCpuTarget(cpu, int_nm) == cpu)
780                               : (getCpuTarget(cpu, int_nm) & (1 << cpu)))) {
781                            highest_pri = getIntPriority(cpu, int_nm);
782                            highest_int = int_nm;
783                        }
784                }
785            }
786        }
787
788        uint32_t prev_highest = cpuHighestInt[cpu];
789        cpuHighestInt[cpu] = highest_int;
790
791        if (highest_int == SPURIOUS_INT) {
792            if (isLevelSensitive(cpu, prev_highest)) {
793
794                DPRINTF(Interrupt, "Clear IRQ for cpu%d\n", cpu);
795                platform->intrctrl->clear(cpu, ArmISA::INT_IRQ, 0);
796            }
797            continue;
798        }
799
800        /* @todo make this work for more than one cpu, need to handle 1:N, N:N
801         * models */
802        if (enabled && cpuEnabled[cpu] &&
803            (highest_pri < getCpuPriority(cpu)) &&
804            !(getActiveInt(cpu, intNumToWord(highest_int))
805              & (1 << intNumToBit(highest_int)))) {
806
807            DPRINTF(Interrupt, "Posting interrupt %d to cpu%d\n", highest_int,
808                    cpu);
809            postInt(cpu, curTick() + intLatency);
810        }
811    }
812}
813
814void
815GicV2::updateRunPri()
816{
817    for (int cpu = 0; cpu < sys->numContexts(); cpu++) {
818        if (!cpuEnabled[cpu])
819            continue;
820        uint8_t maxPriority = 0xff;
821        for (int i = 0; i < itLines; i++) {
822            if (i < SGI_MAX) {
823                if (((cpuSgiActive[i] & genSwiMask(cpu)) ||
824                     (cpuSgiActiveExt[cpu] & (1 << i))) &&
825                        (getIntPriority(cpu, i) < maxPriority))
826                    maxPriority = getIntPriority(cpu, i);
827            } else if (i < (SGI_MAX + PPI_MAX)) {
828                if ((cpuPpiActive[cpu] & ( 1 << (i - SGI_MAX))) &&
829                        (getIntPriority(cpu, i) < maxPriority))
830                    maxPriority = getIntPriority(cpu, i);
831
832            } else {
833                if (getActiveInt(cpu, intNumToWord(i))
834                    & (1 << intNumToBit(i)))
835                    if (getIntPriority(cpu, i) < maxPriority)
836                        maxPriority = getIntPriority(cpu, i);
837            }
838        }
839        iccrpr[cpu] = maxPriority;
840    }
841}
842
843void
844GicV2::sendInt(uint32_t num)
845{
846    uint8_t target = getCpuTarget(0, num);
847    DPRINTF(Interrupt, "Received Interrupt number %d,  cpuTarget %#x: \n",
848            num, target);
849    if ((target & (target - 1)) && !gem5ExtensionsEnabled)
850        panic("Multiple targets for peripheral interrupts is not supported\n");
851    panic_if(num < SGI_MAX + PPI_MAX,
852             "sentInt() must only be used for interrupts 32 and higher");
853    getPendingInt(target, intNumToWord(num)) |= 1 << intNumToBit(num);
854    updateIntState(intNumToWord(num));
855}
856
857void
858GicV2::sendPPInt(uint32_t num, uint32_t cpu)
859{
860    DPRINTF(Interrupt, "Received PPI %d, cpuTarget %#x: \n",
861            num, cpu);
862    cpuPpiPending[cpu] |= 1 << (num - SGI_MAX);
863    updateIntState(intNumToWord(num));
864}
865
866void
867GicV2::clearInt(uint32_t num)
868{
869    if (isLevelSensitive(0, num)) {
870        uint8_t target = getCpuTarget(0, num);
871
872        DPRINTF(Interrupt,
873                "Received Clear interrupt number %d, cpuTarget %#x:\n",
874                num, target);
875
876        getPendingInt(target, intNumToWord(num)) &= ~(1 << intNumToBit(num));
877        updateIntState(intNumToWord(num));
878    } else {
879        /* Nothing to do :
880         * Edge-triggered interrupt remain pending until software
881         * writes GICD_ICPENDR or reads GICC_IAR */
882    }
883}
884
885void
886GicV2::clearPPInt(uint32_t num, uint32_t cpu)
887{
888    DPRINTF(Interrupt, "Clearing PPI %d, cpuTarget %#x: \n",
889            num, cpu);
890    cpuPpiPending[cpu] &= ~(1 << (num - SGI_MAX));
891    updateIntState(intNumToWord(num));
892}
893
894void
895GicV2::postInt(uint32_t cpu, Tick when)
896{
897    if (!(postIntEvent[cpu]->scheduled())) {
898        ++pendingDelayedInterrupts;
899        eventq->schedule(postIntEvent[cpu], when);
900    }
901}
902
903void
904GicV2::postDelayedInt(uint32_t cpu)
905{
906    platform->intrctrl->post(cpu, ArmISA::INT_IRQ, 0);
907    --pendingDelayedInterrupts;
908    assert(pendingDelayedInterrupts >= 0);
909    if (pendingDelayedInterrupts == 0)
910        signalDrainDone();
911}
912
913DrainState
914GicV2::drain()
915{
916    if (pendingDelayedInterrupts == 0) {
917        return DrainState::Drained;
918    } else {
919        return DrainState::Draining;
920    }
921}
922
923
924void
925GicV2::drainResume()
926{
927    // There may be pending interrupts if checkpointed from Kvm; post them.
928    updateIntState(-1);
929}
930
931void
932GicV2::serialize(CheckpointOut &cp) const
933{
934    DPRINTF(Checkpoint, "Serializing Arm GIC\n");
935
936    SERIALIZE_SCALAR(enabled);
937    SERIALIZE_SCALAR(itLines);
938    SERIALIZE_ARRAY(intEnabled, INT_BITS_MAX-1);
939    SERIALIZE_ARRAY(pendingInt, INT_BITS_MAX-1);
940    SERIALIZE_ARRAY(activeInt, INT_BITS_MAX-1);
941    SERIALIZE_ARRAY(iccrpr, CPU_MAX);
942    SERIALIZE_ARRAY(intPriority, GLOBAL_INT_LINES);
943    SERIALIZE_ARRAY(cpuTarget, GLOBAL_INT_LINES);
944    SERIALIZE_ARRAY(intConfig, INT_BITS_MAX * 2);
945    SERIALIZE_ARRAY(cpuEnabled, CPU_MAX);
946    SERIALIZE_ARRAY(cpuPriority, CPU_MAX);
947    SERIALIZE_ARRAY(cpuBpr, CPU_MAX);
948    SERIALIZE_ARRAY(cpuHighestInt, CPU_MAX);
949    SERIALIZE_ARRAY(cpuSgiActive, SGI_MAX);
950    SERIALIZE_ARRAY(cpuSgiPending, SGI_MAX);
951    SERIALIZE_ARRAY(cpuSgiActiveExt, CPU_MAX);
952    SERIALIZE_ARRAY(cpuSgiPendingExt, CPU_MAX);
953    SERIALIZE_ARRAY(cpuPpiActive, CPU_MAX);
954    SERIALIZE_ARRAY(cpuPpiPending, CPU_MAX);
955    SERIALIZE_SCALAR(gem5ExtensionsEnabled);
956
957    for (uint32_t i=0; i < bankedRegs.size(); ++i) {
958        if (!bankedRegs[i])
959            continue;
960        bankedRegs[i]->serializeSection(cp, csprintf("bankedRegs%i", i));
961    }
962}
963
964void
965GicV2::BankedRegs::serialize(CheckpointOut &cp) const
966{
967    SERIALIZE_SCALAR(intEnabled);
968    SERIALIZE_SCALAR(pendingInt);
969    SERIALIZE_SCALAR(activeInt);
970    SERIALIZE_ARRAY(intPriority, SGI_MAX + PPI_MAX);
971}
972
973void
974GicV2::unserialize(CheckpointIn &cp)
975{
976    DPRINTF(Checkpoint, "Unserializing Arm GIC\n");
977
978    UNSERIALIZE_SCALAR(enabled);
979    UNSERIALIZE_SCALAR(itLines);
980    UNSERIALIZE_ARRAY(intEnabled, INT_BITS_MAX-1);
981    UNSERIALIZE_ARRAY(pendingInt, INT_BITS_MAX-1);
982    UNSERIALIZE_ARRAY(activeInt, INT_BITS_MAX-1);
983    UNSERIALIZE_ARRAY(iccrpr, CPU_MAX);
984    UNSERIALIZE_ARRAY(intPriority, GLOBAL_INT_LINES);
985    UNSERIALIZE_ARRAY(cpuTarget, GLOBAL_INT_LINES);
986    UNSERIALIZE_ARRAY(intConfig, INT_BITS_MAX * 2);
987    UNSERIALIZE_ARRAY(cpuEnabled, CPU_MAX);
988    UNSERIALIZE_ARRAY(cpuPriority, CPU_MAX);
989    UNSERIALIZE_ARRAY(cpuBpr, CPU_MAX);
990    UNSERIALIZE_ARRAY(cpuHighestInt, CPU_MAX);
991    UNSERIALIZE_ARRAY(cpuSgiActive, SGI_MAX);
992    UNSERIALIZE_ARRAY(cpuSgiPending, SGI_MAX);
993    UNSERIALIZE_ARRAY(cpuSgiActiveExt, CPU_MAX);
994    UNSERIALIZE_ARRAY(cpuSgiPendingExt, CPU_MAX);
995    UNSERIALIZE_ARRAY(cpuPpiActive, CPU_MAX);
996    UNSERIALIZE_ARRAY(cpuPpiPending, CPU_MAX);
997
998    // Handle checkpoints from before we drained the GIC to prevent
999    // in-flight interrupts.
1000    if (cp.entryExists(Serializable::currentSection(), "interrupt_time")) {
1001        Tick interrupt_time[CPU_MAX];
1002        UNSERIALIZE_ARRAY(interrupt_time, CPU_MAX);
1003
1004        for (uint32_t cpu = 0; cpu < CPU_MAX; cpu++) {
1005            if (interrupt_time[cpu])
1006                schedule(postIntEvent[cpu], interrupt_time[cpu]);
1007        }
1008    }
1009
1010    if (!UNSERIALIZE_OPT_SCALAR(gem5ExtensionsEnabled))
1011        gem5ExtensionsEnabled = false;
1012
1013    for (uint32_t i=0; i < CPU_MAX; ++i) {
1014        ScopedCheckpointSection sec(cp, csprintf("bankedRegs%i", i));
1015        if (cp.sectionExists(Serializable::currentSection())) {
1016            getBankedRegs(i).unserialize(cp);
1017        }
1018    }
1019}
1020
1021void
1022GicV2::BankedRegs::unserialize(CheckpointIn &cp)
1023{
1024    UNSERIALIZE_SCALAR(intEnabled);
1025    UNSERIALIZE_SCALAR(pendingInt);
1026    UNSERIALIZE_SCALAR(activeInt);
1027    UNSERIALIZE_ARRAY(intPriority, SGI_MAX + PPI_MAX);
1028}
1029
1030GicV2 *
1031GicV2Params::create()
1032{
1033    return new GicV2(this);
1034}
1035