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