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.
38 #include "arch/arm/pmu.hh"
40 #include "arch/arm/isa.hh"
41 #include "arch/arm/utility.hh"
42 #include "base/trace.hh"
43 #include "cpu/base.hh"
44 #include "debug/Checkpoint.hh"
45 #include "debug/PMUVerbose.hh"
46 #include "dev/arm/base_gic.hh"
47 #include "dev/arm/generic_timer.hh"
48 #include "params/ArmPMU.hh"
52 const RegVal
PMU::reg_pmcr_wr_mask
= 0x39;
54 PMU::PMU(const ArmPMUParams
&p
)
55 : SimObject(p
), BaseISADevice(),
56 reg_pmcnten(0), reg_pmcr(0),
57 reg_pmselr(0), reg_pminten(0), reg_pmovsr(0),
58 reg_pmceid0(0),reg_pmceid1(0),
60 maximumCounterCount(p
.eventCounters
),
61 cycleCounter(*this, maximumCounterCount
),
62 cycleCounterEventId(p
.cycleEventId
),
63 swIncrementEvent(nullptr),
67 DPRINTF(PMUVerbose
, "Initializing the PMU.\n");
69 if (maximumCounterCount
> 31) {
70 fatal("The PMU can only accept 31 counters, %d counters requested.\n",
74 warn_if(!p
.interrupt
, "ARM PMU: No interrupt specified, interrupt " \
75 "delivery disabled.\n");
77 /* Setup the performance counter ID registers */
78 reg_pmcr_conf
.imp
= 0x41; // ARM Ltd.
79 reg_pmcr_conf
.idcode
= 0x00;
80 reg_pmcr_conf
.n
= p
.eventCounters
;
82 // Setup the hard-coded cycle counter, which is equivalent to
83 // architected counter event type 0x11.
84 cycleCounter
.eventId
= 0x11;
92 PMU::setThreadContext(ThreadContext
*tc
)
94 DPRINTF(PMUVerbose
, "Assigning PMU to ContextID %i.\n", tc
->contextId());
95 const auto &pmu_params
= static_cast<const ArmPMUParams
&>(params());
97 if (pmu_params
.interrupt
)
98 interrupt
= pmu_params
.interrupt
->get(tc
);
102 PMU::addSoftwareIncrementEvent(unsigned int id
)
104 auto old_event
= eventMap
.find(id
);
105 DPRINTF(PMUVerbose
, "PMU: Adding SW increment event with id '0x%x'\n", id
);
107 if (swIncrementEvent
) {
108 fatal_if(old_event
== eventMap
.end() ||
109 old_event
->second
!= swIncrementEvent
,
110 "Trying to add a software increment event with multiple"
111 "IDs. This is not supported.\n");
115 fatal_if(old_event
!= eventMap
.end(), "An event with id %d has "
116 "been previously defined\n", id
);
118 swIncrementEvent
= new SWIncrementEvent();
119 eventMap
[id
] = swIncrementEvent
;
124 PMU::addEventProbe(unsigned int id
, SimObject
*obj
, const char *probe_name
)
127 DPRINTF(PMUVerbose
, "PMU: Adding Probe Driven event with id '0x%x'"
128 "as probe %s:%s\n",id
, obj
->name(), probe_name
);
130 RegularEvent
*event
= nullptr;
131 auto event_entry
= eventMap
.find(id
);
132 if (event_entry
== eventMap
.end()) {
134 event
= new RegularEvent();
135 eventMap
[id
] = event
;
138 event
= dynamic_cast<RegularEvent
*>(event_entry
->second
);
140 fatal("Event with id %d is not probe driven\n", id
);
143 event
->addMicroarchitectureProbe(obj
, probe_name
);
150 PMU::registerEvent(uint32_t id
)
152 // Flag the event as available in the corresponding PMCEID register if it
153 // is an architected event.
155 reg_pmceid0
|= ((uint64_t)1) << id
;
156 } else if (id
> 0x20 && id
< 0x40) {
157 reg_pmceid1
|= ((uint64_t)1) << (id
- 0x20);
158 } else if (id
>= 0x4000 && id
< 0x4020) {
159 reg_pmceid0
|= ((uint64_t)1) << (id
- 0x4000 + 32);
160 } else if (id
>= 0x4020 && id
< 0x4040) {
161 reg_pmceid1
|= ((uint64_t)1) << (id
- 0x4020 + 32);
168 // Re-attach enabled counters after a resume in case they changed.
173 PMU::regProbeListeners()
176 // at this stage all probe configurations are done
177 // counters can be configured
178 for (uint32_t index
= 0; index
< maximumCounterCount
-1; index
++) {
179 counters
.emplace_back(*this, index
);
182 PMUEvent
*event
= getEvent(cycleCounterEventId
);
183 panic_if(!event
, "core cycle event is not present\n");
184 cycleCounter
.enabled
= true;
185 cycleCounter
.attach(event
);
189 PMU::setMiscReg(int misc_reg
, RegVal val
)
191 DPRINTF(PMUVerbose
, "setMiscReg(%s, 0x%x)\n",
192 miscRegName
[unflattenMiscReg(misc_reg
)], val
);
194 switch (unflattenMiscReg(misc_reg
)) {
195 case MISCREG_PMCR_EL0
:
200 case MISCREG_PMCNTENSET_EL0
:
201 case MISCREG_PMCNTENSET
:
206 case MISCREG_PMCNTENCLR_EL0
:
207 case MISCREG_PMCNTENCLR
:
212 case MISCREG_PMOVSCLR_EL0
:
214 setOverflowStatus(reg_pmovsr
& ~val
);
217 case MISCREG_PMSWINC_EL0
:
218 case MISCREG_PMSWINC
:
219 if (swIncrementEvent
) {
220 swIncrementEvent
->write(val
);
224 case MISCREG_PMCCNTR_EL0
:
225 case MISCREG_PMCCNTR
:
226 cycleCounter
.setValue(val
);
229 case MISCREG_PMSELR_EL0
:
233 //TODO: implement MISCREF_PMCEID{2,3}
234 case MISCREG_PMCEID0_EL0
:
235 case MISCREG_PMCEID0
:
236 case MISCREG_PMCEID1_EL0
:
237 case MISCREG_PMCEID1
:
241 case MISCREG_PMEVTYPER0_EL0
...MISCREG_PMEVTYPER5_EL0
:
242 setCounterTypeRegister(misc_reg
- MISCREG_PMEVTYPER0_EL0
, val
);
245 case MISCREG_PMCCFILTR
:
246 case MISCREG_PMCCFILTR_EL0
:
247 DPRINTF(PMUVerbose
, "Setting PMCCFILTR: 0x%x\n", val
);
248 setCounterTypeRegister(PMCCNTR
, val
);
251 case MISCREG_PMXEVTYPER_PMCCFILTR
:
252 case MISCREG_PMXEVTYPER_EL0
:
253 case MISCREG_PMXEVTYPER
:
254 DPRINTF(PMUVerbose
, "Setting counter type: "
255 "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n",
256 reg_pmselr
, reg_pmselr
.sel
, val
);
257 setCounterTypeRegister(reg_pmselr
.sel
, val
);
260 case MISCREG_PMEVCNTR0_EL0
...MISCREG_PMEVCNTR5_EL0
:
261 setCounterValue(misc_reg
- MISCREG_PMEVCNTR0_EL0
, val
);
264 case MISCREG_PMXEVCNTR_EL0
:
265 case MISCREG_PMXEVCNTR
:
266 setCounterValue(reg_pmselr
.sel
, val
);
269 case MISCREG_PMUSERENR_EL0
:
270 case MISCREG_PMUSERENR
:
274 case MISCREG_PMINTENSET_EL1
:
275 case MISCREG_PMINTENSET
:
279 case MISCREG_PMINTENCLR_EL1
:
280 case MISCREG_PMINTENCLR
:
284 case MISCREG_PMOVSSET_EL0
:
285 case MISCREG_PMOVSSET
:
286 setOverflowStatus(reg_pmovsr
| val
);
290 panic("Unexpected PMU register: %i\n", miscRegName
[misc_reg
]);
293 warn("Not doing anything for write to miscreg %s\n",
294 miscRegName
[misc_reg
]);
298 PMU::readMiscReg(int misc_reg
)
300 RegVal
val(readMiscRegInt(misc_reg
));
301 DPRINTF(PMUVerbose
, "readMiscReg(%s): 0x%x\n",
302 miscRegName
[unflattenMiscReg(misc_reg
)], val
);
307 PMU::readMiscRegInt(int misc_reg
)
309 misc_reg
= unflattenMiscReg(misc_reg
);
311 case MISCREG_PMCR_EL0
:
313 return reg_pmcr_conf
| (reg_pmcr
& reg_pmcr_wr_mask
);
315 case MISCREG_PMCNTENSET_EL0
:
316 case MISCREG_PMCNTENCLR_EL0
:
317 case MISCREG_PMCNTENSET
:
318 case MISCREG_PMCNTENCLR
:
321 case MISCREG_PMOVSCLR_EL0
:
322 case MISCREG_PMOVSSET_EL0
:
323 case MISCREG_PMOVSR
: // Overflow Status Register
324 case MISCREG_PMOVSSET
:
327 case MISCREG_PMSWINC_EL0
:
328 case MISCREG_PMSWINC
: // Software Increment Register (RAZ)
331 case MISCREG_PMSELR_EL0
:
335 case MISCREG_PMCEID0_EL0
:
338 case MISCREG_PMCEID1_EL0
:
341 //TODO: implement MISCREF_PMCEID{2,3}
342 case MISCREG_PMCEID0
: // Common Event ID register
343 return reg_pmceid0
& 0xFFFFFFFF;
345 case MISCREG_PMCEID1
: // Common Event ID register
346 return reg_pmceid1
& 0xFFFFFFFF;
348 case MISCREG_PMCCNTR_EL0
:
349 return cycleCounter
.getValue();
351 case MISCREG_PMCCNTR
:
352 return cycleCounter
.getValue() & 0xFFFFFFFF;
354 case MISCREG_PMEVTYPER0_EL0
...MISCREG_PMEVTYPER5_EL0
:
355 return getCounterTypeRegister(misc_reg
- MISCREG_PMEVTYPER0_EL0
);
357 case MISCREG_PMCCFILTR
:
358 case MISCREG_PMCCFILTR_EL0
:
359 return getCounterTypeRegister(PMCCNTR
);
361 case MISCREG_PMXEVTYPER_PMCCFILTR
:
362 case MISCREG_PMXEVTYPER_EL0
:
363 case MISCREG_PMXEVTYPER
:
364 return getCounterTypeRegister(reg_pmselr
.sel
);
366 case MISCREG_PMEVCNTR0_EL0
...MISCREG_PMEVCNTR5_EL0
: {
367 return getCounterValue(misc_reg
- MISCREG_PMEVCNTR0_EL0
) &
372 case MISCREG_PMXEVCNTR_EL0
:
373 case MISCREG_PMXEVCNTR
:
374 return getCounterValue(reg_pmselr
.sel
) & 0xFFFFFFFF;
376 case MISCREG_PMUSERENR_EL0
:
377 case MISCREG_PMUSERENR
:
381 case MISCREG_PMINTENSET_EL1
:
382 case MISCREG_PMINTENCLR_EL1
:
383 case MISCREG_PMINTENSET
:
384 case MISCREG_PMINTENCLR
:
388 panic("Unexpected PMU register: %i\n", miscRegName
[misc_reg
]);
391 warn("Not doing anything for read from miscreg %s\n",
392 miscRegName
[misc_reg
]);
397 PMU::setControlReg(PMCR_t val
)
399 DPRINTF(PMUVerbose
, "Set Control Reg 0x%08x.\n", val
);
402 DPRINTF(PMUVerbose
, "PMU reset all events to zero.\n");
407 DPRINTF(PMUVerbose
, "PMU reset cycle counter to zero.\n");
408 cycleCounter
.setValue(0);
411 // Reset the clock remainder if divide by 64-mode is toggled.
412 if (reg_pmcr
.d
!= val
.d
)
415 reg_pmcr
= val
& reg_pmcr_wr_mask
;
420 PMU::updateAllCounters()
422 const bool global_enable(reg_pmcr
.e
);
424 for (int i
= 0; i
< counters
.size(); ++i
) {
425 CounterState
&ctr(counters
[i
]);
426 const bool enable(global_enable
&& (reg_pmcnten
& (1 << i
)));
427 if (ctr
.enabled
!= enable
) {
428 ctr
.enabled
= enable
;
433 const bool ccntr_enable(global_enable
&& (reg_pmcnten
& (1 << PMCCNTR
)));
434 if (cycleCounter
.enabled
!= ccntr_enable
) {
435 cycleCounter
.enabled
= ccntr_enable
;
436 updateCounter(cycleCounter
);
441 PMU::PMUEvent::attachEvent(PMU::CounterState
*user
)
443 if (userCounters
.empty()) {
446 userCounters
.insert(user
);
447 updateAttachedCounters();
451 PMU::PMUEvent::increment(const uint64_t val
)
453 for (auto& counter
: userCounters
) {
459 PMU::PMUEvent::detachEvent(PMU::CounterState
*user
)
461 userCounters
.erase(user
);
463 if (userCounters
.empty()) {
469 PMU::RegularEvent::RegularProbe::notify(const uint64_t &val
)
471 parentEvent
->increment(val
);
475 PMU::RegularEvent::enable()
477 for (auto& subEvents
: microArchitectureEventSet
) {
478 attachedProbePointList
.emplace_back(
479 new RegularProbe(this, subEvents
.first
, subEvents
.second
));
484 PMU::RegularEvent::disable()
486 attachedProbePointList
.clear();
490 PMU::CounterState::isFiltered() const
494 const PMEVTYPER_t
filter(this->filter
);
495 const SCR
scr(pmu
.isa
->readMiscRegNoEffect(MISCREG_SCR
));
496 const CPSR
cpsr(pmu
.isa
->readMiscRegNoEffect(MISCREG_CPSR
));
497 const ExceptionLevel
el(currEL(cpsr
));
498 const bool secure(inSecureState(scr
, cpsr
));
502 return secure
? filter
.u
: (filter
.u
!= filter
.nsu
);
505 return secure
? filter
.p
: (filter
.p
!= filter
.nsk
);
511 return filter
.p
!= filter
.m
;
514 panic("Unexpected execution level in PMU::isFiltered.\n");
519 PMU::CounterState::detach()
522 sourceEvent
->detachEvent(this);
523 sourceEvent
= nullptr;
525 debugCounter("detaching event not currently attached"
531 PMU::CounterState::attach(PMUEvent
* event
)
538 sourceEvent
->attachEvent(this);
542 PMU::CounterState::getValue() const
545 sourceEvent
->updateAttachedCounters();
547 debugCounter("attempted to get value from a counter without"
548 " an associated event\n");
554 PMU::CounterState::setValue(uint64_t val
)
560 sourceEvent
->updateAttachedCounters();
562 debugCounter("attempted to set value from a counter without"
563 " an associated event\n");
568 PMU::updateCounter(CounterState
&ctr
)
571 DPRINTF(PMUVerbose
, "updateCounter(%i): Disabling counter\n",
576 DPRINTF(PMUVerbose
, "updateCounter(%i): Enable event id 0x%x\n",
577 ctr
.getCounterId(), ctr
.eventId
);
579 auto sourceEvent
= eventMap
.find(ctr
.eventId
);
580 if (sourceEvent
== eventMap
.end()) {
581 warn("Can't enable PMU counter of type '0x%x': "
582 "No such event type.\n", ctr
.eventId
);
584 ctr
.attach(sourceEvent
->second
);
591 PMU::resetEventCounts()
593 for (CounterState
&ctr
: counters
)
598 PMU::setCounterValue(CounterId id
, uint64_t val
)
600 if (!isValidCounter(id
)) {
601 warn_once("Can't change counter value: Counter %i does not exist.\n",
606 CounterState
&ctr(getCounter(id
));
611 PMU::getCounterTypeRegister(CounterId id
) const
613 if (!isValidCounter(id
))
616 const CounterState
&cs(getCounter(id
));
617 PMEVTYPER_t
type(cs
.filter
);
619 type
.evtCount
= cs
.eventId
;
625 PMU::setCounterTypeRegister(CounterId id
, PMEVTYPER_t val
)
627 DPRINTF(PMUVerbose
, "Set Event [%d] = 0x%08x\n", id
, val
);
628 if (!isValidCounter(id
)) {
629 warn_once("Can't change counter type: Counter %i does not exist.\n",
634 CounterState
&ctr(getCounter(id
));
635 const EventTypeId
old_event_id(ctr
.eventId
);
639 // If PMCCNTR Register, do not change event type. PMCCNTR can
640 // count processor cycles only. If we change the event type, we
641 // need to update the probes the counter is using.
642 if (id
!= PMCCNTR
&& old_event_id
!= val
.evtCount
) {
643 ctr
.eventId
= val
.evtCount
;
649 PMU::setOverflowStatus(RegVal new_val
)
651 const bool int_old
= reg_pmovsr
!= 0;
652 const bool int_new
= new_val
!= 0;
654 reg_pmovsr
= new_val
;
655 if (int_old
&& !int_new
) {
657 } else if (!int_old
&& int_new
&& (reg_pminten
& reg_pmovsr
)) {
663 PMU::raiseInterrupt()
666 DPRINTF(PMUVerbose
, "Delivering PMU interrupt.\n");
669 warn_once("Dropping PMU interrupt as no interrupt has "
675 PMU::clearInterrupt()
678 DPRINTF(PMUVerbose
, "Clearing PMU interrupt.\n");
681 warn_once("Dropping PMU interrupt as no interrupt has "
687 PMU::serialize(CheckpointOut
&cp
) const
689 DPRINTF(Checkpoint
, "Serializing Arm PMU\n");
691 SERIALIZE_SCALAR(reg_pmcr
);
692 SERIALIZE_SCALAR(reg_pmcnten
);
693 SERIALIZE_SCALAR(reg_pmselr
);
694 SERIALIZE_SCALAR(reg_pminten
);
695 SERIALIZE_SCALAR(reg_pmovsr
);
696 SERIALIZE_SCALAR(reg_pmceid0
);
697 SERIALIZE_SCALAR(reg_pmceid1
);
698 SERIALIZE_SCALAR(clock_remainder
);
700 for (size_t i
= 0; i
< counters
.size(); ++i
)
701 counters
[i
].serializeSection(cp
, csprintf("counters.%i", i
));
703 cycleCounter
.serializeSection(cp
, "cycleCounter");
707 PMU::unserialize(CheckpointIn
&cp
)
709 DPRINTF(Checkpoint
, "Unserializing Arm PMU\n");
711 UNSERIALIZE_SCALAR(reg_pmcr
);
712 UNSERIALIZE_SCALAR(reg_pmcnten
);
713 UNSERIALIZE_SCALAR(reg_pmselr
);
714 UNSERIALIZE_SCALAR(reg_pminten
);
715 UNSERIALIZE_SCALAR(reg_pmovsr
);
717 // Old checkpoints used to store the entire PMCEID value in a
718 // single 64-bit entry (reg_pmceid). The register was extended in
719 // ARMv8.1, so we now need to store it as two 64-bit registers.
720 if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid0
))
721 paramIn(cp
, "reg_pmceid", reg_pmceid0
);
723 if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid1
))
726 UNSERIALIZE_SCALAR(clock_remainder
);
728 for (size_t i
= 0; i
< counters
.size(); ++i
)
729 counters
[i
].unserializeSection(cp
, csprintf("counters.%i", i
));
731 cycleCounter
.unserializeSection(cp
, "cycleCounter");
735 PMU::getEvent(uint64_t eventId
)
737 auto entry
= eventMap
.find(eventId
);
739 if (entry
== eventMap
.end()) {
740 warn("event %d does not exist\n", eventId
);
743 return entry
->second
;
748 PMU::CounterState::serialize(CheckpointOut
&cp
) const
750 SERIALIZE_SCALAR(eventId
);
751 SERIALIZE_SCALAR(value
);
752 SERIALIZE_SCALAR(overflow64
);
756 PMU::CounterState::unserialize(CheckpointIn
&cp
)
758 UNSERIALIZE_SCALAR(eventId
);
759 UNSERIALIZE_SCALAR(value
);
760 UNSERIALIZE_SCALAR(overflow64
);
764 PMU::CounterState::add(uint64_t delta
)
766 uint64_t value_until_overflow
;
768 value_until_overflow
= UINT64_MAX
- value
;
770 value_until_overflow
= UINT32_MAX
- (uint32_t)value
;
774 return value_until_overflow
;
783 if (delta
> value_until_overflow
) {
785 // overflow situation detected
786 // flag the overflow occurence
787 pmu
.reg_pmovsr
|= (1 << counterId
);
789 // Deliver a PMU interrupt if interrupt delivery is enabled
791 if (pmu
.reg_pminten
& (1 << counterId
)) {
792 pmu
.raiseInterrupt();
794 return overflow64
? UINT64_MAX
: UINT32_MAX
;
796 return value_until_overflow
- delta
+ 1;
800 PMU::SWIncrementEvent::write(uint64_t val
)
802 for (auto& counter
: userCounters
) {
803 if (val
& (0x1 << counter
->getCounterId())) {
809 } // namespace ArmISA