1/*
2 * Copyright (c) 2011-2014 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_pmceid(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 PMCEID register if it is an
98 // architected event.
99 if (id < 0x40)
100 reg_pmceid |= (ULL(1) << id);
101}
102
103void
104PMU::drainResume()
105{
106 // Re-attach enabled counters after a resume in case they changed.
107 updateAllCounters();
108}
109
110void
111PMU::setMiscReg(int misc_reg, MiscReg val)
112{
113 DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n",
114 miscRegName[unflattenMiscReg(misc_reg)], val);
115
116 switch (unflattenMiscReg(misc_reg)) {
117 case MISCREG_PMCR_EL0:
118 case MISCREG_PMCR:
119 setControlReg(val);
120 return;
121
122 case MISCREG_PMCNTENSET_EL0:
123 case MISCREG_PMCNTENSET:
124 reg_pmcnten |= val;
125 updateAllCounters();
126 return;
127
128 case MISCREG_PMCNTENCLR_EL0:
129 case MISCREG_PMCNTENCLR:
130 reg_pmcnten &= ~val;
131 updateAllCounters();
132 return;
133
134 case MISCREG_PMOVSCLR_EL0:
135 case MISCREG_PMOVSR:
136 reg_pmovsr &= ~val;
137 return;
138
139 case MISCREG_PMSWINC_EL0:
140 case MISCREG_PMSWINC:
141 for (int i = 0; i < counters.size(); ++i) {
142 CounterState &ctr(getCounter(i));
143 if (ctr.enabled && (val & (1 << i)))
144 ++ctr.value;
145 }
146 break;
147
148 case MISCREG_PMCCNTR_EL0:
149 case MISCREG_PMCCNTR:
150 cycleCounter.value = val;
151 return;
152
153 case MISCREG_PMSELR_EL0:
154 case MISCREG_PMSELR:
155 reg_pmselr = val;
156 return;
157
158 case MISCREG_PMCEID0_EL0:
159 case MISCREG_PMCEID0:
160 case MISCREG_PMCEID1_EL0:
161 case MISCREG_PMCEID1:
162 // Ignore writes
163 return;
164
165 case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
166 setCounterTypeRegister(misc_reg - MISCREG_PMEVCNTR0_EL0, val);
167 return;
168
169 case MISCREG_PMCCFILTR:
170 case MISCREG_PMCCFILTR_EL0:
171 DPRINTF(PMUVerbose, "Setting PMCCFILTR: 0x%x\n", val);
172 setCounterTypeRegister(PMCCNTR, val);
173 return;
174
175 case MISCREG_PMXEVTYPER_PMCCFILTR:
176 case MISCREG_PMXEVTYPER_EL0:
177 case MISCREG_PMXEVTYPER:
178 DPRINTF(PMUVerbose, "Setting counter type: "
179 "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n",
180 reg_pmselr, reg_pmselr.sel, val);
181 setCounterTypeRegister(reg_pmselr.sel, val);
182 return;
183
184 case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0:
185 setCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0, val);
186 return;
187
188 case MISCREG_PMXEVCNTR_EL0:
189 case MISCREG_PMXEVCNTR:
190 setCounterValue(reg_pmselr.sel, val);
191 return;
192
193 case MISCREG_PMUSERENR_EL0:
194 case MISCREG_PMUSERENR:
195 // TODO
196 break;
197
198 case MISCREG_PMINTENSET_EL1:
199 case MISCREG_PMINTENSET:
200 reg_pminten |= val;
201 return;
202
203 case MISCREG_PMINTENCLR_EL1:
204 case MISCREG_PMINTENCLR:
205 reg_pminten &= ~val;
206 return;
207
208 case MISCREG_PMOVSSET_EL0:
209 case MISCREG_PMOVSSET:
210 reg_pmovsr |= val;
211 return;
212
213 default:
214 panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
215 }
216
217 warn("Not doing anything for write to miscreg %s\n",
218 miscRegName[misc_reg]);
219}
220
221MiscReg
222PMU::readMiscReg(int misc_reg)
223{
224 MiscReg val(readMiscRegInt(misc_reg));
225 DPRINTF(PMUVerbose, "readMiscReg(%s): 0x%x\n",
226 miscRegName[unflattenMiscReg(misc_reg)], val);
227 return val;
228}
229
230MiscReg
231PMU::readMiscRegInt(int misc_reg)
232{
233 misc_reg = unflattenMiscReg(misc_reg);
234 switch (misc_reg) {
235 case MISCREG_PMCR_EL0:
236 case MISCREG_PMCR:
237 return reg_pmcr_conf | (reg_pmcr & reg_pmcr_wr_mask);
238
239 case MISCREG_PMCNTENSET_EL0:
240 case MISCREG_PMCNTENCLR_EL0:
241 case MISCREG_PMCNTENSET:
242 case MISCREG_PMCNTENCLR:
243 return reg_pmcnten;
244
245 case MISCREG_PMOVSCLR_EL0:
246 case MISCREG_PMOVSSET_EL0:
247 case MISCREG_PMOVSR: // Overflow Status Register
248 case MISCREG_PMOVSSET:
249 return reg_pmovsr;
250
251 case MISCREG_PMSWINC_EL0:
252 case MISCREG_PMSWINC: // Software Increment Register (RAZ)
253 return 0;
254
255 case MISCREG_PMSELR:
256 return reg_pmselr;
257
258 case MISCREG_PMCEID0_EL0:
259 case MISCREG_PMCEID0: // Common Event ID register
260 return reg_pmceid & 0xFFFFFFFF;
261
262 case MISCREG_PMCEID1_EL0:
263 case MISCREG_PMCEID1: // Common Event ID register
264 return (reg_pmceid >> 32) & 0xFFFFFFFF;
265
266 case MISCREG_PMCCNTR_EL0:
267 return cycleCounter.value;
268
269 case MISCREG_PMCCNTR:
270 return cycleCounter.value & 0xFFFFFFFF;
271
272 case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0:
273 return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0);
274
275 case MISCREG_PMCCFILTR:
276 case MISCREG_PMCCFILTR_EL0:
277 return getCounterTypeRegister(PMCCNTR);
278
279 case MISCREG_PMXEVTYPER_PMCCFILTR:
280 case MISCREG_PMXEVTYPER_EL0:
281 case MISCREG_PMXEVTYPER:
282 return getCounterTypeRegister(reg_pmselr.sel);
283
284 case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0:
285 return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) & 0xFFFFFFFF;
286
287 case MISCREG_PMXEVCNTR_EL0:
288 case MISCREG_PMXEVCNTR:
289 return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF;
290
291 case MISCREG_PMUSERENR_EL0:
292 case MISCREG_PMUSERENR:
293 // TODO
294 return 0;
295
296 case MISCREG_PMINTENSET_EL1:
297 case MISCREG_PMINTENCLR_EL1:
298 case MISCREG_PMINTENSET:
299 case MISCREG_PMINTENCLR:
300 return reg_pminten;
301
302 default:
303 panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]);
304 }
305
306 warn("Not doing anything for read from miscreg %s\n",
307 miscRegName[misc_reg]);
308 return 0;
309}
310
311void
312PMU::setControlReg(PMCR_t val)
313{
314 DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val);
315
316 if (val.p) {
317 DPRINTF(PMUVerbose, "PMU reset all events to zero.\n");
318 resetEventCounts();
319 }
320
321 if (val.c) {
322 DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n");
323 cycleCounter.value = 0;
324 }
325
326 // Reset the clock remainder if divide by 64-mode is toggled.
327 if (reg_pmcr.d != val.d)
328 clock_remainder = 0;
329
330 reg_pmcr = val & reg_pmcr_wr_mask;
331 updateAllCounters();
332}
333
334void
335PMU::updateAllCounters()
336{
337 const bool global_enable(reg_pmcr.e);
338
339 for (int i = 0; i < counters.size(); ++i) {
340 CounterState &ctr(counters[i]);
341 const bool enable(global_enable && (reg_pmcnten & (1 << i)));
342 if (ctr.enabled != enable) {
343 ctr.enabled = enable;
344 updateCounter(i, ctr);
345 }
346 }
347
348 const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR)));
349 if (cycleCounter.enabled != ccntr_enable) {
350 cycleCounter.enabled = ccntr_enable;
351 updateCounter(PMCCNTR, cycleCounter);
352 }
353}
354
355bool
356PMU::isFiltered(const CounterState &ctr) const
357{
358 assert(isa);
359
360 const PMEVTYPER_t filter(ctr.filter);
361 const SCR scr(isa->readMiscRegNoEffect(MISCREG_SCR));
362 const CPSR cpsr(isa->readMiscRegNoEffect(MISCREG_CPSR));
363 const ExceptionLevel el(opModeToEL((OperatingMode)(uint8_t)cpsr.mode));
364 const bool secure(inSecureState(scr, cpsr));
365
366 switch (el) {
367 case EL0:
368 return secure ? filter.u : (filter.u != filter.nsu);
369
370 case EL1:
371 return secure ? filter.p : (filter.p != filter.nsk);
372
373 case EL2:
374 return !filter.nsh;
375
376 case EL3:
377 return filter.p != filter.m;
378
379 default:
380 panic("Unexpected execution level in PMU::isFiltered.\n");
381 }
382}
383
384void
385PMU::handleEvent(CounterId id, uint64_t delta)
386{
387 CounterState &ctr(getCounter(id));
388 const bool overflowed(reg_pmovsr & (1 << id));
389
390 if (isFiltered(ctr))
391 return;
392
393 // Handle the "count every 64 cycles" mode
394 if (id == PMCCNTR && reg_pmcr.d) {
395 clock_remainder += delta;
396 delta = (clock_remainder >> 6);
397 clock_remainder &= 63;
398 }
399
400 // Add delta and handle (new) overflows
401 if (ctr.add(delta) && !overflowed) {
402 DPRINTF(PMUVerbose, "PMU counter '%i' overflowed.\n", id);
403 reg_pmovsr |= (1 << id);
404 // Deliver a PMU interrupt if interrupt delivery is enabled
405 // for this counter.
406 if (reg_pminten & (1 << id))
407 raiseInterrupt();
408 }
409}
410
411void
412PMU::updateCounter(CounterId id, CounterState &ctr)
413{
414 if (!ctr.enabled) {
415 if (!ctr.listeners.empty()) {
416 DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n", id);
417 ctr.listeners.clear();
418 }
419 } else {
420 DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n",
421 id, ctr.eventId);
422
423 // Attach all probes belonging to this event
424 auto range(pmuEventTypes.equal_range(ctr.eventId));
425 for (auto it = range.first; it != range.second; ++it) {
426 const EventType &et(it->second);
427
428 DPRINTF(PMUVerbose, "\tProbe: %s:%s\n", et.obj->name(), et.name);
429 ctr.listeners.emplace_back(et.create(*this, id));
430 }
431
432 /* The SW_INCR event type is a special case which doesn't need
433 * any probes since it is controlled by software and the PMU
434 * itself.
435 */
436 if (ctr.listeners.empty() && ctr.eventId != ARCH_EVENT_SW_INCR) {
437 warn("Can't enable PMU counter of type '0x%x': "
438 "No such event type.\n", ctr.eventId);
439 }
440 }
441}
442
443
444void
445PMU::resetEventCounts()
446{
447 for (CounterState &ctr : counters)
448 ctr.value = 0;
449}
450
451void
452PMU::setCounterValue(CounterId id, uint64_t val)
453{
454 if (!isValidCounter(id)) {
455 warn_once("Can't change counter value: Counter %i does not exist.\n",
456 id);
457 return;
458 }
459
460 CounterState &ctr(getCounter(id));
461 ctr.value = val;
462}
463
464PMU::PMEVTYPER_t
465PMU::getCounterTypeRegister(CounterId id) const
466{
467 if (!isValidCounter(id))
468 return 0;
469
470 const CounterState &cs(getCounter(id));
437 PMEVTYPER_t type(0);
471 PMEVTYPER_t type(cs.filter);
472
439 // TODO: Re-create filtering settings from counter state
473 type.evtCount = cs.eventId;
474
475 return type;
476}
477
478void
479PMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val)
480{
481 DPRINTF(PMUVerbose, "Set Event [%d] = 0x%08x\n", id, val);
482 if (!isValidCounter(id)) {
483 warn_once("Can't change counter type: Counter %i does not exist.\n",
484 id);
485 return;
486 }
487
488 CounterState &ctr(getCounter(id));
456 // TODO: Handle filtering (both for general purpose counters and
457 // the cycle counter)
489 const EventTypeId old_event_id(ctr.eventId);
490
459 // If PMCCNTR Register, do not change event type. PMCCNTR can count
460 // processor cycles only.
461 if (id != PMCCNTR) {
491 ctr.filter = val;
492
493 // If PMCCNTR Register, do not change event type. PMCCNTR can
494 // count processor cycles only. If we change the event type, we
495 // need to update the probes the counter is using.
496 if (id != PMCCNTR && old_event_id != val.evtCount) {
497 ctr.eventId = val.evtCount;
498 updateCounter(reg_pmselr.sel, ctr);
499 }
500}
501
502void
503PMU::raiseInterrupt()
504{
505 RealView *rv(dynamic_cast<RealView *>(platform));
506 if (!rv || !rv->gic) {
507 warn_once("ARM PMU: GIC missing, can't raise interrupt.\n");
508 return;
509 }
510
511 DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n");
512 rv->gic->sendInt(pmuInterrupt);
513}
514
515void
516PMU::serialize(std::ostream &os)
517{
518 DPRINTF(Checkpoint, "Serializing Arm PMU\n");
519
520 SERIALIZE_SCALAR(reg_pmcr);
521 SERIALIZE_SCALAR(reg_pmcnten);
522 SERIALIZE_SCALAR(reg_pmselr);
523 SERIALIZE_SCALAR(reg_pminten);
524 SERIALIZE_SCALAR(reg_pmovsr);
525 SERIALIZE_SCALAR(reg_pmceid);
526 SERIALIZE_SCALAR(clock_remainder);
527
528 for (size_t i = 0; i < counters.size(); ++i) {
529 nameOut(os, csprintf("%s.counters.%i", name(), i));
530 counters[i].serialize(os);
531 }
532
533 nameOut(os, csprintf("%s.cycleCounter", name()));
534 cycleCounter.serialize(os);
535}
536
537void
538PMU::unserialize(Checkpoint *cp, const std::string &section)
539{
540 DPRINTF(Checkpoint, "Unserializing Arm PMU\n");
541
542 UNSERIALIZE_SCALAR(reg_pmcr);
543 UNSERIALIZE_SCALAR(reg_pmcnten);
544 UNSERIALIZE_SCALAR(reg_pmselr);
545 UNSERIALIZE_SCALAR(reg_pminten);
546 UNSERIALIZE_SCALAR(reg_pmovsr);
547 UNSERIALIZE_SCALAR(reg_pmceid);
548 UNSERIALIZE_SCALAR(clock_remainder);
549
550 for (size_t i = 0; i < counters.size(); ++i)
551 counters[i].unserialize(cp, csprintf("%s.counters.%i", section, i));
552
553 cycleCounter.unserialize(cp, csprintf("%s.cycleCounter", section));
554}
555
556void
557PMU::CounterState::serialize(std::ostream &os)
558{
559 SERIALIZE_SCALAR(eventId);
560 SERIALIZE_SCALAR(value);
561 SERIALIZE_SCALAR(enabled);
562 SERIALIZE_SCALAR(overflow64);
563}
564
565void
566PMU::CounterState::unserialize(Checkpoint *cp, const std::string &section)
567{
568 UNSERIALIZE_SCALAR(eventId);
569 UNSERIALIZE_SCALAR(value);
570 UNSERIALIZE_SCALAR(enabled);
571 UNSERIALIZE_SCALAR(overflow64);
572}
573
574bool
575PMU::CounterState::add(uint64_t delta)
576{
577 const uint64_t msb(1ULL << (overflow64 ? 63 : 31));
578 const uint64_t old_value(value);
579
580 assert(delta > 0);
581
582 value += delta;
583
584 // Overflow if the msb goes from 1 to 0
585 return (old_value & msb) && !(value & msb);
586}
587
588} // namespace ArmISA
589
590ArmISA::PMU *
591ArmPMUParams::create()
592{
593 return new ArmISA::PMU(this);
594}