/* * Copyright 2013 Steffen Vogel, Chair for Operating Systems, * RWTH Aachen University * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * This file is part of MetalSVM. */ /** * @author Steffen Vogel * @file arch/x86/include/pmc.h * @brief Simple interface to IA32 Performance Monitor Counters * * This implementation is in parts specific for Intel Core 2 Duo Processors! */ #ifndef _ARCH_PMC_H_ #define _ARCH_PMC_H_ #include // PMC MSR addresses #define MSR_PERF_GLOBAL_STATUS 0x38E // global counter control facilities #define MSR_PERF_GLOBAL_CTRL 0x38F #define MSR_PERF_GLOBAL_OVF_CTRL 0x390 #define IA32_PERF_CAPABILITIES 0x345 #define IA32_PERFEVTSEL(i) (0x186 + i) // general purpose PMC configuration register #define IA32_PMC(i) (0x0C1 + i) // general purpose PMC counter register #define IA32_A_PMC(i) (0x4C1 + i) // general purpose alias PMC counter register for full width writes #define MSR_PERF_FIXED_CTR(i) (0x309 + i) // fixed function PMC counter register #define MSR_PERF_FIXED_CTR_CTRL 0x38D // fixed functiion PMC configuration register /* For Intel Core 2 Duo the MSR_PERF_FIXED_CTRs are mapped as followed: * MSR_PERF_FIXED_CTR(0) => INST_RETIRED.ANY * MSR_PERF_FIXED_CTR(1) => CPU_CLK_UNHALTED.CORE * MSR_PERF_FIXED_CTR(2) => CPU_CLK_UNHALTED.REF */ // architecural flags for IA32_PERFEVTSEL #define PMC_EVTSEL_CMASK 24 // counter mask [31:24] #define PMC_EVTSEL_UMASK 8 // unit mask [15:8] #define PMC_EVTSEL_INC (1 << 23) // invert counter mask #define PMC_EVTSEL_EN (1 << 22) // enable counters #define PMC_EVTSEL_ANY (1 << 21) // any thread (from version 3 on) #define PMC_EVTSEL_INT (1 << 20) // APIC interrupt enable #define PMC_EVTSEL_PC (1 << 19) // pin control #define PMC_EVTSEL_E (1 << 18) // edge detect #define PMC_EVTSEL_OS (1 << 17) // operating system mode #define PMC_EVTSEL_USR (1 << 16) // user mode // Core 2 Duo non-architecural flags for IA32_PERFEVTSEL (bus snooping) #define PMC_EVTSEL_HITM (1 << 11) // HITM response #define PMC_EVTSEL_HIT (1 << 9) // HIT response #define PMV_EVTSEL_CLEAN (1 << 8) // CLEAN response // architecutral PMC events CPUID.0AH.EBX[6:0] #define PMC_EVT_UNHALTED_CORE_CLKS 0x003C // UnHalted Core Cycles #define PMC_EVT_UNHALTED_REF_CLKS 0x013C // UnHalted Reference Cycles #define PMC_EVT_INST_RET 0x00C0 // Instruction Retired #define PMC_EVT_LLC_REF 0x4F2E // LLC Reference #define PMC_EVT_LLC_MISS 0x412E // LLC Misses #define PMC_EVT_BRANCH_RET 0x00C4 // Branch Instruction Retired #define PMC_EVT_BRANCH_MISS_RET 0x00C5 // Branch Miss Retired // Core 2 Duo non-architecural PMC events #define PMC_EVT_DTLB_MISS_ANY 0x0108 // Memory accesses that missed the TLB #define PMC_EVT_DTLB_MISS_LD 0x0208 // DTLB misses due to load operations #define PMC_EVT_DTLB_MISS_L0_LD 0x0408 // Level 0: DTLB misses due to load operations #define PMC_EVT_DTLB_MISS_ST 0x0808 // DTLB misses due to store operations #define PMC_EVT_ITLB_FLUSH 0x4082 // ITLB flushes #define PMC_EVT_ITLB_MISS 0x1282 // ITLB misses (either large or small page) #define PMC_EVT_ITLB_MISS_RET 0x00C9 // Retired instructions that missed the ITLB #define PMC_EVT_ITLB_MISS_SMALL 0x0282 // ITLB small page misses #define PMC_EVT_ITLB_MISS_LARGE 0x1082 // ITLB large page misses #define PMC_EVT_PAGE_WALK_COUNT 0x010C // Number of page-walks executed #define PMC_EVT_PAGE_WALK_CLKS 0x020C // Duration of page-walks in core cycles struct pmc { uint8_t id; void (*start)(); void (*stop)(); void (*reset)(); void (*write)(uint64_t val); uint64_t (*read)(); }; struct pmc_caps { /// Architecural PM version (CPUID.0AH:EAX[7:0]) uint8_t version; /// Number of available General Purpose PMCs (CPUID.0AH:EAX[15:8]) uint8_t gp_count; /// Number of available Fixed Function PMCs (CPUID.0AH.EDX[4:0]) uint8_t ff_count; /// Counter bit width of General Purpose PMCs (CPUID.0AH:EAX[23:16]) uint8_t gp_width; /// Counter bit width of Fixed Function PMCs (CPUID.0AH.EDX[12:5]) uint8_t ff_width; /// Bit mask of supported architecural PMC events (CPUID.0AH.EBX[6:0]) uint32_t arch_events; /// IA32_PERF_CAPABILITIES MSR uint64_t msr; }; /** @brief Queries the CPU about available Performance Monitoring capabilities * * @return A pointer to the capabilities struct **/ struct pmc_caps* pmc_init(); /** @brief Setups and stops the general purpose PMCs * * @param i The counter number to configure (positive for gp PMCs, negative for ff PMCs) * @param event A combined event number including the unit mask (PMC_EVT_*) * @param flags Flags for the IA32_PERFEVTSEL registers (PMC_EVTSEL_*) * @param umask A seperate Unitmask ORed with event * @param cmask A optional counter mask value * @return * - 0 on success * - else failure (invalid counter or flags) */ int pmc_config(uint8_t i, uint16_t event, uint32_t flags, uint8_t umask, uint8_t cmask); /** @brief Start a single general purpose PMC * * @param i The counter number * @return * - 0 on success * - -EINVAL on invalid counter number */ inline int pmc_start(uint8_t i); /** @brief Stop a single general purpose PMC * * @param i The counter number * @return * - 0 on success * - -EINVAL on invalid counter number */ inline int pmc_stop(uint8_t i); /** @brief Start all PMCs at the same time * * @param i The counter number * @return * - 0 on success * - -EINVAL on invalid counter number */ inline int pmc_start_all(); /** @brief Stop all PMCs at the same time * * @param i The counter number * @return * - 0 on success * - -EINVAL on invalid counter number */ inline int pmc_stop_all(); /** @brief Read a single general purpose PMC * * @param i The counter number * @return The counter value (see struct pmc_caps.gp_width) */ inline uint64_t pmc_read(uint8_t i); /** @brief Write a single general purpose PMC value * * Not all architectures support full width writes to the PMCs. * If bit 13 (FW_WRITE) in struct pmc_caps.msr is not set the PMC * is updated with the 32 bit sign extended version of val! * * @param i The counter number * @param val The counter value (see struct pmc_caps.gp_width) */ inline int pmc_write(uint8_t i, uint64_t val); #endif