2 * Copyright (c) 2010, 2013, 2015-2018 ARM Limited
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.
14 * Copyright (c) 2005 The Regents of The University of Michigan
15 * All rights reserved.
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.
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.
44 #include "dev/arm/gic_pl390.hh"
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"
54 const AddrRange
Pl390::GICD_IGROUPR (0x080, 0x0ff);
55 const AddrRange
Pl390::GICD_ISENABLER (0x100, 0x17f);
56 const AddrRange
Pl390::GICD_ICENABLER (0x180, 0x1ff);
57 const AddrRange
Pl390::GICD_ISPENDR (0x200, 0x27f);
58 const AddrRange
Pl390::GICD_ICPENDR (0x280, 0x2ff);
59 const AddrRange
Pl390::GICD_ISACTIVER (0x300, 0x37f);
60 const AddrRange
Pl390::GICD_ICACTIVER (0x380, 0x3ff);
61 const AddrRange
Pl390::GICD_IPRIORITYR(0x400, 0x7ff);
62 const AddrRange
Pl390::GICD_ITARGETSR (0x800, 0xbff);
63 const AddrRange
Pl390::GICD_ICFGR (0xc00, 0xcff);
65 Pl390::Pl390(const Params
*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
),
74 intEnabled
{}, pendingInt
{}, activeInt
{},
75 intPriority
{}, cpuTarget
{}, intConfig
{},
76 cpuSgiPending
{}, cpuSgiActive
{},
77 cpuSgiPendingExt
{}, cpuSgiActiveExt
{},
78 cpuPpiPending
{}, cpuPpiActive
{},
79 pendingDelayedInterrupts(0)
81 for (int x
= 0; x
< CPU_MAX
; x
++) {
83 cpuEnabled
[x
] = false;
84 cpuPriority
[x
] = 0xff;
85 cpuBpr
[x
] = GICC_BPR_MINIMUM
;
86 // Initialize cpu highest int
87 cpuHighestInt
[x
] = SPURIOUS_INT
;
89 new EventFunctionWrapper([this, x
]{ postDelayedInt(x
); },
90 "Post Interrupt to CPU");
92 DPRINTF(Interrupt
, "cpuEnabled[0]=%d cpuEnabled[1]=%d\n", cpuEnabled
[0],
95 gem5ExtensionsEnabled
= false;
100 for (int x
= 0; x
< CPU_MAX
; x
++)
101 delete postIntEvent
[x
];
105 Pl390::read(PacketPtr pkt
)
107 const Addr addr
= pkt
->getAddr();
109 if (distRange
.contains(addr
))
110 return readDistributor(pkt
);
111 else if (cpuRange
.contains(addr
))
114 panic("Read to unknown address %#x\n", pkt
->getAddr());
119 Pl390::write(PacketPtr pkt
)
121 const Addr addr
= pkt
->getAddr();
123 if (distRange
.contains(addr
))
124 return writeDistributor(pkt
);
125 else if (cpuRange
.contains(addr
))
126 return writeCpu(pkt
);
128 panic("Write to unknown address %#x\n", pkt
->getAddr());
132 Pl390::readDistributor(PacketPtr pkt
)
134 const Addr daddr
= pkt
->getAddr() - distRange
.start();
135 const ContextID ctx
= pkt
->req
->contextId();
137 DPRINTF(GIC
, "gic distributor read register %#x\n", daddr
);
139 const uint32_t resp
= readDistributor(ctx
, daddr
, pkt
->getSize());
141 switch (pkt
->getSize()) {
143 pkt
->set
<uint8_t>(resp
);
146 pkt
->set
<uint16_t>(resp
);
149 pkt
->set
<uint32_t>(resp
);
152 panic("Invalid size while reading Distributor regs in GIC: %d\n",
156 pkt
->makeAtomicResponse();
161 Pl390::readDistributor(ContextID ctx
, Addr daddr
, size_t resp_sz
)
163 if (GICD_IGROUPR
.contains(daddr
)) {
164 return 0; // unimplemented; RAZ (read as zero)
167 if (GICD_ISENABLER
.contains(daddr
)) {
168 uint32_t ix
= (daddr
- GICD_ISENABLER
.start()) >> 2;
170 return getIntEnabled(ctx
, ix
);
173 if (GICD_ICENABLER
.contains(daddr
)) {
174 uint32_t ix
= (daddr
- GICD_ICENABLER
.start()) >> 2;
176 return getIntEnabled(ctx
, ix
);
179 if (GICD_ISPENDR
.contains(daddr
)) {
180 uint32_t ix
= (daddr
- GICD_ISPENDR
.start()) >> 2;
182 return getPendingInt(ctx
, ix
);
185 if (GICD_ICPENDR
.contains(daddr
)) {
186 uint32_t ix
= (daddr
- GICD_ICPENDR
.start()) >> 2;
188 return getPendingInt(ctx
, ix
);
191 if (GICD_ISACTIVER
.contains(daddr
)) {
192 uint32_t ix
= (daddr
- GICD_ISACTIVER
.start()) >> 2;
194 return getActiveInt(ctx
, ix
);
197 if (GICD_ICACTIVER
.contains(daddr
)) {
198 uint32_t ix
= (daddr
- GICD_ICACTIVER
.start()) >> 2;
200 return getActiveInt(ctx
, ix
);
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",int_num
);
209 default: // will panic() after return to caller anyway
211 return getIntPriority(ctx
, int_num
);
213 assert((int_num
+ 1) < INT_LINES_MAX
);
214 return (getIntPriority(ctx
, int_num
) |
215 getIntPriority(ctx
, int_num
+1) << 8);
217 assert((int_num
+ 3) < INT_LINES_MAX
);
218 return (getIntPriority(ctx
, int_num
) |
219 getIntPriority(ctx
, int_num
+1) << 8 |
220 getIntPriority(ctx
, int_num
+2) << 16 |
221 getIntPriority(ctx
, int_num
+3) << 24);
225 if (GICD_ITARGETSR
.contains(daddr
)) {
226 Addr int_num
= daddr
- GICD_ITARGETSR
.start();
227 DPRINTF(GIC
, "Reading processor target register for int# %#x \n",
229 assert(int_num
< INT_LINES_MAX
);
232 return getCpuTarget(ctx
, int_num
);
234 assert(resp_sz
== 4);
235 int_num
= mbits(int_num
, 31, 2);
236 return (getCpuTarget(ctx
, int_num
) |
237 getCpuTarget(ctx
, int_num
+1) << 8 |
238 getCpuTarget(ctx
, int_num
+2) << 16 |
239 getCpuTarget(ctx
, int_num
+3) << 24) ;
243 if (GICD_ICFGR
.contains(daddr
)) {
244 uint32_t ix
= (daddr
- GICD_ICFGR
.start()) >> 2;
246 /** @todo software generated interrupts and PPIs
247 * can't be configured in some ways */
248 return intConfig
[ix
];
255 /* The 0x100 is a made-up flag to show that gem5 extensions
257 * write 0x200 to this register to enable it. */
258 return (((sys
->numRunningContexts() - 1) << 5) |
259 (itLines
/INT_BITS_MAX
-1) |
260 (haveGem5Extensions
? 0x100 : 0x0));
263 return (GICD_400_PIDR_VALUE
& 0xFF);
265 return ((GICD_400_PIDR_VALUE
>> 8) & 0xFF);
267 return ((GICD_400_PIDR_VALUE
>> 16) & 0xFF);
269 return ((GICD_400_PIDR_VALUE
>> 24) & 0xFF);
271 /* revision id is resorted to 1 and variant to 0*/
272 return GICD_400_IIDR_VALUE
;
274 panic("Tried to read Gic distributor at offset %#x\n", daddr
);
280 Pl390::readCpu(PacketPtr pkt
)
282 const Addr daddr
= pkt
->getAddr() - cpuRange
.start();
284 assert(pkt
->req
->hasContextId());
285 const ContextID ctx
= pkt
->req
->contextId();
286 assert(ctx
< sys
->numRunningContexts());
288 DPRINTF(GIC
, "gic cpu read register %#x cpu context: %d\n", daddr
,
291 pkt
->set
<uint32_t>(readCpu(ctx
, daddr
));
293 pkt
->makeAtomicResponse();
298 Pl390::readCpu(ContextID ctx
, Addr daddr
)
302 return GICC_400_IIDR_VALUE
;
304 return cpuEnabled
[ctx
];
306 return cpuPriority
[ctx
];
310 if (enabled
&& cpuEnabled
[ctx
]) {
311 int active_int
= cpuHighestInt
[ctx
];
313 iar
.ack_id
= active_int
;
315 if (active_int
< SGI_MAX
) {
316 // this is a software interrupt from another CPU
317 if (!gem5ExtensionsEnabled
) {
318 panic_if(!cpuSgiPending
[active_int
],
319 "Interrupt %d active but no CPU generated it?\n",
321 for (int x
= 0; x
< sys
->numRunningContexts(); x
++) {
322 // See which CPU generated the interrupt
324 bits(cpuSgiPending
[active_int
], 7 + 8 * x
, 8 * x
);
325 if (cpugen
& (1 << ctx
)) {
330 uint64_t sgi_num
= ULL(1) << (ctx
+ 8 * iar
.cpu_id
);
331 cpuSgiActive
[iar
.ack_id
] |= sgi_num
;
332 cpuSgiPending
[iar
.ack_id
] &= ~sgi_num
;
334 uint64_t sgi_num
= ULL(1) << iar
.ack_id
;
335 cpuSgiActiveExt
[ctx
] |= sgi_num
;
336 cpuSgiPendingExt
[ctx
] &= ~sgi_num
;
338 } else if (active_int
< (SGI_MAX
+ PPI_MAX
) ) {
339 uint32_t int_num
= 1 << (cpuHighestInt
[ctx
] - SGI_MAX
);
340 cpuPpiActive
[ctx
] |= int_num
;
342 cpuPpiPending
[ctx
] &= ~int_num
;
345 uint32_t int_num
= 1 << intNumToBit(cpuHighestInt
[ctx
]);
346 getActiveInt(ctx
, intNumToWord(cpuHighestInt
[ctx
])) |= int_num
;
348 getPendingInt(ctx
, intNumToWord(cpuHighestInt
[ctx
]))
352 DPRINTF(Interrupt
,"CPU %d reading IAR.id=%d IAR.cpu=%d, iar=0x%x\n",
353 ctx
, iar
.ack_id
, iar
.cpu_id
, iar
);
354 cpuHighestInt
[ctx
] = SPURIOUS_INT
;
356 platform
->intrctrl
->clear(ctx
, ArmISA::INT_IRQ
, 0);
366 panic("Need to implement HPIR");
369 panic("Tried to read Gic cpu at offset %#x\n", daddr
);
375 Pl390::writeDistributor(PacketPtr pkt
)
377 const Addr daddr
= pkt
->getAddr() - distRange
.start();
379 assert(pkt
->req
->hasContextId());
380 const ContextID ctx
= pkt
->req
->contextId();
381 const size_t data_sz
= pkt
->getSize();
383 uint32_t pkt_data M5_VAR_USED
;
387 pkt_data
= pkt
->get
<uint8_t>();
390 pkt_data
= pkt
->get
<uint16_t>();
393 pkt_data
= pkt
->get
<uint32_t>();
396 panic("Invalid size when writing to priority regs in Gic: %d\n",
400 DPRINTF(GIC
, "gic distributor write register %#x size %#x value %#x \n",
401 daddr
, data_sz
, pkt_data
);
403 writeDistributor(ctx
, daddr
, pkt_data
, data_sz
);
405 pkt
->makeAtomicResponse();
410 Pl390::writeDistributor(ContextID ctx
, Addr daddr
, uint32_t data
,
413 if (GICD_IGROUPR
.contains(daddr
)) {
414 return; // unimplemented; WI (writes ignored)
417 if (GICD_ISENABLER
.contains(daddr
)) {
418 uint32_t ix
= (daddr
- GICD_ISENABLER
.start()) >> 2;
420 getIntEnabled(ctx
, ix
) |= data
;
424 if (GICD_ICENABLER
.contains(daddr
)) {
425 uint32_t ix
= (daddr
- GICD_ICENABLER
.start()) >> 2;
427 getIntEnabled(ctx
, ix
) &= ~data
;
431 if (GICD_ISPENDR
.contains(daddr
)) {
432 uint32_t ix
= (daddr
- GICD_ISPENDR
.start()) >> 2;
434 if (ix
== 0) mask
&= SGI_MASK
; // Don't allow SGIs to be changed
435 getPendingInt(ctx
, ix
) |= mask
;
440 if (GICD_ICPENDR
.contains(daddr
)) {
441 uint32_t ix
= (daddr
- GICD_ICPENDR
.start()) >> 2;
443 if (ix
== 0) mask
&= SGI_MASK
; // Don't allow SGIs to be changed
444 getPendingInt(ctx
, ix
) &= ~mask
;
449 if (GICD_ISACTIVER
.contains(daddr
)) {
450 uint32_t ix
= (daddr
- GICD_ISACTIVER
.start()) >> 2;
451 getActiveInt(ctx
, ix
) |= data
;
455 if (GICD_ICACTIVER
.contains(daddr
)) {
456 uint32_t ix
= (daddr
- GICD_ICACTIVER
.start()) >> 2;
457 getActiveInt(ctx
, ix
) &= ~data
;
461 if (GICD_IPRIORITYR
.contains(daddr
)) {
462 Addr int_num
= daddr
- GICD_IPRIORITYR
.start();
465 getIntPriority(ctx
, int_num
) = data
;
468 getIntPriority(ctx
, int_num
) = bits(data
, 7, 0);
469 getIntPriority(ctx
, int_num
+ 1) = bits(data
, 15, 8);
473 getIntPriority(ctx
, int_num
) = bits(data
, 7, 0);
474 getIntPriority(ctx
, int_num
+ 1) = bits(data
, 15, 8);
475 getIntPriority(ctx
, int_num
+ 2) = bits(data
, 23, 16);
476 getIntPriority(ctx
, int_num
+ 3) = bits(data
, 31, 24);
480 panic("Invalid size when writing to priority regs in Gic: %d\n",
489 if (GICD_ITARGETSR
.contains(daddr
)) {
490 Addr int_num
= daddr
- GICD_ITARGETSR
.start();
491 // Interrupts 0-31 are read only
492 unsigned offset
= SGI_MAX
+ PPI_MAX
;
493 if (int_num
>= offset
) {
494 unsigned ix
= int_num
- offset
; // index into cpuTarget array
496 cpuTarget
[ix
] = data
& 0xff;
498 assert (data_sz
== 4);
499 cpuTarget
[ix
] = bits(data
, 7, 0);
500 cpuTarget
[ix
+1] = bits(data
, 15, 8);
501 cpuTarget
[ix
+2] = bits(data
, 23, 16);
502 cpuTarget
[ix
+3] = bits(data
, 31, 24);
504 updateIntState(int_num
>> 2);
509 if (GICD_ICFGR
.contains(daddr
)) {
510 uint32_t ix
= (daddr
- GICD_ICFGR
.start()) >> 2;
511 assert(ix
< INT_BITS_MAX
*2);
512 intConfig
[ix
] = data
;
513 if (data
& NN_CONFIG_MASK
)
514 warn("GIC N:N mode selected and not supported at this time\n");
521 DPRINTF(Interrupt
, "Distributor enable flag set to = %d\n", enabled
);
524 /* 0x200 is a made-up flag to enable gem5 extension functionality.
525 * This reg is not normally written.
527 gem5ExtensionsEnabled
= (data
& 0x200) && haveGem5Extensions
;
528 DPRINTF(GIC
, "gem5 extensions %s\n",
529 gem5ExtensionsEnabled
? "enabled" : "disabled");
535 panic("Tried to write Gic distributor at offset %#x\n", daddr
);
541 Pl390::writeCpu(PacketPtr pkt
)
543 const Addr daddr
= pkt
->getAddr() - cpuRange
.start();
545 assert(pkt
->req
->hasContextId());
546 const ContextID ctx
= pkt
->req
->contextId();
547 const uint32_t data
= pkt
->get
<uint32_t>();
549 DPRINTF(GIC
, "gic cpu write register cpu:%d %#x val: %#x\n",
552 writeCpu(ctx
, daddr
, data
);
554 pkt
->makeAtomicResponse();
559 Pl390::writeCpu(ContextID ctx
, Addr daddr
, uint32_t data
)
563 cpuEnabled
[ctx
] = data
;
566 cpuPriority
[ctx
] = data
;
569 auto bpr
= data
& 0x7;
570 if (bpr
< GICC_BPR_MINIMUM
)
571 bpr
= GICC_BPR_MINIMUM
;
576 const IAR iar
= data
;
577 if (iar
.ack_id
< SGI_MAX
) {
578 // Clear out the bit that corresponds to the cleared int
579 uint64_t clr_int
= ULL(1) << (ctx
+ 8 * iar
.cpu_id
);
580 if (!(cpuSgiActive
[iar
.ack_id
] & clr_int
) &&
581 !(cpuSgiActiveExt
[ctx
] & (1 << iar
.ack_id
)))
582 panic("Done handling a SGI that isn't active?\n");
583 if (gem5ExtensionsEnabled
)
584 cpuSgiActiveExt
[ctx
] &= ~(1 << iar
.ack_id
);
586 cpuSgiActive
[iar
.ack_id
] &= ~clr_int
;
587 } else if (iar
.ack_id
< (SGI_MAX
+ PPI_MAX
) ) {
588 uint32_t int_num
= 1 << (iar
.ack_id
- SGI_MAX
);
589 if (!(cpuPpiActive
[ctx
] & int_num
))
590 panic("CPU %d Done handling a PPI interrupt "
591 "that isn't active?\n", ctx
);
592 cpuPpiActive
[ctx
] &= ~int_num
;
594 uint32_t int_num
= 1 << intNumToBit(iar
.ack_id
);
595 if (!(getActiveInt(ctx
, intNumToWord(iar
.ack_id
)) & int_num
))
596 warn("Done handling interrupt that isn't active: %d\n",
597 intNumToBit(iar
.ack_id
));
598 getActiveInt(ctx
, intNumToWord(iar
.ack_id
)) &= ~int_num
;
601 DPRINTF(Interrupt
, "CPU %d done handling intr IAR = %d from cpu %d\n",
602 ctx
, iar
.ack_id
, iar
.cpu_id
);
609 warn("GIC APRn write ignored because not implemented: %#x\n", daddr
);
612 panic("Tried to write Gic cpu at offset %#x\n", daddr
);
615 if (cpuEnabled
[ctx
]) updateIntState(-1);
619 Pl390::getBankedRegs(ContextID ctx
) {
620 if (bankedRegs
.size() <= ctx
)
621 bankedRegs
.resize(ctx
+ 1);
623 if (!bankedRegs
[ctx
])
624 bankedRegs
[ctx
] = new BankedRegs
;
625 return *bankedRegs
[ctx
];
629 Pl390::softInt(ContextID ctx
, SWI swi
)
631 if (gem5ExtensionsEnabled
) {
632 switch (swi
.list_type
) {
634 // interrupt cpus specified
635 int dest
= swi
.cpu_list
;
636 DPRINTF(IPI
, "Generating softIRQ from CPU %d for CPU %d\n",
638 if (cpuEnabled
[dest
]) {
639 cpuSgiPendingExt
[dest
] |= (1 << swi
.sgi_id
);
640 DPRINTF(IPI
, "SGI[%d]=%#x\n", dest
,
641 cpuSgiPendingExt
[dest
]);
646 for (int i
= 0; i
< sys
->numContexts(); i
++) {
647 DPRINTF(IPI
, "Processing CPU %d\n", i
);
650 cpuSgiPendingExt
[i
] |= 1 << swi
.sgi_id
;
651 DPRINTF(IPI
, "SGI[%d]=%#x\n", swi
.sgi_id
,
652 cpuSgiPendingExt
[i
]);
656 // Interrupt requesting cpu only
657 DPRINTF(IPI
, "Generating softIRQ from CPU %d for CPU %d\n",
659 if (cpuEnabled
[ctx
]) {
660 cpuSgiPendingExt
[ctx
] |= (1 << swi
.sgi_id
);
661 DPRINTF(IPI
, "SGI[%d]=%#x\n", ctx
,
662 cpuSgiPendingExt
[ctx
]);
667 switch (swi
.list_type
) {
672 for (int x
= 0; x
< sys
->numContexts(); x
++)
673 cpu_list
|= cpuEnabled
[x
] ? 1 << x
: 0;
674 swi
.cpu_list
= cpu_list
;
677 // interrupt requesting cpu only
678 swi
.cpu_list
= 1 << ctx
;
680 // else interrupt cpus specified
683 DPRINTF(IPI
, "Generating softIRQ from CPU %d for %#x\n", ctx
,
685 for (int i
= 0; i
< sys
->numContexts(); i
++) {
686 DPRINTF(IPI
, "Processing CPU %d\n", i
);
689 if (swi
.cpu_list
& (1 << i
))
690 cpuSgiPending
[swi
.sgi_id
] |= (1 << i
) << (8 * ctx
);
691 DPRINTF(IPI
, "SGI[%d]=%#x\n", swi
.sgi_id
,
692 cpuSgiPending
[swi
.sgi_id
]);
699 Pl390::genSwiMask(int cpu
)
701 if (cpu
> sys
->numContexts())
702 panic("Invalid CPU ID\n");
703 return ULL(0x0101010101010101) << cpu
;
707 Pl390::getCpuPriority(unsigned cpu
)
709 // see Table 3-2 in IHI0048B.b (GICv2)
710 // mask some low-order priority bits per BPR value
711 // NB: the GIC prioritization scheme is upside down:
712 // lower values are higher priority; masking off bits
713 // actually creates a higher priority, not lower.
714 return cpuPriority
[cpu
] & (0xff00 >> (7 - cpuBpr
[cpu
]));
718 Pl390::updateIntState(int hint
)
720 for (int cpu
= 0; cpu
< sys
->numContexts(); cpu
++) {
721 if (!cpuEnabled
[cpu
])
724 /*@todo use hint to do less work. */
725 int highest_int
= SPURIOUS_INT
;
726 // Priorities below that set in GICC_PMR can be ignored
727 uint8_t highest_pri
= getCpuPriority(cpu
);
730 for (int swi
= 0; swi
< SGI_MAX
; swi
++) {
731 if (!cpuSgiPending
[swi
] && !cpuSgiPendingExt
[cpu
])
733 if ((cpuSgiPending
[swi
] & genSwiMask(cpu
)) ||
734 (cpuSgiPendingExt
[cpu
] & (1 << swi
)))
735 if (highest_pri
> getIntPriority(cpu
, swi
)) {
736 highest_pri
= getIntPriority(cpu
, swi
);
742 if (cpuPpiPending
[cpu
]) {
743 for (int ppi
= 0; ppi
< PPI_MAX
; ppi
++) {
744 if (cpuPpiPending
[cpu
] & (1 << ppi
))
745 if (highest_pri
> getIntPriority(cpu
, SGI_MAX
+ ppi
)) {
746 highest_pri
= getIntPriority(cpu
, SGI_MAX
+ ppi
);
747 highest_int
= SGI_MAX
+ ppi
;
752 bool mp_sys
= sys
->numRunningContexts() > 1;
754 for (int x
= 0; x
< (itLines
/INT_BITS_MAX
); x
++) {
755 if (getIntEnabled(cpu
, x
) & getPendingInt(cpu
, x
)) {
756 for (int y
= 0; y
< INT_BITS_MAX
; y
++) {
757 uint32_t int_nm
= x
* INT_BITS_MAX
+ y
;
758 DPRINTF(GIC
, "Checking for interrupt# %d \n",int_nm
);
759 /* Set current pending int as highest int for current cpu
760 if the interrupt's priority higher than current priority
761 and if current cpu is the target (for mp configs only)
763 if ((bits(getIntEnabled(cpu
, x
), y
)
764 &bits(getPendingInt(cpu
, x
), y
)) &&
765 (getIntPriority(cpu
, int_nm
) < highest_pri
))
767 (gem5ExtensionsEnabled
768 ? (getCpuTarget(cpu
, int_nm
) == cpu
)
769 : (getCpuTarget(cpu
, int_nm
) & (1 << cpu
)))) {
770 highest_pri
= getIntPriority(cpu
, int_nm
);
771 highest_int
= int_nm
;
777 cpuHighestInt
[cpu
] = highest_int
;
779 if (highest_int
== SPURIOUS_INT
)
782 /* @todo make this work for more than one cpu, need to handle 1:N, N:N
784 if (enabled
&& cpuEnabled
[cpu
] &&
785 (highest_pri
< getCpuPriority(cpu
)) &&
786 !(getActiveInt(cpu
, intNumToWord(highest_int
))
787 & (1 << intNumToBit(highest_int
)))) {
789 DPRINTF(Interrupt
, "Posting interrupt %d to cpu%d\n", highest_int
,
791 postInt(cpu
, curTick() + intLatency
);
797 Pl390::updateRunPri()
799 for (int cpu
= 0; cpu
< sys
->numContexts(); cpu
++) {
800 if (!cpuEnabled
[cpu
])
802 uint8_t maxPriority
= 0xff;
803 for (int i
= 0; i
< itLines
; i
++) {
805 if (((cpuSgiActive
[i
] & genSwiMask(cpu
)) ||
806 (cpuSgiActiveExt
[cpu
] & (1 << i
))) &&
807 (getIntPriority(cpu
, i
) < maxPriority
))
808 maxPriority
= getIntPriority(cpu
, i
);
809 } else if (i
< (SGI_MAX
+ PPI_MAX
)) {
810 if ((cpuPpiActive
[cpu
] & ( 1 << (i
- SGI_MAX
))) &&
811 (getIntPriority(cpu
, i
) < maxPriority
))
812 maxPriority
= getIntPriority(cpu
, i
);
815 if (getActiveInt(cpu
, intNumToWord(i
))
816 & (1 << intNumToBit(i
)))
817 if (getIntPriority(cpu
, i
) < maxPriority
)
818 maxPriority
= getIntPriority(cpu
, i
);
821 iccrpr
[cpu
] = maxPriority
;
826 Pl390::sendInt(uint32_t num
)
828 uint8_t target
= getCpuTarget(0, num
);
829 DPRINTF(Interrupt
, "Received Interrupt number %d, cpuTarget %#x: \n",
831 if ((target
& (target
- 1)) && !gem5ExtensionsEnabled
)
832 panic("Multiple targets for peripheral interrupts is not supported\n");
833 panic_if(num
< SGI_MAX
+ PPI_MAX
,
834 "sentInt() must only be used for interrupts 32 and higher");
835 getPendingInt(target
, intNumToWord(num
)) |= 1 << intNumToBit(num
);
836 updateIntState(intNumToWord(num
));
840 Pl390::sendPPInt(uint32_t num
, uint32_t cpu
)
842 DPRINTF(Interrupt
, "Received PPI %d, cpuTarget %#x: \n",
844 cpuPpiPending
[cpu
] |= 1 << (num
- SGI_MAX
);
845 updateIntState(intNumToWord(num
));
849 Pl390::clearInt(uint32_t number
)
851 /* @todo assume edge triggered only at the moment. Nothing to do. */
855 Pl390::clearPPInt(uint32_t num
, uint32_t cpu
)
857 DPRINTF(Interrupt
, "Clearing PPI %d, cpuTarget %#x: \n",
859 cpuPpiPending
[cpu
] &= ~(1 << (num
- SGI_MAX
));
860 updateIntState(intNumToWord(num
));
864 Pl390::postInt(uint32_t cpu
, Tick when
)
866 if (!(postIntEvent
[cpu
]->scheduled())) {
867 ++pendingDelayedInterrupts
;
868 eventq
->schedule(postIntEvent
[cpu
], when
);
873 Pl390::postDelayedInt(uint32_t cpu
)
875 platform
->intrctrl
->post(cpu
, ArmISA::INT_IRQ
, 0);
876 --pendingDelayedInterrupts
;
877 assert(pendingDelayedInterrupts
>= 0);
878 if (pendingDelayedInterrupts
== 0)
885 if (pendingDelayedInterrupts
== 0) {
886 return DrainState::Drained
;
888 return DrainState::Draining
;
896 // There may be pending interrupts if checkpointed from Kvm; post them.
901 Pl390::serialize(CheckpointOut
&cp
) const
903 DPRINTF(Checkpoint
, "Serializing Arm GIC\n");
905 SERIALIZE_SCALAR(enabled
);
906 SERIALIZE_SCALAR(itLines
);
907 SERIALIZE_ARRAY(intEnabled
, INT_BITS_MAX
-1);
908 SERIALIZE_ARRAY(pendingInt
, INT_BITS_MAX
-1);
909 SERIALIZE_ARRAY(activeInt
, INT_BITS_MAX
-1);
910 SERIALIZE_ARRAY(iccrpr
, CPU_MAX
);
911 SERIALIZE_ARRAY(intPriority
, GLOBAL_INT_LINES
);
912 SERIALIZE_ARRAY(cpuTarget
, GLOBAL_INT_LINES
);
913 SERIALIZE_ARRAY(intConfig
, INT_BITS_MAX
* 2);
914 SERIALIZE_ARRAY(cpuEnabled
, CPU_MAX
);
915 SERIALIZE_ARRAY(cpuPriority
, CPU_MAX
);
916 SERIALIZE_ARRAY(cpuBpr
, CPU_MAX
);
917 SERIALIZE_ARRAY(cpuHighestInt
, CPU_MAX
);
918 SERIALIZE_ARRAY(cpuSgiActive
, SGI_MAX
);
919 SERIALIZE_ARRAY(cpuSgiPending
, SGI_MAX
);
920 SERIALIZE_ARRAY(cpuSgiActiveExt
, CPU_MAX
);
921 SERIALIZE_ARRAY(cpuSgiPendingExt
, CPU_MAX
);
922 SERIALIZE_ARRAY(cpuPpiActive
, CPU_MAX
);
923 SERIALIZE_ARRAY(cpuPpiPending
, CPU_MAX
);
924 SERIALIZE_SCALAR(gem5ExtensionsEnabled
);
926 for (uint32_t i
=0; i
< bankedRegs
.size(); ++i
) {
929 bankedRegs
[i
]->serializeSection(cp
, csprintf("bankedRegs%i", i
));
934 Pl390::BankedRegs::serialize(CheckpointOut
&cp
) const
936 SERIALIZE_SCALAR(intEnabled
);
937 SERIALIZE_SCALAR(pendingInt
);
938 SERIALIZE_SCALAR(activeInt
);
939 SERIALIZE_ARRAY(intPriority
, SGI_MAX
+ PPI_MAX
);
943 Pl390::unserialize(CheckpointIn
&cp
)
945 DPRINTF(Checkpoint
, "Unserializing Arm GIC\n");
947 UNSERIALIZE_SCALAR(enabled
);
948 UNSERIALIZE_SCALAR(itLines
);
949 UNSERIALIZE_ARRAY(intEnabled
, INT_BITS_MAX
-1);
950 UNSERIALIZE_ARRAY(pendingInt
, INT_BITS_MAX
-1);
951 UNSERIALIZE_ARRAY(activeInt
, INT_BITS_MAX
-1);
952 UNSERIALIZE_ARRAY(iccrpr
, CPU_MAX
);
953 UNSERIALIZE_ARRAY(intPriority
, GLOBAL_INT_LINES
);
954 UNSERIALIZE_ARRAY(cpuTarget
, GLOBAL_INT_LINES
);
955 UNSERIALIZE_ARRAY(intConfig
, INT_BITS_MAX
* 2);
956 UNSERIALIZE_ARRAY(cpuEnabled
, CPU_MAX
);
957 UNSERIALIZE_ARRAY(cpuPriority
, CPU_MAX
);
958 UNSERIALIZE_ARRAY(cpuBpr
, CPU_MAX
);
959 UNSERIALIZE_ARRAY(cpuHighestInt
, CPU_MAX
);
960 UNSERIALIZE_ARRAY(cpuSgiActive
, SGI_MAX
);
961 UNSERIALIZE_ARRAY(cpuSgiPending
, SGI_MAX
);
962 UNSERIALIZE_ARRAY(cpuSgiActiveExt
, CPU_MAX
);
963 UNSERIALIZE_ARRAY(cpuSgiPendingExt
, CPU_MAX
);
964 UNSERIALIZE_ARRAY(cpuPpiActive
, CPU_MAX
);
965 UNSERIALIZE_ARRAY(cpuPpiPending
, CPU_MAX
);
967 // Handle checkpoints from before we drained the GIC to prevent
968 // in-flight interrupts.
969 if (cp
.entryExists(Serializable::currentSection(), "interrupt_time")) {
970 Tick interrupt_time
[CPU_MAX
];
971 UNSERIALIZE_ARRAY(interrupt_time
, CPU_MAX
);
973 for (uint32_t cpu
= 0; cpu
< CPU_MAX
; cpu
++) {
974 if (interrupt_time
[cpu
])
975 schedule(postIntEvent
[cpu
], interrupt_time
[cpu
]);
979 if (!UNSERIALIZE_OPT_SCALAR(gem5ExtensionsEnabled
))
980 gem5ExtensionsEnabled
= false;
982 for (uint32_t i
=0; i
< CPU_MAX
; ++i
) {
983 ScopedCheckpointSection
sec(cp
, csprintf("bankedRegs%i", i
));
984 if (cp
.sectionExists(Serializable::currentSection())) {
985 getBankedRegs(i
).unserialize(cp
);
991 Pl390::BankedRegs::unserialize(CheckpointIn
&cp
)
993 UNSERIALIZE_SCALAR(intEnabled
);
994 UNSERIALIZE_SCALAR(pendingInt
);
995 UNSERIALIZE_SCALAR(activeInt
);
996 UNSERIALIZE_ARRAY(intPriority
, SGI_MAX
+ PPI_MAX
);
1000 Pl390Params::create()
1002 return new Pl390(this);