2 * Copyright (c) 2011-2014, 2017-2018 ARM Limited
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.
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.
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.
43 #include "arch/arm/pmu.hh"
45 #include "arch/arm/isa.hh"
46 #include "arch/arm/utility.hh"
47 #include "base/trace.hh"
48 #include "cpu/base.hh"
49 #include "debug/Checkpoint.hh"
50 #include "debug/PMUVerbose.hh"
51 #include "dev/arm/base_gic.hh"
52 #include "dev/arm/generic_timer.hh"
53 #include "params/ArmPMU.hh"
57 const MiscReg
PMU::reg_pmcr_wr_mask
= 0x39;
59 PMU::PMU(const ArmPMUParams
*p
)
60 : SimObject(p
), BaseISADevice(),
61 reg_pmcnten(0), reg_pmcr(0),
62 reg_pmselr(0), reg_pminten(0), reg_pmovsr(0),
63 reg_pmceid0(0),reg_pmceid1(0),
65 maximumCounterCount(p
->eventCounters
),
66 cycleCounter(*this, maximumCounterCount
),
67 cycleCounterEventId(p
->cycleEventId
),
68 swIncrementEvent(nullptr),
70 interrupt(p
->interrupt
)
72 DPRINTF(PMUVerbose
, "Initializing the PMU.\n");
74 if (maximumCounterCount
> 31) {
75 fatal("The PMU can only accept 31 counters, %d counters requested.\n",
79 warn_if(!interrupt
, "ARM PMU: No interrupt specified, interrupt " \
80 "delivery disabled.\n");
82 /* Setup the performance counter ID registers */
83 reg_pmcr_conf
.imp
= 0x41; // ARM Ltd.
84 reg_pmcr_conf
.idcode
= 0x00;
85 reg_pmcr_conf
.n
= p
->eventCounters
;
87 // Setup the hard-coded cycle counter, which is equivalent to
88 // architected counter event type 0x11.
89 cycleCounter
.eventId
= 0x11;
97 PMU::setThreadContext(ThreadContext
*tc
)
99 DPRINTF(PMUVerbose
, "Assigning PMU to ContextID %i.\n", tc
->contextId());
101 interrupt
->setThreadContext(tc
);
105 PMU::addSoftwareIncrementEvent(unsigned int id
)
107 auto old_event
= eventMap
.find(id
);
108 DPRINTF(PMUVerbose
, "PMU: Adding SW increment event with id '0x%x'\n", id
);
110 if (swIncrementEvent
) {
111 fatal_if(old_event
== eventMap
.end() ||
112 old_event
->second
!= swIncrementEvent
,
113 "Trying to add a software increment event with multiple"
114 "IDs. This is not supported.\n");
118 fatal_if(old_event
!= eventMap
.end(), "An event with id %d has "
119 "been previously defined\n", id
);
121 swIncrementEvent
= new SWIncrementEvent();
122 eventMap
[id
] = swIncrementEvent
;
127 PMU::addEventProbe(unsigned int id
, SimObject
*obj
, const char *probe_name
)
130 DPRINTF(PMUVerbose
, "PMU: Adding Probe Driven event with id '0x%x'"
131 "as probe %s:%s\n",id
, obj
->name(), probe_name
);
133 RegularEvent
*event
= nullptr;
134 auto event_entry
= eventMap
.find(id
);
135 if (event_entry
== eventMap
.end()) {
137 event
= new RegularEvent();
138 eventMap
[id
] = event
;
141 event
= dynamic_cast<RegularEvent
*>(event_entry
->second
);
143 fatal("Event with id %d is not probe driven\n", id
);
146 event
->addMicroarchitectureProbe(obj
, probe_name
);
153 PMU::registerEvent(uint32_t id
)
155 // Flag the event as available in the corresponding PMCEID register if it
156 // is an architected event.
158 reg_pmceid0
|= ((uint64_t)1) << id
;
159 } else if (id
> 0x20 && id
< 0x40) {
160 reg_pmceid1
|= ((uint64_t)1) << (id
- 0x20);
161 } else if (id
>= 0x4000 && id
< 0x4020) {
162 reg_pmceid0
|= ((uint64_t)1) << (id
- 0x4000 + 32);
163 } else if (id
>= 0x4020 && id
< 0x4040) {
164 reg_pmceid1
|= ((uint64_t)1) << (id
- 0x4020 + 32);
171 // Re-attach enabled counters after a resume in case they changed.
176 PMU::regProbeListeners()
179 // at this stage all probe configurations are done
180 // counters can be configured
181 for (uint32_t index
= 0; index
< maximumCounterCount
-1; index
++) {
182 counters
.emplace_back(*this, index
);
185 PMUEvent
*event
= getEvent(cycleCounterEventId
);
186 panic_if(!event
, "core cycle event is not present\n");
187 cycleCounter
.enabled
= true;
188 cycleCounter
.attach(event
);
192 PMU::setMiscReg(int misc_reg
, MiscReg val
)
194 DPRINTF(PMUVerbose
, "setMiscReg(%s, 0x%x)\n",
195 miscRegName
[unflattenMiscReg(misc_reg
)], val
);
197 switch (unflattenMiscReg(misc_reg
)) {
198 case MISCREG_PMCR_EL0
:
203 case MISCREG_PMCNTENSET_EL0
:
204 case MISCREG_PMCNTENSET
:
209 case MISCREG_PMCNTENCLR_EL0
:
210 case MISCREG_PMCNTENCLR
:
215 case MISCREG_PMOVSCLR_EL0
:
220 case MISCREG_PMSWINC_EL0
:
221 case MISCREG_PMSWINC
:
222 if (swIncrementEvent
) {
223 swIncrementEvent
->write(val
);
227 case MISCREG_PMCCNTR_EL0
:
228 case MISCREG_PMCCNTR
:
229 cycleCounter
.setValue(val
);
232 case MISCREG_PMSELR_EL0
:
236 //TODO: implement MISCREF_PMCEID{2,3}
237 case MISCREG_PMCEID0_EL0
:
238 case MISCREG_PMCEID0
:
239 case MISCREG_PMCEID1_EL0
:
240 case MISCREG_PMCEID1
:
244 case MISCREG_PMEVTYPER0_EL0
...MISCREG_PMEVTYPER5_EL0
:
245 setCounterTypeRegister(misc_reg
- MISCREG_PMEVTYPER0_EL0
, val
);
248 case MISCREG_PMCCFILTR
:
249 case MISCREG_PMCCFILTR_EL0
:
250 DPRINTF(PMUVerbose
, "Setting PMCCFILTR: 0x%x\n", val
);
251 setCounterTypeRegister(PMCCNTR
, val
);
254 case MISCREG_PMXEVTYPER_PMCCFILTR
:
255 case MISCREG_PMXEVTYPER_EL0
:
256 case MISCREG_PMXEVTYPER
:
257 DPRINTF(PMUVerbose
, "Setting counter type: "
258 "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n",
259 reg_pmselr
, reg_pmselr
.sel
, val
);
260 setCounterTypeRegister(reg_pmselr
.sel
, val
);
263 case MISCREG_PMEVCNTR0_EL0
...MISCREG_PMEVCNTR5_EL0
:
264 setCounterValue(misc_reg
- MISCREG_PMEVCNTR0_EL0
, val
);
267 case MISCREG_PMXEVCNTR_EL0
:
268 case MISCREG_PMXEVCNTR
:
269 setCounterValue(reg_pmselr
.sel
, val
);
272 case MISCREG_PMUSERENR_EL0
:
273 case MISCREG_PMUSERENR
:
277 case MISCREG_PMINTENSET_EL1
:
278 case MISCREG_PMINTENSET
:
282 case MISCREG_PMINTENCLR_EL1
:
283 case MISCREG_PMINTENCLR
:
287 case MISCREG_PMOVSSET_EL0
:
288 case MISCREG_PMOVSSET
:
293 panic("Unexpected PMU register: %i\n", miscRegName
[misc_reg
]);
296 warn("Not doing anything for write to miscreg %s\n",
297 miscRegName
[misc_reg
]);
301 PMU::readMiscReg(int misc_reg
)
303 MiscReg
val(readMiscRegInt(misc_reg
));
304 DPRINTF(PMUVerbose
, "readMiscReg(%s): 0x%x\n",
305 miscRegName
[unflattenMiscReg(misc_reg
)], val
);
310 PMU::readMiscRegInt(int misc_reg
)
312 misc_reg
= unflattenMiscReg(misc_reg
);
314 case MISCREG_PMCR_EL0
:
316 return reg_pmcr_conf
| (reg_pmcr
& reg_pmcr_wr_mask
);
318 case MISCREG_PMCNTENSET_EL0
:
319 case MISCREG_PMCNTENCLR_EL0
:
320 case MISCREG_PMCNTENSET
:
321 case MISCREG_PMCNTENCLR
:
324 case MISCREG_PMOVSCLR_EL0
:
325 case MISCREG_PMOVSSET_EL0
:
326 case MISCREG_PMOVSR
: // Overflow Status Register
327 case MISCREG_PMOVSSET
:
330 case MISCREG_PMSWINC_EL0
:
331 case MISCREG_PMSWINC
: // Software Increment Register (RAZ)
337 case MISCREG_PMCEID0_EL0
:
340 case MISCREG_PMCEID1_EL0
:
343 //TODO: implement MISCREF_PMCEID{2,3}
344 case MISCREG_PMCEID0
: // Common Event ID register
345 return reg_pmceid0
& 0xFFFFFFFF;
347 case MISCREG_PMCEID1
: // Common Event ID register
348 return reg_pmceid1
& 0xFFFFFFFF;
350 case MISCREG_PMCCNTR_EL0
:
351 return cycleCounter
.getValue();
353 case MISCREG_PMCCNTR
:
354 return cycleCounter
.getValue() & 0xFFFFFFFF;
356 case MISCREG_PMEVTYPER0_EL0
...MISCREG_PMEVTYPER5_EL0
:
357 return getCounterTypeRegister(misc_reg
- MISCREG_PMEVTYPER0_EL0
);
359 case MISCREG_PMCCFILTR
:
360 case MISCREG_PMCCFILTR_EL0
:
361 return getCounterTypeRegister(PMCCNTR
);
363 case MISCREG_PMXEVTYPER_PMCCFILTR
:
364 case MISCREG_PMXEVTYPER_EL0
:
365 case MISCREG_PMXEVTYPER
:
366 return getCounterTypeRegister(reg_pmselr
.sel
);
368 case MISCREG_PMEVCNTR0_EL0
...MISCREG_PMEVCNTR5_EL0
: {
369 return getCounterValue(misc_reg
- MISCREG_PMEVCNTR0_EL0
) &
374 case MISCREG_PMXEVCNTR_EL0
:
375 case MISCREG_PMXEVCNTR
:
376 return getCounterValue(reg_pmselr
.sel
) & 0xFFFFFFFF;
378 case MISCREG_PMUSERENR_EL0
:
379 case MISCREG_PMUSERENR
:
383 case MISCREG_PMINTENSET_EL1
:
384 case MISCREG_PMINTENCLR_EL1
:
385 case MISCREG_PMINTENSET
:
386 case MISCREG_PMINTENCLR
:
390 panic("Unexpected PMU register: %i\n", miscRegName
[misc_reg
]);
393 warn("Not doing anything for read from miscreg %s\n",
394 miscRegName
[misc_reg
]);
399 PMU::setControlReg(PMCR_t val
)
401 DPRINTF(PMUVerbose
, "Set Control Reg 0x%08x.\n", val
);
404 DPRINTF(PMUVerbose
, "PMU reset all events to zero.\n");
409 DPRINTF(PMUVerbose
, "PMU reset cycle counter to zero.\n");
410 cycleCounter
.setValue(0);
413 // Reset the clock remainder if divide by 64-mode is toggled.
414 if (reg_pmcr
.d
!= val
.d
)
417 reg_pmcr
= val
& reg_pmcr_wr_mask
;
422 PMU::updateAllCounters()
424 const bool global_enable(reg_pmcr
.e
);
426 for (int i
= 0; i
< counters
.size(); ++i
) {
427 CounterState
&ctr(counters
[i
]);
428 const bool enable(global_enable
&& (reg_pmcnten
& (1 << i
)));
429 if (ctr
.enabled
!= enable
) {
430 ctr
.enabled
= enable
;
435 const bool ccntr_enable(global_enable
&& (reg_pmcnten
& (1 << PMCCNTR
)));
436 if (cycleCounter
.enabled
!= ccntr_enable
) {
437 cycleCounter
.enabled
= ccntr_enable
;
438 updateCounter(cycleCounter
);
443 PMU::PMUEvent::attachEvent(PMU::CounterState
*user
)
445 if (userCounters
.empty()) {
448 userCounters
.insert(user
);
449 updateAttachedCounters();
453 PMU::PMUEvent::increment(const uint64_t val
)
455 for (auto& counter
: userCounters
) {
461 PMU::PMUEvent::detachEvent(PMU::CounterState
*user
)
463 userCounters
.erase(user
);
465 if (userCounters
.empty()) {
471 PMU::RegularEvent::RegularProbe::notify(const uint64_t &val
)
473 parentEvent
->increment(val
);
477 PMU::RegularEvent::enable()
479 for (auto& subEvents
: microArchitectureEventSet
) {
480 attachedProbePointList
.emplace_back(
481 new RegularProbe(this, subEvents
.first
, subEvents
.second
));
486 PMU::RegularEvent::disable()
488 attachedProbePointList
.clear();
492 PMU::CounterState::isFiltered() const
496 const PMEVTYPER_t
filter(this->filter
);
497 const SCR
scr(pmu
.isa
->readMiscRegNoEffect(MISCREG_SCR
));
498 const CPSR
cpsr(pmu
.isa
->readMiscRegNoEffect(MISCREG_CPSR
));
499 const ExceptionLevel
el(opModeToEL((OperatingMode
)(uint8_t)cpsr
.mode
));
500 const bool secure(inSecureState(scr
, cpsr
));
504 return secure
? filter
.u
: (filter
.u
!= filter
.nsu
);
507 return secure
? filter
.p
: (filter
.p
!= filter
.nsk
);
513 return filter
.p
!= filter
.m
;
516 panic("Unexpected execution level in PMU::isFiltered.\n");
521 PMU::CounterState::detach()
524 sourceEvent
->detachEvent(this);
525 sourceEvent
= nullptr;
527 debugCounter("detaching event not currently attached"
533 PMU::CounterState::attach(PMUEvent
* event
)
537 sourceEvent
->attachEvent(this);
541 PMU::CounterState::getValue() const
544 sourceEvent
->updateAttachedCounters();
546 debugCounter("attempted to get value from a counter without"
547 " an associated event\n");
553 PMU::CounterState::setValue(uint64_t val
)
559 sourceEvent
->updateAttachedCounters();
561 debugCounter("attempted to set value from a counter without"
562 " an associated event\n");
567 PMU::updateCounter(CounterState
&ctr
)
570 DPRINTF(PMUVerbose
, "updateCounter(%i): Disabling counter\n",
575 DPRINTF(PMUVerbose
, "updateCounter(%i): Enable event id 0x%x\n",
576 ctr
.getCounterId(), ctr
.eventId
);
578 auto sourceEvent
= eventMap
.find(ctr
.eventId
);
579 if (sourceEvent
== eventMap
.end()) {
580 warn("Can't enable PMU counter of type '0x%x': "
581 "No such event type.\n", ctr
.eventId
);
583 ctr
.attach(sourceEvent
->second
);
590 PMU::resetEventCounts()
592 for (CounterState
&ctr
: counters
)
597 PMU::setCounterValue(CounterId id
, uint64_t val
)
599 if (!isValidCounter(id
)) {
600 warn_once("Can't change counter value: Counter %i does not exist.\n",
605 CounterState
&ctr(getCounter(id
));
610 PMU::getCounterTypeRegister(CounterId id
) const
612 if (!isValidCounter(id
))
615 const CounterState
&cs(getCounter(id
));
616 PMEVTYPER_t
type(cs
.filter
);
618 type
.evtCount
= cs
.eventId
;
624 PMU::setCounterTypeRegister(CounterId id
, PMEVTYPER_t val
)
626 DPRINTF(PMUVerbose
, "Set Event [%d] = 0x%08x\n", id
, val
);
627 if (!isValidCounter(id
)) {
628 warn_once("Can't change counter type: Counter %i does not exist.\n",
633 CounterState
&ctr(getCounter(id
));
634 const EventTypeId
old_event_id(ctr
.eventId
);
638 // If PMCCNTR Register, do not change event type. PMCCNTR can
639 // count processor cycles only. If we change the event type, we
640 // need to update the probes the counter is using.
641 if (id
!= PMCCNTR
&& old_event_id
!= val
.evtCount
) {
642 ctr
.eventId
= val
.evtCount
;
648 PMU::raiseInterrupt()
651 DPRINTF(PMUVerbose
, "Delivering PMU interrupt.\n");
654 warn_once("Dropping PMU interrupt as no interrupt has "
660 PMU::serialize(CheckpointOut
&cp
) const
662 DPRINTF(Checkpoint
, "Serializing Arm PMU\n");
664 SERIALIZE_SCALAR(reg_pmcr
);
665 SERIALIZE_SCALAR(reg_pmcnten
);
666 SERIALIZE_SCALAR(reg_pmselr
);
667 SERIALIZE_SCALAR(reg_pminten
);
668 SERIALIZE_SCALAR(reg_pmovsr
);
669 SERIALIZE_SCALAR(reg_pmceid0
);
670 SERIALIZE_SCALAR(reg_pmceid1
);
671 SERIALIZE_SCALAR(clock_remainder
);
673 for (size_t i
= 0; i
< counters
.size(); ++i
)
674 counters
[i
].serializeSection(cp
, csprintf("counters.%i", i
));
676 cycleCounter
.serializeSection(cp
, "cycleCounter");
680 PMU::unserialize(CheckpointIn
&cp
)
682 DPRINTF(Checkpoint
, "Unserializing Arm PMU\n");
684 UNSERIALIZE_SCALAR(reg_pmcr
);
685 UNSERIALIZE_SCALAR(reg_pmcnten
);
686 UNSERIALIZE_SCALAR(reg_pmselr
);
687 UNSERIALIZE_SCALAR(reg_pminten
);
688 UNSERIALIZE_SCALAR(reg_pmovsr
);
690 // Old checkpoints used to store the entire PMCEID value in a
691 // single 64-bit entry (reg_pmceid). The register was extended in
692 // ARMv8.1, so we now need to store it as two 64-bit registers.
693 if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid0
))
694 paramIn(cp
, "reg_pmceid", reg_pmceid0
);
696 if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid1
))
699 UNSERIALIZE_SCALAR(clock_remainder
);
701 for (size_t i
= 0; i
< counters
.size(); ++i
)
702 counters
[i
].unserializeSection(cp
, csprintf("counters.%i", i
));
704 cycleCounter
.unserializeSection(cp
, "cycleCounter");
708 PMU::getEvent(uint64_t eventId
)
710 auto entry
= eventMap
.find(eventId
);
712 if (entry
== eventMap
.end()) {
713 warn("event %d does not exist\n", eventId
);
716 return entry
->second
;
721 PMU::CounterState::serialize(CheckpointOut
&cp
) const
723 SERIALIZE_SCALAR(eventId
);
724 SERIALIZE_SCALAR(value
);
725 SERIALIZE_SCALAR(overflow64
);
729 PMU::CounterState::unserialize(CheckpointIn
&cp
)
731 UNSERIALIZE_SCALAR(eventId
);
732 UNSERIALIZE_SCALAR(value
);
733 UNSERIALIZE_SCALAR(overflow64
);
737 PMU::CounterState::add(uint64_t delta
)
739 uint64_t value_until_overflow
;
741 value_until_overflow
= UINT64_MAX
- value
;
743 value_until_overflow
= UINT32_MAX
- (uint32_t)value
;
747 return value_until_overflow
;
756 if (delta
> value_until_overflow
) {
758 // overflow situation detected
759 // flag the overflow occurence
760 pmu
.reg_pmovsr
|= (1 << counterId
);
762 // Deliver a PMU interrupt if interrupt delivery is enabled
764 if (pmu
.reg_pminten
& (1 << counterId
)) {
765 pmu
.raiseInterrupt();
767 return overflow64
? UINT64_MAX
: UINT32_MAX
;
769 return value_until_overflow
- delta
+ 1;
773 PMU::SWIncrementEvent::write(uint64_t val
)
775 for (auto& counter
: userCounters
) {
776 if (val
& (0x1 << counter
->getCounterId())) {
782 } // namespace ArmISA
785 ArmPMUParams::create()
787 return new ArmISA::PMU(this);