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}