pmu.cc revision 12117
110461SAndreas.Sandberg@ARM.com/* 212117Sjose.marinho@arm.com * Copyright (c) 2011-2014, 2017 ARM Limited 310461SAndreas.Sandberg@ARM.com * All rights reserved 410461SAndreas.Sandberg@ARM.com * 510461SAndreas.Sandberg@ARM.com * The license below extends only to copyright in the software and shall 610461SAndreas.Sandberg@ARM.com * not be construed as granting a license to any other intellectual 710461SAndreas.Sandberg@ARM.com * property including but not limited to intellectual property relating 810461SAndreas.Sandberg@ARM.com * to a hardware implementation of the functionality of the software 910461SAndreas.Sandberg@ARM.com * licensed hereunder. You may use the software subject to the license 1010461SAndreas.Sandberg@ARM.com * terms below provided that you ensure that this notice is replicated 1110461SAndreas.Sandberg@ARM.com * unmodified and in its entirety in all distributions of the software, 1210461SAndreas.Sandberg@ARM.com * modified or unmodified, in source code or in binary form. 1310461SAndreas.Sandberg@ARM.com * 1410461SAndreas.Sandberg@ARM.com * Redistribution and use in source and binary forms, with or without 1510461SAndreas.Sandberg@ARM.com * modification, are permitted provided that the following conditions are 1610461SAndreas.Sandberg@ARM.com * met: redistributions of source code must retain the above copyright 1710461SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer; 1810461SAndreas.Sandberg@ARM.com * redistributions in binary form must reproduce the above copyright 1910461SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer in the 2010461SAndreas.Sandberg@ARM.com * documentation and/or other materials provided with the distribution; 2110461SAndreas.Sandberg@ARM.com * neither the name of the copyright holders nor the names of its 2210461SAndreas.Sandberg@ARM.com * contributors may be used to endorse or promote products derived from 2310461SAndreas.Sandberg@ARM.com * this software without specific prior written permission. 2410461SAndreas.Sandberg@ARM.com * 2510461SAndreas.Sandberg@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2610461SAndreas.Sandberg@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2710461SAndreas.Sandberg@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2810461SAndreas.Sandberg@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2910461SAndreas.Sandberg@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3010461SAndreas.Sandberg@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3110461SAndreas.Sandberg@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3210461SAndreas.Sandberg@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3310461SAndreas.Sandberg@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3410461SAndreas.Sandberg@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3510461SAndreas.Sandberg@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3610461SAndreas.Sandberg@ARM.com * 3710461SAndreas.Sandberg@ARM.com * Authors: Dam Sunwoo 3810461SAndreas.Sandberg@ARM.com * Matt Horsnell 3910461SAndreas.Sandberg@ARM.com * Andreas Sandberg 4010461SAndreas.Sandberg@ARM.com */ 4110461SAndreas.Sandberg@ARM.com 4210461SAndreas.Sandberg@ARM.com#include "arch/arm/pmu.hh" 4310461SAndreas.Sandberg@ARM.com 4410609Sandreas.sandberg@arm.com#include "arch/arm/isa.hh" 4510609Sandreas.sandberg@arm.com#include "arch/arm/utility.hh" 4610461SAndreas.Sandberg@ARM.com#include "base/trace.hh" 4710461SAndreas.Sandberg@ARM.com#include "cpu/base.hh" 4810461SAndreas.Sandberg@ARM.com#include "debug/Checkpoint.hh" 4910461SAndreas.Sandberg@ARM.com#include "debug/PMUVerbose.hh" 5010461SAndreas.Sandberg@ARM.com#include "dev/arm/base_gic.hh" 5110461SAndreas.Sandberg@ARM.com#include "dev/arm/realview.hh" 5210461SAndreas.Sandberg@ARM.com#include "params/ArmPMU.hh" 5310461SAndreas.Sandberg@ARM.com 5410461SAndreas.Sandberg@ARM.comnamespace ArmISA { 5510461SAndreas.Sandberg@ARM.com 5610461SAndreas.Sandberg@ARM.comconst MiscReg PMU::reg_pmcr_wr_mask = 0x39; 5710461SAndreas.Sandberg@ARM.com 5810461SAndreas.Sandberg@ARM.comPMU::PMU(const ArmPMUParams *p) 5910461SAndreas.Sandberg@ARM.com : SimObject(p), BaseISADevice(), 6010461SAndreas.Sandberg@ARM.com reg_pmcnten(0), reg_pmcr(0), 6110461SAndreas.Sandberg@ARM.com reg_pmselr(0), reg_pminten(0), reg_pmovsr(0), 6212117Sjose.marinho@arm.com reg_pmceid0(0),reg_pmceid1(0), 6310461SAndreas.Sandberg@ARM.com clock_remainder(0), 6410461SAndreas.Sandberg@ARM.com counters(p->eventCounters), 6510461SAndreas.Sandberg@ARM.com reg_pmcr_conf(0), 6610461SAndreas.Sandberg@ARM.com pmuInterrupt(p->pmuInterrupt), 6710461SAndreas.Sandberg@ARM.com platform(p->platform) 6810461SAndreas.Sandberg@ARM.com{ 6910461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "Initializing the PMU.\n"); 7010461SAndreas.Sandberg@ARM.com 7110461SAndreas.Sandberg@ARM.com if (p->eventCounters > 31) { 7210461SAndreas.Sandberg@ARM.com fatal("The PMU can only accept 31 counters, %d counters requested.\n", 7310461SAndreas.Sandberg@ARM.com p->eventCounters); 7410461SAndreas.Sandberg@ARM.com } 7510461SAndreas.Sandberg@ARM.com 7610461SAndreas.Sandberg@ARM.com /* Setup the performance counter ID registers */ 7710461SAndreas.Sandberg@ARM.com reg_pmcr_conf.imp = 0x41; // ARM Ltd. 7810461SAndreas.Sandberg@ARM.com reg_pmcr_conf.idcode = 0x00; 7910461SAndreas.Sandberg@ARM.com reg_pmcr_conf.n = p->eventCounters; 8010461SAndreas.Sandberg@ARM.com 8110461SAndreas.Sandberg@ARM.com // Setup the hard-coded cycle counter, which is equivalent to 8210461SAndreas.Sandberg@ARM.com // architected counter event type 0x11. 8310461SAndreas.Sandberg@ARM.com cycleCounter.eventId = 0x11; 8410461SAndreas.Sandberg@ARM.com} 8510461SAndreas.Sandberg@ARM.com 8610461SAndreas.Sandberg@ARM.comPMU::~PMU() 8710461SAndreas.Sandberg@ARM.com{ 8810461SAndreas.Sandberg@ARM.com} 8910461SAndreas.Sandberg@ARM.com 9010461SAndreas.Sandberg@ARM.comvoid 9110461SAndreas.Sandberg@ARM.comPMU::addEventProbe(unsigned int id, SimObject *obj, const char *probe_name) 9210461SAndreas.Sandberg@ARM.com{ 9310461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "PMU: Adding event type '0x%x' as probe %s:%s\n", 9410461SAndreas.Sandberg@ARM.com id, obj->name(), probe_name); 9510461SAndreas.Sandberg@ARM.com pmuEventTypes.insert(std::make_pair(id, EventType(obj, probe_name))); 9610461SAndreas.Sandberg@ARM.com 9712117Sjose.marinho@arm.com // Flag the event as available in the corresponding PMCEID register if it 9812117Sjose.marinho@arm.com // is an architected event. 9912117Sjose.marinho@arm.com if (id < 0x20) { 10012117Sjose.marinho@arm.com reg_pmceid0 |= ((uint64_t)1) << id; 10112117Sjose.marinho@arm.com } else if (id > 0x20 && id < 0x40) { 10212117Sjose.marinho@arm.com reg_pmceid1 |= ((uint64_t)1) << (id - 0x20); 10312117Sjose.marinho@arm.com } else if (id >= 0x4000 && id < 0x4020) { 10412117Sjose.marinho@arm.com reg_pmceid0 |= ((uint64_t)1) << (id - 0x4000 + 32); 10512117Sjose.marinho@arm.com } else if (id >= 0x4020 && id < 0x4040) { 10612117Sjose.marinho@arm.com reg_pmceid1 |= ((uint64_t)1) << (id - 0x4020 + 32); 10712117Sjose.marinho@arm.com } 10810461SAndreas.Sandberg@ARM.com} 10910461SAndreas.Sandberg@ARM.com 11010461SAndreas.Sandberg@ARM.comvoid 11110461SAndreas.Sandberg@ARM.comPMU::drainResume() 11210461SAndreas.Sandberg@ARM.com{ 11310461SAndreas.Sandberg@ARM.com // Re-attach enabled counters after a resume in case they changed. 11410461SAndreas.Sandberg@ARM.com updateAllCounters(); 11510461SAndreas.Sandberg@ARM.com} 11610461SAndreas.Sandberg@ARM.com 11710461SAndreas.Sandberg@ARM.comvoid 11810461SAndreas.Sandberg@ARM.comPMU::setMiscReg(int misc_reg, MiscReg val) 11910461SAndreas.Sandberg@ARM.com{ 12010461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "setMiscReg(%s, 0x%x)\n", 12110461SAndreas.Sandberg@ARM.com miscRegName[unflattenMiscReg(misc_reg)], val); 12210461SAndreas.Sandberg@ARM.com 12310461SAndreas.Sandberg@ARM.com switch (unflattenMiscReg(misc_reg)) { 12410461SAndreas.Sandberg@ARM.com case MISCREG_PMCR_EL0: 12510461SAndreas.Sandberg@ARM.com case MISCREG_PMCR: 12610461SAndreas.Sandberg@ARM.com setControlReg(val); 12710461SAndreas.Sandberg@ARM.com return; 12810461SAndreas.Sandberg@ARM.com 12910461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENSET_EL0: 13010461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENSET: 13110461SAndreas.Sandberg@ARM.com reg_pmcnten |= val; 13210461SAndreas.Sandberg@ARM.com updateAllCounters(); 13310461SAndreas.Sandberg@ARM.com return; 13410461SAndreas.Sandberg@ARM.com 13510461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENCLR_EL0: 13610461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENCLR: 13710461SAndreas.Sandberg@ARM.com reg_pmcnten &= ~val; 13810461SAndreas.Sandberg@ARM.com updateAllCounters(); 13910461SAndreas.Sandberg@ARM.com return; 14010461SAndreas.Sandberg@ARM.com 14110461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSCLR_EL0: 14210461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSR: 14310461SAndreas.Sandberg@ARM.com reg_pmovsr &= ~val; 14410461SAndreas.Sandberg@ARM.com return; 14510461SAndreas.Sandberg@ARM.com 14610461SAndreas.Sandberg@ARM.com case MISCREG_PMSWINC_EL0: 14710461SAndreas.Sandberg@ARM.com case MISCREG_PMSWINC: 14810461SAndreas.Sandberg@ARM.com for (int i = 0; i < counters.size(); ++i) { 14910461SAndreas.Sandberg@ARM.com CounterState &ctr(getCounter(i)); 15010461SAndreas.Sandberg@ARM.com if (ctr.enabled && (val & (1 << i))) 15110461SAndreas.Sandberg@ARM.com ++ctr.value; 15210461SAndreas.Sandberg@ARM.com } 15310461SAndreas.Sandberg@ARM.com break; 15410461SAndreas.Sandberg@ARM.com 15510461SAndreas.Sandberg@ARM.com case MISCREG_PMCCNTR_EL0: 15610461SAndreas.Sandberg@ARM.com case MISCREG_PMCCNTR: 15710461SAndreas.Sandberg@ARM.com cycleCounter.value = val; 15810461SAndreas.Sandberg@ARM.com return; 15910461SAndreas.Sandberg@ARM.com 16010461SAndreas.Sandberg@ARM.com case MISCREG_PMSELR_EL0: 16110461SAndreas.Sandberg@ARM.com case MISCREG_PMSELR: 16210461SAndreas.Sandberg@ARM.com reg_pmselr = val; 16310461SAndreas.Sandberg@ARM.com return; 16412117Sjose.marinho@arm.com //TODO: implement MISCREF_PMCEID{2,3} 16510461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID0_EL0: 16610461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID0: 16710461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID1_EL0: 16810461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID1: 16910461SAndreas.Sandberg@ARM.com // Ignore writes 17010461SAndreas.Sandberg@ARM.com return; 17110461SAndreas.Sandberg@ARM.com 17210461SAndreas.Sandberg@ARM.com case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0: 17312042Sandreas.sandberg@arm.com setCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0, val); 17410461SAndreas.Sandberg@ARM.com return; 17510461SAndreas.Sandberg@ARM.com 17610461SAndreas.Sandberg@ARM.com case MISCREG_PMCCFILTR: 17710461SAndreas.Sandberg@ARM.com case MISCREG_PMCCFILTR_EL0: 17810461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "Setting PMCCFILTR: 0x%x\n", val); 17910461SAndreas.Sandberg@ARM.com setCounterTypeRegister(PMCCNTR, val); 18010461SAndreas.Sandberg@ARM.com return; 18110461SAndreas.Sandberg@ARM.com 18210461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER_PMCCFILTR: 18310461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER_EL0: 18410461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER: 18510461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "Setting counter type: " 18610461SAndreas.Sandberg@ARM.com "[PMSELR: 0x%x, PMSELER.sel: 0x%x, EVTYPER: 0x%x]\n", 18710461SAndreas.Sandberg@ARM.com reg_pmselr, reg_pmselr.sel, val); 18810461SAndreas.Sandberg@ARM.com setCounterTypeRegister(reg_pmselr.sel, val); 18910461SAndreas.Sandberg@ARM.com return; 19010461SAndreas.Sandberg@ARM.com 19110461SAndreas.Sandberg@ARM.com case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: 19210461SAndreas.Sandberg@ARM.com setCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0, val); 19310461SAndreas.Sandberg@ARM.com return; 19410461SAndreas.Sandberg@ARM.com 19510461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVCNTR_EL0: 19610461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVCNTR: 19710461SAndreas.Sandberg@ARM.com setCounterValue(reg_pmselr.sel, val); 19810461SAndreas.Sandberg@ARM.com return; 19910461SAndreas.Sandberg@ARM.com 20010461SAndreas.Sandberg@ARM.com case MISCREG_PMUSERENR_EL0: 20110461SAndreas.Sandberg@ARM.com case MISCREG_PMUSERENR: 20210461SAndreas.Sandberg@ARM.com // TODO 20310461SAndreas.Sandberg@ARM.com break; 20410461SAndreas.Sandberg@ARM.com 20510461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENSET_EL1: 20610461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENSET: 20710461SAndreas.Sandberg@ARM.com reg_pminten |= val; 20810461SAndreas.Sandberg@ARM.com return; 20910461SAndreas.Sandberg@ARM.com 21010461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENCLR_EL1: 21110461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENCLR: 21210461SAndreas.Sandberg@ARM.com reg_pminten &= ~val; 21310461SAndreas.Sandberg@ARM.com return; 21410461SAndreas.Sandberg@ARM.com 21510461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSSET_EL0: 21610461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSSET: 21710461SAndreas.Sandberg@ARM.com reg_pmovsr |= val; 21810461SAndreas.Sandberg@ARM.com return; 21910461SAndreas.Sandberg@ARM.com 22010461SAndreas.Sandberg@ARM.com default: 22110461SAndreas.Sandberg@ARM.com panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]); 22210461SAndreas.Sandberg@ARM.com } 22310461SAndreas.Sandberg@ARM.com 22410461SAndreas.Sandberg@ARM.com warn("Not doing anything for write to miscreg %s\n", 22510461SAndreas.Sandberg@ARM.com miscRegName[misc_reg]); 22610461SAndreas.Sandberg@ARM.com} 22710461SAndreas.Sandberg@ARM.com 22810461SAndreas.Sandberg@ARM.comMiscReg 22910461SAndreas.Sandberg@ARM.comPMU::readMiscReg(int misc_reg) 23010461SAndreas.Sandberg@ARM.com{ 23110461SAndreas.Sandberg@ARM.com MiscReg val(readMiscRegInt(misc_reg)); 23210461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "readMiscReg(%s): 0x%x\n", 23310461SAndreas.Sandberg@ARM.com miscRegName[unflattenMiscReg(misc_reg)], val); 23410461SAndreas.Sandberg@ARM.com return val; 23510461SAndreas.Sandberg@ARM.com} 23610461SAndreas.Sandberg@ARM.com 23710461SAndreas.Sandberg@ARM.comMiscReg 23810461SAndreas.Sandberg@ARM.comPMU::readMiscRegInt(int misc_reg) 23910461SAndreas.Sandberg@ARM.com{ 24010461SAndreas.Sandberg@ARM.com misc_reg = unflattenMiscReg(misc_reg); 24110461SAndreas.Sandberg@ARM.com switch (misc_reg) { 24210461SAndreas.Sandberg@ARM.com case MISCREG_PMCR_EL0: 24310461SAndreas.Sandberg@ARM.com case MISCREG_PMCR: 24410461SAndreas.Sandberg@ARM.com return reg_pmcr_conf | (reg_pmcr & reg_pmcr_wr_mask); 24510461SAndreas.Sandberg@ARM.com 24610461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENSET_EL0: 24710461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENCLR_EL0: 24810461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENSET: 24910461SAndreas.Sandberg@ARM.com case MISCREG_PMCNTENCLR: 25010461SAndreas.Sandberg@ARM.com return reg_pmcnten; 25110461SAndreas.Sandberg@ARM.com 25210461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSCLR_EL0: 25310461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSSET_EL0: 25410461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSR: // Overflow Status Register 25510461SAndreas.Sandberg@ARM.com case MISCREG_PMOVSSET: 25610461SAndreas.Sandberg@ARM.com return reg_pmovsr; 25710461SAndreas.Sandberg@ARM.com 25810461SAndreas.Sandberg@ARM.com case MISCREG_PMSWINC_EL0: 25910461SAndreas.Sandberg@ARM.com case MISCREG_PMSWINC: // Software Increment Register (RAZ) 26010461SAndreas.Sandberg@ARM.com return 0; 26110461SAndreas.Sandberg@ARM.com 26210461SAndreas.Sandberg@ARM.com case MISCREG_PMSELR: 26310461SAndreas.Sandberg@ARM.com return reg_pmselr; 26410461SAndreas.Sandberg@ARM.com 26510461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID0_EL0: 26612117Sjose.marinho@arm.com return reg_pmceid0; 26710461SAndreas.Sandberg@ARM.com 26810461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID1_EL0: 26912117Sjose.marinho@arm.com return reg_pmceid1; 27012117Sjose.marinho@arm.com 27112117Sjose.marinho@arm.com //TODO: implement MISCREF_PMCEID{2,3} 27212117Sjose.marinho@arm.com case MISCREG_PMCEID0: // Common Event ID register 27312117Sjose.marinho@arm.com return reg_pmceid0 & 0xFFFFFFFF; 27412117Sjose.marinho@arm.com 27510461SAndreas.Sandberg@ARM.com case MISCREG_PMCEID1: // Common Event ID register 27612117Sjose.marinho@arm.com return reg_pmceid1 & 0xFFFFFFFF; 27710461SAndreas.Sandberg@ARM.com 27810461SAndreas.Sandberg@ARM.com case MISCREG_PMCCNTR_EL0: 27910461SAndreas.Sandberg@ARM.com return cycleCounter.value; 28010461SAndreas.Sandberg@ARM.com 28110461SAndreas.Sandberg@ARM.com case MISCREG_PMCCNTR: 28210461SAndreas.Sandberg@ARM.com return cycleCounter.value & 0xFFFFFFFF; 28310461SAndreas.Sandberg@ARM.com 28410461SAndreas.Sandberg@ARM.com case MISCREG_PMEVTYPER0_EL0...MISCREG_PMEVTYPER5_EL0: 28510461SAndreas.Sandberg@ARM.com return getCounterTypeRegister(misc_reg - MISCREG_PMEVTYPER0_EL0); 28610461SAndreas.Sandberg@ARM.com 28710461SAndreas.Sandberg@ARM.com case MISCREG_PMCCFILTR: 28810461SAndreas.Sandberg@ARM.com case MISCREG_PMCCFILTR_EL0: 28910461SAndreas.Sandberg@ARM.com return getCounterTypeRegister(PMCCNTR); 29010461SAndreas.Sandberg@ARM.com 29110461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER_PMCCFILTR: 29210461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER_EL0: 29310461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVTYPER: 29410461SAndreas.Sandberg@ARM.com return getCounterTypeRegister(reg_pmselr.sel); 29510461SAndreas.Sandberg@ARM.com 29610461SAndreas.Sandberg@ARM.com case MISCREG_PMEVCNTR0_EL0...MISCREG_PMEVCNTR5_EL0: 29710461SAndreas.Sandberg@ARM.com return getCounterValue(misc_reg - MISCREG_PMEVCNTR0_EL0) & 0xFFFFFFFF; 29810461SAndreas.Sandberg@ARM.com 29910461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVCNTR_EL0: 30010461SAndreas.Sandberg@ARM.com case MISCREG_PMXEVCNTR: 30110461SAndreas.Sandberg@ARM.com return getCounterValue(reg_pmselr.sel) & 0xFFFFFFFF; 30210461SAndreas.Sandberg@ARM.com 30310461SAndreas.Sandberg@ARM.com case MISCREG_PMUSERENR_EL0: 30410461SAndreas.Sandberg@ARM.com case MISCREG_PMUSERENR: 30510461SAndreas.Sandberg@ARM.com // TODO 30610461SAndreas.Sandberg@ARM.com return 0; 30710461SAndreas.Sandberg@ARM.com 30810461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENSET_EL1: 30910461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENCLR_EL1: 31010461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENSET: 31110461SAndreas.Sandberg@ARM.com case MISCREG_PMINTENCLR: 31210461SAndreas.Sandberg@ARM.com return reg_pminten; 31310461SAndreas.Sandberg@ARM.com 31410461SAndreas.Sandberg@ARM.com default: 31510461SAndreas.Sandberg@ARM.com panic("Unexpected PMU register: %i\n", miscRegName[misc_reg]); 31610461SAndreas.Sandberg@ARM.com } 31710461SAndreas.Sandberg@ARM.com 31810461SAndreas.Sandberg@ARM.com warn("Not doing anything for read from miscreg %s\n", 31910461SAndreas.Sandberg@ARM.com miscRegName[misc_reg]); 32010461SAndreas.Sandberg@ARM.com return 0; 32110461SAndreas.Sandberg@ARM.com} 32210461SAndreas.Sandberg@ARM.com 32310461SAndreas.Sandberg@ARM.comvoid 32410461SAndreas.Sandberg@ARM.comPMU::setControlReg(PMCR_t val) 32510461SAndreas.Sandberg@ARM.com{ 32610461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "Set Control Reg 0x%08x.\n", val); 32710461SAndreas.Sandberg@ARM.com 32810461SAndreas.Sandberg@ARM.com if (val.p) { 32910461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "PMU reset all events to zero.\n"); 33010461SAndreas.Sandberg@ARM.com resetEventCounts(); 33110461SAndreas.Sandberg@ARM.com } 33210461SAndreas.Sandberg@ARM.com 33310461SAndreas.Sandberg@ARM.com if (val.c) { 33410461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "PMU reset cycle counter to zero.\n"); 33510461SAndreas.Sandberg@ARM.com cycleCounter.value = 0; 33610461SAndreas.Sandberg@ARM.com } 33710461SAndreas.Sandberg@ARM.com 33810461SAndreas.Sandberg@ARM.com // Reset the clock remainder if divide by 64-mode is toggled. 33910461SAndreas.Sandberg@ARM.com if (reg_pmcr.d != val.d) 34010461SAndreas.Sandberg@ARM.com clock_remainder = 0; 34110461SAndreas.Sandberg@ARM.com 34210461SAndreas.Sandberg@ARM.com reg_pmcr = val & reg_pmcr_wr_mask; 34310461SAndreas.Sandberg@ARM.com updateAllCounters(); 34410461SAndreas.Sandberg@ARM.com} 34510461SAndreas.Sandberg@ARM.com 34610461SAndreas.Sandberg@ARM.comvoid 34710461SAndreas.Sandberg@ARM.comPMU::updateAllCounters() 34810461SAndreas.Sandberg@ARM.com{ 34910461SAndreas.Sandberg@ARM.com const bool global_enable(reg_pmcr.e); 35010461SAndreas.Sandberg@ARM.com 35110461SAndreas.Sandberg@ARM.com for (int i = 0; i < counters.size(); ++i) { 35210461SAndreas.Sandberg@ARM.com CounterState &ctr(counters[i]); 35310461SAndreas.Sandberg@ARM.com const bool enable(global_enable && (reg_pmcnten & (1 << i))); 35410461SAndreas.Sandberg@ARM.com if (ctr.enabled != enable) { 35510461SAndreas.Sandberg@ARM.com ctr.enabled = enable; 35610461SAndreas.Sandberg@ARM.com updateCounter(i, ctr); 35710461SAndreas.Sandberg@ARM.com } 35810461SAndreas.Sandberg@ARM.com } 35910461SAndreas.Sandberg@ARM.com 36010461SAndreas.Sandberg@ARM.com const bool ccntr_enable(global_enable && (reg_pmcnten & (1 << PMCCNTR))); 36110461SAndreas.Sandberg@ARM.com if (cycleCounter.enabled != ccntr_enable) { 36210461SAndreas.Sandberg@ARM.com cycleCounter.enabled = ccntr_enable; 36310461SAndreas.Sandberg@ARM.com updateCounter(PMCCNTR, cycleCounter); 36410461SAndreas.Sandberg@ARM.com } 36510461SAndreas.Sandberg@ARM.com} 36610461SAndreas.Sandberg@ARM.com 36710609Sandreas.sandberg@arm.combool 36810609Sandreas.sandberg@arm.comPMU::isFiltered(const CounterState &ctr) const 36910609Sandreas.sandberg@arm.com{ 37010609Sandreas.sandberg@arm.com assert(isa); 37110609Sandreas.sandberg@arm.com 37210609Sandreas.sandberg@arm.com const PMEVTYPER_t filter(ctr.filter); 37310609Sandreas.sandberg@arm.com const SCR scr(isa->readMiscRegNoEffect(MISCREG_SCR)); 37410609Sandreas.sandberg@arm.com const CPSR cpsr(isa->readMiscRegNoEffect(MISCREG_CPSR)); 37510609Sandreas.sandberg@arm.com const ExceptionLevel el(opModeToEL((OperatingMode)(uint8_t)cpsr.mode)); 37610609Sandreas.sandberg@arm.com const bool secure(inSecureState(scr, cpsr)); 37710609Sandreas.sandberg@arm.com 37810609Sandreas.sandberg@arm.com switch (el) { 37910609Sandreas.sandberg@arm.com case EL0: 38010609Sandreas.sandberg@arm.com return secure ? filter.u : (filter.u != filter.nsu); 38110609Sandreas.sandberg@arm.com 38210609Sandreas.sandberg@arm.com case EL1: 38310609Sandreas.sandberg@arm.com return secure ? filter.p : (filter.p != filter.nsk); 38410609Sandreas.sandberg@arm.com 38510609Sandreas.sandberg@arm.com case EL2: 38610609Sandreas.sandberg@arm.com return !filter.nsh; 38710609Sandreas.sandberg@arm.com 38810609Sandreas.sandberg@arm.com case EL3: 38910609Sandreas.sandberg@arm.com return filter.p != filter.m; 39010609Sandreas.sandberg@arm.com 39110609Sandreas.sandberg@arm.com default: 39210609Sandreas.sandberg@arm.com panic("Unexpected execution level in PMU::isFiltered.\n"); 39310609Sandreas.sandberg@arm.com } 39410609Sandreas.sandberg@arm.com} 39510609Sandreas.sandberg@arm.com 39610461SAndreas.Sandberg@ARM.comvoid 39710461SAndreas.Sandberg@ARM.comPMU::handleEvent(CounterId id, uint64_t delta) 39810461SAndreas.Sandberg@ARM.com{ 39910461SAndreas.Sandberg@ARM.com CounterState &ctr(getCounter(id)); 40010461SAndreas.Sandberg@ARM.com const bool overflowed(reg_pmovsr & (1 << id)); 40110461SAndreas.Sandberg@ARM.com 40210609Sandreas.sandberg@arm.com if (isFiltered(ctr)) 40310609Sandreas.sandberg@arm.com return; 40410609Sandreas.sandberg@arm.com 40510461SAndreas.Sandberg@ARM.com // Handle the "count every 64 cycles" mode 40610461SAndreas.Sandberg@ARM.com if (id == PMCCNTR && reg_pmcr.d) { 40710461SAndreas.Sandberg@ARM.com clock_remainder += delta; 40810461SAndreas.Sandberg@ARM.com delta = (clock_remainder >> 6); 40910461SAndreas.Sandberg@ARM.com clock_remainder &= 63; 41010461SAndreas.Sandberg@ARM.com } 41110461SAndreas.Sandberg@ARM.com 41210461SAndreas.Sandberg@ARM.com // Add delta and handle (new) overflows 41310461SAndreas.Sandberg@ARM.com if (ctr.add(delta) && !overflowed) { 41410461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "PMU counter '%i' overflowed.\n", id); 41510461SAndreas.Sandberg@ARM.com reg_pmovsr |= (1 << id); 41610461SAndreas.Sandberg@ARM.com // Deliver a PMU interrupt if interrupt delivery is enabled 41710461SAndreas.Sandberg@ARM.com // for this counter. 41810461SAndreas.Sandberg@ARM.com if (reg_pminten & (1 << id)) 41910461SAndreas.Sandberg@ARM.com raiseInterrupt(); 42010461SAndreas.Sandberg@ARM.com } 42110461SAndreas.Sandberg@ARM.com} 42210461SAndreas.Sandberg@ARM.com 42310461SAndreas.Sandberg@ARM.comvoid 42410461SAndreas.Sandberg@ARM.comPMU::updateCounter(CounterId id, CounterState &ctr) 42510461SAndreas.Sandberg@ARM.com{ 42610461SAndreas.Sandberg@ARM.com if (!ctr.enabled) { 42710461SAndreas.Sandberg@ARM.com if (!ctr.listeners.empty()) { 42810461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "updateCounter(%i): Disabling counter\n", id); 42910461SAndreas.Sandberg@ARM.com ctr.listeners.clear(); 43010461SAndreas.Sandberg@ARM.com } 43110461SAndreas.Sandberg@ARM.com } else { 43210461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "updateCounter(%i): Enable event id 0x%x\n", 43310461SAndreas.Sandberg@ARM.com id, ctr.eventId); 43410461SAndreas.Sandberg@ARM.com 43510461SAndreas.Sandberg@ARM.com // Attach all probes belonging to this event 43610461SAndreas.Sandberg@ARM.com auto range(pmuEventTypes.equal_range(ctr.eventId)); 43710461SAndreas.Sandberg@ARM.com for (auto it = range.first; it != range.second; ++it) { 43810461SAndreas.Sandberg@ARM.com const EventType &et(it->second); 43910461SAndreas.Sandberg@ARM.com 44010461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "\tProbe: %s:%s\n", et.obj->name(), et.name); 44110461SAndreas.Sandberg@ARM.com ctr.listeners.emplace_back(et.create(*this, id)); 44210461SAndreas.Sandberg@ARM.com } 44310461SAndreas.Sandberg@ARM.com 44410461SAndreas.Sandberg@ARM.com /* The SW_INCR event type is a special case which doesn't need 44510461SAndreas.Sandberg@ARM.com * any probes since it is controlled by software and the PMU 44610461SAndreas.Sandberg@ARM.com * itself. 44710461SAndreas.Sandberg@ARM.com */ 44810461SAndreas.Sandberg@ARM.com if (ctr.listeners.empty() && ctr.eventId != ARCH_EVENT_SW_INCR) { 44910461SAndreas.Sandberg@ARM.com warn("Can't enable PMU counter of type '0x%x': " 45010461SAndreas.Sandberg@ARM.com "No such event type.\n", ctr.eventId); 45110461SAndreas.Sandberg@ARM.com } 45210461SAndreas.Sandberg@ARM.com } 45310461SAndreas.Sandberg@ARM.com} 45410461SAndreas.Sandberg@ARM.com 45510461SAndreas.Sandberg@ARM.com 45610461SAndreas.Sandberg@ARM.comvoid 45710461SAndreas.Sandberg@ARM.comPMU::resetEventCounts() 45810461SAndreas.Sandberg@ARM.com{ 45910461SAndreas.Sandberg@ARM.com for (CounterState &ctr : counters) 46010461SAndreas.Sandberg@ARM.com ctr.value = 0; 46110461SAndreas.Sandberg@ARM.com} 46210461SAndreas.Sandberg@ARM.com 46310461SAndreas.Sandberg@ARM.comvoid 46410461SAndreas.Sandberg@ARM.comPMU::setCounterValue(CounterId id, uint64_t val) 46510461SAndreas.Sandberg@ARM.com{ 46610461SAndreas.Sandberg@ARM.com if (!isValidCounter(id)) { 46710461SAndreas.Sandberg@ARM.com warn_once("Can't change counter value: Counter %i does not exist.\n", 46810461SAndreas.Sandberg@ARM.com id); 46910461SAndreas.Sandberg@ARM.com return; 47010461SAndreas.Sandberg@ARM.com } 47110461SAndreas.Sandberg@ARM.com 47210461SAndreas.Sandberg@ARM.com CounterState &ctr(getCounter(id)); 47310461SAndreas.Sandberg@ARM.com ctr.value = val; 47410461SAndreas.Sandberg@ARM.com} 47510461SAndreas.Sandberg@ARM.com 47610461SAndreas.Sandberg@ARM.comPMU::PMEVTYPER_t 47710461SAndreas.Sandberg@ARM.comPMU::getCounterTypeRegister(CounterId id) const 47810461SAndreas.Sandberg@ARM.com{ 47910461SAndreas.Sandberg@ARM.com if (!isValidCounter(id)) 48010461SAndreas.Sandberg@ARM.com return 0; 48110461SAndreas.Sandberg@ARM.com 48210461SAndreas.Sandberg@ARM.com const CounterState &cs(getCounter(id)); 48310609Sandreas.sandberg@arm.com PMEVTYPER_t type(cs.filter); 48410461SAndreas.Sandberg@ARM.com 48510461SAndreas.Sandberg@ARM.com type.evtCount = cs.eventId; 48610461SAndreas.Sandberg@ARM.com 48710461SAndreas.Sandberg@ARM.com return type; 48810461SAndreas.Sandberg@ARM.com} 48910461SAndreas.Sandberg@ARM.com 49010461SAndreas.Sandberg@ARM.comvoid 49110461SAndreas.Sandberg@ARM.comPMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val) 49210461SAndreas.Sandberg@ARM.com{ 49310461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "Set Event [%d] = 0x%08x\n", id, val); 49410461SAndreas.Sandberg@ARM.com if (!isValidCounter(id)) { 49510461SAndreas.Sandberg@ARM.com warn_once("Can't change counter type: Counter %i does not exist.\n", 49610461SAndreas.Sandberg@ARM.com id); 49710461SAndreas.Sandberg@ARM.com return; 49810461SAndreas.Sandberg@ARM.com } 49910461SAndreas.Sandberg@ARM.com 50010461SAndreas.Sandberg@ARM.com CounterState &ctr(getCounter(id)); 50110609Sandreas.sandberg@arm.com const EventTypeId old_event_id(ctr.eventId); 50210461SAndreas.Sandberg@ARM.com 50310609Sandreas.sandberg@arm.com ctr.filter = val; 50410609Sandreas.sandberg@arm.com 50510609Sandreas.sandberg@arm.com // If PMCCNTR Register, do not change event type. PMCCNTR can 50610609Sandreas.sandberg@arm.com // count processor cycles only. If we change the event type, we 50710609Sandreas.sandberg@arm.com // need to update the probes the counter is using. 50810609Sandreas.sandberg@arm.com if (id != PMCCNTR && old_event_id != val.evtCount) { 50910461SAndreas.Sandberg@ARM.com ctr.eventId = val.evtCount; 51010461SAndreas.Sandberg@ARM.com updateCounter(reg_pmselr.sel, ctr); 51110461SAndreas.Sandberg@ARM.com } 51210461SAndreas.Sandberg@ARM.com} 51310461SAndreas.Sandberg@ARM.com 51410461SAndreas.Sandberg@ARM.comvoid 51510461SAndreas.Sandberg@ARM.comPMU::raiseInterrupt() 51610461SAndreas.Sandberg@ARM.com{ 51710461SAndreas.Sandberg@ARM.com RealView *rv(dynamic_cast<RealView *>(platform)); 51810461SAndreas.Sandberg@ARM.com if (!rv || !rv->gic) { 51910461SAndreas.Sandberg@ARM.com warn_once("ARM PMU: GIC missing, can't raise interrupt.\n"); 52010461SAndreas.Sandberg@ARM.com return; 52110461SAndreas.Sandberg@ARM.com } 52210461SAndreas.Sandberg@ARM.com 52310461SAndreas.Sandberg@ARM.com DPRINTF(PMUVerbose, "Delivering PMU interrupt.\n"); 52410461SAndreas.Sandberg@ARM.com rv->gic->sendInt(pmuInterrupt); 52510461SAndreas.Sandberg@ARM.com} 52610461SAndreas.Sandberg@ARM.com 52710461SAndreas.Sandberg@ARM.comvoid 52810905Sandreas.sandberg@arm.comPMU::serialize(CheckpointOut &cp) const 52910461SAndreas.Sandberg@ARM.com{ 53010461SAndreas.Sandberg@ARM.com DPRINTF(Checkpoint, "Serializing Arm PMU\n"); 53110461SAndreas.Sandberg@ARM.com 53210461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(reg_pmcr); 53310461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(reg_pmcnten); 53410461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(reg_pmselr); 53510461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(reg_pminten); 53610461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(reg_pmovsr); 53712117Sjose.marinho@arm.com SERIALIZE_SCALAR(reg_pmceid0); 53812117Sjose.marinho@arm.com SERIALIZE_SCALAR(reg_pmceid1); 53910461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(clock_remainder); 54010461SAndreas.Sandberg@ARM.com 54110905Sandreas.sandberg@arm.com for (size_t i = 0; i < counters.size(); ++i) 54210905Sandreas.sandberg@arm.com counters[i].serializeSection(cp, csprintf("counters.%i", i)); 54310461SAndreas.Sandberg@ARM.com 54410905Sandreas.sandberg@arm.com cycleCounter.serializeSection(cp, "cycleCounter"); 54510461SAndreas.Sandberg@ARM.com} 54610461SAndreas.Sandberg@ARM.com 54710461SAndreas.Sandberg@ARM.comvoid 54810905Sandreas.sandberg@arm.comPMU::unserialize(CheckpointIn &cp) 54910461SAndreas.Sandberg@ARM.com{ 55010461SAndreas.Sandberg@ARM.com DPRINTF(Checkpoint, "Unserializing Arm PMU\n"); 55110461SAndreas.Sandberg@ARM.com 55210461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(reg_pmcr); 55310461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(reg_pmcnten); 55410461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(reg_pmselr); 55510461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(reg_pminten); 55610461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(reg_pmovsr); 55712117Sjose.marinho@arm.com 55812117Sjose.marinho@arm.com // Old checkpoints used to store the entire PMCEID value in a 55912117Sjose.marinho@arm.com // single 64-bit entry (reg_pmceid). The register was extended in 56012117Sjose.marinho@arm.com // ARMv8.1, so we now need to store it as two 64-bit registers. 56112117Sjose.marinho@arm.com if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid0)) 56212117Sjose.marinho@arm.com paramIn(cp, "reg_pmceid", reg_pmceid0); 56312117Sjose.marinho@arm.com 56412117Sjose.marinho@arm.com if (!UNSERIALIZE_OPT_SCALAR(reg_pmceid1)) 56512117Sjose.marinho@arm.com reg_pmceid1 = 0; 56612117Sjose.marinho@arm.com 56710461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(clock_remainder); 56810461SAndreas.Sandberg@ARM.com 56910461SAndreas.Sandberg@ARM.com for (size_t i = 0; i < counters.size(); ++i) 57010905Sandreas.sandberg@arm.com counters[i].unserializeSection(cp, csprintf("counters.%i", i)); 57110461SAndreas.Sandberg@ARM.com 57210905Sandreas.sandberg@arm.com cycleCounter.unserializeSection(cp, "cycleCounter"); 57310461SAndreas.Sandberg@ARM.com} 57410461SAndreas.Sandberg@ARM.com 57510461SAndreas.Sandberg@ARM.comvoid 57610905Sandreas.sandberg@arm.comPMU::CounterState::serialize(CheckpointOut &cp) const 57710461SAndreas.Sandberg@ARM.com{ 57810461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(eventId); 57910461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(value); 58010461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(enabled); 58110461SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(overflow64); 58210461SAndreas.Sandberg@ARM.com} 58310461SAndreas.Sandberg@ARM.com 58410461SAndreas.Sandberg@ARM.comvoid 58510905Sandreas.sandberg@arm.comPMU::CounterState::unserialize(CheckpointIn &cp) 58610461SAndreas.Sandberg@ARM.com{ 58710461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(eventId); 58810461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(value); 58910461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(enabled); 59010461SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(overflow64); 59110461SAndreas.Sandberg@ARM.com} 59210461SAndreas.Sandberg@ARM.com 59310461SAndreas.Sandberg@ARM.combool 59410461SAndreas.Sandberg@ARM.comPMU::CounterState::add(uint64_t delta) 59510461SAndreas.Sandberg@ARM.com{ 59610461SAndreas.Sandberg@ARM.com const uint64_t msb(1ULL << (overflow64 ? 63 : 31)); 59710461SAndreas.Sandberg@ARM.com const uint64_t old_value(value); 59810461SAndreas.Sandberg@ARM.com 59910461SAndreas.Sandberg@ARM.com value += delta; 60010461SAndreas.Sandberg@ARM.com 60110461SAndreas.Sandberg@ARM.com // Overflow if the msb goes from 1 to 0 60210461SAndreas.Sandberg@ARM.com return (old_value & msb) && !(value & msb); 60310461SAndreas.Sandberg@ARM.com} 60410461SAndreas.Sandberg@ARM.com 60510461SAndreas.Sandberg@ARM.com} // namespace ArmISA 60610461SAndreas.Sandberg@ARM.com 60710461SAndreas.Sandberg@ARM.comArmISA::PMU * 60810461SAndreas.Sandberg@ARM.comArmPMUParams::create() 60910461SAndreas.Sandberg@ARM.com{ 61010461SAndreas.Sandberg@ARM.com return new ArmISA::PMU(this); 61110461SAndreas.Sandberg@ARM.com} 612