metalsvm/arch/x86/include/asm/pmc.h
2014-05-14 15:12:02 +02:00

252 lines
8.4 KiB
C

/*
* 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 <stddef.h>
// 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
#define PMC_FIXED_OS (1 << 0)
#define PMC_FIXED_USR (1 << 1)
#define PMV_FIXED_PMI (1 << 3)
/* 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 */
// architectural 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
#define PMC_EVT_MEM_LOAD_RETIRED_L1D_MISS 0x01CB // Retired loads that miss the L1 data cache (precise event)
#define PMC_EVT_MEM_LOAD_RETIRED_L1D_LINE_MISS 0x02CB // L1 data cache line missed by retired loads (precise event)
#define PMC_EVT_MEM_LOAD_RETIRED_L2_MISS 0x04CB // Retired loads that miss the L2 cache (precise event)
#define PMC_EVT_MEM_LOAD_RETIRED_L2_LINE_MISS 0x08CB // L2 cache line missed by retired loads (precise event)
#define PMC_EVT_MEM_LOAD_RETIRED_DTLB_MISS 0x10CB // Retired loads that miss the DTLB (precise event)
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_gp_config(uint8_t i, uint16_t event, uint32_t flags, uint8_t umask, uint8_t cmask);
/** @brief Setups and stops the fixed function PMCs
*
* @param i The counter number to configure (positive for gp PMCs, negative for ff PMCs)
* @param flags Flags for the MSR_PERF_FIXED_CTR_CTRL register
* @return
* - 0 on success
* - else failure (invalid counter or flags)
*/
int pmc_ff_config(uint8_t i, uint8_t flags);
/** @brief Start a single general purpose PMC
*
* @param i The counter number
* @return
* - 0 on success
* - -EINVAL on invalid counter number
*/
inline int pmc_gp_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_gp_stop(uint8_t i);
/** @brief Start a single fixed function PMC
*
* @param i The counter number
* @return
* - 0 on success
* - -EINVAL on invalid counter number
*/
inline int pmc_ff_start(uint8_t i);
/** @brief Stop a single fixed function PMC
*
* @param i The counter number
* @return
* - 0 on success
* - -EINVAL on invalid counter number
*/
inline int pmc_ff_stop(uint8_t i);
/** @brief Start all PMCs at the same time
*
* @return
* - 0 on success
* - -EINVAL on invalid counter number
*/
inline int pmc_start_all();
/** @brief Stop all PMCs at the same time
*
* @return
* - 0 on success
* - -EINVAL on invalid counter number
*/
inline int pmc_stop_all();
/** @brief Reset all PMCs to zero
*
* @return
* - 0 on success
* - -EINVAL on invalid counter number
*/
inline int pmc_reset_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_gp_read(uint8_t i);
/** @brief Read a single fixed function PMC
*
* @param i The counter number
* @return The counter value (see struct pmc_caps.gp_width)
*/
inline uint64_t pmc_ff_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_gp_write(uint8_t i, uint64_t val);
/** @brief Write a single fixed function PMC value
*
* @param i The counter number
* @param val The counter value (see struct pmc_caps.ff_width)
*/
inline int pmc_ff_write(uint8_t i, uint64_t val);
#endif