Add support for using the 586- and 686-class performance
counters.
This commit is contained in:
parent
b9b07590ec
commit
90a2e46ab1
|
@ -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
|
# new style config file for i386 architecture
|
||||||
#
|
#
|
||||||
|
@ -31,6 +31,9 @@ defopt USER_LDT
|
||||||
# Speed hack; make NOPs dummies (might break on some machines)
|
# Speed hack; make NOPs dummies (might break on some machines)
|
||||||
defopt DUMMY_NOPS
|
defopt DUMMY_NOPS
|
||||||
|
|
||||||
|
# Performance counter support
|
||||||
|
defopt PERFCTRS
|
||||||
|
|
||||||
# X server support in console drivers
|
# X server support in console drivers
|
||||||
defopt opt_xserver.h XSERVER XSERVER_DDB
|
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 arch/i386/i386/vm_machdep.c
|
||||||
file dev/cons.c
|
file dev/cons.c
|
||||||
|
|
||||||
|
file arch/i386/i386/pmc.c perfctrs
|
||||||
|
|
||||||
#
|
#
|
||||||
# Machine-independent SCSI drivers
|
# Machine-independent SCSI drivers
|
||||||
#
|
#
|
||||||
|
|
|
@ -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)));
|
||||||
|
}
|
|
@ -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.
|
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||||
|
@ -76,6 +76,7 @@
|
||||||
|
|
||||||
#include "opt_vm86.h"
|
#include "opt_vm86.h"
|
||||||
#include "opt_user_ldt.h"
|
#include "opt_user_ldt.h"
|
||||||
|
#include "opt_perfctrs.h"
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/systm.h>
|
#include <sys/systm.h>
|
||||||
|
@ -106,6 +107,10 @@
|
||||||
#include <machine/vm86.h>
|
#include <machine/vm86.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef PERFCTRS
|
||||||
|
#include <machine/pmc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
extern vm_map_t kernel_map;
|
extern vm_map_t kernel_map;
|
||||||
|
|
||||||
#ifdef USER_LDT
|
#ifdef USER_LDT
|
||||||
|
@ -476,6 +481,20 @@ sys_sysarch(p, v, retval)
|
||||||
break;
|
break;
|
||||||
#endif
|
#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:
|
default:
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -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
|
|
@ -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_
|
#ifndef _I386_SYSARCH_H_
|
||||||
#define _I386_SYSARCH_H_
|
#define _I386_SYSARCH_H_
|
||||||
|
@ -12,6 +12,9 @@
|
||||||
#define I386_GET_IOPERM 3
|
#define I386_GET_IOPERM 3
|
||||||
#define I386_SET_IOPERM 4
|
#define I386_SET_IOPERM 4
|
||||||
#define I386_VM86 5
|
#define I386_VM86 5
|
||||||
|
#define I386_PMC_INFO 8
|
||||||
|
#define I386_PMC_STARTSTOP 9
|
||||||
|
#define I386_PMC_READ 10
|
||||||
|
|
||||||
struct i386_get_ldt_args {
|
struct i386_get_ldt_args {
|
||||||
int start;
|
int start;
|
||||||
|
@ -37,12 +40,48 @@ struct i386_set_ioperm_args {
|
||||||
u_long *iomap;
|
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
|
#ifndef _KERNEL
|
||||||
int i386_get_ldt __P((int, union descriptor *, int));
|
int i386_get_ldt __P((int, union descriptor *, int));
|
||||||
int i386_set_ldt __P((int, union descriptor *, int));
|
int i386_set_ldt __P((int, union descriptor *, int));
|
||||||
int i386_iopl __P((int));
|
int i386_iopl __P((int));
|
||||||
int i386_get_ioperm __P((u_long *));
|
int i386_get_ioperm __P((u_long *));
|
||||||
int i386_set_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 *));
|
int sysarch __P((int, void *));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue