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