Blame src/perfctr-2.7.x/usr.lib/x86.c

Packit 577717
/* $Id: x86.c,v 1.23 2007/10/06 13:02:07 mikpe Exp $
Packit 577717
 * x86-specific perfctr library procedures.
Packit 577717
 *
Packit 577717
 * Copyright (C) 1999-2007  Mikael Pettersson
Packit 577717
 */
Packit 577717
#include <errno.h>
Packit 577717
#include <asm/unistd.h>
Packit 577717
#include <stdio.h>
Packit 577717
#include <string.h>	/* memset() */
Packit 577717
#include "libperfctr.h"
Packit 577717
#include "x86.h"
Packit 577717
#include "x86_cpuinfo.h"
Packit 577717
Packit 577717
static unsigned int __NR_vperfctr_open;
Packit 577717
#define __NR_vperfctr_control	(__NR_vperfctr_open+1)
Packit 577717
#define __NR_vperfctr_write	(__NR_vperfctr_open+2)
Packit 577717
#define __NR_vperfctr_read	(__NR_vperfctr_open+3)
Packit 577717
Packit 577717
#include <unistd.h>
Packit 577717
Packit 577717
static void init_sys_vperfctr(void)
Packit 577717
{
Packit 577717
    if (!__NR_vperfctr_open) {
Packit 577717
	unsigned int nr;
Packit 577717
	unsigned int kver = perfctr_linux_version_code();
Packit 577717
Packit 577717
#if defined(__x86_64__)
Packit 577717
	if (kver >= PERFCTR_KERNEL_VERSION(2,6,18))
Packit 577717
	    nr = 286;
Packit 577717
	else if (kver >= PERFCTR_KERNEL_VERSION(2,6,16))
Packit 577717
	    nr = 280;
Packit 577717
	else
Packit 577717
	    nr = 257;
Packit 577717
#elif defined(__i386__)
Packit 577717
	if (kver >= PERFCTR_KERNEL_VERSION(2,6,18))
Packit 577717
	    nr = 325;
Packit 577717
	else if (kver >= PERFCTR_KERNEL_VERSION(2,6,16))
Packit 577717
	    nr = 318;
Packit 577717
	else
Packit 577717
	    nr = 296;
Packit 577717
#endif
Packit 577717
	__NR_vperfctr_open = nr;
Packit 577717
    }
Packit 577717
}
Packit 577717
Packit 577717
/*
Packit 577717
 * The actual syscalls.
Packit 577717
 */
Packit 577717
Packit 577717
int _sys_vperfctr_open(int fd_unused, int tid, int creat)
Packit 577717
{
Packit 577717
    init_sys_vperfctr();
Packit 577717
    return syscall(__NR_vperfctr_open, tid, creat);
Packit 577717
}
Packit 577717
Packit 577717
static int _sys_vperfctr_control(int fd, unsigned int cmd)
Packit 577717
{
Packit 577717
    init_sys_vperfctr();
Packit 577717
    return syscall(__NR_vperfctr_control, fd, cmd);
Packit 577717
}
Packit 577717
Packit 577717
static int _sys_vperfctr_write(int fd, unsigned int domain, const void *arg, unsigned int argbytes)
Packit 577717
{
Packit 577717
    init_sys_vperfctr();
Packit 577717
    return syscall(__NR_vperfctr_write, fd, domain, arg, argbytes);
Packit 577717
}
Packit 577717
Packit 577717
static int _sys_vperfctr_read(int fd, unsigned int domain, void *arg, unsigned int argbytes)
Packit 577717
{
Packit 577717
    init_sys_vperfctr();
Packit 577717
    return syscall(__NR_vperfctr_read, fd, domain, arg, argbytes);
Packit 577717
}
Packit 577717
Packit 577717
/*
Packit 577717
 * Simple syscall wrappers.
Packit 577717
 */
Packit 577717
Packit 577717
int _sys_vperfctr_read_sum(int fd, struct perfctr_sum_ctrs *arg)
Packit 577717
{
Packit 577717
    return _sys_vperfctr_read(fd, VPERFCTR_DOMAIN_SUM, arg, sizeof(*arg));
Packit 577717
}
Packit 577717
Packit 577717
int _sys_vperfctr_read_children(int fd, struct perfctr_sum_ctrs *arg)
Packit 577717
{
Packit 577717
    return _sys_vperfctr_read(fd, VPERFCTR_DOMAIN_CHILDREN, arg, sizeof(*arg));
Packit 577717
}
Packit 577717
Packit 577717
int _sys_vperfctr_unlink(int fd)
Packit 577717
{
Packit 577717
    return _sys_vperfctr_control(fd, VPERFCTR_CONTROL_UNLINK);
Packit 577717
}
Packit 577717
Packit 577717
int _sys_vperfctr_iresume(int fd)
Packit 577717
{
Packit 577717
    return _sys_vperfctr_control(fd, VPERFCTR_CONTROL_RESUME);
Packit 577717
}
Packit 577717
Packit 577717
/*
Packit 577717
 * Complex syscall wrappers, for transmitting control data
Packit 577717
 * in CPU family specific formats.
Packit 577717
 */
Packit 577717
Packit 577717
#define MSR_P5_CESR		0x11
Packit 577717
#define MSR_P6_PERFCTR0		0xC1		/* .. 0xC2 */
Packit 577717
#define MSR_P6_EVNTSEL0		0x186		/* .. 0x187 */
Packit 577717
#define MSR_K7_EVNTSEL0		0xC0010000	/* .. 0xC0010003 */
Packit 577717
#define MSR_K7_PERFCTR0		0xC0010004	/* .. 0xC0010007 */
Packit 577717
#define MSR_P4_PERFCTR0		0x300		/* .. 0x311 */
Packit 577717
#define MSR_P4_CCCR0		0x360		/* .. 0x371 */
Packit 577717
#define MSR_P4_ESCR0		0x3A0		/* .. 0x3E1, with some gaps */
Packit 577717
#define MSR_P4_PEBS_ENABLE	0x3F1
Packit 577717
#define MSR_P4_PEBS_MATRIX_VERT	0x3F2
Packit 577717
#define P4_CCCR_ESCR_SELECT(X)	(((X) >> 13) & 0x7)
Packit 577717
#define P4_FAST_RDPMC		0x80000000
Packit 577717
Packit 577717
#if 0
Packit 577717
static void show_regs(const struct perfctr_cpu_reg *regs, unsigned int n)
Packit 577717
{
Packit 577717
    unsigned int i;
Packit 577717
Packit 577717
    fprintf(stderr, "CPU Register Values:\n");
Packit 577717
    for(i = 0; i < n; ++i)
Packit 577717
	fprintf(stderr, "MSR %#x\t0x%08x\n", regs[i].nr, regs[i].value);
Packit 577717
}
Packit 577717
#else
Packit 577717
#define show_regs(regs, n) do{}while(0)
Packit 577717
#endif
Packit 577717
Packit 577717
static int read_packet(int fd, unsigned int domain, void *arg, unsigned int argbytes)
Packit 577717
{
Packit 577717
    int ret;
Packit 577717
Packit 577717
    ret = _sys_vperfctr_read(fd, domain, arg, argbytes);
Packit 577717
    if (ret != argbytes && ret >= 0) {
Packit 577717
	errno = EPROTO;
Packit 577717
	return -1;
Packit 577717
    }
Packit 577717
    return ret;
Packit 577717
}
Packit 577717
Packit 577717
#if !defined(__x86_64__)
Packit 577717
static int p5_write_regs(int fd, const struct perfctr_cpu_control *arg)
Packit 577717
{
Packit 577717
    struct perfctr_cpu_reg reg;
Packit 577717
    unsigned short cesr_half[2];
Packit 577717
    unsigned int i, pmc;
Packit 577717
Packit 577717
    if (!arg->nractrs)
Packit 577717
	return 0;
Packit 577717
    memset(cesr_half, 0, sizeof cesr_half);
Packit 577717
    for(i = 0; i < arg->nractrs; ++i) {
Packit 577717
	pmc = arg->pmc_map[i];
Packit 577717
	if (pmc > 1) {
Packit 577717
	    errno = EINVAL;
Packit 577717
	    return -1;
Packit 577717
	}
Packit 577717
	cesr_half[pmc] = arg->evntsel[i];
Packit 577717
    }
Packit 577717
    reg.nr = MSR_P5_CESR;
Packit 577717
    reg.value = (cesr_half[1] << 16) | cesr_half[0];
Packit 577717
    show_regs(&reg, 1);
Packit 577717
    return _sys_vperfctr_write(fd, PERFCTR_DOMAIN_CPU_REGS, &reg, sizeof reg);
Packit 577717
}
Packit 577717
Packit 577717
static int p5_read_regs(int fd, struct perfctr_cpu_control *arg)
Packit 577717
{
Packit 577717
    struct perfctr_cpu_reg reg;
Packit 577717
    unsigned short cesr_half[2];
Packit 577717
    unsigned int i, pmc;
Packit 577717
    int ret;
Packit 577717
Packit 577717
    if (!arg->nractrs)
Packit 577717
	return 0;
Packit 577717
    reg.nr = MSR_P5_CESR;
Packit 577717
    ret = read_packet(fd, PERFCTR_DOMAIN_CPU_REGS, &reg, sizeof reg);
Packit 577717
    if (ret < 0)
Packit 577717
	return ret;
Packit 577717
    show_regs(&reg, 1);
Packit 577717
    cesr_half[0] = reg.value & 0xffff;
Packit 577717
    cesr_half[1] = reg.value >> 16;
Packit 577717
    for(i = 0; i < arg->nractrs; ++i) {
Packit 577717
	pmc = arg->pmc_map[i];
Packit 577717
	if (pmc > 1) {
Packit 577717
	    errno = EINVAL;
Packit 577717
	    return -1;
Packit 577717
	}
Packit 577717
	arg->evntsel[i] = cesr_half[pmc];
Packit 577717
    }
Packit 577717
    return 0;
Packit 577717
}
Packit 577717
#endif
Packit 577717
Packit 577717
static int p6_like_read_write_regs(int fd, struct perfctr_cpu_control *control,
Packit 577717
				   unsigned int msr_evntsel0, unsigned int msr_perfctr0,
Packit 577717
				   int do_write)
Packit 577717
{
Packit 577717
    struct perfctr_cpu_reg regs[4+4];
Packit 577717
    unsigned int nrctrs, nractrs, pmc_mask, nr_regs, i, pmc;
Packit 577717
    int ret;
Packit 577717
Packit 577717
    nractrs = control->nractrs;
Packit 577717
    nrctrs = nractrs + control->nrictrs;
Packit 577717
    if (nrctrs < nractrs || nrctrs > 4) {
Packit 577717
	errno = EINVAL;
Packit 577717
	return -1;
Packit 577717
    }
Packit 577717
Packit 577717
    if (!nrctrs)
Packit 577717
	return 0;
Packit 577717
Packit 577717
    nr_regs = 0;
Packit 577717
    pmc_mask = 0;
Packit 577717
    for(i = 0; i < nrctrs; ++i) {
Packit 577717
	pmc = control->pmc_map[i];
Packit 577717
	if (pmc >= 4 || (pmc_mask & (1<
Packit 577717
	    errno = EINVAL;
Packit 577717
	    return -1;
Packit 577717
	}
Packit 577717
	pmc_mask |= (1<
Packit 577717
	regs[nr_regs].nr = msr_evntsel0 + pmc;
Packit 577717
	regs[nr_regs].value = control->evntsel[i];
Packit 577717
	++nr_regs;
Packit 577717
	if (i >= nractrs) {
Packit 577717
	    regs[nr_regs].nr = msr_perfctr0 + pmc;
Packit 577717
	    regs[nr_regs].value = control->ireset[i];
Packit 577717
	    ++nr_regs;
Packit 577717
	}
Packit 577717
    }
Packit 577717
    if (do_write) {
Packit 577717
	show_regs(regs, nr_regs);
Packit 577717
	return _sys_vperfctr_write(fd, PERFCTR_DOMAIN_CPU_REGS, regs, nr_regs*sizeof(regs[0]));
Packit 577717
    }
Packit 577717
    ret = read_packet(fd, PERFCTR_DOMAIN_CPU_REGS, regs, nr_regs*sizeof(regs[0]));
Packit 577717
    if (ret < 0)
Packit 577717
	return ret;
Packit 577717
    show_regs(regs, nr_regs);
Packit 577717
    nr_regs = 0;
Packit 577717
    for(i = 0; i < nrctrs; ++i) {
Packit 577717
	control->evntsel[i] = regs[nr_regs].value;
Packit 577717
	++nr_regs;
Packit 577717
	if (i >= nractrs) {
Packit 577717
	    control->ireset[i] = regs[nr_regs].value;
Packit 577717
	    ++nr_regs;
Packit 577717
	}
Packit 577717
    }
Packit 577717
    return 0;
Packit 577717
}
Packit 577717
Packit 577717
/*
Packit 577717
 * Table 15-4 in the IA32 Volume 3 manual contains a 18x8 entry mapping
Packit 577717
 * from counter/CCCR number (0-17) and ESCR SELECT value (0-7) to the
Packit 577717
 * actual ESCR MSR number. This mapping contains some repeated patterns,
Packit 577717
 * so we can compact it to a 4x8 table of MSR offsets:
Packit 577717
 *
Packit 577717
 * 1. CCCRs 16 and 17 are mapped just like CCCRs 13 and 14, respectively.
Packit 577717
 *    Thus, we only consider the 16 CCCRs 0-15.
Packit 577717
 * 2. The CCCRs are organised in pairs, and both CCCRs in a pair use the
Packit 577717
 *    same mapping. Thus, we only consider the 8 pairs 0-7.
Packit 577717
 * 3. In each pair of pairs, the second odd-numbered pair has the same domain
Packit 577717
 *    as the first even-numbered pair, and the range is 1+ the range of the
Packit 577717
 *    the first even-numbered pair. For example, CCCR(0) and (1) map ESCR
Packit 577717
 *    SELECT(7) to 0x3A0, and CCCR(2) and (3) map it to 0x3A1.
Packit 577717
 *    The only exception is that pair (7) [CCCRs 14 and 15] does not have
Packit 577717
 *    ESCR SELECT(3) in its domain, like pair (6) [CCCRs 12 and 13] has.
Packit 577717
 *    NOTE: Revisions of IA32 Volume 3 older than #245472-007 had an error
Packit 577717
 *    in this table: CCCRs 12, 13, and 16 had their mappings for ESCR SELECT
Packit 577717
 *    values 2 and 3 swapped.
Packit 577717
 * 4. All MSR numbers are on the form 0x3??. Instead of storing these as
Packit 577717
 *    16-bit numbers, the table only stores the 8-bit offsets from 0x300.
Packit 577717
 */
Packit 577717
Packit 577717
static const unsigned char p4_cccr_escr_map[4][8] = {
Packit 577717
	/* 0x00 and 0x01 as is, 0x02 and 0x03 are +1 */
Packit 577717
	[0x00/4] {	[7] 0xA0,
Packit 577717
			[6] 0xA2,
Packit 577717
			[2] 0xAA,
Packit 577717
			[4] 0xAC,
Packit 577717
			[0] 0xB2,
Packit 577717
			[1] 0xB4,
Packit 577717
			[3] 0xB6,
Packit 577717
			[5] 0xC8, },
Packit 577717
	/* 0x04 and 0x05 as is, 0x06 and 0x07 are +1 */
Packit 577717
	[0x04/4] {	[0] 0xC0,
Packit 577717
			[2] 0xC2,
Packit 577717
			[1] 0xC4, },
Packit 577717
	/* 0x08 and 0x09 as is, 0x0A and 0x0B are +1 */
Packit 577717
	[0x08/4] {	[1] 0xA4,
Packit 577717
			[0] 0xA6,
Packit 577717
			[5] 0xA8,
Packit 577717
			[2] 0xAE,
Packit 577717
			[3] 0xB0, },
Packit 577717
	/* 0x0C, 0x0D, and 0x10 as is,
Packit 577717
	   0x0E, 0x0F, and 0x11 are +1 except [3] is not in the domain */
Packit 577717
	[0x0C/4] {	[4] 0xB8,
Packit 577717
			[5] 0xCC,
Packit 577717
			[6] 0xE0,
Packit 577717
			[0] 0xBA,
Packit 577717
			[2] 0xBC,
Packit 577717
			[3] 0xBE,
Packit 577717
			[1] 0xCA, },
Packit 577717
};
Packit 577717
Packit 577717
static unsigned int p4_escr_addr(unsigned int pmc, unsigned int cccr_val)
Packit 577717
{
Packit 577717
	unsigned int escr_select, pair, escr_offset;
Packit 577717
Packit 577717
	escr_select = P4_CCCR_ESCR_SELECT(cccr_val);
Packit 577717
	if (pmc > 0x11)
Packit 577717
		return 0;	/* pmc range error */
Packit 577717
	if (pmc > 0x0F)
Packit 577717
		pmc -= 3;	/* 0 <= pmc <= 0x0F */
Packit 577717
	pair = pmc / 2;		/* 0 <= pair <= 7 */
Packit 577717
	escr_offset = p4_cccr_escr_map[pair / 2][escr_select];
Packit 577717
	if (!escr_offset || (pair == 7 && escr_select == 3))
Packit 577717
		return 0;	/* ESCR SELECT range error */
Packit 577717
	return escr_offset + (pair & 1) + 0x300;
Packit 577717
};
Packit 577717
Packit 577717
static int p4_read_write_regs(int fd, struct perfctr_cpu_control *control, int do_write)
Packit 577717
{
Packit 577717
    struct perfctr_cpu_reg regs[18*3+2];
Packit 577717
    unsigned int nrctrs, nractrs, pmc_mask, nr_regs, i, pmc, escr_addr;
Packit 577717
    int ret;
Packit 577717
Packit 577717
    nractrs = control->nractrs;
Packit 577717
    nrctrs = nractrs + control->nrictrs;
Packit 577717
    if (nrctrs < nractrs || nrctrs > 18) {
Packit 577717
	errno = EINVAL;
Packit 577717
	return -1;
Packit 577717
    }
Packit 577717
Packit 577717
    if (!nrctrs)
Packit 577717
	return 0;
Packit 577717
Packit 577717
    nr_regs = 0;
Packit 577717
    pmc_mask = 0;
Packit 577717
    for(i = 0; i < nrctrs; ++i) {
Packit 577717
	pmc = control->pmc_map[i] & ~P4_FAST_RDPMC;
Packit 577717
	if (pmc >= 18 || (pmc_mask & (1<
Packit 577717
	    errno = EINVAL;
Packit 577717
	    return -1;
Packit 577717
	}
Packit 577717
	pmc_mask |= (1<
Packit 577717
	regs[nr_regs].nr = MSR_P4_CCCR0 + pmc;
Packit 577717
	regs[nr_regs].value = control->evntsel[i];
Packit 577717
	++nr_regs;
Packit 577717
	escr_addr = p4_escr_addr(pmc, control->evntsel[i]);
Packit 577717
	if (!escr_addr) {
Packit 577717
	    errno = EINVAL;
Packit 577717
	    return -1;
Packit 577717
	}
Packit 577717
	regs[nr_regs].nr = escr_addr;
Packit 577717
	regs[nr_regs].value = control->p4.escr[i];
Packit 577717
	++nr_regs;
Packit 577717
	if (i >= nractrs) {
Packit 577717
	    regs[nr_regs].nr = MSR_P4_PERFCTR0 + pmc;
Packit 577717
	    regs[nr_regs].value = control->ireset[i];
Packit 577717
	    ++nr_regs;
Packit 577717
	}
Packit 577717
    }
Packit 577717
    regs[nr_regs].nr = MSR_P4_PEBS_ENABLE;
Packit 577717
    regs[nr_regs].value = control->p4.pebs_enable;
Packit 577717
    ++nr_regs;
Packit 577717
    regs[nr_regs].nr = MSR_P4_PEBS_MATRIX_VERT;
Packit 577717
    regs[nr_regs].value = control->p4.pebs_matrix_vert;
Packit 577717
    ++nr_regs;
Packit 577717
    if (do_write) {
Packit 577717
	show_regs(regs, nr_regs);
Packit 577717
	return _sys_vperfctr_write(fd, PERFCTR_DOMAIN_CPU_REGS, regs, nr_regs*sizeof(regs[0]));
Packit 577717
    }
Packit 577717
    ret = read_packet(fd, PERFCTR_DOMAIN_CPU_REGS, regs, nr_regs*sizeof(regs[0]));
Packit 577717
    if (ret < 0)
Packit 577717
	return ret;
Packit 577717
    show_regs(regs, nr_regs);
Packit 577717
    nr_regs = 0;
Packit 577717
    for(i = 0; i < nrctrs; ++i) {
Packit 577717
	control->evntsel[i] = regs[nr_regs].value;
Packit 577717
	++nr_regs;
Packit 577717
	control->p4.escr[i] = regs[nr_regs].value;
Packit 577717
	++nr_regs;
Packit 577717
	if (i >= nractrs) {
Packit 577717
	    control->ireset[i] = regs[nr_regs].value;
Packit 577717
	    ++nr_regs;
Packit 577717
	}
Packit 577717
    }
Packit 577717
    control->p4.pebs_enable = regs[nr_regs].value;
Packit 577717
    ++nr_regs;
Packit 577717
    control->p4.pebs_matrix_vert = regs[nr_regs].value;
Packit 577717
    ++nr_regs;
Packit 577717
    return 0;
Packit 577717
}
Packit 577717
Packit 577717
static int write_cpu_regs(int fd, unsigned int cpu_type, struct perfctr_cpu_control *arg)
Packit 577717
{
Packit 577717
    switch (cpu_type) {
Packit 577717
      case PERFCTR_X86_GENERIC:
Packit 577717
	return 0;
Packit 577717
#if !defined(__x86_64__)
Packit 577717
      case PERFCTR_X86_INTEL_P5:
Packit 577717
      case PERFCTR_X86_INTEL_P5MMX:
Packit 577717
      case PERFCTR_X86_CYRIX_MII:
Packit 577717
      case PERFCTR_X86_WINCHIP_C6:
Packit 577717
      case PERFCTR_X86_WINCHIP_2:
Packit 577717
	return p5_write_regs(fd, arg);
Packit 577717
      case PERFCTR_X86_INTEL_P6:
Packit 577717
      case PERFCTR_X86_INTEL_PII:
Packit 577717
      case PERFCTR_X86_INTEL_PIII:
Packit 577717
      case PERFCTR_X86_INTEL_PENTM:
Packit 577717
      case PERFCTR_X86_VIA_C3:
Packit 577717
	return p6_like_read_write_regs(fd, arg, MSR_P6_EVNTSEL0, MSR_P6_PERFCTR0, 1);
Packit 577717
      case PERFCTR_X86_AMD_K7:
Packit 577717
#endif
Packit 577717
      case PERFCTR_X86_AMD_K8:
Packit 577717
      case PERFCTR_X86_AMD_K8C:
Packit 577717
	return p6_like_read_write_regs(fd, arg, MSR_K7_EVNTSEL0, MSR_K7_PERFCTR0, 1);
Packit 577717
#if !defined(__x86_64__)
Packit 577717
      case PERFCTR_X86_INTEL_P4:
Packit 577717
      case PERFCTR_X86_INTEL_P4M2:
Packit 577717
#endif
Packit 577717
      case PERFCTR_X86_INTEL_P4M3:
Packit 577717
	return p4_read_write_regs(fd, arg, 1);
Packit 577717
	break;
Packit 577717
      default:
Packit 577717
	fprintf(stderr, "unable to write control registers for cpu type %u\n",
Packit 577717
		cpu_type);
Packit 577717
	errno = EINVAL;
Packit 577717
	return -1;
Packit 577717
    }
Packit 577717
}
Packit 577717
Packit 577717
int _sys_vperfctr_write_control(int fd, unsigned int cpu_type, const struct vperfctr_control *control)
Packit 577717
{
Packit 577717
    union {
Packit 577717
	struct vperfctr_control_kernel control;
Packit 577717
	struct perfctr_cpu_control_header header;
Packit 577717
    } u;
Packit 577717
    unsigned int nrctrs;
Packit 577717
    int ret;
Packit 577717
    
Packit 577717
    ret = _sys_vperfctr_control(fd, VPERFCTR_CONTROL_CLEAR);
Packit 577717
    if (ret < 0)
Packit 577717
	return ret;
Packit 577717
Packit 577717
    u.control.si_signo = control->si_signo;
Packit 577717
    u.control.preserve = control->preserve;
Packit 577717
    ret = _sys_vperfctr_write(fd, VPERFCTR_DOMAIN_CONTROL,
Packit 577717
			      &u.control, sizeof u.control);
Packit 577717
    if (ret < 0)
Packit 577717
	return ret;
Packit 577717
Packit 577717
    u.header.tsc_on = control->cpu_control.tsc_on;
Packit 577717
    u.header.nractrs = control->cpu_control.nractrs;
Packit 577717
    u.header.nrictrs = control->cpu_control.nrictrs;
Packit 577717
    ret = _sys_vperfctr_write(fd, PERFCTR_DOMAIN_CPU_CONTROL,
Packit 577717
			      &u.header, sizeof u.header);
Packit 577717
    if (ret < 0)
Packit 577717
	return ret;
Packit 577717
Packit 577717
    nrctrs = control->cpu_control.nractrs + control->cpu_control.nrictrs;
Packit 577717
    ret = _sys_vperfctr_write(fd, PERFCTR_DOMAIN_CPU_MAP,
Packit 577717
			      &control->cpu_control.pmc_map,
Packit 577717
			      nrctrs * sizeof control->cpu_control.pmc_map[0]);
Packit 577717
    if (ret < 0)
Packit 577717
	return ret;
Packit 577717
Packit 577717
    ret = write_cpu_regs(fd, cpu_type, (struct perfctr_cpu_control*)&control->cpu_control);
Packit 577717
    if (ret < 0)
Packit 577717
	return ret;
Packit 577717
Packit 577717
    return _sys_vperfctr_control(fd, VPERFCTR_CONTROL_RESUME);
Packit 577717
}
Packit 577717
Packit 577717
static int read_cpu_regs(int fd, unsigned int cpu_type, struct perfctr_cpu_control *arg)
Packit 577717
{
Packit 577717
    switch (cpu_type) {
Packit 577717
      case PERFCTR_X86_GENERIC:
Packit 577717
	return 0;
Packit 577717
#if !defined(__x86_64__)
Packit 577717
      case PERFCTR_X86_INTEL_P5:
Packit 577717
      case PERFCTR_X86_INTEL_P5MMX:
Packit 577717
      case PERFCTR_X86_CYRIX_MII:
Packit 577717
      case PERFCTR_X86_WINCHIP_C6:
Packit 577717
      case PERFCTR_X86_WINCHIP_2:
Packit 577717
	return p5_read_regs(fd, arg);
Packit 577717
      case PERFCTR_X86_INTEL_P6:
Packit 577717
      case PERFCTR_X86_INTEL_PII:
Packit 577717
      case PERFCTR_X86_INTEL_PIII:
Packit 577717
      case PERFCTR_X86_INTEL_PENTM:
Packit 577717
      case PERFCTR_X86_VIA_C3:
Packit 577717
	return p6_like_read_write_regs(fd, arg, MSR_P6_EVNTSEL0, MSR_P6_PERFCTR0, 0);
Packit 577717
      case PERFCTR_X86_AMD_K7:
Packit 577717
#endif
Packit 577717
      case PERFCTR_X86_AMD_K8:
Packit 577717
      case PERFCTR_X86_AMD_K8C:
Packit 577717
	return p6_like_read_write_regs(fd, arg, MSR_K7_EVNTSEL0, MSR_K7_PERFCTR0, 0);
Packit 577717
#if !defined(__x86_64__)
Packit 577717
      case PERFCTR_X86_INTEL_P4:
Packit 577717
      case PERFCTR_X86_INTEL_P4M2:
Packit 577717
#endif
Packit 577717
      case PERFCTR_X86_INTEL_P4M3:
Packit 577717
	return p4_read_write_regs(fd, arg, 0);
Packit 577717
	break;
Packit 577717
      default:
Packit 577717
	fprintf(stderr, "unable to read control registers for cpu type %u\n",
Packit 577717
		cpu_type);
Packit 577717
	errno = EINVAL;
Packit 577717
	return -1;
Packit 577717
    }
Packit 577717
}
Packit 577717
Packit 577717
int _sys_vperfctr_read_control(int fd, unsigned int cpu_type, struct vperfctr_control *control)
Packit 577717
{
Packit 577717
    union {
Packit 577717
	struct vperfctr_control_kernel control;
Packit 577717
	struct perfctr_cpu_control_header header;
Packit 577717
    } u;
Packit 577717
    unsigned int nrctrs;
Packit 577717
    int ret;
Packit 577717
    
Packit 577717
    memset(control, 0, sizeof *control);
Packit 577717
Packit 577717
    ret = read_packet(fd, VPERFCTR_DOMAIN_CONTROL,
Packit 577717
		      &u.control, sizeof u.control);
Packit 577717
    if (ret < 0)
Packit 577717
	return ret;
Packit 577717
    control->si_signo = u.control.si_signo;
Packit 577717
    control->preserve = u.control.preserve;
Packit 577717
Packit 577717
    ret = read_packet(fd, PERFCTR_DOMAIN_CPU_CONTROL,
Packit 577717
		      &u.header, sizeof u.header);
Packit 577717
    if (ret < 0)
Packit 577717
	return ret;
Packit 577717
    control->cpu_control.tsc_on = u.header.tsc_on;
Packit 577717
    control->cpu_control.nractrs = u.header.nractrs;
Packit 577717
    control->cpu_control.nrictrs = u.header.nrictrs;
Packit 577717
Packit 577717
    nrctrs = control->cpu_control.nractrs + control->cpu_control.nrictrs;
Packit 577717
    ret = read_packet(fd, PERFCTR_DOMAIN_CPU_MAP,
Packit 577717
		      &control->cpu_control.pmc_map,
Packit 577717
		      nrctrs * sizeof control->cpu_control.pmc_map[0]);
Packit 577717
    if (ret < 0)
Packit 577717
	return ret;
Packit 577717
Packit 577717
    return read_cpu_regs(fd, cpu_type, &control->cpu_control);
Packit 577717
}
Packit 577717
Packit 577717
static int intel_init(const struct cpuinfo *cpuinfo,
Packit 577717
		      struct perfctr_info *info)
Packit 577717
{
Packit 577717
    unsigned int family, model, stepping;
Packit 577717
Packit 577717
    if (!cpu_has(cpuinfo, X86_FEATURE_TSC))
Packit 577717
	return -1;
Packit 577717
    family = cpu_family(cpuinfo);
Packit 577717
    model = cpu_model(cpuinfo);
Packit 577717
    stepping = cpu_stepping(cpuinfo);
Packit 577717
    switch (family) {
Packit 577717
      case 5:
Packit 577717
	if (cpu_has(cpuinfo, X86_FEATURE_MMX)) {
Packit 577717
	    /* Avoid Pentium Erratum 74. */
Packit 577717
	    if (model == 4 &&
Packit 577717
		(stepping == 4 ||
Packit 577717
		 (stepping == 3 &&
Packit 577717
		  cpu_type(cpuinfo) == 1)))
Packit 577717
		info->cpu_features &= ~PERFCTR_FEATURE_RDPMC;
Packit 577717
	    return PERFCTR_X86_INTEL_P5MMX;
Packit 577717
	} else {
Packit 577717
	    info->cpu_features &= ~PERFCTR_FEATURE_RDPMC;
Packit 577717
	    return PERFCTR_X86_INTEL_P5;
Packit 577717
	}
Packit 577717
      case 6:
Packit 577717
	if (model == 9 || model == 13)
Packit 577717
	    return PERFCTR_X86_INTEL_PENTM;
Packit 577717
	else if (model >= 7)
Packit 577717
	    return PERFCTR_X86_INTEL_PIII;
Packit 577717
	else if (model >= 3)
Packit 577717
	    return PERFCTR_X86_INTEL_PII;
Packit 577717
	else {
Packit 577717
	    /* Avoid Pentium Pro Erratum 26. */
Packit 577717
	    if (stepping < 9)
Packit 577717
		info->cpu_features &= ~PERFCTR_FEATURE_RDPMC;
Packit 577717
	    return PERFCTR_X86_INTEL_P6;
Packit 577717
	}
Packit 577717
      case 15:
Packit 577717
	if (model >= 3)
Packit 577717
	    return PERFCTR_X86_INTEL_P4M3;
Packit 577717
	else if (model >= 2)
Packit 577717
	    return PERFCTR_X86_INTEL_P4M2;
Packit 577717
	else
Packit 577717
	    return PERFCTR_X86_INTEL_P4;
Packit 577717
    }
Packit 577717
    return -1;
Packit 577717
}
Packit 577717
Packit 577717
static int amd_init(const struct cpuinfo *cpuinfo,
Packit 577717
		    struct perfctr_info *info)
Packit 577717
{
Packit 577717
    unsigned int family, model, stepping;
Packit 577717
Packit 577717
    if (!cpu_has(cpuinfo, X86_FEATURE_TSC))
Packit 577717
	return -1;
Packit 577717
    family = cpu_family(cpuinfo);
Packit 577717
    model = cpu_model(cpuinfo);
Packit 577717
    stepping = cpu_stepping(cpuinfo);
Packit 577717
    switch (family) {
Packit 577717
      case 15:
Packit 577717
	if (model > 5 || (model >= 4 && stepping >= 8))
Packit 577717
	    return PERFCTR_X86_AMD_K8C;
Packit 577717
	else
Packit 577717
	    return PERFCTR_X86_AMD_K8;
Packit 577717
      case 6:
Packit 577717
	return PERFCTR_X86_AMD_K7;
Packit 577717
    }
Packit 577717
    return -1;
Packit 577717
}
Packit 577717
Packit 577717
static int cyrix_init(const struct cpuinfo *cpuinfo,
Packit 577717
		      struct perfctr_info *info)
Packit 577717
{
Packit 577717
    if (!cpu_has(cpuinfo, X86_FEATURE_TSC))
Packit 577717
	return -1;
Packit 577717
    switch (cpu_family(cpuinfo)) {
Packit 577717
      case 6: /* 6x86MX, MII, or III */
Packit 577717
	return PERFCTR_X86_CYRIX_MII;
Packit 577717
    }
Packit 577717
    return -1;
Packit 577717
}
Packit 577717
Packit 577717
static int centaur_init(const struct cpuinfo *cpuinfo,
Packit 577717
			struct perfctr_info *info)
Packit 577717
{
Packit 577717
    unsigned int family, model;
Packit 577717
Packit 577717
    family = cpu_family(cpuinfo);
Packit 577717
    model = cpu_model(cpuinfo);
Packit 577717
    switch (family) {
Packit 577717
      case 5:
Packit 577717
	if (cpu_has(cpuinfo, X86_FEATURE_TSC))
Packit 577717
	    return -1;
Packit 577717
	info->cpu_features &= ~PERFCTR_FEATURE_RDTSC;
Packit 577717
	switch (model) {
Packit 577717
	  case 4:
Packit 577717
	    return PERFCTR_X86_WINCHIP_C6;
Packit 577717
	  case 8: /* WinChip 2, 2A, or 2B */
Packit 577717
	  case 9: /* WinChip 3 */
Packit 577717
	    return PERFCTR_X86_WINCHIP_2;
Packit 577717
	  default:
Packit 577717
	    return -1;
Packit 577717
	}
Packit 577717
      case 6:
Packit 577717
	if (!cpu_has(cpuinfo, X86_FEATURE_TSC))
Packit 577717
	    return -1;
Packit 577717
	switch (model) {
Packit 577717
	  case 6: /* Cyrix III */
Packit 577717
	  case 7: /* Samuel 2 */
Packit 577717
	  case 8: /* Ezra-T */
Packit 577717
	  case 9: /* Antaur/Nehemiah */
Packit 577717
	    return PERFCTR_X86_VIA_C3;
Packit 577717
	  default:
Packit 577717
	    return -1;
Packit 577717
	}
Packit 577717
    }
Packit 577717
    return -1;
Packit 577717
}
Packit 577717
Packit 577717
static int generic_init(const struct cpuinfo *cpuinfo,
Packit 577717
			struct perfctr_info *info)
Packit 577717
{
Packit 577717
    if (!cpu_has(cpuinfo, X86_FEATURE_TSC))
Packit 577717
	return -1;
Packit 577717
    info->cpu_features &= ~PERFCTR_FEATURE_RDPMC;
Packit 577717
    return PERFCTR_X86_GENERIC;
Packit 577717
}
Packit 577717
Packit 577717
void perfctr_info_cpu_init(struct perfctr_info *info)
Packit 577717
{
Packit 577717
    struct cpuinfo cpuinfo;
Packit 577717
    int cpu_type;
Packit 577717
Packit 577717
    identify_cpu(&cpuinfo);
Packit 577717
    cpu_type = -1; /* binary compat prevents using 0 for "unknown" */
Packit 577717
    if (cpu_has(&cpuinfo, X86_FEATURE_MSR)) {
Packit 577717
	switch (cpuinfo.vendor) {
Packit 577717
	  case X86_VENDOR_INTEL:
Packit 577717
	    cpu_type = intel_init(&cpuinfo, info);
Packit 577717
	    break;
Packit 577717
	  case X86_VENDOR_AMD:
Packit 577717
	    cpu_type = amd_init(&cpuinfo, info);
Packit 577717
	    break;
Packit 577717
	  case X86_VENDOR_CYRIX:
Packit 577717
	    cpu_type = cyrix_init(&cpuinfo, info);
Packit 577717
	    break;
Packit 577717
	  case X86_VENDOR_CENTAUR:	
Packit 577717
	    cpu_type = centaur_init(&cpuinfo, info);
Packit 577717
	    break;
Packit 577717
	}
Packit 577717
    }
Packit 577717
    if (cpu_type < 0)
Packit 577717
	cpu_type = generic_init(&cpuinfo, info);
Packit 577717
    info->cpu_type = cpu_type;
Packit 577717
}
Packit 577717
Packit 577717
unsigned int perfctr_info_nrctrs(const struct perfctr_info *info)
Packit 577717
{
Packit 577717
    switch( info->cpu_type ) {
Packit 577717
#if !defined(__x86_64__)
Packit 577717
      case PERFCTR_X86_INTEL_P5:
Packit 577717
      case PERFCTR_X86_INTEL_P5MMX:
Packit 577717
      case PERFCTR_X86_INTEL_P6:
Packit 577717
      case PERFCTR_X86_INTEL_PII:
Packit 577717
      case PERFCTR_X86_INTEL_PIII:
Packit 577717
      case PERFCTR_X86_CYRIX_MII:
Packit 577717
      case PERFCTR_X86_WINCHIP_C6:
Packit 577717
      case PERFCTR_X86_WINCHIP_2:
Packit 577717
      case PERFCTR_X86_INTEL_PENTM:
Packit 577717
	return 2;
Packit 577717
      case PERFCTR_X86_AMD_K7:
Packit 577717
	return 4;
Packit 577717
      case PERFCTR_X86_VIA_C3:
Packit 577717
	return 1;
Packit 577717
      case PERFCTR_X86_INTEL_P4:
Packit 577717
      case PERFCTR_X86_INTEL_P4M2:
Packit 577717
	return 18;
Packit 577717
#endif
Packit 577717
      case PERFCTR_X86_INTEL_P4M3:
Packit 577717
	return 18;
Packit 577717
      case PERFCTR_X86_AMD_K8:
Packit 577717
      case PERFCTR_X86_AMD_K8C:
Packit 577717
	return 4;
Packit 577717
      case PERFCTR_X86_GENERIC:
Packit 577717
      default:
Packit 577717
	return 0;
Packit 577717
    }
Packit 577717
}
Packit 577717
Packit 577717
const char *perfctr_info_cpu_name(const struct perfctr_info *info)
Packit 577717
{
Packit 577717
    switch( info->cpu_type ) {
Packit 577717
      case PERFCTR_X86_GENERIC:
Packit 577717
	return "Generic x86 with TSC";
Packit 577717
#if !defined(__x86_64__)
Packit 577717
      case PERFCTR_X86_INTEL_P5:
Packit 577717
        return "Intel Pentium";
Packit 577717
      case PERFCTR_X86_INTEL_P5MMX:
Packit 577717
        return "Intel Pentium MMX";
Packit 577717
      case PERFCTR_X86_INTEL_P6:
Packit 577717
        return "Intel Pentium Pro";
Packit 577717
      case PERFCTR_X86_INTEL_PII:
Packit 577717
        return "Intel Pentium II";
Packit 577717
      case PERFCTR_X86_INTEL_PIII:
Packit 577717
        return "Intel Pentium III";
Packit 577717
      case PERFCTR_X86_CYRIX_MII:
Packit 577717
        return "Cyrix 6x86MX/MII/III";
Packit 577717
      case PERFCTR_X86_WINCHIP_C6:
Packit 577717
	return "WinChip C6";
Packit 577717
      case PERFCTR_X86_WINCHIP_2:
Packit 577717
	return "WinChip 2/3";
Packit 577717
      case PERFCTR_X86_AMD_K7:
Packit 577717
	return "AMD K7";
Packit 577717
      case PERFCTR_X86_VIA_C3:
Packit 577717
	return "VIA C3";
Packit 577717
      case PERFCTR_X86_INTEL_P4:
Packit 577717
	return "Intel Pentium 4";
Packit 577717
      case PERFCTR_X86_INTEL_P4M2:
Packit 577717
	return "Intel Pentium 4 Model 2";
Packit 577717
      case PERFCTR_X86_INTEL_PENTM:
Packit 577717
	return "Intel Pentium M";
Packit 577717
#endif
Packit 577717
      case PERFCTR_X86_INTEL_P4M3:
Packit 577717
	return "Intel Pentium 4 Model 3";
Packit 577717
      case PERFCTR_X86_AMD_K8:
Packit 577717
	return "AMD K8";
Packit 577717
      case PERFCTR_X86_AMD_K8C:
Packit 577717
	return "AMD K8 Revision C";
Packit 577717
      default:
Packit 577717
        return "?";
Packit 577717
    }
Packit 577717
}
Packit 577717
Packit 577717
void perfctr_cpu_control_print(const struct perfctr_cpu_control *control)
Packit 577717
{
Packit 577717
    unsigned int i, nractrs, nrictrs, nrctrs;
Packit 577717
Packit 577717
    nractrs = control->nractrs;
Packit 577717
    nrictrs = control->nrictrs;
Packit 577717
    nrctrs = control->nractrs + nrictrs;
Packit 577717
Packit 577717
    printf("tsc_on\t\t\t%u\n", control->tsc_on);
Packit 577717
    printf("nractrs\t\t\t%u\n", nractrs);
Packit 577717
    if( nrictrs )
Packit 577717
	printf("nrictrs\t\t\t%u\n", nrictrs);
Packit 577717
    for(i = 0; i < nrctrs; ++i) {
Packit 577717
        if( control->pmc_map[i] >= 18 ) /* for P4 'fast rdpmc' cases */
Packit 577717
            printf("pmc_map[%u]\t\t0x%08X\n", i, control->pmc_map[i]);
Packit 577717
        else
Packit 577717
            printf("pmc_map[%u]\t\t%u\n", i, control->pmc_map[i]);
Packit 577717
        printf("evntsel[%u]\t\t0x%08X\n", i, control->evntsel[i]);
Packit 577717
        if( control->p4.escr[i] )
Packit 577717
            printf("escr[%u]\t\t\t0x%08X\n", i, control->p4.escr[i]);
Packit 577717
	if( i >= nractrs )
Packit 577717
	    printf("ireset[%u]\t\t%d\n", i, control->ireset[i]);
Packit 577717
    }
Packit 577717
    if( control->p4.pebs_enable )
Packit 577717
	printf("pebs_enable\t\t0x%08X\n", control->p4.pebs_enable);
Packit 577717
    if( control->p4.pebs_matrix_vert )
Packit 577717
	printf("pebs_matrix_vert\t0x%08X\n", control->p4.pebs_matrix_vert);
Packit 577717
}