Add support for using the 586- and 686-class performance

counters.
This commit is contained in:
thorpej 2000-09-13 04:47:00 +00:00
parent b9b07590ec
commit 90a2e46ab1
5 changed files with 332 additions and 3 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: files.i386,v 1.166 2000/09/07 17:20:58 thorpej Exp $
# $NetBSD: files.i386,v 1.167 2000/09/13 04:47:00 thorpej Exp $
#
# new style config file for i386 architecture
#
@ -31,6 +31,9 @@ defopt USER_LDT
# Speed hack; make NOPs dummies (might break on some machines)
defopt DUMMY_NOPS
# Performance counter support
defopt PERFCTRS
# X server support in console drivers
defopt opt_xserver.h XSERVER XSERVER_DDB
@ -73,6 +76,8 @@ file arch/i386/i386/trap.c
file arch/i386/i386/vm_machdep.c
file dev/cons.c
file arch/i386/i386/pmc.c perfctrs
#
# Machine-independent SCSI drivers
#

223
sys/arch/i386/i386/pmc.c Normal file
View File

@ -0,0 +1,223 @@
/* $NetBSD: pmc.c,v 1.1 2000/09/13 04:47:01 thorpej Exp $ */
/*-
* Copyright (c) 2000 Zembu Labs, Inc.
* All rights reserved.
*
* Author: Jason R. Thorpe <thorpej@zembu.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Zembu Labs, Inc.
* 4. Neither the name of Zembu Labs nor the names of its employees may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ZEMBU LABS, INC. ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAR-
* RANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DIS-
* CLAIMED. IN NO EVENT SHALL ZEMBU LABS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Interface to x86 CPU Performance Counters.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <machine/cpufunc.h>
#include <machine/specialreg.h>
#include <machine/sysarch.h>
#include <machine/pmc.h>
static int pmc_initialized;
static int pmc_type;
static int pmc_flags;
static struct pmc_state {
u_int64_t pmcs_val;
u_int64_t pmcs_tsc;
u_int64_t pmcs_control;
u_int32_t pmcs_ctrmsr;
} pmc_state[PMC_NCOUNTERS];
static int pmc_running;
static void
pmc_init(void)
{
if (pmc_initialized)
return;
switch (cpu_class) {
case CPUCLASS_586:
pmc_type = PMC_TYPE_I586;
pmc_state[0].pmcs_ctrmsr = MSR_CTR0;
pmc_state[1].pmcs_ctrmsr = MSR_CTR1;
break;
case CPUCLASS_686:
pmc_type = PMC_TYPE_I686;
pmc_state[0].pmcs_ctrmsr = MSR_PERFCTR0;
pmc_state[1].pmcs_ctrmsr = MSR_PERFCTR1;
break;
default:
pmc_type = PMC_TYPE_NONE;
}
if (pmc_type != PMC_TYPE_NONE && (cpu_feature & CPUID_TSC) != 0)
pmc_flags |= PMC_INFO_HASTSC;
pmc_initialized = 1;
}
int
pmc_info(struct proc *p, struct i386_pmc_info_args *uargs, register_t *retval)
{
struct i386_pmc_info_args rv;
memset(&rv, 0, sizeof(rv));
if (pmc_initialized == 0)
pmc_init();
rv.type = pmc_type;
rv.flags = pmc_flags;
return (copyout(&rv, uargs, sizeof(rv)));
}
int
pmc_startstop(struct proc *p, struct i386_pmc_startstop_args *uargs,
register_t *retval)
{
struct i386_pmc_startstop_args args;
int error, mask, start;
if (pmc_initialized == 0)
pmc_init();
if (pmc_type == PMC_TYPE_NONE)
return (ENODEV);
error = copyin(uargs, &args, sizeof(args));
if (error)
return (error);
if (args.counter < 0 || args.counter >= PMC_NCOUNTERS)
return (EINVAL);
mask = 1 << args.counter;
start = (args.flags & (PMC_SETUP_KERNEL|PMC_SETUP_USER)) != 0;
if ((pmc_running & mask) != 0 && start != 0)
return (EBUSY);
else if ((pmc_running & mask) == 0 && start == 0)
return (0);
if (start) {
pmc_running |= mask;
pmc_state[args.counter].pmcs_val = args.val;
switch (pmc_type) {
case PMC_TYPE_I586:
pmc_state[args.counter].pmcs_control = args.event |
((args.flags & PMC_SETUP_KERNEL) ?
PMC5_CESR_OS : 0) |
((args.flags & PMC_SETUP_USER) ?
PMC5_CESR_USR : 0) |
((args.flags & PMC_SETUP_EDGE) ?
PMC5_CESR_E : 0);
break;
case PMC_TYPE_I686:
pmc_state[args.counter].pmcs_control = args.event |
(args.unit << PMC6_EVTSEL_UNIT_SHIFT) |
((args.flags & PMC_SETUP_KERNEL) ?
PMC6_EVTSEL_OS : 0) |
((args.flags & PMC_SETUP_USER) ?
PMC6_EVTSEL_USR : 0) |
((args.flags & PMC_SETUP_EDGE) ?
PMC6_EVTSEL_E : 0) |
((args.flags & PMC_SETUP_INV) ?
PMC6_EVTSEL_INV : 0) |
(args.compare << PMC6_EVTSEL_COUNTER_MASK_SHIFT);
break;
}
disable_intr();
wrmsr(pmc_state[args.counter].pmcs_ctrmsr,
pmc_state[args.counter].pmcs_val);
enable_intr();
} else {
pmc_running &= ~mask;
pmc_state[args.counter].pmcs_control = 0;
}
switch (pmc_type) {
case PMC_TYPE_I586:
disable_intr();
wrmsr(MSR_CESR, pmc_state[0].pmcs_control |
(pmc_state[1].pmcs_control << 16));
enable_intr();
break;
case PMC_TYPE_I686:
disable_intr();
if (args.counter == 1)
wrmsr(MSR_EVNTSEL1, pmc_state[1].pmcs_control);
wrmsr(MSR_EVNTSEL0, pmc_state[0].pmcs_control |
(pmc_running ? PMC6_EVTSEL_EN : 0));
enable_intr();
break;
}
return (0);
}
int
pmc_read(struct proc *p, struct i386_pmc_read_args *uargs, register_t *retval)
{
struct i386_pmc_read_args args;
int error;
if (pmc_initialized == 0)
pmc_init();
if (pmc_type == PMC_TYPE_NONE)
return (ENODEV);
error = copyin(uargs, &args, sizeof(args));
if (error)
return (error);
if (args.counter < 0 || args.counter >= PMC_NCOUNTERS)
return (EINVAL);
if (pmc_running & (1 << args.counter)) {
pmc_state[args.counter].pmcs_val =
rdmsr(pmc_state[args.counter].pmcs_ctrmsr) &
0xffffffffffULL;
if (pmc_flags & PMC_INFO_HASTSC)
pmc_state[args.counter].pmcs_tsc = rdtsc();
}
args.val = pmc_state[args.counter].pmcs_val;
args.time = pmc_state[args.counter].pmcs_tsc;
return (copyout(&args, uargs, sizeof(args)));
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: sys_machdep.c,v 1.50 2000/06/29 08:44:54 mrg Exp $ */
/* $NetBSD: sys_machdep.c,v 1.51 2000/09/13 04:47:01 thorpej Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -76,6 +76,7 @@
#include "opt_vm86.h"
#include "opt_user_ldt.h"
#include "opt_perfctrs.h"
#include <sys/param.h>
#include <sys/systm.h>
@ -106,6 +107,10 @@
#include <machine/vm86.h>
#endif
#ifdef PERFCTRS
#include <machine/pmc.h>
#endif
extern vm_map_t kernel_map;
#ifdef USER_LDT
@ -476,6 +481,20 @@ sys_sysarch(p, v, retval)
break;
#endif
#ifdef PERFCTRS
case I386_PMC_INFO:
error = pmc_info(p, SCARG(uap, parms), retval);
break;
case I386_PMC_STARTSTOP:
error = pmc_startstop(p, SCARG(uap, parms), retval);
break;
case I386_PMC_READ:
error = pmc_read(p, SCARG(uap, parms), retval);
break;
#endif
default:
error = EINVAL;
break;

View File

@ -0,0 +1,43 @@
/* $NetBSD: pmc.h,v 1.1 2000/09/13 04:47:01 thorpej Exp $ */
/*-
* Copyright (c) 2000 Zembu Labs, Inc.
* All rights reserved.
*
* Author: Jason R. Thorpe <thorpej@zembu.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Zembu Labs, Inc.
* 4. Neither the name of Zembu Labs nor the names of its employees may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ZEMBU LABS, INC. ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAR-
* RANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DIS-
* CLAIMED. IN NO EVENT SHALL ZEMBU LABS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef _KERNEL
int pmc_info(struct proc *, struct i386_pmc_info_args *,
register_t *);
int pmc_startstop(struct proc *, struct i386_pmc_startstop_args *,
register_t *);
int pmc_read(struct proc *, struct i386_pmc_read_args *,
register_t *);
#endif

View File

@ -1,4 +1,4 @@
/* $NetBSD: sysarch.h,v 1.9 1998/02/25 21:27:05 perry Exp $ */
/* $NetBSD: sysarch.h,v 1.10 2000/09/13 04:47:01 thorpej Exp $ */
#ifndef _I386_SYSARCH_H_
#define _I386_SYSARCH_H_
@ -12,6 +12,9 @@
#define I386_GET_IOPERM 3
#define I386_SET_IOPERM 4
#define I386_VM86 5
#define I386_PMC_INFO 8
#define I386_PMC_STARTSTOP 9
#define I386_PMC_READ 10
struct i386_get_ldt_args {
int start;
@ -37,12 +40,48 @@ struct i386_set_ioperm_args {
u_long *iomap;
};
struct i386_pmc_info_args {
int type;
int flags;
};
#define PMC_TYPE_NONE 0
#define PMC_TYPE_I586 1
#define PMC_TYPE_I686 2
#define PMC_INFO_HASTSC 0x01
#define PMC_NCOUNTERS 2
struct i386_pmc_startstop_args {
int counter;
u_int64_t val;
u_int8_t event;
u_int8_t unit;
u_int8_t compare;
u_int8_t flags;
};
#define PMC_SETUP_KERNEL 0x01
#define PMC_SETUP_USER 0x02
#define PMC_SETUP_EDGE 0x04
#define PMC_SETUP_INV 0x08
struct i386_pmc_read_args {
int counter;
u_int64_t val;
u_int64_t time;
};
#ifndef _KERNEL
int i386_get_ldt __P((int, union descriptor *, int));
int i386_set_ldt __P((int, union descriptor *, int));
int i386_iopl __P((int));
int i386_get_ioperm __P((u_long *));
int i386_set_ioperm __P((u_long *));
int i386_pmc_info __P((struct i386_pmc_info_args *));
int i386_pmc_startstop __P((struct i386_pmc_startstop_args *));
int i386_pmc_read __P((struct i386_pmc_read_args *));
int sysarch __P((int, void *));
#endif