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