gic_v2.cc revision 13014:a4f71c3dc602
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 = 0; ppi < PPI_MAX; ppi++) { 746 if (cpuPpiPending[cpu] & (1 << ppi)) 747 if (highest_pri > getIntPriority(cpu, SGI_MAX + ppi)) { 748 highest_pri = getIntPriority(cpu, SGI_MAX + ppi); 749 highest_int = SGI_MAX + ppi; 750 } 751 } 752 } 753 754 bool mp_sys = sys->numRunningContexts() > 1; 755 // Check other ints 756 for (int x = 0; x < (itLines/INT_BITS_MAX); x++) { 757 if (getIntEnabled(cpu, x) & getPendingInt(cpu, x)) { 758 for (int y = 0; y < INT_BITS_MAX; y++) { 759 uint32_t int_nm = x * INT_BITS_MAX + y; 760 DPRINTF(GIC, "Checking for interrupt# %d \n",int_nm); 761 /* Set current pending int as highest int for current cpu 762 if the interrupt's priority higher than current priority 763 and if current cpu is the target (for mp configs only) 764 */ 765 if ((bits(getIntEnabled(cpu, x), y) 766 &bits(getPendingInt(cpu, x), y)) && 767 (getIntPriority(cpu, int_nm) < highest_pri)) 768 if ((!mp_sys) || 769 (gem5ExtensionsEnabled 770 ? (getCpuTarget(cpu, int_nm) == cpu) 771 : (getCpuTarget(cpu, int_nm) & (1 << cpu)))) { 772 highest_pri = getIntPriority(cpu, int_nm); 773 highest_int = int_nm; 774 } 775 } 776 } 777 } 778 779 cpuHighestInt[cpu] = highest_int; 780 781 if (highest_int == SPURIOUS_INT) 782 continue; 783 784 /* @todo make this work for more than one cpu, need to handle 1:N, N:N 785 * models */ 786 if (enabled && cpuEnabled[cpu] && 787 (highest_pri < getCpuPriority(cpu)) && 788 !(getActiveInt(cpu, intNumToWord(highest_int)) 789 & (1 << intNumToBit(highest_int)))) { 790 791 DPRINTF(Interrupt, "Posting interrupt %d to cpu%d\n", highest_int, 792 cpu); 793 postInt(cpu, curTick() + intLatency); 794 } 795 } 796} 797 798void 799GicV2::updateRunPri() 800{ 801 for (int cpu = 0; cpu < sys->numContexts(); cpu++) { 802 if (!cpuEnabled[cpu]) 803 continue; 804 uint8_t maxPriority = 0xff; 805 for (int i = 0; i < itLines; i++) { 806 if (i < SGI_MAX) { 807 if (((cpuSgiActive[i] & genSwiMask(cpu)) || 808 (cpuSgiActiveExt[cpu] & (1 << i))) && 809 (getIntPriority(cpu, i) < maxPriority)) 810 maxPriority = getIntPriority(cpu, i); 811 } else if (i < (SGI_MAX + PPI_MAX)) { 812 if ((cpuPpiActive[cpu] & ( 1 << (i - SGI_MAX))) && 813 (getIntPriority(cpu, i) < maxPriority)) 814 maxPriority = getIntPriority(cpu, i); 815 816 } else { 817 if (getActiveInt(cpu, intNumToWord(i)) 818 & (1 << intNumToBit(i))) 819 if (getIntPriority(cpu, i) < maxPriority) 820 maxPriority = getIntPriority(cpu, i); 821 } 822 } 823 iccrpr[cpu] = maxPriority; 824 } 825} 826 827void 828GicV2::sendInt(uint32_t num) 829{ 830 uint8_t target = getCpuTarget(0, num); 831 DPRINTF(Interrupt, "Received Interrupt number %d, cpuTarget %#x: \n", 832 num, target); 833 if ((target & (target - 1)) && !gem5ExtensionsEnabled) 834 panic("Multiple targets for peripheral interrupts is not supported\n"); 835 panic_if(num < SGI_MAX + PPI_MAX, 836 "sentInt() must only be used for interrupts 32 and higher"); 837 getPendingInt(target, intNumToWord(num)) |= 1 << intNumToBit(num); 838 updateIntState(intNumToWord(num)); 839} 840 841void 842GicV2::sendPPInt(uint32_t num, uint32_t cpu) 843{ 844 DPRINTF(Interrupt, "Received PPI %d, cpuTarget %#x: \n", 845 num, cpu); 846 cpuPpiPending[cpu] |= 1 << (num - SGI_MAX); 847 updateIntState(intNumToWord(num)); 848} 849 850void 851GicV2::clearInt(uint32_t number) 852{ 853 /* @todo assume edge triggered only at the moment. Nothing to do. */ 854} 855 856void 857GicV2::clearPPInt(uint32_t num, uint32_t cpu) 858{ 859 DPRINTF(Interrupt, "Clearing PPI %d, cpuTarget %#x: \n", 860 num, cpu); 861 cpuPpiPending[cpu] &= ~(1 << (num - SGI_MAX)); 862 updateIntState(intNumToWord(num)); 863} 864 865void 866GicV2::postInt(uint32_t cpu, Tick when) 867{ 868 if (!(postIntEvent[cpu]->scheduled())) { 869 ++pendingDelayedInterrupts; 870 eventq->schedule(postIntEvent[cpu], when); 871 } 872} 873 874void 875GicV2::postDelayedInt(uint32_t cpu) 876{ 877 platform->intrctrl->post(cpu, ArmISA::INT_IRQ, 0); 878 --pendingDelayedInterrupts; 879 assert(pendingDelayedInterrupts >= 0); 880 if (pendingDelayedInterrupts == 0) 881 signalDrainDone(); 882} 883 884DrainState 885GicV2::drain() 886{ 887 if (pendingDelayedInterrupts == 0) { 888 return DrainState::Drained; 889 } else { 890 return DrainState::Draining; 891 } 892} 893 894 895void 896GicV2::drainResume() 897{ 898 // There may be pending interrupts if checkpointed from Kvm; post them. 899 updateIntState(-1); 900} 901 902void 903GicV2::serialize(CheckpointOut &cp) const 904{ 905 DPRINTF(Checkpoint, "Serializing Arm GIC\n"); 906 907 SERIALIZE_SCALAR(enabled); 908 SERIALIZE_SCALAR(itLines); 909 SERIALIZE_ARRAY(intEnabled, INT_BITS_MAX-1); 910 SERIALIZE_ARRAY(pendingInt, INT_BITS_MAX-1); 911 SERIALIZE_ARRAY(activeInt, INT_BITS_MAX-1); 912 SERIALIZE_ARRAY(iccrpr, CPU_MAX); 913 SERIALIZE_ARRAY(intPriority, GLOBAL_INT_LINES); 914 SERIALIZE_ARRAY(cpuTarget, GLOBAL_INT_LINES); 915 SERIALIZE_ARRAY(intConfig, INT_BITS_MAX * 2); 916 SERIALIZE_ARRAY(cpuEnabled, CPU_MAX); 917 SERIALIZE_ARRAY(cpuPriority, CPU_MAX); 918 SERIALIZE_ARRAY(cpuBpr, CPU_MAX); 919 SERIALIZE_ARRAY(cpuHighestInt, CPU_MAX); 920 SERIALIZE_ARRAY(cpuSgiActive, SGI_MAX); 921 SERIALIZE_ARRAY(cpuSgiPending, SGI_MAX); 922 SERIALIZE_ARRAY(cpuSgiActiveExt, CPU_MAX); 923 SERIALIZE_ARRAY(cpuSgiPendingExt, CPU_MAX); 924 SERIALIZE_ARRAY(cpuPpiActive, CPU_MAX); 925 SERIALIZE_ARRAY(cpuPpiPending, CPU_MAX); 926 SERIALIZE_SCALAR(gem5ExtensionsEnabled); 927 928 for (uint32_t i=0; i < bankedRegs.size(); ++i) { 929 if (!bankedRegs[i]) 930 continue; 931 bankedRegs[i]->serializeSection(cp, csprintf("bankedRegs%i", i)); 932 } 933} 934 935void 936GicV2::BankedRegs::serialize(CheckpointOut &cp) const 937{ 938 SERIALIZE_SCALAR(intEnabled); 939 SERIALIZE_SCALAR(pendingInt); 940 SERIALIZE_SCALAR(activeInt); 941 SERIALIZE_ARRAY(intPriority, SGI_MAX + PPI_MAX); 942} 943 944void 945GicV2::unserialize(CheckpointIn &cp) 946{ 947 DPRINTF(Checkpoint, "Unserializing Arm GIC\n"); 948 949 UNSERIALIZE_SCALAR(enabled); 950 UNSERIALIZE_SCALAR(itLines); 951 UNSERIALIZE_ARRAY(intEnabled, INT_BITS_MAX-1); 952 UNSERIALIZE_ARRAY(pendingInt, INT_BITS_MAX-1); 953 UNSERIALIZE_ARRAY(activeInt, INT_BITS_MAX-1); 954 UNSERIALIZE_ARRAY(iccrpr, CPU_MAX); 955 UNSERIALIZE_ARRAY(intPriority, GLOBAL_INT_LINES); 956 UNSERIALIZE_ARRAY(cpuTarget, GLOBAL_INT_LINES); 957 UNSERIALIZE_ARRAY(intConfig, INT_BITS_MAX * 2); 958 UNSERIALIZE_ARRAY(cpuEnabled, CPU_MAX); 959 UNSERIALIZE_ARRAY(cpuPriority, CPU_MAX); 960 UNSERIALIZE_ARRAY(cpuBpr, CPU_MAX); 961 UNSERIALIZE_ARRAY(cpuHighestInt, CPU_MAX); 962 UNSERIALIZE_ARRAY(cpuSgiActive, SGI_MAX); 963 UNSERIALIZE_ARRAY(cpuSgiPending, SGI_MAX); 964 UNSERIALIZE_ARRAY(cpuSgiActiveExt, CPU_MAX); 965 UNSERIALIZE_ARRAY(cpuSgiPendingExt, CPU_MAX); 966 UNSERIALIZE_ARRAY(cpuPpiActive, CPU_MAX); 967 UNSERIALIZE_ARRAY(cpuPpiPending, CPU_MAX); 968 969 // Handle checkpoints from before we drained the GIC to prevent 970 // in-flight interrupts. 971 if (cp.entryExists(Serializable::currentSection(), "interrupt_time")) { 972 Tick interrupt_time[CPU_MAX]; 973 UNSERIALIZE_ARRAY(interrupt_time, CPU_MAX); 974 975 for (uint32_t cpu = 0; cpu < CPU_MAX; cpu++) { 976 if (interrupt_time[cpu]) 977 schedule(postIntEvent[cpu], interrupt_time[cpu]); 978 } 979 } 980 981 if (!UNSERIALIZE_OPT_SCALAR(gem5ExtensionsEnabled)) 982 gem5ExtensionsEnabled = false; 983 984 for (uint32_t i=0; i < CPU_MAX; ++i) { 985 ScopedCheckpointSection sec(cp, csprintf("bankedRegs%i", i)); 986 if (cp.sectionExists(Serializable::currentSection())) { 987 getBankedRegs(i).unserialize(cp); 988 } 989 } 990} 991 992void 993GicV2::BankedRegs::unserialize(CheckpointIn &cp) 994{ 995 UNSERIALIZE_SCALAR(intEnabled); 996 UNSERIALIZE_SCALAR(pendingInt); 997 UNSERIALIZE_SCALAR(activeInt); 998 UNSERIALIZE_ARRAY(intPriority, SGI_MAX + PPI_MAX); 999} 1000 1001GicV2 * 1002GicV2Params::create() 1003{ 1004 return new GicV2(this); 1005} 1006