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