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