2 * Copyright (c) 2011-2014, 2017-2019 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 RegVal
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),
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(!p
->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());
100 auto pmu_params
= static_cast<const ArmPMUParams
*>(params());
102 if (pmu_params
->interrupt
)
103 interrupt
= pmu_params
->interrupt
->get(tc
);
107 PMU::addSoftwareIncrementEvent(unsigned int id
)
109 auto old_event
= eventMap
.find(id
);
110 DPRINTF(PMUVerbose
, "PMU: Adding SW increment event with id '0x%x'\n", id
);
112 if (swIncrementEvent
) {
113 fatal_if(old_event
== eventMap
.end() ||
114 old_event
->second
!= swIncrementEvent
,
115 "Trying to add a software increment event with multiple"
116 "IDs. This is not supported.\n");
120 fatal_if(old_event
!= eventMap
.end(), "An event with id %d has "
121 "been previously defined\n", id
);
123 swIncrementEvent
= new SWIncrementEvent();
124 eventMap
[id
] = swIncrementEvent
;
129 PMU::addEventProbe(unsigned int id
, SimObject
*obj
, const char *probe_name
)
132 DPRINTF(PMUVerbose
, "PMU: Adding Probe Driven event with id '0x%x'"
133 "as probe %s:%s\n",id
, obj
->name(), probe_name
);
135 RegularEvent
*event
= nullptr;
136 auto event_entry
= eventMap
.find(id
);
137 if (event_entry
== eventMap
.end()) {
139 event
= new RegularEvent();
140 eventMap
[id
] = event
;
143 event
= dynamic_cast<RegularEvent
*>(event_entry
->second
);
145 fatal("Event with id %d is not probe driven\n", id
);
148 event
->addMicroarchitectureProbe(obj
, probe_name
);
155 PMU::registerEvent(uint32_t id
)
157 // Flag the event as available in the corresponding PMCEID register if it
158 // is an architected event.
160 reg_pmceid0
|= ((uint64_t)1) << id
;
161 } else if (id
> 0x20 && id
< 0x40) {
162 reg_pmceid1
|= ((uint64_t)1) << (id
- 0x20);
163 } else if (id
>= 0x4000 && id
< 0x4020) {
164 reg_pmceid0
|= ((uint64_t)1) << (id
- 0x4000 + 32);
165 } else if (id
>= 0x4020 && id
< 0x4040) {
166 reg_pmceid1
|= ((uint64_t)1) << (id
- 0x4020 + 32);
173 // Re-attach enabled counters after a resume in case they changed.
178 PMU::regProbeListeners()
181 // at this stage all probe configurations are done
182 // counters can be configured
183 for (uint32_t index
= 0; index
< maximumCounterCount
-1; index
++) {
184 counters
.emplace_back(*this, index
);
187 PMUEvent
*event
= getEvent(cycleCounterEventId
);
188 panic_if(!event
, "core cycle event is not present\n");
189 cycleCounter
.enabled
= true;
190 cycleCounter
.attach(event
);
194 PMU::setMiscReg(int misc_reg
, RegVal val
)
196 DPRINTF(PMUVerbose
, "setMiscReg(%s, 0x%x)\n",
197 miscRegName
[unflattenMiscReg(misc_reg
)], val
);
199 switch (unflattenMiscReg(misc_reg
)) {
200 case MISCREG_PMCR_EL0
:
205 case MISCREG_PMCNTENSET_EL0
:
206 case MISCREG_PMCNTENSET
:
211 case MISCREG_PMCNTENCLR_EL0
:
212 case MISCREG_PMCNTENCLR
:
217 case MISCREG_PMOVSCLR_EL0
:
219 setOverflowStatus(reg_pmovsr
& ~val
);
222 case MISCREG_PMSWINC_EL0
:
223 case MISCREG_PMSWINC
:
224 if (swIncrementEvent
) {
225 swIncrementEvent
->write(val
);
229 case MISCREG_PMCCNTR_EL0
:
230 case MISCREG_PMCCNTR
:
231 cycleCounter
.setValue(val
);
234 case MISCREG_PMSELR_EL0
:
238 //TODO: implement MISCREF_PMCEID{2,3}
239 case MISCREG_PMCEID0_EL0
:
240 case MISCREG_PMCEID0
:
241 case MISCREG_PMCEID1_EL0
:
242 case MISCREG_PMCEID1
:
246 case MISCREG_PMEVTYPER0_EL0
...MISCREG_PMEVTYPER5_EL0
:
247 setCounterTypeRegister(misc_reg
- MISCREG_PMEVTYPER0_EL0
, val
);
250 case MISCREG_PMCCFILTR
:
251 case MISCREG_PMCCFILTR_EL0
:
252 DPRINTF(PMUVerbose
, "Setting PMCCFILTR: 0x%x\n", val
);
253 setCounterTypeRegister(PMCCNTR
, val
);
256 case MISCREG_PMXEVTYPER_PMCCFILTR
:
257 case MISCREG_PMXEVTYPER_EL0
:
258 case MISCREG_PMXEVTYPER
:
259 DPRINTF(PMUVerbose
, "Setting counter type: "
260 "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n",
261 reg_pmselr
, reg_pmselr
.sel
, val
);
262 setCounterTypeRegister(reg_pmselr
.sel
, val
);
265 case MISCREG_PMEVCNTR0_EL0
...MISCREG_PMEVCNTR5_EL0
:
266 setCounterValue(misc_reg
- MISCREG_PMEVCNTR0_EL0
, val
);
269 case MISCREG_PMXEVCNTR_EL0
:
270 case MISCREG_PMXEVCNTR
:
271 setCounterValue(reg_pmselr
.sel
, val
);
274 case MISCREG_PMUSERENR_EL0
:
275 case MISCREG_PMUSERENR
:
279 case MISCREG_PMINTENSET_EL1
:
280 case MISCREG_PMINTENSET
:
284 case MISCREG_PMINTENCLR_EL1
:
285 case MISCREG_PMINTENCLR
:
289 case MISCREG_PMOVSSET_EL0
:
290 case MISCREG_PMOVSSET
:
291 setOverflowStatus(reg_pmovsr
| val
);
295 panic("Unexpected PMU register: %i\n", miscRegName
[misc_reg
]);
298 warn("Not doing anything for write to miscreg %s\n",
299 miscRegName
[misc_reg
]);
303 PMU::readMiscReg(int misc_reg
)
305 RegVal
val(readMiscRegInt(misc_reg
));
306 DPRINTF(PMUVerbose
, "readMiscReg(%s): 0x%x\n",
307 miscRegName
[unflattenMiscReg(misc_reg
)], val
);
312 PMU::readMiscRegInt(int misc_reg
)
314 misc_reg
= unflattenMiscReg(misc_reg
);
316 case MISCREG_PMCR_EL0
:
318 return reg_pmcr_conf
| (reg_pmcr
& reg_pmcr_wr_mask
);
320 case MISCREG_PMCNTENSET_EL0
:
321 case MISCREG_PMCNTENCLR_EL0
:
322 case MISCREG_PMCNTENSET
:
323 case MISCREG_PMCNTENCLR
:
326 case MISCREG_PMOVSCLR_EL0
:
327 case MISCREG_PMOVSSET_EL0
:
328 case MISCREG_PMOVSR
: // Overflow Status Register
329 case MISCREG_PMOVSSET
:
332 case MISCREG_PMSWINC_EL0
:
333 case MISCREG_PMSWINC
: // Software Increment Register (RAZ)
336 case MISCREG_PMSELR_EL0
:
340 case MISCREG_PMCEID0_EL0
:
343 case MISCREG_PMCEID1_EL0
:
346 //TODO: implement MISCREF_PMCEID{2,3}
347 case MISCREG_PMCEID0
: // Common Event ID register
348 return reg_pmceid0
& 0xFFFFFFFF;
350 case MISCREG_PMCEID1
: // Common Event ID register
351 return reg_pmceid1
& 0xFFFFFFFF;
353 case MISCREG_PMCCNTR_EL0
:
354 return cycleCounter
.getValue();
356 case MISCREG_PMCCNTR
:
357 return cycleCounter
.getValue() & 0xFFFFFFFF;
359 case MISCREG_PMEVTYPER0_EL0
...MISCREG_PMEVTYPER5_EL0
:
360 return getCounterTypeRegister(misc_reg
- MISCREG_PMEVTYPER0_EL0
);
362 case MISCREG_PMCCFILTR
:
363 case MISCREG_PMCCFILTR_EL0
:
364 return getCounterTypeRegister(PMCCNTR
);
366 case MISCREG_PMXEVTYPER_PMCCFILTR
:
367 case MISCREG_PMXEVTYPER_EL0
:
368 case MISCREG_PMXEVTYPER
:
369 return getCounterTypeRegister(reg_pmselr
.sel
);
371 case MISCREG_PMEVCNTR0_EL0
...MISCREG_PMEVCNTR5_EL0
: {
372 return getCounterValue(misc_reg
- MISCREG_PMEVCNTR0_EL0
) &
377 case MISCREG_PMXEVCNTR_EL0
:
378 case MISCREG_PMXEVCNTR
:
379 return getCounterValue(reg_pmselr
.sel
) & 0xFFFFFFFF;
381 case MISCREG_PMUSERENR_EL0
:
382 case MISCREG_PMUSERENR
:
386 case MISCREG_PMINTENSET_EL1
:
387 case MISCREG_PMINTENCLR_EL1
:
388 case MISCREG_PMINTENSET
:
389 case MISCREG_PMINTENCLR
:
393 panic("Unexpected PMU register: %i\n", miscRegName
[misc_reg
]);
396 warn("Not doing anything for read from miscreg %s\n",
397 miscRegName
[misc_reg
]);
402 PMU::setControlReg(PMCR_t val
)
404 DPRINTF(PMUVerbose
, "Set Control Reg 0x%08x.\n", val
);
407 DPRINTF(PMUVerbose
, "PMU reset all events to zero.\n");
412 DPRINTF(PMUVerbose
, "PMU reset cycle counter to zero.\n");
413 cycleCounter
.setValue(0);
416 // Reset the clock remainder if divide by 64-mode is toggled.
417 if (reg_pmcr
.d
!= val
.d
)
420 reg_pmcr
= val
& reg_pmcr_wr_mask
;
425 PMU::updateAllCounters()
427 const bool global_enable(reg_pmcr
.e
);
429 for (int i
= 0; i
< counters
.size(); ++i
) {
430 CounterState
&ctr(counters
[i
]);
431 const bool enable(global_enable
&& (reg_pmcnten
& (1 << i
)));
432 if (ctr
.enabled
!= enable
) {
433 ctr
.enabled
= enable
;
438 const bool ccntr_enable(global_enable
&& (reg_pmcnten
& (1 << PMCCNTR
)));
439 if (cycleCounter
.enabled
!= ccntr_enable
) {
440 cycleCounter
.enabled
= ccntr_enable
;
441 updateCounter(cycleCounter
);
446 PMU::PMUEvent::attachEvent(PMU::CounterState
*user
)
448 if (userCounters
.empty()) {
451 userCounters
.insert(user
);
452 updateAttachedCounters();
456 PMU::PMUEvent::increment(const uint64_t val
)
458 for (auto& counter
: userCounters
) {
464 PMU::PMUEvent::detachEvent(PMU::CounterState
*user
)
466 userCounters
.erase(user
);
468 if (userCounters
.empty()) {
474 PMU::RegularEvent::RegularProbe::notify(const uint64_t &val
)
476 parentEvent
->increment(val
);
480 PMU::RegularEvent::enable()
482 for (auto& subEvents
: microArchitectureEventSet
) {
483 attachedProbePointList
.emplace_back(
484 new RegularProbe(this, subEvents
.first
, subEvents
.second
));
489 PMU::RegularEvent::disable()
491 attachedProbePointList
.clear();
495 PMU::CounterState::isFiltered() const
499 const PMEVTYPER_t
filter(this->filter
);
500 const SCR
scr(pmu
.isa
->readMiscRegNoEffect(MISCREG_SCR
));
501 const CPSR
cpsr(pmu
.isa
->readMiscRegNoEffect(MISCREG_CPSR
));
502 const ExceptionLevel
el(currEL(cpsr
));
503 const bool secure(inSecureState(scr
, cpsr
));
507 return secure
? filter
.u
: (filter
.u
!= filter
.nsu
);
510 return secure
? filter
.p
: (filter
.p
!= filter
.nsk
);
516 return filter
.p
!= filter
.m
;
519 panic("Unexpected execution level in PMU::isFiltered.\n");
524 PMU::CounterState::detach()
527 sourceEvent
->detachEvent(this);
528 sourceEvent
= nullptr;
530 debugCounter("detaching event not currently attached"
536 PMU::CounterState::attach(PMUEvent
* event
)
543 sourceEvent
->attachEvent(this);
547 PMU::CounterState::getValue() const
550 sourceEvent
->updateAttachedCounters();
552 debugCounter("attempted to get value from a counter without"
553 " an associated event\n");
559 PMU::CounterState::setValue(uint64_t val
)
565 sourceEvent
->updateAttachedCounters();
567 debugCounter("attempted to set value from a counter without"
568 " an associated event\n");
573 PMU::updateCounter(CounterState
&ctr
)
576 DPRINTF(PMUVerbose
, "updateCounter(%i): Disabling counter\n",
581 DPRINTF(PMUVerbose
, "updateCounter(%i): Enable event id 0x%x\n",
582 ctr
.getCounterId(), ctr
.eventId
);
584 auto sourceEvent
= eventMap
.find(ctr
.eventId
);
585 if (sourceEvent
== eventMap
.end()) {
586 warn("Can't enable PMU counter of type '0x%x': "
587 "No such event type.\n", ctr
.eventId
);
589 ctr
.attach(sourceEvent
->second
);
596 PMU::resetEventCounts()
598 for (CounterState
&ctr
: counters
)
603 PMU::setCounterValue(CounterId id
, uint64_t val
)
605 if (!isValidCounter(id
)) {
606 warn_once("Can't change counter value: Counter %i does not exist.\n",
611 CounterState
&ctr(getCounter(id
));
616 PMU::getCounterTypeRegister(CounterId id
) const
618 if (!isValidCounter(id
))
621 const CounterState
&cs(getCounter(id
));
622 PMEVTYPER_t
type(cs
.filter
);
624 type
.evtCount
= cs
.eventId
;
630 PMU::setCounterTypeRegister(CounterId id
, PMEVTYPER_t val
)
632 DPRINTF(PMUVerbose
, "Set Event [%d] = 0x%08x\n", id
, val
);
633 if (!isValidCounter(id
)) {
634 warn_once("Can't change counter type: Counter %i does not exist.\n",
639 CounterState
&ctr(getCounter(id
));
640 const EventTypeId
old_event_id(ctr
.eventId
);
644 // If PMCCNTR Register, do not change event type. PMCCNTR can
645 // count processor cycles only. If we change the event type, we
646 // need to update the probes the counter is using.
647 if (id
!= PMCCNTR
&& old_event_id
!= val
.evtCount
) {
648 ctr
.eventId
= val
.evtCount
;
654 PMU::setOverflowStatus(RegVal new_val
)
656 const bool int_old
= reg_pmovsr
!= 0;
657 const bool int_new
= new_val
!= 0;
659 reg_pmovsr
= new_val
;
660 if (int_old
&& !int_new
) {
662 } else if (!int_old
&& int_new
&& (reg_pminten
& reg_pmovsr
)) {
668 PMU::raiseInterrupt()
671 DPRINTF(PMUVerbose
, "Delivering PMU interrupt.\n");
674 warn_once("Dropping PMU interrupt as no interrupt has "
680 PMU::clearInterrupt()
683 DPRINTF(PMUVerbose
, "Clearing PMU interrupt.\n");
686 warn_once("Dropping PMU interrupt as no interrupt has "
692 PMU::serialize(CheckpointOut
&cp
) const
694 DPRINTF(Checkpoint
, "Serializing Arm PMU\n");
696 SERIALIZE_SCALAR(reg_pmcr
);
697 SERIALIZE_SCALAR(reg_pmcnten
);
698 SERIALIZE_SCALAR(reg_pmselr
);
699 SERIALIZE_SCALAR(reg_pminten
);
700 SERIALIZE_SCALAR(reg_pmovsr
);
701 SERIALIZE_SCALAR(reg_pmceid0
);
702 SERIALIZE_SCALAR(reg_pmceid1
);
703 SERIALIZE_SCALAR(clock_remainder
);
705 for (size_t i
= 0; i
< counters
.size(); ++i
)
706 counters
[i
].serializeSection(cp
, csprintf("counters.%i", i
));
708 cycleCounter
.serializeSection(cp
, "cycleCounter");
712 PMU::unserialize(CheckpointIn
&cp
)
714 DPRINTF(Checkpoint
, "Unserializing Arm PMU\n");
716 UNSERIALIZE_SCALAR(reg_pmcr
);
717 UNSERIALIZE_SCALAR(reg_pmcnten
);
718 UNSERIALIZE_SCALAR(reg_pmselr
);
719 UNSERIALIZE_SCALAR(reg_pminten
);
720 UNSERIALIZE_SCALAR(reg_pmovsr
);
722 // Old checkpoints used to store the entire PMCEID value in a
723 // single 64-bit entry (reg_pmceid). The register was extended in
724 // ARMv8.1, so we now need to store it as two 64-bit registers.
725 if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid0
))
726 paramIn(cp
, "reg_pmceid", reg_pmceid0
);
728 if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid1
))
731 UNSERIALIZE_SCALAR(clock_remainder
);
733 for (size_t i
= 0; i
< counters
.size(); ++i
)
734 counters
[i
].unserializeSection(cp
, csprintf("counters.%i", i
));
736 cycleCounter
.unserializeSection(cp
, "cycleCounter");
740 PMU::getEvent(uint64_t eventId
)
742 auto entry
= eventMap
.find(eventId
);
744 if (entry
== eventMap
.end()) {
745 warn("event %d does not exist\n", eventId
);
748 return entry
->second
;
753 PMU::CounterState::serialize(CheckpointOut
&cp
) const
755 SERIALIZE_SCALAR(eventId
);
756 SERIALIZE_SCALAR(value
);
757 SERIALIZE_SCALAR(overflow64
);
761 PMU::CounterState::unserialize(CheckpointIn
&cp
)
763 UNSERIALIZE_SCALAR(eventId
);
764 UNSERIALIZE_SCALAR(value
);
765 UNSERIALIZE_SCALAR(overflow64
);
769 PMU::CounterState::add(uint64_t delta
)
771 uint64_t value_until_overflow
;
773 value_until_overflow
= UINT64_MAX
- value
;
775 value_until_overflow
= UINT32_MAX
- (uint32_t)value
;
779 return value_until_overflow
;
788 if (delta
> value_until_overflow
) {
790 // overflow situation detected
791 // flag the overflow occurence
792 pmu
.reg_pmovsr
|= (1 << counterId
);
794 // Deliver a PMU interrupt if interrupt delivery is enabled
796 if (pmu
.reg_pminten
& (1 << counterId
)) {
797 pmu
.raiseInterrupt();
799 return overflow64
? UINT64_MAX
: UINT32_MAX
;
801 return value_until_overflow
- delta
+ 1;
805 PMU::SWIncrementEvent::write(uint64_t val
)
807 for (auto& counter
: userCounters
) {
808 if (val
& (0x1 << counter
->getCounterId())) {
814 } // namespace ArmISA
817 ArmPMUParams::create()
819 return new ArmISA::PMU(this);