gic_v2.cc revision 13014:a4f71c3dc602
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 = 0; ppi < PPI_MAX; ppi++) {
746            if (cpuPpiPending[cpu] & (1 << ppi))
747                if (highest_pri > getIntPriority(cpu, SGI_MAX + ppi)) {
748                    highest_pri = getIntPriority(cpu, SGI_MAX + ppi);
749                    highest_int = SGI_MAX + ppi;
750                }
751            }
752        }
753
754        bool mp_sys = sys->numRunningContexts() > 1;
755        // Check other ints
756        for (int x = 0; x < (itLines/INT_BITS_MAX); x++) {
757            if (getIntEnabled(cpu, x) & getPendingInt(cpu, x)) {
758                for (int y = 0; y < INT_BITS_MAX; y++) {
759                   uint32_t int_nm = x * INT_BITS_MAX + y;
760                   DPRINTF(GIC, "Checking for interrupt# %d \n",int_nm);
761                    /* Set current pending int as highest int for current cpu
762                       if the interrupt's priority higher than current priority
763                       and if current cpu is the target (for mp configs only)
764                     */
765                    if ((bits(getIntEnabled(cpu, x), y)
766                        &bits(getPendingInt(cpu, x), y)) &&
767                        (getIntPriority(cpu, int_nm) < highest_pri))
768                        if ((!mp_sys) ||
769                            (gem5ExtensionsEnabled
770                               ? (getCpuTarget(cpu, int_nm) == cpu)
771                               : (getCpuTarget(cpu, int_nm) & (1 << cpu)))) {
772                            highest_pri = getIntPriority(cpu, int_nm);
773                            highest_int = int_nm;
774                        }
775                }
776            }
777        }
778
779        cpuHighestInt[cpu] = highest_int;
780
781        if (highest_int == SPURIOUS_INT)
782            continue;
783
784        /* @todo make this work for more than one cpu, need to handle 1:N, N:N
785         * models */
786        if (enabled && cpuEnabled[cpu] &&
787            (highest_pri < getCpuPriority(cpu)) &&
788            !(getActiveInt(cpu, intNumToWord(highest_int))
789              & (1 << intNumToBit(highest_int)))) {
790
791            DPRINTF(Interrupt, "Posting interrupt %d to cpu%d\n", highest_int,
792                    cpu);
793            postInt(cpu, curTick() + intLatency);
794        }
795    }
796}
797
798void
799GicV2::updateRunPri()
800{
801    for (int cpu = 0; cpu < sys->numContexts(); cpu++) {
802        if (!cpuEnabled[cpu])
803            continue;
804        uint8_t maxPriority = 0xff;
805        for (int i = 0; i < itLines; i++) {
806            if (i < SGI_MAX) {
807                if (((cpuSgiActive[i] & genSwiMask(cpu)) ||
808                     (cpuSgiActiveExt[cpu] & (1 << i))) &&
809                        (getIntPriority(cpu, i) < maxPriority))
810                    maxPriority = getIntPriority(cpu, i);
811            } else if (i < (SGI_MAX + PPI_MAX)) {
812                if ((cpuPpiActive[cpu] & ( 1 << (i - SGI_MAX))) &&
813                        (getIntPriority(cpu, i) < maxPriority))
814                    maxPriority = getIntPriority(cpu, i);
815
816            } else {
817                if (getActiveInt(cpu, intNumToWord(i))
818                    & (1 << intNumToBit(i)))
819                    if (getIntPriority(cpu, i) < maxPriority)
820                        maxPriority = getIntPriority(cpu, i);
821            }
822        }
823        iccrpr[cpu] = maxPriority;
824    }
825}
826
827void
828GicV2::sendInt(uint32_t num)
829{
830    uint8_t target = getCpuTarget(0, num);
831    DPRINTF(Interrupt, "Received Interrupt number %d,  cpuTarget %#x: \n",
832            num, target);
833    if ((target & (target - 1)) && !gem5ExtensionsEnabled)
834        panic("Multiple targets for peripheral interrupts is not supported\n");
835    panic_if(num < SGI_MAX + PPI_MAX,
836             "sentInt() must only be used for interrupts 32 and higher");
837    getPendingInt(target, intNumToWord(num)) |= 1 << intNumToBit(num);
838    updateIntState(intNumToWord(num));
839}
840
841void
842GicV2::sendPPInt(uint32_t num, uint32_t cpu)
843{
844    DPRINTF(Interrupt, "Received PPI %d, cpuTarget %#x: \n",
845            num, cpu);
846    cpuPpiPending[cpu] |= 1 << (num - SGI_MAX);
847    updateIntState(intNumToWord(num));
848}
849
850void
851GicV2::clearInt(uint32_t number)
852{
853    /* @todo assume edge triggered only at the moment. Nothing to do. */
854}
855
856void
857GicV2::clearPPInt(uint32_t num, uint32_t cpu)
858{
859    DPRINTF(Interrupt, "Clearing PPI %d, cpuTarget %#x: \n",
860            num, cpu);
861    cpuPpiPending[cpu] &= ~(1 << (num - SGI_MAX));
862    updateIntState(intNumToWord(num));
863}
864
865void
866GicV2::postInt(uint32_t cpu, Tick when)
867{
868    if (!(postIntEvent[cpu]->scheduled())) {
869        ++pendingDelayedInterrupts;
870        eventq->schedule(postIntEvent[cpu], when);
871    }
872}
873
874void
875GicV2::postDelayedInt(uint32_t cpu)
876{
877    platform->intrctrl->post(cpu, ArmISA::INT_IRQ, 0);
878    --pendingDelayedInterrupts;
879    assert(pendingDelayedInterrupts >= 0);
880    if (pendingDelayedInterrupts == 0)
881        signalDrainDone();
882}
883
884DrainState
885GicV2::drain()
886{
887    if (pendingDelayedInterrupts == 0) {
888        return DrainState::Drained;
889    } else {
890        return DrainState::Draining;
891    }
892}
893
894
895void
896GicV2::drainResume()
897{
898    // There may be pending interrupts if checkpointed from Kvm; post them.
899    updateIntState(-1);
900}
901
902void
903GicV2::serialize(CheckpointOut &cp) const
904{
905    DPRINTF(Checkpoint, "Serializing Arm GIC\n");
906
907    SERIALIZE_SCALAR(enabled);
908    SERIALIZE_SCALAR(itLines);
909    SERIALIZE_ARRAY(intEnabled, INT_BITS_MAX-1);
910    SERIALIZE_ARRAY(pendingInt, INT_BITS_MAX-1);
911    SERIALIZE_ARRAY(activeInt, INT_BITS_MAX-1);
912    SERIALIZE_ARRAY(iccrpr, CPU_MAX);
913    SERIALIZE_ARRAY(intPriority, GLOBAL_INT_LINES);
914    SERIALIZE_ARRAY(cpuTarget, GLOBAL_INT_LINES);
915    SERIALIZE_ARRAY(intConfig, INT_BITS_MAX * 2);
916    SERIALIZE_ARRAY(cpuEnabled, CPU_MAX);
917    SERIALIZE_ARRAY(cpuPriority, CPU_MAX);
918    SERIALIZE_ARRAY(cpuBpr, CPU_MAX);
919    SERIALIZE_ARRAY(cpuHighestInt, CPU_MAX);
920    SERIALIZE_ARRAY(cpuSgiActive, SGI_MAX);
921    SERIALIZE_ARRAY(cpuSgiPending, SGI_MAX);
922    SERIALIZE_ARRAY(cpuSgiActiveExt, CPU_MAX);
923    SERIALIZE_ARRAY(cpuSgiPendingExt, CPU_MAX);
924    SERIALIZE_ARRAY(cpuPpiActive, CPU_MAX);
925    SERIALIZE_ARRAY(cpuPpiPending, CPU_MAX);
926    SERIALIZE_SCALAR(gem5ExtensionsEnabled);
927
928    for (uint32_t i=0; i < bankedRegs.size(); ++i) {
929        if (!bankedRegs[i])
930            continue;
931        bankedRegs[i]->serializeSection(cp, csprintf("bankedRegs%i", i));
932    }
933}
934
935void
936GicV2::BankedRegs::serialize(CheckpointOut &cp) const
937{
938    SERIALIZE_SCALAR(intEnabled);
939    SERIALIZE_SCALAR(pendingInt);
940    SERIALIZE_SCALAR(activeInt);
941    SERIALIZE_ARRAY(intPriority, SGI_MAX + PPI_MAX);
942}
943
944void
945GicV2::unserialize(CheckpointIn &cp)
946{
947    DPRINTF(Checkpoint, "Unserializing Arm GIC\n");
948
949    UNSERIALIZE_SCALAR(enabled);
950    UNSERIALIZE_SCALAR(itLines);
951    UNSERIALIZE_ARRAY(intEnabled, INT_BITS_MAX-1);
952    UNSERIALIZE_ARRAY(pendingInt, INT_BITS_MAX-1);
953    UNSERIALIZE_ARRAY(activeInt, INT_BITS_MAX-1);
954    UNSERIALIZE_ARRAY(iccrpr, CPU_MAX);
955    UNSERIALIZE_ARRAY(intPriority, GLOBAL_INT_LINES);
956    UNSERIALIZE_ARRAY(cpuTarget, GLOBAL_INT_LINES);
957    UNSERIALIZE_ARRAY(intConfig, INT_BITS_MAX * 2);
958    UNSERIALIZE_ARRAY(cpuEnabled, CPU_MAX);
959    UNSERIALIZE_ARRAY(cpuPriority, CPU_MAX);
960    UNSERIALIZE_ARRAY(cpuBpr, CPU_MAX);
961    UNSERIALIZE_ARRAY(cpuHighestInt, CPU_MAX);
962    UNSERIALIZE_ARRAY(cpuSgiActive, SGI_MAX);
963    UNSERIALIZE_ARRAY(cpuSgiPending, SGI_MAX);
964    UNSERIALIZE_ARRAY(cpuSgiActiveExt, CPU_MAX);
965    UNSERIALIZE_ARRAY(cpuSgiPendingExt, CPU_MAX);
966    UNSERIALIZE_ARRAY(cpuPpiActive, CPU_MAX);
967    UNSERIALIZE_ARRAY(cpuPpiPending, CPU_MAX);
968
969    // Handle checkpoints from before we drained the GIC to prevent
970    // in-flight interrupts.
971    if (cp.entryExists(Serializable::currentSection(), "interrupt_time")) {
972        Tick interrupt_time[CPU_MAX];
973        UNSERIALIZE_ARRAY(interrupt_time, CPU_MAX);
974
975        for (uint32_t cpu = 0; cpu < CPU_MAX; cpu++) {
976            if (interrupt_time[cpu])
977                schedule(postIntEvent[cpu], interrupt_time[cpu]);
978        }
979    }
980
981    if (!UNSERIALIZE_OPT_SCALAR(gem5ExtensionsEnabled))
982        gem5ExtensionsEnabled = false;
983
984    for (uint32_t i=0; i < CPU_MAX; ++i) {
985        ScopedCheckpointSection sec(cp, csprintf("bankedRegs%i", i));
986        if (cp.sectionExists(Serializable::currentSection())) {
987            getBankedRegs(i).unserialize(cp);
988        }
989    }
990}
991
992void
993GicV2::BankedRegs::unserialize(CheckpointIn &cp)
994{
995    UNSERIALIZE_SCALAR(intEnabled);
996    UNSERIALIZE_SCALAR(pendingInt);
997    UNSERIALIZE_SCALAR(activeInt);
998    UNSERIALIZE_ARRAY(intPriority, SGI_MAX + PPI_MAX);
999}
1000
1001GicV2 *
1002GicV2Params::create()
1003{
1004    return new GicV2(this);
1005}
1006