17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*23a1cceaSRoger A. Faulkner  * Common Development and Distribution License (the "License").
6*23a1cceaSRoger A. Faulkner  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21*23a1cceaSRoger A. Faulkner 
227c478bd9Sstevel@tonic-gate /*
23*23a1cceaSRoger A. Faulkner  * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * Routines to capture processor-dependencies in event specification.
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <sys/types.h>
317c478bd9Sstevel@tonic-gate #include <string.h>
327c478bd9Sstevel@tonic-gate #include <strings.h>
337c478bd9Sstevel@tonic-gate #include <stdlib.h>
347c478bd9Sstevel@tonic-gate #include <stdio.h>
357c478bd9Sstevel@tonic-gate #include <libintl.h>
367c478bd9Sstevel@tonic-gate #include <assert.h>
377c478bd9Sstevel@tonic-gate #include <errno.h>
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #include "libcpc.h"
407c478bd9Sstevel@tonic-gate #include "libcpc_impl.h"
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /*
437c478bd9Sstevel@tonic-gate  * Event specifications for Pentium performance counters are based
447c478bd9Sstevel@tonic-gate  * on the content of a getsubopt-like string.
457c478bd9Sstevel@tonic-gate  * The string should contain something that looks like this:
467c478bd9Sstevel@tonic-gate  *
477c478bd9Sstevel@tonic-gate  *	pic0=<eventspec>,pic1=<eventspec>
487c478bd9Sstevel@tonic-gate  *		[,cmask0=<maskspec>][,cmask1=<maskspec>]
497c478bd9Sstevel@tonic-gate  *		[,umask0=<maskspec>][,umask1=<maskspec>]
507c478bd9Sstevel@tonic-gate  *		[,inv[0|1]][,noedge[0|1]]
517c478bd9Sstevel@tonic-gate  *		[,sys[0|1]][,nouser[0|1]]
527c478bd9Sstevel@tonic-gate  *
537c478bd9Sstevel@tonic-gate  * For example:
547c478bd9Sstevel@tonic-gate  *	pic0=data_mem_refs,pic1=l2_ld,sys
557c478bd9Sstevel@tonic-gate  * or
567c478bd9Sstevel@tonic-gate  *	pic0=l2_ld,pic1=bus_drdy_clocks,umask1=0x20,nouser1
577c478bd9Sstevel@tonic-gate  *
587c478bd9Sstevel@tonic-gate  * By default, user event counting is enabled, system event counting
597c478bd9Sstevel@tonic-gate  * is disabled.
607c478bd9Sstevel@tonic-gate  *
617c478bd9Sstevel@tonic-gate  * Note that Pentium and Pentium Pro have different event specifications.
627c478bd9Sstevel@tonic-gate  *
637c478bd9Sstevel@tonic-gate  * The two events must be named.  The names can be ascii or
647c478bd9Sstevel@tonic-gate  * a decimal, octal or hexadecimal number as parsed by strtol(3C).
657c478bd9Sstevel@tonic-gate  *
667c478bd9Sstevel@tonic-gate  * The routine counts the number of errors encountered while parsing
677c478bd9Sstevel@tonic-gate  * the string, if no errors are encountered, the event handle is
687c478bd9Sstevel@tonic-gate  * returned.
697c478bd9Sstevel@tonic-gate  */
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate const char *
cpc_getusage(int cpuver)727c478bd9Sstevel@tonic-gate cpc_getusage(int cpuver)
737c478bd9Sstevel@tonic-gate {
747c478bd9Sstevel@tonic-gate 	switch (cpuver) {
757c478bd9Sstevel@tonic-gate 	case CPC_PENTIUM_PRO_MMX:
767c478bd9Sstevel@tonic-gate 	case CPC_PENTIUM_PRO:
777c478bd9Sstevel@tonic-gate 		return ("pic0=<event0>,pic1=<event1> "
787c478bd9Sstevel@tonic-gate 		    "[,sys[0|1]] "
797c478bd9Sstevel@tonic-gate 		    "[,nouser[0|1]] "
807c478bd9Sstevel@tonic-gate 		    "[,noedge[0|1]] "
817c478bd9Sstevel@tonic-gate 		    "[,pc[0|1]] "
827c478bd9Sstevel@tonic-gate 		    "[,int[0|1]] "
837c478bd9Sstevel@tonic-gate 		    "[,inv[0|1]] "
847c478bd9Sstevel@tonic-gate 		    "[,cmask[0|1]=<maskspec>] "
857c478bd9Sstevel@tonic-gate 		    "[,umask[0|1]=<maskspec>] ");
867c478bd9Sstevel@tonic-gate 	case CPC_PENTIUM_MMX:
877c478bd9Sstevel@tonic-gate 	case CPC_PENTIUM:
887c478bd9Sstevel@tonic-gate 		return ("pic0=<event0>,pic1=<event1> "
897c478bd9Sstevel@tonic-gate 		    "[,sys[0|1]] "
907c478bd9Sstevel@tonic-gate 		    "[,nouser[0|1]] "
917c478bd9Sstevel@tonic-gate 		    "[,noedge[0|1]] "
927c478bd9Sstevel@tonic-gate 		    "[,pc[0|1]]");
937c478bd9Sstevel@tonic-gate 	default:
947c478bd9Sstevel@tonic-gate 		return (NULL);
957c478bd9Sstevel@tonic-gate 	}
967c478bd9Sstevel@tonic-gate }
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate struct keyval {
997c478bd9Sstevel@tonic-gate 	char *kv_token;
1007c478bd9Sstevel@tonic-gate 	int (*kv_action)(const char *,
1017c478bd9Sstevel@tonic-gate 	    const struct keyval *, int, char *, uint32_t *);
1027c478bd9Sstevel@tonic-gate 	uint_t kv_regno;
1037c478bd9Sstevel@tonic-gate 	uint32_t kv_mask;
1047c478bd9Sstevel@tonic-gate 	int kv_shift;
1057c478bd9Sstevel@tonic-gate };
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1087c478bd9Sstevel@tonic-gate static int
eightbits(const char * fn,const struct keyval * kv,int cpuver,char * value,uint32_t * bits)1097c478bd9Sstevel@tonic-gate eightbits(const char *fn,
1107c478bd9Sstevel@tonic-gate     const struct keyval *kv, int cpuver, char *value, uint32_t *bits)
1117c478bd9Sstevel@tonic-gate {
1127c478bd9Sstevel@tonic-gate 	char *eptr = NULL;
1137c478bd9Sstevel@tonic-gate 	long l;
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	if (value == NULL) {
1167c478bd9Sstevel@tonic-gate 		__cpc_error(fn, gettext("missing '%s' value\n"),
1177c478bd9Sstevel@tonic-gate 		    kv->kv_token);
1187c478bd9Sstevel@tonic-gate 		return (-1);
1197c478bd9Sstevel@tonic-gate 	}
1207c478bd9Sstevel@tonic-gate 	l = strtol(value, &eptr, 0);
1217c478bd9Sstevel@tonic-gate 	if (value == eptr || l < 0 || l > UINT8_MAX) {
1227c478bd9Sstevel@tonic-gate 		__cpc_error(fn, gettext("bad '%s' value\n"), kv->kv_token);
1237c478bd9Sstevel@tonic-gate 		return (-1);
1247c478bd9Sstevel@tonic-gate 	}
1257c478bd9Sstevel@tonic-gate 	bits[kv->kv_regno] |= ((uint8_t)l & kv->kv_mask) << kv->kv_shift;
1267c478bd9Sstevel@tonic-gate 	return (0);
1277c478bd9Sstevel@tonic-gate }
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate static int
picbits(const char * fn,const struct keyval * kv,int cpuver,char * value,uint32_t * bits)1307c478bd9Sstevel@tonic-gate picbits(const char *fn,
1317c478bd9Sstevel@tonic-gate     const struct keyval *kv, int cpuver, char *value, uint32_t *bits)
1327c478bd9Sstevel@tonic-gate {
1337c478bd9Sstevel@tonic-gate 	uint8_t val8;
1347c478bd9Sstevel@tonic-gate 	uint_t regno;
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	regno = strcmp(kv->kv_token, "pic0") == 0 ? 0 : 1;
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	if (value == NULL) {
1397c478bd9Sstevel@tonic-gate 		__cpc_error(fn, gettext("missing '%s' value\n"),
1407c478bd9Sstevel@tonic-gate 		    kv->kv_token);
1417c478bd9Sstevel@tonic-gate 		return (-1);
1427c478bd9Sstevel@tonic-gate 	}
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	if (__cpc_name_to_reg(cpuver, regno, value, &val8) != 0) {
1457c478bd9Sstevel@tonic-gate 		switch (cpuver) {
1467c478bd9Sstevel@tonic-gate 		case CPC_PENTIUM_PRO_MMX:
1477c478bd9Sstevel@tonic-gate 		case CPC_PENTIUM_PRO:
1487c478bd9Sstevel@tonic-gate 			assert(kv->kv_regno == regno);
1497c478bd9Sstevel@tonic-gate 			__cpc_error(fn, gettext(
1507c478bd9Sstevel@tonic-gate 			    "PerfCtr%d cannot measure '%s' on this cpu\n"),
1517c478bd9Sstevel@tonic-gate 			    regno, value);
1527c478bd9Sstevel@tonic-gate 			break;
1537c478bd9Sstevel@tonic-gate 		case CPC_PENTIUM_MMX:
1547c478bd9Sstevel@tonic-gate 		case CPC_PENTIUM:
1557c478bd9Sstevel@tonic-gate 			assert(kv->kv_regno == 0);
1567c478bd9Sstevel@tonic-gate 			__cpc_error(fn, gettext(
1577c478bd9Sstevel@tonic-gate 			    "CTR%d cannot measure '%s' on this cpu\n"),
1587c478bd9Sstevel@tonic-gate 			    regno, value);
1597c478bd9Sstevel@tonic-gate 			break;
1607c478bd9Sstevel@tonic-gate 		}
1617c478bd9Sstevel@tonic-gate 		return (-1);
1627c478bd9Sstevel@tonic-gate 	}
1637c478bd9Sstevel@tonic-gate 	bits[kv->kv_regno] |= (val8 & kv->kv_mask) << kv->kv_shift;
1647c478bd9Sstevel@tonic-gate 	return (0);
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate /*ARGSUSED2*/
1687c478bd9Sstevel@tonic-gate static int
bitclr(const char * fn,const struct keyval * kv,int cpuver,char * value,uint32_t * bits)1697c478bd9Sstevel@tonic-gate bitclr(const char *fn,
1707c478bd9Sstevel@tonic-gate     const struct keyval *kv, int cpuver, char *value, uint32_t *bits)
1717c478bd9Sstevel@tonic-gate {
1727c478bd9Sstevel@tonic-gate 	if (value != NULL) {
1737c478bd9Sstevel@tonic-gate 		__cpc_error(fn, gettext("bad arg to '%s'\n"), kv->kv_token);
1747c478bd9Sstevel@tonic-gate 		return (-1);
1757c478bd9Sstevel@tonic-gate 	}
1767c478bd9Sstevel@tonic-gate 	bits[kv->kv_regno] &= ~(kv->kv_mask << kv->kv_shift);
1777c478bd9Sstevel@tonic-gate 	return (0);
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate /*ARGSUSED2*/
1817c478bd9Sstevel@tonic-gate static int
bitset(const char * fn,const struct keyval * kv,int cpuver,char * value,uint32_t * bits)1827c478bd9Sstevel@tonic-gate bitset(const char *fn,
1837c478bd9Sstevel@tonic-gate     const struct keyval *kv, int cpuver, char *value, uint32_t *bits)
1847c478bd9Sstevel@tonic-gate {
1857c478bd9Sstevel@tonic-gate 	if (value != NULL) {
1867c478bd9Sstevel@tonic-gate 		__cpc_error(fn, gettext("bad arg to '%s'\n"), kv->kv_token);
1877c478bd9Sstevel@tonic-gate 		return (-1);
1887c478bd9Sstevel@tonic-gate 	}
1897c478bd9Sstevel@tonic-gate 	bits[kv->kv_regno] |= (kv->kv_mask << kv->kv_shift);
1907c478bd9Sstevel@tonic-gate 	return (0);
1917c478bd9Sstevel@tonic-gate }
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate static int
nextpair(const char * fn,const struct keyval * kv,int cpuver,char * value,uint32_t * bits)1947c478bd9Sstevel@tonic-gate nextpair(const char *fn,
1957c478bd9Sstevel@tonic-gate     const struct keyval *kv, int cpuver, char *value, uint32_t *bits)
1967c478bd9Sstevel@tonic-gate {
1977c478bd9Sstevel@tonic-gate 	int rv;
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	if (value != NULL) {
2007c478bd9Sstevel@tonic-gate 		__cpc_error(fn, gettext("bad arg to '%s'\n"), kv->kv_token);
2017c478bd9Sstevel@tonic-gate 		return (-1);
2027c478bd9Sstevel@tonic-gate 	}
2037c478bd9Sstevel@tonic-gate 	kv++;
2047c478bd9Sstevel@tonic-gate 	if ((rv = kv->kv_action(fn, kv, cpuver, value, bits)) != 0)
2057c478bd9Sstevel@tonic-gate 		return (rv);
2067c478bd9Sstevel@tonic-gate 	kv++;
2077c478bd9Sstevel@tonic-gate 	return (kv->kv_action(fn, kv, cpuver, value, bits));
2087c478bd9Sstevel@tonic-gate }
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate /*
2117c478bd9Sstevel@tonic-gate  * This token table must match the keyval tables below.
2127c478bd9Sstevel@tonic-gate  */
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate static char * const tokens[] = {
2157c478bd9Sstevel@tonic-gate #define	D_pic0		0
2167c478bd9Sstevel@tonic-gate 	"pic0",			/* takes a valid event name */
2177c478bd9Sstevel@tonic-gate #define	D_pic1		1
2187c478bd9Sstevel@tonic-gate 	"pic1",			/* takes a valid event name */
2197c478bd9Sstevel@tonic-gate #define	D_nouser	2
2207c478bd9Sstevel@tonic-gate 	"nouser",		/* disables user counts */
2217c478bd9Sstevel@tonic-gate #define	D_nouser0	3
2227c478bd9Sstevel@tonic-gate 	"nouser0",
2237c478bd9Sstevel@tonic-gate #define	D_nouser1	4
2247c478bd9Sstevel@tonic-gate 	"nouser1",
2257c478bd9Sstevel@tonic-gate #define	D_sys		5
2267c478bd9Sstevel@tonic-gate 	"sys",			/* enables system counts */
2277c478bd9Sstevel@tonic-gate #define	D_sys0		6
2287c478bd9Sstevel@tonic-gate 	"sys0",
2297c478bd9Sstevel@tonic-gate #define	D_sys1		7
2307c478bd9Sstevel@tonic-gate 	"sys1",
2317c478bd9Sstevel@tonic-gate #define	D_noedge	8
2327c478bd9Sstevel@tonic-gate 	"noedge",		/* disable edge detect */
2337c478bd9Sstevel@tonic-gate #define	D_noedge0	9
2347c478bd9Sstevel@tonic-gate 	"noedge0",
2357c478bd9Sstevel@tonic-gate #define	D_noedge1	10
2367c478bd9Sstevel@tonic-gate 	"noedge1",
2377c478bd9Sstevel@tonic-gate #define	D_pc		11
2387c478bd9Sstevel@tonic-gate 	"pc",			/* sets pin control high */
2397c478bd9Sstevel@tonic-gate #define	D_pc0		12
2407c478bd9Sstevel@tonic-gate 	"pc0",
2417c478bd9Sstevel@tonic-gate #define	D_pc1		13
2427c478bd9Sstevel@tonic-gate 	"pc1",
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate /*
2457c478bd9Sstevel@tonic-gate  * These additional keywords are for Pentium Pro / Pentium II machines.
2467c478bd9Sstevel@tonic-gate  */
2477c478bd9Sstevel@tonic-gate #define	D_int		14
2487c478bd9Sstevel@tonic-gate 	"int",			/* enable interrupt on counter overflow */
2497c478bd9Sstevel@tonic-gate #define	D_int0		15
2507c478bd9Sstevel@tonic-gate 	"int0",
2517c478bd9Sstevel@tonic-gate #define	D_int1		16
2527c478bd9Sstevel@tonic-gate 	"int1",
2537c478bd9Sstevel@tonic-gate #define	D_inv		17
2547c478bd9Sstevel@tonic-gate 	"inv",			/* invert cmask comparison */
2557c478bd9Sstevel@tonic-gate #define	D_inv0		18
2567c478bd9Sstevel@tonic-gate 	"inv0",
2577c478bd9Sstevel@tonic-gate #define	D_inv1		19
2587c478bd9Sstevel@tonic-gate 	"inv1",
2597c478bd9Sstevel@tonic-gate #define	D_umask0	20
2607c478bd9Sstevel@tonic-gate 	"umask0",		/* PerfCtr0 unit mask */
2617c478bd9Sstevel@tonic-gate #define	D_umask1	21
2627c478bd9Sstevel@tonic-gate 	"umask1",		/* PerfCtr1 unit mask */
2637c478bd9Sstevel@tonic-gate #define	D_cmask0	22
2647c478bd9Sstevel@tonic-gate 	"cmask0",		/* PerfCtr0 counter mask */
2657c478bd9Sstevel@tonic-gate #define	D_cmask1	23
2667c478bd9Sstevel@tonic-gate 	"cmask1",		/* PerfCtr1 counter mask */
2677c478bd9Sstevel@tonic-gate 	NULL
2687c478bd9Sstevel@tonic-gate };
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate static const struct keyval p6_keyvals[] = {
2717c478bd9Sstevel@tonic-gate 	{ "pic0",	picbits,	0,
2727c478bd9Sstevel@tonic-gate 		CPC_P6_PES_PIC0_MASK,	0 },
2737c478bd9Sstevel@tonic-gate 	{ "pic1",	picbits,	1,
2747c478bd9Sstevel@tonic-gate 		CPC_P6_PES_PIC1_MASK,	0 },
2757c478bd9Sstevel@tonic-gate 	{ "nouser",	nextpair },
2767c478bd9Sstevel@tonic-gate 	{ "nouser0",	bitclr,		0,
2777c478bd9Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_USR },
2787c478bd9Sstevel@tonic-gate 	{ "nouser1",	bitclr,		1,
2797c478bd9Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_USR },
2807c478bd9Sstevel@tonic-gate 	{ "sys",	nextpair },
2817c478bd9Sstevel@tonic-gate 	{ "sys0",	bitset,		0,
2827c478bd9Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_OS },
2837c478bd9Sstevel@tonic-gate 	{ "sys1",	bitset,		1,
2847c478bd9Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_OS },
2857c478bd9Sstevel@tonic-gate 	{ "noedge",	nextpair },
2867c478bd9Sstevel@tonic-gate 	{ "noedge0",	bitclr,		0,
2877c478bd9Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_E },
2887c478bd9Sstevel@tonic-gate 	{ "noedge1",	bitclr,		1,
2897c478bd9Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_E },
2907c478bd9Sstevel@tonic-gate 	{ "pc",		nextpair },
2917c478bd9Sstevel@tonic-gate 	{ "pc0",	bitset,		0,
2927c478bd9Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_PC },
2937c478bd9Sstevel@tonic-gate 	{ "pc1",	bitset,		1,
2947c478bd9Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_PC },
2957c478bd9Sstevel@tonic-gate 	{ "int",	nextpair },
2967c478bd9Sstevel@tonic-gate 	{ "int0",	bitset,		0,
2977c478bd9Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_INT },
2987c478bd9Sstevel@tonic-gate 	{ "int1",	bitset,		1,
2997c478bd9Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_INT },
3007c478bd9Sstevel@tonic-gate 	{ "inv",	nextpair },
3017c478bd9Sstevel@tonic-gate 	{ "inv0",	bitset,		0,
3027c478bd9Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_INV },
3037c478bd9Sstevel@tonic-gate 	{ "inv1",	bitset,		1,
3047c478bd9Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_INV },
3057c478bd9Sstevel@tonic-gate 	{ "umask0",	eightbits,	0,
3067c478bd9Sstevel@tonic-gate 		CPC_P6_PES_UMASK_MASK,	CPC_P6_PES_UMASK_SHIFT },
3077c478bd9Sstevel@tonic-gate 	{ "umask1",	eightbits,	1,
3087c478bd9Sstevel@tonic-gate 		CPC_P6_PES_UMASK_MASK,	CPC_P6_PES_UMASK_SHIFT },
3097c478bd9Sstevel@tonic-gate 	{ "cmask0",	eightbits,	0,
3107c478bd9Sstevel@tonic-gate 		CPC_P6_PES_CMASK_MASK,	CPC_P6_PES_CMASK_SHIFT },
3117c478bd9Sstevel@tonic-gate 	{ "cmask1",	eightbits,	1,
3127c478bd9Sstevel@tonic-gate 		CPC_P6_PES_CMASK_MASK,	CPC_P6_PES_CMASK_SHIFT },
3137c478bd9Sstevel@tonic-gate };
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate /*
3167c478bd9Sstevel@tonic-gate  * Note that this table -must- be an identically indexed
3177c478bd9Sstevel@tonic-gate  * subset of p6_keyvals.
3187c478bd9Sstevel@tonic-gate  */
3197c478bd9Sstevel@tonic-gate static const struct keyval p5_keyvals[] = {
3207c478bd9Sstevel@tonic-gate 	{ "pic0",	picbits,	0,
3217c478bd9Sstevel@tonic-gate 		CPC_P5_CESR_ES0_MASK,	CPC_P5_CESR_ES0_SHIFT },
3227c478bd9Sstevel@tonic-gate 	{ "pic1",	picbits,	0,
3237c478bd9Sstevel@tonic-gate 		CPC_P5_CESR_ES1_MASK,	CPC_P5_CESR_ES1_SHIFT },
3247c478bd9Sstevel@tonic-gate 	{ "nouser",	nextpair },
3257c478bd9Sstevel@tonic-gate 	{ "nouser0",	bitclr,		0,
3267c478bd9Sstevel@tonic-gate 		UINT32_C(1),		CPC_P5_CESR_USR0 },
3277c478bd9Sstevel@tonic-gate 	{ "nouser1",	bitclr,		0,
3287c478bd9Sstevel@tonic-gate 		UINT32_C(1),		CPC_P5_CESR_USR1 },
3297c478bd9Sstevel@tonic-gate 	{ "sys",	nextpair },
3307c478bd9Sstevel@tonic-gate 	{ "sys0",	bitset,		0,
3317c478bd9Sstevel@tonic-gate 		UINT32_C(1),		CPC_P5_CESR_OS0 },
3327c478bd9Sstevel@tonic-gate 	{ "sys1",	bitset,		0,
3337c478bd9Sstevel@tonic-gate 		UINT32_C(1),		CPC_P5_CESR_OS1 },
3347c478bd9Sstevel@tonic-gate 	{ "noedge",	nextpair },
3357c478bd9Sstevel@tonic-gate 	{ "noedge0",	bitset,		0,
3367c478bd9Sstevel@tonic-gate 		UINT32_C(1),		CPC_P5_CESR_CLK0 },
3377c478bd9Sstevel@tonic-gate 	{ "noedge1",	bitset,		0,
3387c478bd9Sstevel@tonic-gate 		UINT32_C(1),		CPC_P5_CESR_CLK1 },
3397c478bd9Sstevel@tonic-gate 	{ "pc",		nextpair },
3407c478bd9Sstevel@tonic-gate 	{ "pc0",	bitset,		0,
3417c478bd9Sstevel@tonic-gate 		UINT32_C(1),		CPC_P5_CESR_PC0 },
3427c478bd9Sstevel@tonic-gate 	{ "pc1",	bitset,		0,
3437c478bd9Sstevel@tonic-gate 		UINT32_C(1),		CPC_P5_CESR_PC1 },
3447c478bd9Sstevel@tonic-gate };
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate #if !defined(NDEBUG)
3477c478bd9Sstevel@tonic-gate #pragma	init(__tablecheck)
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate static void
__tablecheck(void)3507c478bd9Sstevel@tonic-gate __tablecheck(void)
3517c478bd9Sstevel@tonic-gate {
3527c478bd9Sstevel@tonic-gate 	uint_t ntokens = sizeof (tokens) / sizeof (tokens[0]) - 1;
3537c478bd9Sstevel@tonic-gate 	uint_t p6_nkeys = sizeof (p6_keyvals) / sizeof (p6_keyvals[0]);
3547c478bd9Sstevel@tonic-gate 	uint_t p5_nkeys = sizeof (p5_keyvals) / sizeof (p5_keyvals[0]);
3557c478bd9Sstevel@tonic-gate 	uint_t n;
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	assert(ntokens == p6_nkeys);
3587c478bd9Sstevel@tonic-gate 	for (n = 0; n < ntokens; n++)
3597c478bd9Sstevel@tonic-gate 		assert(strcmp(tokens[n], p6_keyvals[n].kv_token) == 0);
3607c478bd9Sstevel@tonic-gate 	assert(p6_nkeys >= p5_nkeys);
3617c478bd9Sstevel@tonic-gate 	for (n = 0; n < p5_nkeys; n++)
3627c478bd9Sstevel@tonic-gate 		assert(strcmp(tokens[n], p5_keyvals[n].kv_token) == 0);
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate #endif	/* !NDEBUG */
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate int
cpc_strtoevent(int cpuver,const char * spec,cpc_event_t * event)3687c478bd9Sstevel@tonic-gate cpc_strtoevent(int cpuver, const char *spec, cpc_event_t *event)
3697c478bd9Sstevel@tonic-gate {
3707c478bd9Sstevel@tonic-gate 	static const char fn[] = "strtoevent";
3717c478bd9Sstevel@tonic-gate 	char *value;
3727c478bd9Sstevel@tonic-gate 	char *pic[2];
3737c478bd9Sstevel@tonic-gate 	char *opts;
3747c478bd9Sstevel@tonic-gate 	int errcnt = 0;
3757c478bd9Sstevel@tonic-gate 	uint_t ntokens;
3767c478bd9Sstevel@tonic-gate 	const struct keyval *keyvals;
3777c478bd9Sstevel@tonic-gate 	uint32_t *bits;
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	if (spec == NULL)
3807c478bd9Sstevel@tonic-gate 		return (errcnt = 1);
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	bzero(event, sizeof (*event));
3837c478bd9Sstevel@tonic-gate 	switch (event->ce_cpuver = cpuver) {
3847c478bd9Sstevel@tonic-gate 	case CPC_PENTIUM_PRO_MMX:
3857c478bd9Sstevel@tonic-gate 	case CPC_PENTIUM_PRO:
3867c478bd9Sstevel@tonic-gate 		keyvals = p6_keyvals;
3877c478bd9Sstevel@tonic-gate 		ntokens = sizeof (p6_keyvals) / sizeof (p6_keyvals[0]);
3887c478bd9Sstevel@tonic-gate 		bits = &event->ce_pes[0];
3897c478bd9Sstevel@tonic-gate 		bits[0] = bits[1] =
3907c478bd9Sstevel@tonic-gate 		    (1u << CPC_P6_PES_USR) | (1u << CPC_P6_PES_E);
3917c478bd9Sstevel@tonic-gate 		break;
3927c478bd9Sstevel@tonic-gate 	case CPC_PENTIUM_MMX:
3937c478bd9Sstevel@tonic-gate 	case CPC_PENTIUM:
3947c478bd9Sstevel@tonic-gate 		keyvals = p5_keyvals;
3957c478bd9Sstevel@tonic-gate 		ntokens = sizeof (p5_keyvals) / sizeof (p5_keyvals[0]);
3967c478bd9Sstevel@tonic-gate 		bits = &event->ce_cesr;
3977c478bd9Sstevel@tonic-gate 		bits[0] =
3987c478bd9Sstevel@tonic-gate 		    (1u << CPC_P5_CESR_USR0) | (1u << CPC_P5_CESR_USR1);
3997c478bd9Sstevel@tonic-gate 		break;
4007c478bd9Sstevel@tonic-gate 	default:
4017c478bd9Sstevel@tonic-gate 		return (errcnt = 1);
4027c478bd9Sstevel@tonic-gate 	}
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	pic[0] = pic[1] = NULL;
4057c478bd9Sstevel@tonic-gate 
406*23a1cceaSRoger A. Faulkner 	opts = strdupa(spec);
4077c478bd9Sstevel@tonic-gate 	while (*opts != '\0') {
4087c478bd9Sstevel@tonic-gate 		const struct keyval *kv;
4097c478bd9Sstevel@tonic-gate 		int idx = getsubopt(&opts, tokens, &value);
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 		if (idx >= 0 && idx < ntokens) {
4127c478bd9Sstevel@tonic-gate 			kv = &keyvals[idx];
4137c478bd9Sstevel@tonic-gate 			if (kv->kv_action(fn, kv, cpuver, value, bits) != 0) {
4147c478bd9Sstevel@tonic-gate 				errcnt++;
4157c478bd9Sstevel@tonic-gate 				break;
4167c478bd9Sstevel@tonic-gate 			}
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 			if (idx == D_pic0) {
4197c478bd9Sstevel@tonic-gate 				if (pic[0] != NULL) {
4207c478bd9Sstevel@tonic-gate 					__cpc_error(fn,
4217c478bd9Sstevel@tonic-gate 					    "repeated '%s' token\n",
4227c478bd9Sstevel@tonic-gate 					    tokens[idx]);
4237c478bd9Sstevel@tonic-gate 					errcnt++;
4247c478bd9Sstevel@tonic-gate 					break;
4257c478bd9Sstevel@tonic-gate 				}
4267c478bd9Sstevel@tonic-gate 				pic[0] = value;
4277c478bd9Sstevel@tonic-gate 			} else if (idx == D_pic1) {
4287c478bd9Sstevel@tonic-gate 				if (pic[1] != NULL) {
4297c478bd9Sstevel@tonic-gate 					__cpc_error(fn,
4307c478bd9Sstevel@tonic-gate 					    "repeated '%s' token\n",
4317c478bd9Sstevel@tonic-gate 					    tokens[idx]);
4327c478bd9Sstevel@tonic-gate 					errcnt++;
4337c478bd9Sstevel@tonic-gate 					break;
4347c478bd9Sstevel@tonic-gate 				}
4357c478bd9Sstevel@tonic-gate 				pic[1] = value;
4367c478bd9Sstevel@tonic-gate 			}
4377c478bd9Sstevel@tonic-gate 		} else if (idx == -1) {
4387c478bd9Sstevel@tonic-gate 			/*
4397c478bd9Sstevel@tonic-gate 			 * The token given wasn't recognized.
4407c478bd9Sstevel@tonic-gate 			 * See if it was an implicit pic specification..
4417c478bd9Sstevel@tonic-gate 			 */
4427c478bd9Sstevel@tonic-gate 			if (pic[0] == NULL) {
4437c478bd9Sstevel@tonic-gate 				kv = &keyvals[D_pic0];
4447c478bd9Sstevel@tonic-gate 				if (kv->kv_action(fn,
4457c478bd9Sstevel@tonic-gate 				    kv, cpuver, value, bits) != 0) {
4467c478bd9Sstevel@tonic-gate 					errcnt++;
4477c478bd9Sstevel@tonic-gate 					break;
4487c478bd9Sstevel@tonic-gate 				}
4497c478bd9Sstevel@tonic-gate 				pic[0] = value;
4507c478bd9Sstevel@tonic-gate 			} else if (pic[1] == NULL) {
4517c478bd9Sstevel@tonic-gate 				kv = &keyvals[D_pic1];
4527c478bd9Sstevel@tonic-gate 				if (kv->kv_action(fn,
4537c478bd9Sstevel@tonic-gate 				    kv, cpuver, value, bits) != 0) {
4547c478bd9Sstevel@tonic-gate 					errcnt++;
4557c478bd9Sstevel@tonic-gate 					break;
4567c478bd9Sstevel@tonic-gate 				}
4577c478bd9Sstevel@tonic-gate 				pic[1] = value;
4587c478bd9Sstevel@tonic-gate 			} else {
4597c478bd9Sstevel@tonic-gate 				__cpc_error(fn,
4607c478bd9Sstevel@tonic-gate 				    gettext("bad token '%s'\n"), value);
4617c478bd9Sstevel@tonic-gate 				errcnt++;
4627c478bd9Sstevel@tonic-gate 				break;
4637c478bd9Sstevel@tonic-gate 			}
4647c478bd9Sstevel@tonic-gate 		} else {
4657c478bd9Sstevel@tonic-gate 			if (idx >= 0 &&
4667c478bd9Sstevel@tonic-gate 			    idx < sizeof (tokens) / sizeof (tokens[0]))
4677c478bd9Sstevel@tonic-gate 				__cpc_error(fn,
4687c478bd9Sstevel@tonic-gate 				    gettext("bad token '%s'\n"), tokens[idx]);
4697c478bd9Sstevel@tonic-gate 			else
4707c478bd9Sstevel@tonic-gate 				__cpc_error(fn, gettext("bad token\n"));
4717c478bd9Sstevel@tonic-gate 			errcnt++;
4727c478bd9Sstevel@tonic-gate 			break;
4737c478bd9Sstevel@tonic-gate 		}
4747c478bd9Sstevel@tonic-gate 	}
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	if (pic[0] == NULL || pic[1] == NULL) {
4777c478bd9Sstevel@tonic-gate 		__cpc_error(fn, gettext("two events must be specified\n"));
4787c478bd9Sstevel@tonic-gate 		errcnt++;
4797c478bd9Sstevel@tonic-gate 	}
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	return (errcnt);
4827c478bd9Sstevel@tonic-gate }
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate /*
4857c478bd9Sstevel@tonic-gate  * Return a printable description of the control registers.
4867c478bd9Sstevel@tonic-gate  *
4877c478bd9Sstevel@tonic-gate  * This routine should always succeed (notwithstanding heap problems),
4887c478bd9Sstevel@tonic-gate  * but may not be able to correctly decode the registers, if, for
4897c478bd9Sstevel@tonic-gate  * example, a new processor is under test.
4907c478bd9Sstevel@tonic-gate  *
4917c478bd9Sstevel@tonic-gate  * The caller is responsible for free(3c)ing the string returned.
4927c478bd9Sstevel@tonic-gate  */
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate static void
flagstostr(char * buf,int flag0,int flag1,int defvalue,char * tok)4957c478bd9Sstevel@tonic-gate flagstostr(char *buf, int flag0, int flag1, int defvalue, char *tok)
4967c478bd9Sstevel@tonic-gate {
4977c478bd9Sstevel@tonic-gate 	buf += strlen(buf);
4987c478bd9Sstevel@tonic-gate 	if (flag0 != defvalue) {
4997c478bd9Sstevel@tonic-gate 		if (flag1 != defvalue)
5007c478bd9Sstevel@tonic-gate 			(void) sprintf(buf, ",%s", tok);
5017c478bd9Sstevel@tonic-gate 		else
5027c478bd9Sstevel@tonic-gate 			(void) sprintf(buf, ",%s0", tok);
5037c478bd9Sstevel@tonic-gate 	} else {
5047c478bd9Sstevel@tonic-gate 		if (flag1 != defvalue)
5057c478bd9Sstevel@tonic-gate 			(void) sprintf(buf, ",%s1", tok);
5067c478bd9Sstevel@tonic-gate 	}
5077c478bd9Sstevel@tonic-gate }
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate static void
masktostr(char * buf,uint8_t bits,char * tok)5107c478bd9Sstevel@tonic-gate masktostr(char *buf, uint8_t bits, char *tok)
5117c478bd9Sstevel@tonic-gate {
5127c478bd9Sstevel@tonic-gate 	if (bits != 0) {
5137c478bd9Sstevel@tonic-gate 		buf += strlen(buf);
5147c478bd9Sstevel@tonic-gate 		(void) sprintf(buf, ",%s=0x%x", tok, bits);
5157c478bd9Sstevel@tonic-gate 	}
5167c478bd9Sstevel@tonic-gate }
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate static char *
val8tostr(uint8_t bits)5197c478bd9Sstevel@tonic-gate val8tostr(uint8_t bits)
5207c478bd9Sstevel@tonic-gate {
5217c478bd9Sstevel@tonic-gate 	char buf[2 + 2 + 1];	/* 0x %2x \0 */
5227c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "0x%x", bits);
5237c478bd9Sstevel@tonic-gate 	return (strdup(buf));
5247c478bd9Sstevel@tonic-gate }
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate static char *
regtostr(int cpuver,int regno,uint8_t bits)5277c478bd9Sstevel@tonic-gate regtostr(int cpuver, int regno, uint8_t bits)
5287c478bd9Sstevel@tonic-gate {
5297c478bd9Sstevel@tonic-gate 	const char *sname;
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	if ((sname = __cpc_reg_to_name(cpuver, regno, bits)) != NULL)
5327c478bd9Sstevel@tonic-gate 		return (strdup(sname));
5337c478bd9Sstevel@tonic-gate 	return (val8tostr(bits));
5347c478bd9Sstevel@tonic-gate }
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate struct xpes {
5377c478bd9Sstevel@tonic-gate 	uint8_t cmask, umask, evsel;
5387c478bd9Sstevel@tonic-gate 	int usr, sys, edge, inv, irupt, pc;
5397c478bd9Sstevel@tonic-gate };
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
5427c478bd9Sstevel@tonic-gate static void
unmake_pes(uint32_t pes,int cpuver,struct xpes * xpes)5437c478bd9Sstevel@tonic-gate unmake_pes(uint32_t pes, int cpuver, struct xpes *xpes)
5447c478bd9Sstevel@tonic-gate {
5457c478bd9Sstevel@tonic-gate 	xpes->cmask = (uint8_t)(pes >> CPC_P6_PES_CMASK_SHIFT);
5467c478bd9Sstevel@tonic-gate 	xpes->pc = (pes >> CPC_P6_PES_PC) & 1u;
5477c478bd9Sstevel@tonic-gate 	xpes->inv = (pes >> CPC_P6_PES_INV) & 1u;
5487c478bd9Sstevel@tonic-gate 	xpes->irupt = (pes >> CPC_P6_PES_INT) & 1u;
5497c478bd9Sstevel@tonic-gate 	xpes->edge = (pes >> CPC_P6_PES_E) & 1u;
5507c478bd9Sstevel@tonic-gate 	xpes->sys = (pes >> CPC_P6_PES_OS) & 1u;
5517c478bd9Sstevel@tonic-gate 	xpes->usr = (pes >> CPC_P6_PES_USR) & 1u;
5527c478bd9Sstevel@tonic-gate 	xpes->umask = (uint8_t)(pes >> CPC_P6_PES_UMASK_SHIFT);
5537c478bd9Sstevel@tonic-gate 	xpes->evsel = (uint8_t)pes;
5547c478bd9Sstevel@tonic-gate }
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate struct xcesr {
5577c478bd9Sstevel@tonic-gate 	uint8_t evsel[2];
5587c478bd9Sstevel@tonic-gate 	int usr[2], sys[2], clk[2], pc[2];
5597c478bd9Sstevel@tonic-gate };
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
5627c478bd9Sstevel@tonic-gate static void
unmake_cesr(uint32_t cesr,int cpuver,struct xcesr * xcesr)5637c478bd9Sstevel@tonic-gate unmake_cesr(uint32_t cesr, int cpuver, struct xcesr *xcesr)
5647c478bd9Sstevel@tonic-gate {
5657c478bd9Sstevel@tonic-gate 	xcesr->evsel[0] = (cesr >> CPC_P5_CESR_ES0_SHIFT) &
5667c478bd9Sstevel@tonic-gate 	    CPC_P5_CESR_ES0_MASK;
5677c478bd9Sstevel@tonic-gate 	xcesr->evsel[1] = (cesr >> CPC_P5_CESR_ES1_SHIFT) &
5687c478bd9Sstevel@tonic-gate 	    CPC_P5_CESR_ES1_MASK;
5697c478bd9Sstevel@tonic-gate 	xcesr->usr[0] = (cesr >> CPC_P5_CESR_USR0) & 1u;
5707c478bd9Sstevel@tonic-gate 	xcesr->usr[1] = (cesr >> CPC_P5_CESR_USR1) & 1u;
5717c478bd9Sstevel@tonic-gate 	xcesr->sys[0] = (cesr >> CPC_P5_CESR_OS0) & 1u;
5727c478bd9Sstevel@tonic-gate 	xcesr->sys[1] = (cesr >> CPC_P5_CESR_OS1) & 1u;
5737c478bd9Sstevel@tonic-gate 	xcesr->clk[0] = (cesr >> CPC_P5_CESR_CLK0) & 1u;
5747c478bd9Sstevel@tonic-gate 	xcesr->clk[1] = (cesr >> CPC_P5_CESR_CLK1) & 1u;
5757c478bd9Sstevel@tonic-gate 	xcesr->pc[0] = (cesr >> CPC_P5_CESR_PC0) & 1u;
5767c478bd9Sstevel@tonic-gate 	xcesr->pc[1] = (cesr >> CPC_P5_CESR_PC1) & 1u;
5777c478bd9Sstevel@tonic-gate 	/*
5787c478bd9Sstevel@tonic-gate 	 * If usr and sys are both disabled, the counter is disabled.
5797c478bd9Sstevel@tonic-gate 	 */
5807c478bd9Sstevel@tonic-gate 	if (xcesr->usr[0] == 0 && xcesr->sys[0] == 0)
5817c478bd9Sstevel@tonic-gate 		xcesr->clk[0] = 0;
5827c478bd9Sstevel@tonic-gate 	if (xcesr->usr[1] == 0 && xcesr->sys[1] == 0)
5837c478bd9Sstevel@tonic-gate 		xcesr->clk[1] = 0;
5847c478bd9Sstevel@tonic-gate }
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate char *
cpc_eventtostr(cpc_event_t * event)5877c478bd9Sstevel@tonic-gate cpc_eventtostr(cpc_event_t *event)
5887c478bd9Sstevel@tonic-gate {
5897c478bd9Sstevel@tonic-gate 	char *pic[2];
5907c478bd9Sstevel@tonic-gate 	char buffer[1024];
5917c478bd9Sstevel@tonic-gate 	int cpuver = event->ce_cpuver;
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 	switch (cpuver) {
5947c478bd9Sstevel@tonic-gate 	case CPC_PENTIUM_PRO_MMX:
5957c478bd9Sstevel@tonic-gate 	case CPC_PENTIUM_PRO:
5967c478bd9Sstevel@tonic-gate 	{
5977c478bd9Sstevel@tonic-gate 		struct xpes xpes[2];
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 		unmake_pes(event->ce_pes[0], cpuver, &xpes[0]);
6007c478bd9Sstevel@tonic-gate 		if ((pic[0] = regtostr(cpuver, 0, xpes[0].evsel)) == NULL)
6017c478bd9Sstevel@tonic-gate 			return (NULL);
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 		unmake_pes(event->ce_pes[1], cpuver, &xpes[1]);
6047c478bd9Sstevel@tonic-gate 		if ((pic[1] = regtostr(cpuver, 1, xpes[1].evsel)) == NULL) {
6057c478bd9Sstevel@tonic-gate 			free(pic[0]);
6067c478bd9Sstevel@tonic-gate 			return (NULL);
6077c478bd9Sstevel@tonic-gate 		}
6087c478bd9Sstevel@tonic-gate 		(void) snprintf(buffer, sizeof (buffer), "%s=%s,%s=%s",
6097c478bd9Sstevel@tonic-gate 		    tokens[D_pic0], pic[0], tokens[D_pic1], pic[1]);
6107c478bd9Sstevel@tonic-gate 		free(pic[1]);
6117c478bd9Sstevel@tonic-gate 		free(pic[0]);
6127c478bd9Sstevel@tonic-gate 		masktostr(buffer, xpes[0].cmask, tokens[D_cmask0]);
6137c478bd9Sstevel@tonic-gate 		masktostr(buffer, xpes[1].cmask, tokens[D_cmask1]);
6147c478bd9Sstevel@tonic-gate 		masktostr(buffer, xpes[0].umask, tokens[D_umask0]);
6157c478bd9Sstevel@tonic-gate 		masktostr(buffer, xpes[1].umask, tokens[D_umask1]);
6167c478bd9Sstevel@tonic-gate 		flagstostr(buffer,
6177c478bd9Sstevel@tonic-gate 		    xpes[0].usr, xpes[1].usr, 1, tokens[D_nouser]);
6187c478bd9Sstevel@tonic-gate 		flagstostr(buffer,
6197c478bd9Sstevel@tonic-gate 		    xpes[0].sys, xpes[1].sys, 0, tokens[D_sys]);
6207c478bd9Sstevel@tonic-gate 		flagstostr(buffer,
6217c478bd9Sstevel@tonic-gate 		    xpes[0].edge, xpes[1].edge, 1, tokens[D_noedge]);
6227c478bd9Sstevel@tonic-gate 		flagstostr(buffer,
6237c478bd9Sstevel@tonic-gate 		    xpes[0].irupt, xpes[1].irupt, 0, tokens[D_int]);
6247c478bd9Sstevel@tonic-gate 		flagstostr(buffer,
6257c478bd9Sstevel@tonic-gate 		    xpes[0].inv, xpes[1].inv, 0, tokens[D_inv]);
6267c478bd9Sstevel@tonic-gate 		flagstostr(buffer,
6277c478bd9Sstevel@tonic-gate 		    xpes[0].pc, xpes[1].pc, 0, tokens[D_pc]);
628*23a1cceaSRoger A. Faulkner 		break;
629*23a1cceaSRoger A. Faulkner 	}
6307c478bd9Sstevel@tonic-gate 	case CPC_PENTIUM_MMX:
6317c478bd9Sstevel@tonic-gate 	case CPC_PENTIUM:
6327c478bd9Sstevel@tonic-gate 	{
6337c478bd9Sstevel@tonic-gate 		struct xcesr xcesr;
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 		unmake_cesr(event->ce_cesr, cpuver, &xcesr);
6367c478bd9Sstevel@tonic-gate 		if ((pic[0] = regtostr(cpuver, 0, xcesr.evsel[0])) == NULL)
6377c478bd9Sstevel@tonic-gate 			return (NULL);
6387c478bd9Sstevel@tonic-gate 		if ((pic[1] = regtostr(cpuver, 1, xcesr.evsel[1])) == NULL) {
6397c478bd9Sstevel@tonic-gate 			free(pic[0]);
6407c478bd9Sstevel@tonic-gate 			return (NULL);
6417c478bd9Sstevel@tonic-gate 		}
6427c478bd9Sstevel@tonic-gate 		(void) snprintf(buffer, sizeof (buffer), "%s=%s,%s=%s",
6437c478bd9Sstevel@tonic-gate 		    tokens[D_pic0], pic[0], tokens[D_pic1], pic[1]);
6447c478bd9Sstevel@tonic-gate 		free(pic[1]);
6457c478bd9Sstevel@tonic-gate 		free(pic[0]);
6467c478bd9Sstevel@tonic-gate 		flagstostr(buffer,
6477c478bd9Sstevel@tonic-gate 		    xcesr.usr[0], xcesr.usr[1], 1, tokens[D_nouser]);
6487c478bd9Sstevel@tonic-gate 		flagstostr(buffer,
6497c478bd9Sstevel@tonic-gate 		    xcesr.sys[0], xcesr.sys[1], 0, tokens[D_sys]);
6507c478bd9Sstevel@tonic-gate 		flagstostr(buffer,
6517c478bd9Sstevel@tonic-gate 		    xcesr.clk[0], xcesr.clk[1], 0, tokens[D_noedge]);
6527c478bd9Sstevel@tonic-gate 		flagstostr(buffer,
6537c478bd9Sstevel@tonic-gate 		    xcesr.pc[0], xcesr.pc[1], 0, tokens[D_pc]);
654*23a1cceaSRoger A. Faulkner 		break;
655*23a1cceaSRoger A. Faulkner 	}
6567c478bd9Sstevel@tonic-gate 	default:
6577c478bd9Sstevel@tonic-gate 		return (NULL);
6587c478bd9Sstevel@tonic-gate 	}
6597c478bd9Sstevel@tonic-gate 	return (strdup(buffer));
6607c478bd9Sstevel@tonic-gate }
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate /*
6637c478bd9Sstevel@tonic-gate  * Utility operations on events
6647c478bd9Sstevel@tonic-gate  */
6657c478bd9Sstevel@tonic-gate void
cpc_event_accum(cpc_event_t * accum,cpc_event_t * event)6667c478bd9Sstevel@tonic-gate cpc_event_accum(cpc_event_t *accum, cpc_event_t *event)
6677c478bd9Sstevel@tonic-gate {
6687c478bd9Sstevel@tonic-gate 	if (accum->ce_hrt < event->ce_hrt)
6697c478bd9Sstevel@tonic-gate 		accum->ce_hrt = event->ce_hrt;
6707c478bd9Sstevel@tonic-gate 	accum->ce_tsc += event->ce_tsc;
6717c478bd9Sstevel@tonic-gate 	accum->ce_pic[0] += event->ce_pic[0];
6727c478bd9Sstevel@tonic-gate 	accum->ce_pic[1] += event->ce_pic[1];
6737c478bd9Sstevel@tonic-gate }
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate void
cpc_event_diff(cpc_event_t * diff,cpc_event_t * left,cpc_event_t * right)6767c478bd9Sstevel@tonic-gate cpc_event_diff(cpc_event_t *diff, cpc_event_t *left, cpc_event_t *right)
6777c478bd9Sstevel@tonic-gate {
6787c478bd9Sstevel@tonic-gate 	diff->ce_hrt = left->ce_hrt;
6797c478bd9Sstevel@tonic-gate 	diff->ce_tsc = left->ce_tsc - right->ce_tsc;
6807c478bd9Sstevel@tonic-gate 	diff->ce_pic[0] = left->ce_pic[0] - right->ce_pic[0];
6817c478bd9Sstevel@tonic-gate 	diff->ce_pic[1] = left->ce_pic[1] - right->ce_pic[1];
6827c478bd9Sstevel@tonic-gate }
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate /*
6857c478bd9Sstevel@tonic-gate  * Given a cpc_event_t and cpc_bind_event() flags,
6867c478bd9Sstevel@tonic-gate  * translate the cpc_event_t into the cpc_set_t format.
6877c478bd9Sstevel@tonic-gate  *
6887c478bd9Sstevel@tonic-gate  * Returns NULL on failure.
6897c478bd9Sstevel@tonic-gate  */
6907c478bd9Sstevel@tonic-gate cpc_set_t *
__cpc_eventtoset(cpc_t * cpc,cpc_event_t * event,int iflags)6917c478bd9Sstevel@tonic-gate __cpc_eventtoset(cpc_t *cpc, cpc_event_t *event, int iflags)
6927c478bd9Sstevel@tonic-gate {
6937c478bd9Sstevel@tonic-gate 	cpc_set_t	*set;
6947c478bd9Sstevel@tonic-gate 	int		cpuver = event->ce_cpuver;
6957c478bd9Sstevel@tonic-gate 	char		*pic[2];
6967c478bd9Sstevel@tonic-gate 	int		flags[2] = { 0, 0 };
6977c478bd9Sstevel@tonic-gate 	int		i;
6987c478bd9Sstevel@tonic-gate 	int		j;
6997c478bd9Sstevel@tonic-gate 	int		nattrs;
7007c478bd9Sstevel@tonic-gate 	cpc_attr_t	*attr;
7017c478bd9Sstevel@tonic-gate 	int		intr;
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	if ((set = cpc_set_create(cpc)) == NULL) {
7047c478bd9Sstevel@tonic-gate 		return (NULL);
7057c478bd9Sstevel@tonic-gate 	}
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	if (iflags & CPC_BIND_EMT_OVF)
7087c478bd9Sstevel@tonic-gate 		flags[0] = flags[1] = CPC_OVF_NOTIFY_EMT;
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	switch (cpuver) {
7117c478bd9Sstevel@tonic-gate 	case CPC_PENTIUM_PRO_MMX:
7127c478bd9Sstevel@tonic-gate 	case CPC_PENTIUM_PRO:
7137c478bd9Sstevel@tonic-gate 	{
7147c478bd9Sstevel@tonic-gate 		struct xpes xpes[2];
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 		for (i = 0; i < 2; i++) {
7177c478bd9Sstevel@tonic-gate 			intr = 0;
7187c478bd9Sstevel@tonic-gate 			nattrs = j = 1;
7197c478bd9Sstevel@tonic-gate 			unmake_pes(event->ce_pes[i], cpuver, &xpes[i]);
7207c478bd9Sstevel@tonic-gate 			if ((pic[i] = regtostr(cpuver, i,
7217c478bd9Sstevel@tonic-gate 			    xpes[i].evsel)) == NULL) {
7227c478bd9Sstevel@tonic-gate 				(void) cpc_set_destroy(cpc, set);
7237c478bd9Sstevel@tonic-gate 				return (NULL);
7247c478bd9Sstevel@tonic-gate 			}
7257c478bd9Sstevel@tonic-gate 			if (xpes[i].usr == 1)
7267c478bd9Sstevel@tonic-gate 				flags[i] |= CPC_COUNT_USER;
7277c478bd9Sstevel@tonic-gate 			if (xpes[i].sys == 1)
7287c478bd9Sstevel@tonic-gate 				flags[i] |= CPC_COUNT_SYSTEM;
7297c478bd9Sstevel@tonic-gate 			if (xpes[i].irupt == 1) {
7307c478bd9Sstevel@tonic-gate 				nattrs++;
7317c478bd9Sstevel@tonic-gate 				intr = 1;
7327c478bd9Sstevel@tonic-gate 			}
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 			if (xpes[i].cmask)
7357c478bd9Sstevel@tonic-gate 				nattrs++;
7367c478bd9Sstevel@tonic-gate 			if (xpes[i].umask)
7377c478bd9Sstevel@tonic-gate 				nattrs++;
7387c478bd9Sstevel@tonic-gate 			if (xpes[i].inv)
7397c478bd9Sstevel@tonic-gate 				nattrs++;
7407c478bd9Sstevel@tonic-gate 			if (xpes[i].pc)
7417c478bd9Sstevel@tonic-gate 				nattrs++;
7427c478bd9Sstevel@tonic-gate 			if (xpes[i].edge == 0)
7437c478bd9Sstevel@tonic-gate 				nattrs++;
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 			if ((attr = (cpc_attr_t *)malloc(nattrs *
7467c478bd9Sstevel@tonic-gate 			    sizeof (cpc_attr_t))) == NULL) {
7477c478bd9Sstevel@tonic-gate 				(void) cpc_set_destroy(cpc, set);
7487c478bd9Sstevel@tonic-gate 				errno = ENOMEM;
7497c478bd9Sstevel@tonic-gate 				return (NULL);
7507c478bd9Sstevel@tonic-gate 			}
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 			/*
7537c478bd9Sstevel@tonic-gate 			 * Ensure that pic[0] in the cpc_event_t is bound to
7547c478bd9Sstevel@tonic-gate 			 * physical pic0.
7557c478bd9Sstevel@tonic-gate 			 */
7567c478bd9Sstevel@tonic-gate 			attr[0].ca_name = "picnum";
7577c478bd9Sstevel@tonic-gate 			attr[0].ca_val = i;
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 			if (intr) {
7607c478bd9Sstevel@tonic-gate 				attr[j].ca_name = "int";
7617c478bd9Sstevel@tonic-gate 				attr[j].ca_val = 1;
7627c478bd9Sstevel@tonic-gate 				j++;
7637c478bd9Sstevel@tonic-gate 			}
7647c478bd9Sstevel@tonic-gate 			if (xpes[i].cmask) {
7657c478bd9Sstevel@tonic-gate 				attr[j].ca_name = "cmask";
7667c478bd9Sstevel@tonic-gate 				attr[j].ca_val = xpes[i].cmask;
7677c478bd9Sstevel@tonic-gate 				j++;
7687c478bd9Sstevel@tonic-gate 			}
7697c478bd9Sstevel@tonic-gate 			if (xpes[i].umask) {
7707c478bd9Sstevel@tonic-gate 				attr[j].ca_name = "umask";
7717c478bd9Sstevel@tonic-gate 				attr[j].ca_val = xpes[i].umask;
7727c478bd9Sstevel@tonic-gate 				j++;
7737c478bd9Sstevel@tonic-gate 			}
7747c478bd9Sstevel@tonic-gate 			if (xpes[i].inv) {
7757c478bd9Sstevel@tonic-gate 				attr[j].ca_name = "inv";
7767c478bd9Sstevel@tonic-gate 				attr[j].ca_val = 1;
7777c478bd9Sstevel@tonic-gate 				j++;
7787c478bd9Sstevel@tonic-gate 			}
7797c478bd9Sstevel@tonic-gate 			if (xpes[i].pc) {
7807c478bd9Sstevel@tonic-gate 				attr[j].ca_name = "pc";
7817c478bd9Sstevel@tonic-gate 				attr[j].ca_val = 1;
7827c478bd9Sstevel@tonic-gate 				j++;
7837c478bd9Sstevel@tonic-gate 			}
7847c478bd9Sstevel@tonic-gate 			if (xpes[i].edge == 0) {
7857c478bd9Sstevel@tonic-gate 				attr[j].ca_name = "noedge";
7867c478bd9Sstevel@tonic-gate 				attr[j].ca_val = 1;
7877c478bd9Sstevel@tonic-gate 				j++;
7887c478bd9Sstevel@tonic-gate 			}
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 			if (cpc_set_add_request(cpc, set, pic[i],
7917c478bd9Sstevel@tonic-gate 			    event->ce_pic[i], flags[i], nattrs, attr) == -1) {
7927c478bd9Sstevel@tonic-gate 				(void) cpc_set_destroy(cpc, set);
7937c478bd9Sstevel@tonic-gate 				free(pic[i]);
7947c478bd9Sstevel@tonic-gate 				free(attr);
7957c478bd9Sstevel@tonic-gate 				return (NULL);
7967c478bd9Sstevel@tonic-gate 			}
7977c478bd9Sstevel@tonic-gate 			free(pic[i]);
7987c478bd9Sstevel@tonic-gate 			free(attr);
7997c478bd9Sstevel@tonic-gate 		}
8007c478bd9Sstevel@tonic-gate 	}
8017c478bd9Sstevel@tonic-gate 	break;
8027c478bd9Sstevel@tonic-gate 	case CPC_PENTIUM_MMX:
8037c478bd9Sstevel@tonic-gate 	case CPC_PENTIUM:
8047c478bd9Sstevel@tonic-gate 	{
8057c478bd9Sstevel@tonic-gate 		struct xcesr xcesr;
8067c478bd9Sstevel@tonic-gate 		unmake_cesr(event->ce_cesr, cpuver, &xcesr);
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 		for (i = 0; i < 2; i++) {
8097c478bd9Sstevel@tonic-gate 			nattrs = j = 1;
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 			if ((pic[i] = regtostr(cpuver, i, xcesr.evsel[i]))
8127c478bd9Sstevel@tonic-gate 			    == NULL) {
8137c478bd9Sstevel@tonic-gate 				(void) cpc_set_destroy(cpc, set);
8147c478bd9Sstevel@tonic-gate 				return (NULL);
8157c478bd9Sstevel@tonic-gate 			}
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 			if (xcesr.usr[i] == 1)
8187c478bd9Sstevel@tonic-gate 				flags[i] |= CPC_COUNT_USER;
8197c478bd9Sstevel@tonic-gate 			if (xcesr.sys[i] == 1)
8207c478bd9Sstevel@tonic-gate 				flags[i] |= CPC_COUNT_SYSTEM;
8217c478bd9Sstevel@tonic-gate 			if (xcesr.clk[i] == 1)
8227c478bd9Sstevel@tonic-gate 				nattrs++;
8237c478bd9Sstevel@tonic-gate 			if (xcesr.pc[i] == 1)
8247c478bd9Sstevel@tonic-gate 				nattrs++;
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate 			if ((attr = (cpc_attr_t *)malloc(nattrs *
8277c478bd9Sstevel@tonic-gate 			    sizeof (cpc_attr_t))) == NULL) {
8287c478bd9Sstevel@tonic-gate 				(void) cpc_set_destroy(cpc, set);
8297c478bd9Sstevel@tonic-gate 				errno = ENOMEM;
8307c478bd9Sstevel@tonic-gate 				return (NULL);
8317c478bd9Sstevel@tonic-gate 			}
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 			/*
8347c478bd9Sstevel@tonic-gate 			 * Ensure that pic[0] in the cpc_event_t is bound to
8357c478bd9Sstevel@tonic-gate 			 * physical pic0.
8367c478bd9Sstevel@tonic-gate 			 */
8377c478bd9Sstevel@tonic-gate 			attr[0].ca_name = "picnum";
8387c478bd9Sstevel@tonic-gate 			attr[0].ca_val = i;
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 			if (xcesr.clk[i] == 1) {
8417c478bd9Sstevel@tonic-gate 				attr[j].ca_name = "noedge";
8427c478bd9Sstevel@tonic-gate 				attr[j].ca_val = 1;
8437c478bd9Sstevel@tonic-gate 				j++;
8447c478bd9Sstevel@tonic-gate 			}
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 			if (xcesr.pc[i] == 1) {
8477c478bd9Sstevel@tonic-gate 				attr[j].ca_name = "pc";
8487c478bd9Sstevel@tonic-gate 				attr[j].ca_val = 1;
8497c478bd9Sstevel@tonic-gate 				j++;
8507c478bd9Sstevel@tonic-gate 			}
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 			if (cpc_set_add_request(cpc, set, pic[i],
8537c478bd9Sstevel@tonic-gate 			    event->ce_pic[i], flags[i], nattrs, attr) == -1) {
8547c478bd9Sstevel@tonic-gate 				(void) cpc_set_destroy(cpc, set);
8557c478bd9Sstevel@tonic-gate 				free(pic[i]);
8567c478bd9Sstevel@tonic-gate 				free(attr);
8577c478bd9Sstevel@tonic-gate 				return (NULL);
8587c478bd9Sstevel@tonic-gate 			}
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 			free(pic[i]);
8617c478bd9Sstevel@tonic-gate 			free(attr);
8627c478bd9Sstevel@tonic-gate 		}
8637c478bd9Sstevel@tonic-gate 	}
8647c478bd9Sstevel@tonic-gate 	break;
8657c478bd9Sstevel@tonic-gate 	default:
8667c478bd9Sstevel@tonic-gate 		(void) cpc_set_destroy(cpc, set);
8677c478bd9Sstevel@tonic-gate 		return (NULL);
8687c478bd9Sstevel@tonic-gate 	}
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	return (set);
8717c478bd9Sstevel@tonic-gate }
872