pmu.cc (12177:6a730a33da01) | pmu.cc (12278:3a5e50b4f9d9) |
---|---|
1/* 2 * Copyright (c) 2011-2014, 2017 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 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Dam Sunwoo 38 * Matt Horsnell 39 * Andreas Sandberg 40 */ 41 42#include "arch/arm/pmu.hh" 43 44#include "arch/arm/isa.hh" 45#include "arch/arm/utility.hh" 46#include "base/trace.hh" 47#include "cpu/base.hh" 48#include "debug/Checkpoint.hh" 49#include "debug/PMUVerbose.hh" 50#include "dev/arm/base_gic.hh" 51#include "dev/arm/realview.hh" 52#include "params/ArmPMU.hh" 53 54namespace ArmISA { 55 56const MiscReg PMU::reg_pmcr_wr_mask = 0x39; 57 58PMU::PMU(const ArmPMUParams *p) 59 : SimObject(p), BaseISADevice(), 60 reg_pmcnten(0), reg_pmcr(0), 61 reg_pmselr(0), reg_pminten(0), reg_pmovsr(0), 62 reg_pmceid0(0),reg_pmceid1(0), 63 clock_remainder(0), 64 counters(p->eventCounters), 65 reg_pmcr_conf(0), 66 pmuInterrupt(p->pmuInterrupt), 67 platform(p->platform) 68{ 69 DPRINTF(PMUVerbose, "Initializing the PMU.\n"); 70 71 if (p->eventCounters > 31) { 72 fatal("The PMU can only accept 31 counters, %d counters requested.\n", 73 p->eventCounters); 74 } 75 76 /* Setup the performance counter ID registers */ 77 reg_pmcr_conf.imp = 0x41; // ARM Ltd. 78 reg_pmcr_conf.idcode = 0x00; 79 reg_pmcr_conf.n = p->eventCounters; 80 81 // Setup the hard-coded cycle counter, which is equivalent to 82 // architected counter event type 0x11. 83 cycleCounter.eventId = 0x11; 84} 85 86PMU::~PMU() 87{ 88} 89 90void 91PMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name) 92{ 93 DPRINTF(PMUVerbose, "PMU: Adding event type '0x%x' as probe %s:%s\n", 94 id, obj->name(), probe_name); 95 pmuEventTypes.insert(std::make_pair(id, EventType(obj, probe_name))); 96 97 // Flag the event as available in the corresponding PMCEID register if it 98 // is an architected event. 99 if (id < 0x20) { 100 reg_pmceid0 |= ((uint64_t)1) << id; 101 } else if (id > 0x20 && id < 0x40) { 102 reg_pmceid1 |= ((uint64_t)1) << (id - 0x20); 103 } else if (id >= 0x4000 && id < 0x4020) { 104 reg_pmceid0 |= ((uint64_t)1) << (id - 0x4000 + 32); 105 } else if (id >= 0x4020 && id < 0x4040) { 106 reg_pmceid1 |= ((uint64_t)1) << (id - 0x4020 + 32); 107 } 108} 109 110void 111PMU::drainResume() 112{ 113 // Re-attach enabled counters after a resume in case they changed. 114 updateAllCounters(); 115} 116 117void 118PMU::setMiscReg(int misc_reg, MiscReg val) 119{ 120 DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n", 121 miscRegName[unflattenMiscReg(misc_reg)], val); 122 123 switch (unflattenMiscReg(misc_reg)) { 124 case MISCREG_PMCR_EL0: 125 case MISCREG_PMCR: 126 setControlReg(val); 127 return; 128 129 case MISCREG_PMCNTENSET_EL0: 130 case MISCREG_PMCNTENSET: 131 reg_pmcnten |= val; 132 updateAllCounters(); 133 return; 134 135 case MISCREG_PMCNTENCLR_EL0: 136 case MISCREG_PMCNTENCLR: 137 reg_pmcnten &= ~val; 138 updateAllCounters(); 139 return; 140 141 case MISCREG_PMOVSCLR_EL0: 142 case MISCREG_PMOVSR: 143 reg_pmovsr &= ~val; 144 return; 145 146 case MISCREG_PMSWINC_EL0: 147 case MISCREG_PMSWINC: 148 for (int i = 0; i < counters.size(); ++i) { 149 CounterState &ctr(getCounter(i)); 150 if (ctr.enabled && (val & (1 << i)) 151 && ctr.eventId == ARCH_EVENT_SW_INCR ) { 152 ++ctr.value; 153 } 154 } 155 break; 156 157 case MISCREG_PMCCNTR_EL0: 158 case MISCREG_PMCCNTR: 159 cycleCounter.value = val; 160 return; 161 162 case MISCREG_PMSELR_EL0: 163 case MISCREG_PMSELR: 164 reg_pmselr = val; 165 return; 166 //TODO: implement MISCREF_PMCEID{2,3} 167 case MISCREG_PMCEID0_EL0: 168 case MISCREG_PMCEID0: 169 case MISCREG_PMCEID1_EL0: 170 case MISCREG_PMCEID1: 171 // Ignore writes 172 return; 173 174 case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0: 175 setCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0, val); 176 return; 177 178 case MISCREG_PMCCFILTR: 179 case MISCREG_PMCCFILTR_EL0: 180 DPRINTF(PMUVerbose, "Setting PMCCFILTR: 0x%x\n", val); 181 setCounterTypeRegister(PMCCNTR, val); 182 return; 183 184 case MISCREG_PMXEVTYPER_PMCCFILTR: 185 case MISCREG_PMXEVTYPER_EL0: 186 case MISCREG_PMXEVTYPER: 187 DPRINTF(PMUVerbose, "Setting counter type: " 188 "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n", 189 reg_pmselr, reg_pmselr.sel, val); 190 setCounterTypeRegister(reg_pmselr.sel, val); 191 return; 192 193 case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: 194 setCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0, val); 195 return; 196 197 case MISCREG_PMXEVCNTR_EL0: 198 case MISCREG_PMXEVCNTR: 199 setCounterValue(reg_pmselr.sel, val); 200 return; 201 202 case MISCREG_PMUSERENR_EL0: 203 case MISCREG_PMUSERENR: 204 // TODO 205 break; 206 207 case MISCREG_PMINTENSET_EL1: 208 case MISCREG_PMINTENSET: 209 reg_pminten |= val; 210 return; 211 212 case MISCREG_PMINTENCLR_EL1: 213 case MISCREG_PMINTENCLR: 214 reg_pminten &= ~val; 215 return; 216 217 case MISCREG_PMOVSSET_EL0: 218 case MISCREG_PMOVSSET: 219 reg_pmovsr |= val; 220 return; 221 222 default: 223 panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]); 224 } 225 226 warn("Not doing anything for write to miscreg %s\n", 227 miscRegName[misc_reg]); 228} 229 230MiscReg 231PMU::readMiscReg(int misc_reg) 232{ 233 MiscReg val(readMiscRegInt(misc_reg)); 234 DPRINTF(PMUVerbose, "readMiscReg(%s): 0x%x\n", 235 miscRegName[unflattenMiscReg(misc_reg)], val); 236 return val; 237} 238 239MiscReg 240PMU::readMiscRegInt(int misc_reg) 241{ 242 misc_reg = unflattenMiscReg(misc_reg); 243 switch (misc_reg) { 244 case MISCREG_PMCR_EL0: 245 case MISCREG_PMCR: 246 return reg_pmcr_conf | (reg_pmcr & reg_pmcr_wr_mask); 247 248 case MISCREG_PMCNTENSET_EL0: 249 case MISCREG_PMCNTENCLR_EL0: 250 case MISCREG_PMCNTENSET: 251 case MISCREG_PMCNTENCLR: 252 return reg_pmcnten; 253 254 case MISCREG_PMOVSCLR_EL0: 255 case MISCREG_PMOVSSET_EL0: 256 case MISCREG_PMOVSR: // Overflow Status Register 257 case MISCREG_PMOVSSET: 258 return reg_pmovsr; 259 260 case MISCREG_PMSWINC_EL0: 261 case MISCREG_PMSWINC: // Software Increment Register (RAZ) 262 return 0; 263 264 case MISCREG_PMSELR: 265 return reg_pmselr; 266 267 case MISCREG_PMCEID0_EL0: 268 return reg_pmceid0; 269 270 case MISCREG_PMCEID1_EL0: 271 return reg_pmceid1; 272 273 //TODO: implement MISCREF_PMCEID{2,3} 274 case MISCREG_PMCEID0: // Common Event ID register 275 return reg_pmceid0 & 0xFFFFFFFF; 276 277 case MISCREG_PMCEID1: // Common Event ID register 278 return reg_pmceid1 & 0xFFFFFFFF; 279 280 case MISCREG_PMCCNTR_EL0: 281 return cycleCounter.value; 282 283 case MISCREG_PMCCNTR: 284 return cycleCounter.value & 0xFFFFFFFF; 285 286 case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0: 287 return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0); 288 289 case MISCREG_PMCCFILTR: 290 case MISCREG_PMCCFILTR_EL0: 291 return getCounterTypeRegister(PMCCNTR); 292 293 case MISCREG_PMXEVTYPER_PMCCFILTR: 294 case MISCREG_PMXEVTYPER_EL0: 295 case MISCREG_PMXEVTYPER: 296 return getCounterTypeRegister(reg_pmselr.sel); 297 298 case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: 299 return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) & 0xFFFFFFFF; 300 301 case MISCREG_PMXEVCNTR_EL0: 302 case MISCREG_PMXEVCNTR: 303 return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF; 304 305 case MISCREG_PMUSERENR_EL0: 306 case MISCREG_PMUSERENR: 307 // TODO 308 return 0; 309 310 case MISCREG_PMINTENSET_EL1: 311 case MISCREG_PMINTENCLR_EL1: 312 case MISCREG_PMINTENSET: 313 case MISCREG_PMINTENCLR: 314 return reg_pminten; 315 316 default: 317 panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]); 318 } 319 320 warn("Not doing anything for read from miscreg %s\n", 321 miscRegName[misc_reg]); 322 return 0; 323} 324 325void 326PMU::setControlReg(PMCR_t val) 327{ 328 DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val); 329 330 if (val.p) { 331 DPRINTF(PMUVerbose, "PMU reset all events to zero.\n"); 332 resetEventCounts(); 333 } 334 335 if (val.c) { 336 DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n"); 337 cycleCounter.value = 0; 338 } 339 340 // Reset the clock remainder if divide by 64-mode is toggled. 341 if (reg_pmcr.d != val.d) 342 clock_remainder = 0; 343 344 reg_pmcr = val & reg_pmcr_wr_mask; 345 updateAllCounters(); 346} 347 348void 349PMU::updateAllCounters() 350{ 351 const bool global_enable(reg_pmcr.e); 352 353 for (int i = 0; i < counters.size(); ++i) { 354 CounterState &ctr(counters[i]); 355 const bool enable(global_enable && (reg_pmcnten & (1 << i))); 356 if (ctr.enabled != enable) { 357 ctr.enabled = enable; 358 updateCounter(i, ctr); 359 } 360 } 361 362 const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR))); 363 if (cycleCounter.enabled != ccntr_enable) { 364 cycleCounter.enabled = ccntr_enable; 365 updateCounter(PMCCNTR, cycleCounter); 366 } 367} 368 369bool 370PMU::isFiltered(const CounterState &ctr) const 371{ 372 assert(isa); 373 374 const PMEVTYPER_t filter(ctr.filter); 375 const SCR scr(isa->readMiscRegNoEffect(MISCREG_SCR)); 376 const CPSR cpsr(isa->readMiscRegNoEffect(MISCREG_CPSR)); 377 const ExceptionLevel el(opModeToEL((OperatingMode)(uint8_t)cpsr.mode)); 378 const bool secure(inSecureState(scr, cpsr)); 379 380 switch (el) { 381 case EL0: 382 return secure ? filter.u : (filter.u != filter.nsu); 383 384 case EL1: 385 return secure ? filter.p : (filter.p != filter.nsk); 386 387 case EL2: 388 return !filter.nsh; 389 390 case EL3: 391 return filter.p != filter.m; 392 393 default: 394 panic("Unexpected execution level in PMU::isFiltered.\n"); 395 } 396} 397 398void 399PMU::handleEvent(CounterId id, uint64_t delta) 400{ 401 CounterState &ctr(getCounter(id)); 402 const bool overflowed(reg_pmovsr & (1 << id)); 403 404 if (isFiltered(ctr)) 405 return; 406 407 // Handle the "count every 64 cycles" mode 408 if (id == PMCCNTR && reg_pmcr.d) { 409 clock_remainder += delta; 410 delta = (clock_remainder >> 6); 411 clock_remainder &= 63; 412 } 413 414 // Add delta and handle (new) overflows 415 if (ctr.add(delta) && !overflowed) { 416 DPRINTF(PMUVerbose, "PMU counter '%i' overflowed.\n", id); 417 reg_pmovsr |= (1 << id); 418 // Deliver a PMU interrupt if interrupt delivery is enabled 419 // for this counter. 420 if (reg_pminten & (1 << id)) 421 raiseInterrupt(); 422 } 423} 424 425void 426PMU::updateCounter(CounterId id, CounterState &ctr) 427{ 428 if (!ctr.enabled) { 429 if (!ctr.listeners.empty()) { 430 DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n", id); 431 ctr.listeners.clear(); 432 } 433 } else { 434 DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n", 435 id, ctr.eventId); 436 437 // Attach all probes belonging to this event 438 auto range(pmuEventTypes.equal_range(ctr.eventId)); 439 for (auto it = range.first; it != range.second; ++it) { 440 const EventType &et(it->second); 441 442 DPRINTF(PMUVerbose, "\tProbe: %s:%s\n", et.obj->name(), et.name); 443 ctr.listeners.emplace_back(et.create(*this, id)); 444 } 445 446 /* The SW_INCR event type is a special case which doesn't need 447 * any probes since it is controlled by software and the PMU 448 * itself. 449 */ 450 if (ctr.listeners.empty() && ctr.eventId != ARCH_EVENT_SW_INCR) { 451 warn("Can't enable PMU counter of type '0x%x': " 452 "No such event type.\n", ctr.eventId); 453 } 454 } 455} 456 457 458void 459PMU::resetEventCounts() 460{ 461 for (CounterState &ctr : counters) 462 ctr.value = 0; 463} 464 465void 466PMU::setCounterValue(CounterId id, uint64_t val) 467{ 468 if (!isValidCounter(id)) { 469 warn_once("Can't change counter value: Counter %i does not exist.\n", 470 id); 471 return; 472 } 473 474 CounterState &ctr(getCounter(id)); 475 ctr.value = val; 476} 477 478PMU::PMEVTYPER_t 479PMU::getCounterTypeRegister(CounterId id) const 480{ 481 if (!isValidCounter(id)) 482 return 0; 483 484 const CounterState &cs(getCounter(id)); 485 PMEVTYPER_t type(cs.filter); 486 487 type.evtCount = cs.eventId; 488 489 return type; 490} 491 492void 493PMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val) 494{ 495 DPRINTF(PMUVerbose, "Set Event [%d] = 0x%08x\n", id, val); 496 if (!isValidCounter(id)) { 497 warn_once("Can't change counter type: Counter %i does not exist.\n", 498 id); 499 return; 500 } 501 502 CounterState &ctr(getCounter(id)); 503 const EventTypeId old_event_id(ctr.eventId); 504 505 ctr.filter = val; 506 507 // If PMCCNTR Register, do not change event type. PMCCNTR can 508 // count processor cycles only. If we change the event type, we 509 // need to update the probes the counter is using. 510 if (id != PMCCNTR && old_event_id != val.evtCount) { 511 ctr.eventId = val.evtCount; 512 updateCounter(reg_pmselr.sel, ctr); 513 } 514} 515 516void 517PMU::raiseInterrupt() 518{ 519 RealView *rv(dynamic_cast<RealView *>(platform)); 520 if (!rv || !rv->gic) { 521 warn_once("ARM PMU: GIC missing, can't raise interrupt.\n"); 522 return; 523 } 524 525 DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n"); 526 rv->gic->sendInt(pmuInterrupt); 527} 528 529void 530PMU::serialize(CheckpointOut &cp) const 531{ 532 DPRINTF(Checkpoint, "Serializing Arm PMU\n"); 533 534 SERIALIZE_SCALAR(reg_pmcr); 535 SERIALIZE_SCALAR(reg_pmcnten); 536 SERIALIZE_SCALAR(reg_pmselr); 537 SERIALIZE_SCALAR(reg_pminten); 538 SERIALIZE_SCALAR(reg_pmovsr); 539 SERIALIZE_SCALAR(reg_pmceid0); 540 SERIALIZE_SCALAR(reg_pmceid1); 541 SERIALIZE_SCALAR(clock_remainder); 542 543 for (size_t i = 0; i < counters.size(); ++i) 544 counters[i].serializeSection(cp, csprintf("counters.%i", i)); 545 546 cycleCounter.serializeSection(cp, "cycleCounter"); 547} 548 549void 550PMU::unserialize(CheckpointIn &cp) 551{ 552 DPRINTF(Checkpoint, "Unserializing Arm PMU\n"); 553 554 UNSERIALIZE_SCALAR(reg_pmcr); 555 UNSERIALIZE_SCALAR(reg_pmcnten); 556 UNSERIALIZE_SCALAR(reg_pmselr); 557 UNSERIALIZE_SCALAR(reg_pminten); 558 UNSERIALIZE_SCALAR(reg_pmovsr); 559 560 // Old checkpoints used to store the entire PMCEID value in a 561 // single 64-bit entry (reg_pmceid). The register was extended in 562 // ARMv8.1, so we now need to store it as two 64-bit registers. 563 if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid0)) 564 paramIn(cp, "reg_pmceid", reg_pmceid0); 565 566 if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid1)) 567 reg_pmceid1 = 0; 568 569 UNSERIALIZE_SCALAR(clock_remainder); 570 571 for (size_t i = 0; i < counters.size(); ++i) 572 counters[i].unserializeSection(cp, csprintf("counters.%i", i)); 573 574 cycleCounter.unserializeSection(cp, "cycleCounter"); 575} 576 577void 578PMU::CounterState::serialize(CheckpointOut &cp) const 579{ 580 SERIALIZE_SCALAR(eventId); 581 SERIALIZE_SCALAR(value); | 1/* 2 * Copyright (c) 2011-2014, 2017 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 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Dam Sunwoo 38 * Matt Horsnell 39 * Andreas Sandberg 40 */ 41 42#include "arch/arm/pmu.hh" 43 44#include "arch/arm/isa.hh" 45#include "arch/arm/utility.hh" 46#include "base/trace.hh" 47#include "cpu/base.hh" 48#include "debug/Checkpoint.hh" 49#include "debug/PMUVerbose.hh" 50#include "dev/arm/base_gic.hh" 51#include "dev/arm/realview.hh" 52#include "params/ArmPMU.hh" 53 54namespace ArmISA { 55 56const MiscReg PMU::reg_pmcr_wr_mask = 0x39; 57 58PMU::PMU(const ArmPMUParams *p) 59 : SimObject(p), BaseISADevice(), 60 reg_pmcnten(0), reg_pmcr(0), 61 reg_pmselr(0), reg_pminten(0), reg_pmovsr(0), 62 reg_pmceid0(0),reg_pmceid1(0), 63 clock_remainder(0), 64 counters(p->eventCounters), 65 reg_pmcr_conf(0), 66 pmuInterrupt(p->pmuInterrupt), 67 platform(p->platform) 68{ 69 DPRINTF(PMUVerbose, "Initializing the PMU.\n"); 70 71 if (p->eventCounters > 31) { 72 fatal("The PMU can only accept 31 counters, %d counters requested.\n", 73 p->eventCounters); 74 } 75 76 /* Setup the performance counter ID registers */ 77 reg_pmcr_conf.imp = 0x41; // ARM Ltd. 78 reg_pmcr_conf.idcode = 0x00; 79 reg_pmcr_conf.n = p->eventCounters; 80 81 // Setup the hard-coded cycle counter, which is equivalent to 82 // architected counter event type 0x11. 83 cycleCounter.eventId = 0x11; 84} 85 86PMU::~PMU() 87{ 88} 89 90void 91PMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name) 92{ 93 DPRINTF(PMUVerbose, "PMU: Adding event type '0x%x' as probe %s:%s\n", 94 id, obj->name(), probe_name); 95 pmuEventTypes.insert(std::make_pair(id, EventType(obj, probe_name))); 96 97 // Flag the event as available in the corresponding PMCEID register if it 98 // is an architected event. 99 if (id < 0x20) { 100 reg_pmceid0 |= ((uint64_t)1) << id; 101 } else if (id > 0x20 && id < 0x40) { 102 reg_pmceid1 |= ((uint64_t)1) << (id - 0x20); 103 } else if (id >= 0x4000 && id < 0x4020) { 104 reg_pmceid0 |= ((uint64_t)1) << (id - 0x4000 + 32); 105 } else if (id >= 0x4020 && id < 0x4040) { 106 reg_pmceid1 |= ((uint64_t)1) << (id - 0x4020 + 32); 107 } 108} 109 110void 111PMU::drainResume() 112{ 113 // Re-attach enabled counters after a resume in case they changed. 114 updateAllCounters(); 115} 116 117void 118PMU::setMiscReg(int misc_reg, MiscReg val) 119{ 120 DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n", 121 miscRegName[unflattenMiscReg(misc_reg)], val); 122 123 switch (unflattenMiscReg(misc_reg)) { 124 case MISCREG_PMCR_EL0: 125 case MISCREG_PMCR: 126 setControlReg(val); 127 return; 128 129 case MISCREG_PMCNTENSET_EL0: 130 case MISCREG_PMCNTENSET: 131 reg_pmcnten |= val; 132 updateAllCounters(); 133 return; 134 135 case MISCREG_PMCNTENCLR_EL0: 136 case MISCREG_PMCNTENCLR: 137 reg_pmcnten &= ~val; 138 updateAllCounters(); 139 return; 140 141 case MISCREG_PMOVSCLR_EL0: 142 case MISCREG_PMOVSR: 143 reg_pmovsr &= ~val; 144 return; 145 146 case MISCREG_PMSWINC_EL0: 147 case MISCREG_PMSWINC: 148 for (int i = 0; i < counters.size(); ++i) { 149 CounterState &ctr(getCounter(i)); 150 if (ctr.enabled && (val & (1 << i)) 151 && ctr.eventId == ARCH_EVENT_SW_INCR ) { 152 ++ctr.value; 153 } 154 } 155 break; 156 157 case MISCREG_PMCCNTR_EL0: 158 case MISCREG_PMCCNTR: 159 cycleCounter.value = val; 160 return; 161 162 case MISCREG_PMSELR_EL0: 163 case MISCREG_PMSELR: 164 reg_pmselr = val; 165 return; 166 //TODO: implement MISCREF_PMCEID{2,3} 167 case MISCREG_PMCEID0_EL0: 168 case MISCREG_PMCEID0: 169 case MISCREG_PMCEID1_EL0: 170 case MISCREG_PMCEID1: 171 // Ignore writes 172 return; 173 174 case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0: 175 setCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0, val); 176 return; 177 178 case MISCREG_PMCCFILTR: 179 case MISCREG_PMCCFILTR_EL0: 180 DPRINTF(PMUVerbose, "Setting PMCCFILTR: 0x%x\n", val); 181 setCounterTypeRegister(PMCCNTR, val); 182 return; 183 184 case MISCREG_PMXEVTYPER_PMCCFILTR: 185 case MISCREG_PMXEVTYPER_EL0: 186 case MISCREG_PMXEVTYPER: 187 DPRINTF(PMUVerbose, "Setting counter type: " 188 "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n", 189 reg_pmselr, reg_pmselr.sel, val); 190 setCounterTypeRegister(reg_pmselr.sel, val); 191 return; 192 193 case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: 194 setCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0, val); 195 return; 196 197 case MISCREG_PMXEVCNTR_EL0: 198 case MISCREG_PMXEVCNTR: 199 setCounterValue(reg_pmselr.sel, val); 200 return; 201 202 case MISCREG_PMUSERENR_EL0: 203 case MISCREG_PMUSERENR: 204 // TODO 205 break; 206 207 case MISCREG_PMINTENSET_EL1: 208 case MISCREG_PMINTENSET: 209 reg_pminten |= val; 210 return; 211 212 case MISCREG_PMINTENCLR_EL1: 213 case MISCREG_PMINTENCLR: 214 reg_pminten &= ~val; 215 return; 216 217 case MISCREG_PMOVSSET_EL0: 218 case MISCREG_PMOVSSET: 219 reg_pmovsr |= val; 220 return; 221 222 default: 223 panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]); 224 } 225 226 warn("Not doing anything for write to miscreg %s\n", 227 miscRegName[misc_reg]); 228} 229 230MiscReg 231PMU::readMiscReg(int misc_reg) 232{ 233 MiscReg val(readMiscRegInt(misc_reg)); 234 DPRINTF(PMUVerbose, "readMiscReg(%s): 0x%x\n", 235 miscRegName[unflattenMiscReg(misc_reg)], val); 236 return val; 237} 238 239MiscReg 240PMU::readMiscRegInt(int misc_reg) 241{ 242 misc_reg = unflattenMiscReg(misc_reg); 243 switch (misc_reg) { 244 case MISCREG_PMCR_EL0: 245 case MISCREG_PMCR: 246 return reg_pmcr_conf | (reg_pmcr & reg_pmcr_wr_mask); 247 248 case MISCREG_PMCNTENSET_EL0: 249 case MISCREG_PMCNTENCLR_EL0: 250 case MISCREG_PMCNTENSET: 251 case MISCREG_PMCNTENCLR: 252 return reg_pmcnten; 253 254 case MISCREG_PMOVSCLR_EL0: 255 case MISCREG_PMOVSSET_EL0: 256 case MISCREG_PMOVSR: // Overflow Status Register 257 case MISCREG_PMOVSSET: 258 return reg_pmovsr; 259 260 case MISCREG_PMSWINC_EL0: 261 case MISCREG_PMSWINC: // Software Increment Register (RAZ) 262 return 0; 263 264 case MISCREG_PMSELR: 265 return reg_pmselr; 266 267 case MISCREG_PMCEID0_EL0: 268 return reg_pmceid0; 269 270 case MISCREG_PMCEID1_EL0: 271 return reg_pmceid1; 272 273 //TODO: implement MISCREF_PMCEID{2,3} 274 case MISCREG_PMCEID0: // Common Event ID register 275 return reg_pmceid0 & 0xFFFFFFFF; 276 277 case MISCREG_PMCEID1: // Common Event ID register 278 return reg_pmceid1 & 0xFFFFFFFF; 279 280 case MISCREG_PMCCNTR_EL0: 281 return cycleCounter.value; 282 283 case MISCREG_PMCCNTR: 284 return cycleCounter.value & 0xFFFFFFFF; 285 286 case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0: 287 return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0); 288 289 case MISCREG_PMCCFILTR: 290 case MISCREG_PMCCFILTR_EL0: 291 return getCounterTypeRegister(PMCCNTR); 292 293 case MISCREG_PMXEVTYPER_PMCCFILTR: 294 case MISCREG_PMXEVTYPER_EL0: 295 case MISCREG_PMXEVTYPER: 296 return getCounterTypeRegister(reg_pmselr.sel); 297 298 case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: 299 return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) & 0xFFFFFFFF; 300 301 case MISCREG_PMXEVCNTR_EL0: 302 case MISCREG_PMXEVCNTR: 303 return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF; 304 305 case MISCREG_PMUSERENR_EL0: 306 case MISCREG_PMUSERENR: 307 // TODO 308 return 0; 309 310 case MISCREG_PMINTENSET_EL1: 311 case MISCREG_PMINTENCLR_EL1: 312 case MISCREG_PMINTENSET: 313 case MISCREG_PMINTENCLR: 314 return reg_pminten; 315 316 default: 317 panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]); 318 } 319 320 warn("Not doing anything for read from miscreg %s\n", 321 miscRegName[misc_reg]); 322 return 0; 323} 324 325void 326PMU::setControlReg(PMCR_t val) 327{ 328 DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val); 329 330 if (val.p) { 331 DPRINTF(PMUVerbose, "PMU reset all events to zero.\n"); 332 resetEventCounts(); 333 } 334 335 if (val.c) { 336 DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n"); 337 cycleCounter.value = 0; 338 } 339 340 // Reset the clock remainder if divide by 64-mode is toggled. 341 if (reg_pmcr.d != val.d) 342 clock_remainder = 0; 343 344 reg_pmcr = val & reg_pmcr_wr_mask; 345 updateAllCounters(); 346} 347 348void 349PMU::updateAllCounters() 350{ 351 const bool global_enable(reg_pmcr.e); 352 353 for (int i = 0; i < counters.size(); ++i) { 354 CounterState &ctr(counters[i]); 355 const bool enable(global_enable && (reg_pmcnten & (1 << i))); 356 if (ctr.enabled != enable) { 357 ctr.enabled = enable; 358 updateCounter(i, ctr); 359 } 360 } 361 362 const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR))); 363 if (cycleCounter.enabled != ccntr_enable) { 364 cycleCounter.enabled = ccntr_enable; 365 updateCounter(PMCCNTR, cycleCounter); 366 } 367} 368 369bool 370PMU::isFiltered(const CounterState &ctr) const 371{ 372 assert(isa); 373 374 const PMEVTYPER_t filter(ctr.filter); 375 const SCR scr(isa->readMiscRegNoEffect(MISCREG_SCR)); 376 const CPSR cpsr(isa->readMiscRegNoEffect(MISCREG_CPSR)); 377 const ExceptionLevel el(opModeToEL((OperatingMode)(uint8_t)cpsr.mode)); 378 const bool secure(inSecureState(scr, cpsr)); 379 380 switch (el) { 381 case EL0: 382 return secure ? filter.u : (filter.u != filter.nsu); 383 384 case EL1: 385 return secure ? filter.p : (filter.p != filter.nsk); 386 387 case EL2: 388 return !filter.nsh; 389 390 case EL3: 391 return filter.p != filter.m; 392 393 default: 394 panic("Unexpected execution level in PMU::isFiltered.\n"); 395 } 396} 397 398void 399PMU::handleEvent(CounterId id, uint64_t delta) 400{ 401 CounterState &ctr(getCounter(id)); 402 const bool overflowed(reg_pmovsr & (1 << id)); 403 404 if (isFiltered(ctr)) 405 return; 406 407 // Handle the "count every 64 cycles" mode 408 if (id == PMCCNTR && reg_pmcr.d) { 409 clock_remainder += delta; 410 delta = (clock_remainder >> 6); 411 clock_remainder &= 63; 412 } 413 414 // Add delta and handle (new) overflows 415 if (ctr.add(delta) && !overflowed) { 416 DPRINTF(PMUVerbose, "PMU counter '%i' overflowed.\n", id); 417 reg_pmovsr |= (1 << id); 418 // Deliver a PMU interrupt if interrupt delivery is enabled 419 // for this counter. 420 if (reg_pminten & (1 << id)) 421 raiseInterrupt(); 422 } 423} 424 425void 426PMU::updateCounter(CounterId id, CounterState &ctr) 427{ 428 if (!ctr.enabled) { 429 if (!ctr.listeners.empty()) { 430 DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n", id); 431 ctr.listeners.clear(); 432 } 433 } else { 434 DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n", 435 id, ctr.eventId); 436 437 // Attach all probes belonging to this event 438 auto range(pmuEventTypes.equal_range(ctr.eventId)); 439 for (auto it = range.first; it != range.second; ++it) { 440 const EventType &et(it->second); 441 442 DPRINTF(PMUVerbose, "\tProbe: %s:%s\n", et.obj->name(), et.name); 443 ctr.listeners.emplace_back(et.create(*this, id)); 444 } 445 446 /* The SW_INCR event type is a special case which doesn't need 447 * any probes since it is controlled by software and the PMU 448 * itself. 449 */ 450 if (ctr.listeners.empty() && ctr.eventId != ARCH_EVENT_SW_INCR) { 451 warn("Can't enable PMU counter of type '0x%x': " 452 "No such event type.\n", ctr.eventId); 453 } 454 } 455} 456 457 458void 459PMU::resetEventCounts() 460{ 461 for (CounterState &ctr : counters) 462 ctr.value = 0; 463} 464 465void 466PMU::setCounterValue(CounterId id, uint64_t val) 467{ 468 if (!isValidCounter(id)) { 469 warn_once("Can't change counter value: Counter %i does not exist.\n", 470 id); 471 return; 472 } 473 474 CounterState &ctr(getCounter(id)); 475 ctr.value = val; 476} 477 478PMU::PMEVTYPER_t 479PMU::getCounterTypeRegister(CounterId id) const 480{ 481 if (!isValidCounter(id)) 482 return 0; 483 484 const CounterState &cs(getCounter(id)); 485 PMEVTYPER_t type(cs.filter); 486 487 type.evtCount = cs.eventId; 488 489 return type; 490} 491 492void 493PMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val) 494{ 495 DPRINTF(PMUVerbose, "Set Event [%d] = 0x%08x\n", id, val); 496 if (!isValidCounter(id)) { 497 warn_once("Can't change counter type: Counter %i does not exist.\n", 498 id); 499 return; 500 } 501 502 CounterState &ctr(getCounter(id)); 503 const EventTypeId old_event_id(ctr.eventId); 504 505 ctr.filter = val; 506 507 // If PMCCNTR Register, do not change event type. PMCCNTR can 508 // count processor cycles only. If we change the event type, we 509 // need to update the probes the counter is using. 510 if (id != PMCCNTR && old_event_id != val.evtCount) { 511 ctr.eventId = val.evtCount; 512 updateCounter(reg_pmselr.sel, ctr); 513 } 514} 515 516void 517PMU::raiseInterrupt() 518{ 519 RealView *rv(dynamic_cast<RealView *>(platform)); 520 if (!rv || !rv->gic) { 521 warn_once("ARM PMU: GIC missing, can't raise interrupt.\n"); 522 return; 523 } 524 525 DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n"); 526 rv->gic->sendInt(pmuInterrupt); 527} 528 529void 530PMU::serialize(CheckpointOut &cp) const 531{ 532 DPRINTF(Checkpoint, "Serializing Arm PMU\n"); 533 534 SERIALIZE_SCALAR(reg_pmcr); 535 SERIALIZE_SCALAR(reg_pmcnten); 536 SERIALIZE_SCALAR(reg_pmselr); 537 SERIALIZE_SCALAR(reg_pminten); 538 SERIALIZE_SCALAR(reg_pmovsr); 539 SERIALIZE_SCALAR(reg_pmceid0); 540 SERIALIZE_SCALAR(reg_pmceid1); 541 SERIALIZE_SCALAR(clock_remainder); 542 543 for (size_t i = 0; i < counters.size(); ++i) 544 counters[i].serializeSection(cp, csprintf("counters.%i", i)); 545 546 cycleCounter.serializeSection(cp, "cycleCounter"); 547} 548 549void 550PMU::unserialize(CheckpointIn &cp) 551{ 552 DPRINTF(Checkpoint, "Unserializing Arm PMU\n"); 553 554 UNSERIALIZE_SCALAR(reg_pmcr); 555 UNSERIALIZE_SCALAR(reg_pmcnten); 556 UNSERIALIZE_SCALAR(reg_pmselr); 557 UNSERIALIZE_SCALAR(reg_pminten); 558 UNSERIALIZE_SCALAR(reg_pmovsr); 559 560 // Old checkpoints used to store the entire PMCEID value in a 561 // single 64-bit entry (reg_pmceid). The register was extended in 562 // ARMv8.1, so we now need to store it as two 64-bit registers. 563 if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid0)) 564 paramIn(cp, "reg_pmceid", reg_pmceid0); 565 566 if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid1)) 567 reg_pmceid1 = 0; 568 569 UNSERIALIZE_SCALAR(clock_remainder); 570 571 for (size_t i = 0; i < counters.size(); ++i) 572 counters[i].unserializeSection(cp, csprintf("counters.%i", i)); 573 574 cycleCounter.unserializeSection(cp, "cycleCounter"); 575} 576 577void 578PMU::CounterState::serialize(CheckpointOut &cp) const 579{ 580 SERIALIZE_SCALAR(eventId); 581 SERIALIZE_SCALAR(value); |
582 SERIALIZE_SCALAR(enabled); | |
583 SERIALIZE_SCALAR(overflow64); 584} 585 586void 587PMU::CounterState::unserialize(CheckpointIn &cp) 588{ 589 UNSERIALIZE_SCALAR(eventId); 590 UNSERIALIZE_SCALAR(value); | 582 SERIALIZE_SCALAR(overflow64); 583} 584 585void 586PMU::CounterState::unserialize(CheckpointIn &cp) 587{ 588 UNSERIALIZE_SCALAR(eventId); 589 UNSERIALIZE_SCALAR(value); |
591 UNSERIALIZE_SCALAR(enabled); | |
592 UNSERIALIZE_SCALAR(overflow64); 593} 594 595bool 596PMU::CounterState::add(uint64_t delta) 597{ 598 const uint64_t msb(1ULL << (overflow64 ? 63 : 31)); 599 const uint64_t old_value(value); 600 601 value += delta; 602 603 // Overflow if the msb goes from 1 to 0 604 return (old_value & msb) && !(value & msb); 605} 606 607} // namespace ArmISA 608 609ArmISA::PMU * 610ArmPMUParams::create() 611{ 612 return new ArmISA::PMU(this); 613} | 590 UNSERIALIZE_SCALAR(overflow64); 591} 592 593bool 594PMU::CounterState::add(uint64_t delta) 595{ 596 const uint64_t msb(1ULL << (overflow64 ? 63 : 31)); 597 const uint64_t old_value(value); 598 599 value += delta; 600 601 // Overflow if the msb goes from 1 to 0 602 return (old_value & msb) && !(value & msb); 603} 604 605} // namespace ArmISA 606 607ArmISA::PMU * 608ArmPMUParams::create() 609{ 610 return new ArmISA::PMU(this); 611} |