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