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
|
||||
#
|
||||
|
@ -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
|
||||
#
|
||||
|
|
|
@ -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.
|
||||
|
@ -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;
|
||||
|
|
|
@ -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_
|
||||
#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
|
||||
|
||||
|
|
Loading…
Reference in New Issue