Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 22 May 2009 04:49:59 +0000 (UTC)
From:      Kip Macy <kmacy@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r192575 - in user/kmacy/releng_7_2_fcs: lib/libpmc sys/amd64/amd64 sys/amd64/include sys/conf sys/dev/coretemp sys/dev/hwpmc sys/i386/cpufreq sys/i386/i386 sys/i386/include sys/kern sys...
Message-ID:  <200905220450.n4M4o044094085@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kmacy
Date: Fri May 22 04:49:59 2009
New Revision: 192575
URL: http://svn.freebsd.org/changeset/base/192575

Log:
  MFC callchain, core, and i7 support from HEAD

Added:
  user/kmacy/releng_7_2_fcs/lib/libpmc/libpmcinternal.h
  user/kmacy/releng_7_2_fcs/sys/dev/hwpmc/hwpmc_core.c
  user/kmacy/releng_7_2_fcs/sys/dev/hwpmc/hwpmc_core.h
  user/kmacy/releng_7_2_fcs/sys/dev/hwpmc/hwpmc_intel.c
  user/kmacy/releng_7_2_fcs/sys/dev/hwpmc/hwpmc_tsc.c
  user/kmacy/releng_7_2_fcs/sys/dev/hwpmc/hwpmc_tsc.h
Modified:
  user/kmacy/releng_7_2_fcs/lib/libpmc/libpmc.c
  user/kmacy/releng_7_2_fcs/lib/libpmc/pmclog.c
  user/kmacy/releng_7_2_fcs/lib/libpmc/pmclog.h
  user/kmacy/releng_7_2_fcs/sys/amd64/amd64/amd64_mem.c
  user/kmacy/releng_7_2_fcs/sys/amd64/amd64/exception.S
  user/kmacy/releng_7_2_fcs/sys/amd64/amd64/genassym.c
  user/kmacy/releng_7_2_fcs/sys/amd64/amd64/identcpu.c
  user/kmacy/releng_7_2_fcs/sys/amd64/amd64/initcpu.c
  user/kmacy/releng_7_2_fcs/sys/amd64/amd64/local_apic.c
  user/kmacy/releng_7_2_fcs/sys/amd64/amd64/mp_machdep.c
  user/kmacy/releng_7_2_fcs/sys/amd64/amd64/msi.c
  user/kmacy/releng_7_2_fcs/sys/amd64/amd64/trap.c
  user/kmacy/releng_7_2_fcs/sys/amd64/include/cputypes.h
  user/kmacy/releng_7_2_fcs/sys/amd64/include/md_var.h
  user/kmacy/releng_7_2_fcs/sys/amd64/include/pmc_mdep.h
  user/kmacy/releng_7_2_fcs/sys/amd64/include/specialreg.h
  user/kmacy/releng_7_2_fcs/sys/conf/Makefile.amd64
  user/kmacy/releng_7_2_fcs/sys/conf/files.amd64
  user/kmacy/releng_7_2_fcs/sys/conf/files.i386
  user/kmacy/releng_7_2_fcs/sys/conf/files.pc98
  user/kmacy/releng_7_2_fcs/sys/dev/coretemp/coretemp.c
  user/kmacy/releng_7_2_fcs/sys/dev/hwpmc/hwpmc_amd.c
  user/kmacy/releng_7_2_fcs/sys/dev/hwpmc/hwpmc_amd.h
  user/kmacy/releng_7_2_fcs/sys/dev/hwpmc/hwpmc_logging.c
  user/kmacy/releng_7_2_fcs/sys/dev/hwpmc/hwpmc_mod.c
  user/kmacy/releng_7_2_fcs/sys/dev/hwpmc/hwpmc_pentium.c
  user/kmacy/releng_7_2_fcs/sys/dev/hwpmc/hwpmc_pentium.h
  user/kmacy/releng_7_2_fcs/sys/dev/hwpmc/hwpmc_piv.c
  user/kmacy/releng_7_2_fcs/sys/dev/hwpmc/hwpmc_piv.h
  user/kmacy/releng_7_2_fcs/sys/dev/hwpmc/hwpmc_ppro.c
  user/kmacy/releng_7_2_fcs/sys/dev/hwpmc/hwpmc_ppro.h
  user/kmacy/releng_7_2_fcs/sys/dev/hwpmc/hwpmc_x86.c
  user/kmacy/releng_7_2_fcs/sys/dev/hwpmc/pmc_events.h
  user/kmacy/releng_7_2_fcs/sys/i386/cpufreq/est.c
  user/kmacy/releng_7_2_fcs/sys/i386/i386/exception.s
  user/kmacy/releng_7_2_fcs/sys/i386/i386/genassym.c
  user/kmacy/releng_7_2_fcs/sys/i386/i386/i686_mem.c
  user/kmacy/releng_7_2_fcs/sys/i386/i386/identcpu.c
  user/kmacy/releng_7_2_fcs/sys/i386/i386/initcpu.c
  user/kmacy/releng_7_2_fcs/sys/i386/i386/k6_mem.c
  user/kmacy/releng_7_2_fcs/sys/i386/i386/local_apic.c
  user/kmacy/releng_7_2_fcs/sys/i386/i386/longrun.c
  user/kmacy/releng_7_2_fcs/sys/i386/i386/mp_machdep.c
  user/kmacy/releng_7_2_fcs/sys/i386/i386/msi.c
  user/kmacy/releng_7_2_fcs/sys/i386/i386/trap.c
  user/kmacy/releng_7_2_fcs/sys/i386/include/cputypes.h
  user/kmacy/releng_7_2_fcs/sys/i386/include/md_var.h
  user/kmacy/releng_7_2_fcs/sys/i386/include/pmc_mdep.h
  user/kmacy/releng_7_2_fcs/sys/i386/include/specialreg.h
  user/kmacy/releng_7_2_fcs/sys/kern/kern_descrip.c
  user/kmacy/releng_7_2_fcs/sys/kern/kern_pmc.c
  user/kmacy/releng_7_2_fcs/sys/kern/subr_trap.c
  user/kmacy/releng_7_2_fcs/sys/modules/hwpmc/Makefile
  user/kmacy/releng_7_2_fcs/sys/sys/pmc.h
  user/kmacy/releng_7_2_fcs/sys/sys/pmckern.h
  user/kmacy/releng_7_2_fcs/sys/sys/pmclog.h
  user/kmacy/releng_7_2_fcs/sys/sys/proc.h
  user/kmacy/releng_7_2_fcs/usr.sbin/pmcstat/Makefile
  user/kmacy/releng_7_2_fcs/usr.sbin/pmcstat/pmcstat.8
  user/kmacy/releng_7_2_fcs/usr.sbin/pmcstat/pmcstat.c
  user/kmacy/releng_7_2_fcs/usr.sbin/pmcstat/pmcstat.h
  user/kmacy/releng_7_2_fcs/usr.sbin/pmcstat/pmcstat_log.c

Modified: user/kmacy/releng_7_2_fcs/lib/libpmc/libpmc.c
==============================================================================
--- user/kmacy/releng_7_2_fcs/lib/libpmc/libpmc.c	Fri May 22 01:15:07 2009	(r192574)
+++ user/kmacy/releng_7_2_fcs/lib/libpmc/libpmc.c	Fri May 22 04:49:59 2009	(r192575)
@@ -42,12 +42,18 @@ __FBSDID("$FreeBSD$");
 #include <strings.h>
 #include <unistd.h>
 
+#include "libpmcinternal.h"
+
 /* Function prototypes */
 #if defined(__i386__)
 static int k7_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
     struct pmc_op_pmcallocate *_pmc_config);
 #endif
 #if defined(__amd64__) || defined(__i386__)
+static int iaf_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
+    struct pmc_op_pmcallocate *_pmc_config);
+static int iap_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
+    struct pmc_op_pmcallocate *_pmc_config);
 static int k8_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
     struct pmc_op_pmcallocate *_pmc_config);
 static int p4_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
@@ -88,14 +94,131 @@ struct pmc_event_descr {
 	enum pmc_class	pm_ev_class;
 };
 
-static const struct pmc_event_descr
-pmc_event_table[] =
+/*
+ * The pmc_class_descr structure maps class name prefixes for
+ * event names to event tables and other PMC class data.
+ */
+struct pmc_class_descr {
+	const char	*pm_evc_name;
+	size_t		pm_evc_name_size;
+	enum pmc_class	pm_evc_class;
+	const struct pmc_event_descr *pm_evc_event_table;
+	size_t		pm_evc_event_table_size;
+	int		(*pm_evc_allocate_pmc)(enum pmc_event _pe,
+			    char *_ctrspec, struct pmc_op_pmcallocate *_pa);
+};
+
+#define	PMC_TABLE_SIZE(N)	(sizeof(N)/sizeof(N[0]))
+#define	PMC_EVENT_TABLE_SIZE(N)	PMC_TABLE_SIZE(N##_event_table)
+
+#undef	__PMC_EV
+#define	__PMC_EV(C,N) { #N, PMC_EV_ ## C ## _ ## N },
+
+/*
+ * PMC_CLASSDEP_TABLE(NAME, CLASS)
+ *
+ * Define a table mapping event names and aliases to HWPMC event IDs.
+ */
+#define	PMC_CLASSDEP_TABLE(N, C)				\
+	static const struct pmc_event_descr N##_event_table[] =	\
+	{							\
+		__PMC_EV_##C()					\
+	}
+
+PMC_CLASSDEP_TABLE(iaf, IAF);
+PMC_CLASSDEP_TABLE(k7, K7);
+PMC_CLASSDEP_TABLE(k8, K8);
+PMC_CLASSDEP_TABLE(p4, P4);
+PMC_CLASSDEP_TABLE(p5, P5);
+PMC_CLASSDEP_TABLE(p6, P6);
+
+#undef	__PMC_EV_ALIAS
+#define	__PMC_EV_ALIAS(N,CODE) 	{ N, PMC_EV_##CODE },
+
+static const struct pmc_event_descr atom_event_table[] =
+{
+	__PMC_EV_ALIAS_ATOM()
+};
+
+static const struct pmc_event_descr core_event_table[] =
+{
+	__PMC_EV_ALIAS_CORE()
+};
+
+
+static const struct pmc_event_descr core2_event_table[] =
+{
+	__PMC_EV_ALIAS_CORE2()
+};
+
+/*
+ * PMC_MDEP_TABLE(NAME, PRIMARYCLASS, ADDITIONAL_CLASSES...)
+ *
+ * Map a CPU to the PMC classes it supports.
+ */
+#define	PMC_MDEP_TABLE(N,C,...)				\
+	static const enum pmc_class N##_pmc_classes[] = {	\
+		PMC_CLASS_##C, __VA_ARGS__			\
+	}
+
+PMC_MDEP_TABLE(atom, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC);
+PMC_MDEP_TABLE(core, IAP, PMC_CLASS_TSC);
+PMC_MDEP_TABLE(core2, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC);
+PMC_MDEP_TABLE(k7, K7, PMC_CLASS_TSC);
+PMC_MDEP_TABLE(k8, K8, PMC_CLASS_TSC);
+PMC_MDEP_TABLE(p4, P4, PMC_CLASS_TSC);
+PMC_MDEP_TABLE(p5, P5, PMC_CLASS_TSC);
+PMC_MDEP_TABLE(p6, P6, PMC_CLASS_TSC);
+
+static const struct pmc_event_descr tsc_event_table[] =
 {
 #undef  __PMC_EV
 #define	__PMC_EV(C,N,EV) { #EV, PMC_EV_ ## C ## _ ## N, PMC_CLASS_ ## C },
 	__PMC_EVENTS()
 };
 
+#undef	PMC_CLASS_TABLE_DESC
+#define	PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR)	\
+static const struct pmc_class_descr NAME##_class_table_descr =	\
+	{							\
+		.pm_evc_name  = #CLASS "-",			\
+		.pm_evc_name_size = sizeof(#CLASS "-") - 1,	\
+		.pm_evc_class = PMC_CLASS_##CLASS ,		\
+		.pm_evc_event_table = EVENTS##_event_table ,	\
+		.pm_evc_event_table_size = 			\
+			PMC_EVENT_TABLE_SIZE(EVENTS),		\
+		.pm_evc_allocate_pmc = ALLOCATOR##_allocate_pmc	\
+	}
+
+#if	defined(__i386__) || defined(__amd64__)
+PMC_CLASS_TABLE_DESC(iaf, IAF, iaf, iaf);
+PMC_CLASS_TABLE_DESC(atom, IAP, atom, iap);
+PMC_CLASS_TABLE_DESC(core, IAP, core, iap);
+PMC_CLASS_TABLE_DESC(core2, IAP, core2, iap);
+#endif
+#if	defined(__i386__)
+PMC_CLASS_TABLE_DESC(k7, K7, k7, k7);
+#endif
+#if	defined(__i386__) || defined(__amd64__)
+PMC_CLASS_TABLE_DESC(k8, K8, k8, k8);
+PMC_CLASS_TABLE_DESC(p4, P4, p4, p4);
+#endif
+#if	defined(__i386__)
+PMC_CLASS_TABLE_DESC(p5, P5, p5, p5);
+PMC_CLASS_TABLE_DESC(p6, P6, p6, p6);
+#endif
+#if	defined(__i386__) || defined(__amd64__)
+PMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc);
+#endif
+
+#undef	PMC_CLASS_TABLE_DESC
+
+static const struct pmc_class_descr **pmc_class_table;
+#define	PMC_CLASS_TABLE_SIZE	cpu_info.pm_nclass
+
+static const enum pmc_class *pmc_mdep_class_list;
+static size_t pmc_mdep_class_list_size;
+
 /*
  * Mapping tables, mapping enumeration values to human readable
  * strings.
@@ -304,6 +427,238 @@ k7_allocate_pmc(enum pmc_event pe, char 
 #if defined(__amd64__) || defined(__i386__)
 
 /*
+ * Intel Core (Family 6, Model E) PMCs.
+ */
+
+static struct pmc_event_alias core_aliases[] = {
+	EV_ALIAS("branches",		"iap-br-instr-ret"),
+	EV_ALIAS("branch-mispredicts",	"iap-br-mispred-ret"),
+	EV_ALIAS("cycles",		"tsc-tsc"),
+	EV_ALIAS("ic-misses",		"iap-icache-misses"),
+	EV_ALIAS("instructions",	"iap-instr-ret"),
+	EV_ALIAS("interrupts",		"iap-core-hw-int-rx"),
+	EV_ALIAS("unhalted-cycles",	"iap-unhalted-core-cycles"),
+	EV_ALIAS(NULL, NULL)
+};
+
+/*
+ * Intel Core2 (Family 6, Model F), Core2Extreme (Family 6, Model 17H)
+ * and Atom (Family 6, model 1CH) PMCs.
+ */
+
+static struct pmc_event_alias core2_aliases[] = {
+	EV_ALIAS("branches",		"iap-br-inst-retired.any"),
+	EV_ALIAS("branch-mispredicts",	"iap-br-inst-retired.mispred"),
+	EV_ALIAS("cycles",		"tsc-tsc"),
+	EV_ALIAS("ic-misses",		"iap-l1i-misses"),
+	EV_ALIAS("instructions",	"iaf-instr-retired.any"),
+	EV_ALIAS("interrupts",		"iap-hw-int-rcv"),
+	EV_ALIAS("unhalted-cycles",	"iaf-cpu-clk-unhalted.core"),
+	EV_ALIAS(NULL, NULL)
+};
+#define	atom_aliases	core2_aliases
+
+#define	IAF_KW_OS		"os"
+#define	IAF_KW_USR		"usr"
+#define	IAF_KW_ANYTHREAD	"anythread"
+
+/*
+ * Parse an event specifier for Intel fixed function counters.
+ */
+static int
+iaf_allocate_pmc(enum pmc_event pe, char *ctrspec,
+    struct pmc_op_pmcallocate *pmc_config)
+{
+	char *p;
+
+	(void) pe;
+
+	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
+	pmc_config->pm_md.pm_iaf.pm_iaf_flags = 0;
+
+	while ((p = strsep(&ctrspec, ",")) != NULL) {
+		if (KWMATCH(p, IAF_KW_OS))
+			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
+		else if (KWMATCH(p, IAF_KW_USR))
+			pmc_config->pm_caps |= PMC_CAP_USER;
+		else if (KWMATCH(p, IAF_KW_ANYTHREAD))
+			pmc_config->pm_md.pm_iaf.pm_iaf_flags |= IAF_ANY;
+		else
+			return (-1);
+	}
+
+	return (0);
+}
+
+/*
+ * Core/Core2 support.
+ */
+
+#define	IAP_KW_AGENT		"agent"
+#define	IAP_KW_ANYTHREAD	"anythread"
+#define	IAP_KW_CACHESTATE	"cachestate"
+#define	IAP_KW_CMASK		"cmask"
+#define	IAP_KW_CORE		"core"
+#define	IAP_KW_EDGE		"edge"
+#define	IAP_KW_INV		"inv"
+#define	IAP_KW_OS		"os"
+#define	IAP_KW_PREFETCH		"prefetch"
+#define	IAP_KW_SNOOPRESPONSE	"snoopresponse"
+#define	IAP_KW_SNOOPTYPE	"snooptype"
+#define	IAP_KW_TRANSITION	"trans"
+#define	IAP_KW_USR		"usr"
+
+static struct pmc_masks iap_core_mask[] = {
+	PMCMASK(all,	(0x3 << 14)),
+	PMCMASK(this,	(0x1 << 14)),
+	NULLMASK
+};
+
+static struct pmc_masks iap_agent_mask[] = {
+	PMCMASK(this,	0),
+	PMCMASK(any,	(0x1 << 13)),
+	NULLMASK
+};
+
+static struct pmc_masks iap_prefetch_mask[] = {
+	PMCMASK(both,		(0x3 << 12)),
+	PMCMASK(only,		(0x1 << 12)),
+	PMCMASK(exclude,	0),
+	NULLMASK
+};
+
+static struct pmc_masks iap_cachestate_mask[] = {
+	PMCMASK(i,		(1 <<  8)),
+	PMCMASK(s,		(1 <<  9)),
+	PMCMASK(e,		(1 << 10)),
+	PMCMASK(m,		(1 << 11)),
+	NULLMASK
+};
+
+static struct pmc_masks iap_snoopresponse_mask[] = {
+	PMCMASK(clean,		(1 << 8)),
+	PMCMASK(hit,		(1 << 9)),
+	PMCMASK(hitm,		(1 << 11)),
+	NULLMASK
+};
+
+static struct pmc_masks iap_snooptype_mask[] = {
+	PMCMASK(cmp2s,		(1 << 8)),
+	PMCMASK(cmp2i,		(1 << 9)),
+	NULLMASK
+};
+
+static struct pmc_masks iap_transition_mask[] = {
+	PMCMASK(any,		0x00),
+	PMCMASK(frequency,	0x10),
+	NULLMASK
+};
+
+static int
+iap_allocate_pmc(enum pmc_event pe, char *ctrspec,
+    struct pmc_op_pmcallocate *pmc_config)
+{
+	char *e, *p, *q;
+	uint32_t cachestate, evmask;
+	int count, n;
+
+	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE |
+	    PMC_CAP_QUALIFIER);
+	pmc_config->pm_md.pm_iap.pm_iap_config = 0;
+
+	cachestate = evmask = 0;
+
+	/* Parse additional modifiers if present */
+	while ((p = strsep(&ctrspec, ",")) != NULL) {
+
+		n = 0;
+		if (KWPREFIXMATCH(p, IAP_KW_CMASK "=")) {
+			q = strchr(p, '=');
+			if (*++q == '\0') /* skip '=' */
+				return (-1);
+			count = strtol(q, &e, 0);
+			if (e == q || *e != '\0')
+				return (-1);
+			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
+			pmc_config->pm_md.pm_iap.pm_iap_config |=
+			    IAP_CMASK(count);
+		} else if (KWMATCH(p, IAP_KW_EDGE)) {
+			pmc_config->pm_caps |= PMC_CAP_EDGE;
+		} else if (KWMATCH(p, IAP_KW_INV)) {
+			pmc_config->pm_caps |= PMC_CAP_INVERT;
+		} else if (KWMATCH(p, IAP_KW_OS)) {
+			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
+		} else if (KWMATCH(p, IAP_KW_USR)) {
+			pmc_config->pm_caps |= PMC_CAP_USER;
+		} else if (KWMATCH(p, IAP_KW_ANYTHREAD)) {
+			pmc_config->pm_md.pm_iap.pm_iap_config |= IAP_ANY;
+		} else if (KWMATCH(p, IAP_KW_CORE)) {
+			n = pmc_parse_mask(iap_core_mask, p, &evmask);
+			if (n != 1)
+				return (-1);
+		} else if (KWMATCH(p, IAP_KW_AGENT)) {
+			n = pmc_parse_mask(iap_agent_mask, p, &evmask);
+			if (n != 1)
+				return (-1);
+		} else if (KWMATCH(p, IAP_KW_PREFETCH)) {
+			n = pmc_parse_mask(iap_prefetch_mask, p, &evmask);
+			if (n != 1)
+				return (-1);
+		} else if (KWMATCH(p, IAP_KW_CACHESTATE)) {
+			n = pmc_parse_mask(iap_cachestate_mask, p, &cachestate);
+		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_CORE &&
+		    KWMATCH(p, IAP_KW_TRANSITION)) {
+			n = pmc_parse_mask(iap_transition_mask, p, &evmask);
+			if (n != 1)
+				return (-1);
+		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM ||
+		    cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2 ||
+		    cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2EXTREME) {
+			if (KWMATCH(p, IAP_KW_SNOOPRESPONSE)) {
+				n = pmc_parse_mask(iap_snoopresponse_mask, p,
+				    &evmask);
+			} else if (KWMATCH(p, IAP_KW_SNOOPTYPE)) {
+				n = pmc_parse_mask(iap_snooptype_mask, p,
+				    &evmask);
+			} else
+				return (-1);
+		} else
+			return (-1);
+
+		if (n < 0)	/* Parsing failed. */
+			return (-1);
+	}
+
+	pmc_config->pm_md.pm_iap.pm_iap_config |= evmask;
+
+	/*
+	 * If the event requires a 'cachestate' qualifier but was not
+	 * specified by the user, use a sensible default.
+	 */
+	switch (pe) {
+	case PMC_EV_IAP_EVENT_28H: /* Core, Core2, Atom */
+	case PMC_EV_IAP_EVENT_29H: /* Core, Core2, Atom */
+	case PMC_EV_IAP_EVENT_2AH: /* Core, Core2, Atom */
+	case PMC_EV_IAP_EVENT_2BH: /* Atom, Core2 */
+	case PMC_EV_IAP_EVENT_2EH: /* Core, Core2, Atom */
+	case PMC_EV_IAP_EVENT_30H: /* Core, Core2, Atom */
+	case PMC_EV_IAP_EVENT_32H: /* Core */
+	case PMC_EV_IAP_EVENT_40H: /* Core */
+	case PMC_EV_IAP_EVENT_41H: /* Core */
+	case PMC_EV_IAP_EVENT_42H: /* Core, Core2, Atom */
+	case PMC_EV_IAP_EVENT_77H: /* Core */
+		if (cachestate == 0)
+			cachestate = (0xF << 8);
+	default:
+		break;
+	}
+
+	pmc_config->pm_md.pm_iap.pm_iap_config |= cachestate;
+
+	return (0);
+}
+
+/*
  * AMD K8 PMCs.
  *
  * These are very similar to AMD K7 PMCs, but support more kinds of
@@ -1637,6 +1992,75 @@ p6_allocate_pmc(enum pmc_event pe, char 
 #endif
 
 /*
+ * Match an event name `name' with its canonical form.
+ *
+ * Matches are case insensitive and spaces, periods, underscores and
+ * hyphen characters are considered to match each other.
+ *
+ * Returns 1 for a match, 0 otherwise.
+ */
+
+static int
+pmc_match_event_name(const char *name, const char *canonicalname)
+{
+	int cc, nc;
+	const unsigned char *c, *n;
+
+	c = (const unsigned char *) canonicalname;
+	n = (const unsigned char *) name;
+
+	for (; (nc = *n) && (cc = *c); n++, c++) {
+
+		if ((nc == ' ' || nc == '_' || nc == '-' || nc == '.') &&
+		    (cc == ' ' || cc == '_' || cc == '-' || cc == '.'))
+			continue;
+
+		if (toupper(nc) == toupper(cc))
+			continue;
+
+
+		return (0);
+	}
+
+	if (*n == '\0' && *c == '\0')
+		return (1);
+
+	return (0);
+}
+
+/*
+ * Match an event name against all the event named supported by a
+ * PMC class.
+ *
+ * Returns an event descriptor pointer on match or NULL otherwise.
+ */
+static const struct pmc_event_descr *
+pmc_match_event_class(const char *name,
+    const struct pmc_class_descr *pcd)
+{
+	size_t n;
+	const struct pmc_event_descr *ev;
+
+	ev = pcd->pm_evc_event_table;
+	for (n = 0; n < pcd->pm_evc_event_table_size; n++, ev++)
+		if (pmc_match_event_name(name, ev->pm_ev_name))
+			return (ev);
+
+	return (NULL);
+}
+
+static int
+pmc_mdep_is_compatible_class(enum pmc_class pc)
+{
+	size_t n;
+
+	for (n = 0; n < pmc_mdep_class_list_size; n++)
+		if (pmc_mdep_class_list[n] == pc)
+			return (1);
+	return (0);
+}
+
+/*
  * API entry points
  */
 
@@ -1675,13 +2099,34 @@ pmc_allocate(const char *ctrspec, enum p
 	r = spec_copy;
 	ctrname = strsep(&r, ",");
 
-	/* look for the given counter name */
-
-	for (pe = PMC_EVENT_FIRST; pe < (PMC_EVENT_LAST+1); pe++)
-		if (!strcmp(ctrname, pmc_event_table[pe].pm_ev_name))
+	/*
+	 * If a explicit class prefix was given by the user, restrict the
+	 * search for the event to the specified PMC class.
+	 */
+	ev = NULL;
+	for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) {
+		pcd = pmc_class_table[n];
+		if (pmc_mdep_is_compatible_class(pcd->pm_evc_class) &&
+		    strncasecmp(ctrname, pcd->pm_evc_name,
+				pcd->pm_evc_name_size) == 0) {
+			if ((ev = pmc_match_event_class(ctrname +
+			    pcd->pm_evc_name_size, pcd)) == NULL) {
+				errno = EINVAL;
+				goto out;
+			}
 			break;
 
-	if (pe > PMC_EVENT_LAST) {
+	/*
+	 * Otherwise, search for this event in all compatible PMC
+	 * classes.
+	 */
+	for (n = 0; ev == NULL && n < PMC_CLASS_TABLE_SIZE; n++) {
+		pcd = pmc_class_table[n];
+		if (pmc_mdep_is_compatible_class(pcd->pm_evc_class))
+			ev = pmc_match_event_class(ctrname, pcd);
+	}
+
+	if (ev == NULL) {
 		errno = EINVAL;
 		goto out;
 	}
@@ -1817,6 +2262,32 @@ pmc_event_names_of_class(enum pmc_class 
 
 	switch (cl)
 	{
+	case PMC_CLASS_IAF:
+		ev = iaf_event_table;
+		count = PMC_EVENT_TABLE_SIZE(iaf);
+		break;
+	case PMC_CLASS_IAP:
+		/*
+		 * Return the most appropriate set of event name
+		 * spellings for the current CPU.
+		 */
+		switch (cpu_info.pm_cputype) {
+		default:
+		case PMC_CPU_INTEL_ATOM:
+			ev = atom_event_table;
+			count = PMC_EVENT_TABLE_SIZE(atom);
+			break;
+		case PMC_CPU_INTEL_CORE:
+			ev = core_event_table;
+			count = PMC_EVENT_TABLE_SIZE(core);
+			break;
+		case PMC_CPU_INTEL_CORE2:
+		case PMC_CPU_INTEL_CORE2EXTREME:
+			ev = core2_event_table;
+			count = PMC_EVENT_TABLE_SIZE(core2);
+			break;
+		}
+		break;
 	case PMC_CLASS_TSC:
 		ev = &pmc_event_table[PMC_EV_TSC_TSC];
 		count = 1;
@@ -1939,16 +2410,42 @@ pmc_init(void)
 	for (n = 0; n < cpu_info.pm_nclass; n++)
 		cpu_info.pm_classes[n] = op_cpu_info.pm_classes[n];
 
-	/* set parser pointer */
+	pmc_class_table = malloc(PMC_CLASS_TABLE_SIZE *
+	    sizeof(struct pmc_class_descr *));
+
+	if (pmc_class_table == NULL)
+		return (-1);
+
+
+	/*
+	 * Fill in the class table.
+	 */
+	n = 0;
+#if defined(__amd64__) || defined(__i386__)
+	pmc_class_table[n++] = &tsc_class_table_descr;
+#endif
+
+#define	PMC_MDEP_INIT(C) do {					\
+		pmc_mdep_event_aliases    = C##_aliases;	\
+		pmc_mdep_class_list  = C##_pmc_classes;		\
+		pmc_mdep_class_list_size =			\
+		    PMC_TABLE_SIZE(C##_pmc_classes);		\
+	} while (0)
+
+	/* Configure the event name parser. */
 	switch (cpu_info.pm_cputype) {
 #if defined(__i386__)
 	case PMC_CPU_AMD_K7:
 		pmc_mdep_event_aliases = k7_aliases;
 		pmc_mdep_allocate_pmc = k7_allocate_pmc;
+		pmc_class_table[n] = &k7_class_table_descr;
+		pmc_class_table[n] = &k7_class_table_descr;
 		break;
 	case PMC_CPU_INTEL_P5:
 		pmc_mdep_event_aliases = p5_aliases;
 		pmc_mdep_allocate_pmc = p5_allocate_pmc;
+		pmc_class_table[n]  = &p5_class_table_descr;
+		pmc_class_table[n]  = &p5_class_table_descr;
 		break;
 	case PMC_CPU_INTEL_P6:		/* P6 ... Pentium M CPUs have */
 	case PMC_CPU_INTEL_PII:		/* similar PMCs. */
@@ -1956,12 +2453,35 @@ pmc_init(void)
 	case PMC_CPU_INTEL_PM:
 		pmc_mdep_event_aliases = p6_aliases;
 		pmc_mdep_allocate_pmc = p6_allocate_pmc;
+		pmc_class_table[n] = &p6_class_table_descr;
+		pmc_class_table[n] = &p6_class_table_descr;
 		break;
 #endif
 #if defined(__amd64__) || defined(__i386__)
+	case PMC_CPU_AMD_K8:
+		PMC_MDEP_INIT(k8);
+		pmc_class_table[n] = &k8_class_table_descr;
+		break;
+	case PMC_CPU_INTEL_ATOM:
+		PMC_MDEP_INIT(atom);
+		pmc_class_table[n++] = &iaf_class_table_descr;
+		pmc_class_table[n]   = &atom_class_table_descr;
+		break;
+	case PMC_CPU_INTEL_CORE:
+		PMC_MDEP_INIT(core);
+		pmc_class_table[n] = &core_class_table_descr;
+		break;
+	case PMC_CPU_INTEL_CORE2:
+	case PMC_CPU_INTEL_CORE2EXTREME:
+		PMC_MDEP_INIT(core2);
+		pmc_class_table[n++] = &iaf_class_table_descr;
+		pmc_class_table[n]   = &core2_class_table_descr;
+		break;
 	case PMC_CPU_INTEL_PIV:
 		pmc_mdep_event_aliases = p4_aliases;
 		pmc_mdep_allocate_pmc = p4_allocate_pmc;
+		pmc_class_table[n] = &p4_class_table_descr;
+		pmc_class_table[n] = &p4_class_table_descr;
 		break;
 	case PMC_CPU_AMD_K8:
 		pmc_mdep_event_aliases = k8_aliases;
@@ -1969,6 +2489,7 @@ pmc_init(void)
 		break;
 #endif
 
+
 	default:
 		/*
 		 * Some kind of CPU this version of the library knows nothing
@@ -2036,12 +2557,81 @@ pmc_name_of_disposition(enum pmc_disp pd
 }
 
 const char *
-pmc_name_of_event(enum pmc_event pe)
+_pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu)
 {
 	if ((int) pe >= PMC_EVENT_FIRST &&
 	    pe <= PMC_EVENT_LAST)
 		return pmc_event_table[pe].pm_ev_name;
 
+	ev = evfence = NULL;
+	if (pe >= PMC_EV_IAF_FIRST && pe <= PMC_EV_IAF_LAST) {
+		ev = iaf_event_table;
+		evfence = iaf_event_table + PMC_EVENT_TABLE_SIZE(iaf);
+	} else if (pe >= PMC_EV_IAP_FIRST && pe <= PMC_EV_IAP_LAST) {
+		switch (cpu) {
+		case PMC_CPU_INTEL_ATOM:
+			ev = atom_event_table;
+			evfence = atom_event_table + PMC_EVENT_TABLE_SIZE(atom);
+			break;
+		case PMC_CPU_INTEL_CORE:
+			ev = core_event_table;
+			evfence = core_event_table + PMC_EVENT_TABLE_SIZE(core);
+			break;
+		case PMC_CPU_INTEL_CORE2:
+		case PMC_CPU_INTEL_CORE2EXTREME:
+			ev = core2_event_table;
+			evfence = core2_event_table + PMC_EVENT_TABLE_SIZE(core2);
+			break;
+		default:	/* Unknown CPU type. */
+			break;
+		}
+	} if (pe >= PMC_EV_K7_FIRST && pe <= PMC_EV_K7_LAST) {
+		ev = k7_event_table;
+		evfence = k7_event_table + PMC_EVENT_TABLE_SIZE(k7);
+	} else if (pe >= PMC_EV_K8_FIRST && pe <= PMC_EV_K8_LAST) {
+		ev = k8_event_table;
+		evfence = k8_event_table + PMC_EVENT_TABLE_SIZE(k8);
+	} else if (pe >= PMC_EV_P4_FIRST && pe <= PMC_EV_P4_LAST) {
+		ev = p4_event_table;
+		evfence = p4_event_table + PMC_EVENT_TABLE_SIZE(p4);
+	} else if (pe >= PMC_EV_P5_FIRST && pe <= PMC_EV_P5_LAST) {
+		ev = p5_event_table;
+		evfence = p5_event_table + PMC_EVENT_TABLE_SIZE(p5);
+	} else if (pe >= PMC_EV_P6_FIRST && pe <= PMC_EV_P6_LAST) {
+		ev = p6_event_table;
+		evfence = p6_event_table + PMC_EVENT_TABLE_SIZE(p6);
+	} else if (pe == PMC_EV_TSC_TSC) {
+		ev = tsc_event_table;
+		evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc);
+	}
+
+	for (; ev != evfence; ev++)
+		if (pe == ev->pm_ev_code)
+			return (ev->pm_ev_name);
+
+	return (NULL);
+}
+
+const char *
+pmc_name_of_event(enum pmc_event pe)
+{
+	const char *n;
+
+	if ((n = _pmc_name_of_event(pe, cpu_info.pm_cputype)) != NULL)
+		return (n);
+
+	errno = EINVAL;
+	return (NULL);
+}
+
+const char *
+pmc_name_of_event(enum pmc_event pe)
+{
+	const char *n;
+
+	if ((n = _pmc_name_of_event(pe, cpu_info.pm_cputype)) != NULL)
+		return (n);
+
 	errno = EINVAL;
 	return NULL;
 }

Added: user/kmacy/releng_7_2_fcs/lib/libpmc/libpmcinternal.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/kmacy/releng_7_2_fcs/lib/libpmc/libpmcinternal.h	Fri May 22 04:49:59 2009	(r192575)
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef	LIBPMC_INTERNAL_H
+#define	LIBPMC_INTERNAL_H	1
+
+/*
+ * Prototypes.
+ */
+const char *_pmc_name_of_event(enum pmc_event _ev, enum pmc_cputype _cpu);
+
+#endif	/* LIBPMC_INTERNAL_H */

Modified: user/kmacy/releng_7_2_fcs/lib/libpmc/pmclog.c
==============================================================================
--- user/kmacy/releng_7_2_fcs/lib/libpmc/pmclog.c	Fri May 22 01:15:07 2009	(r192574)
+++ user/kmacy/releng_7_2_fcs/lib/libpmc/pmclog.c	Fri May 22 04:49:59 2009	(r192575)
@@ -1,7 +1,11 @@
 /*-
- * Copyright (c) 2005-2006 Joseph Koshy
+ * Copyright (c) 2005-2007 Joseph Koshy
+ * Copyright (c) 2007 The FreeBSD Foundation
  * All rights reserved.
  *
+ * Portions of this software were developed by A. Joseph Koshy under
+ * sponsorship from the FreeBSD Foundation and Google, Inc.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -43,6 +47,8 @@ __FBSDID("$FreeBSD$");
 
 #include <machine/pmc_mdep.h>
 
+#include "libpmcinternal.h"
+
 #define	PMCLOG_BUFFER_SIZE			4096
 
 /*
@@ -270,7 +276,7 @@ pmclog_get_event(void *cookie, char **da
     struct pmclog_ev *ev)
 {
 	int evlen, pathlen;
-	uint32_t h, *le;
+	uint32_t h, *le, npc;
 	enum pmclog_parser_state e;
 	struct pmclog_parse_state *ps;
 
@@ -310,7 +316,22 @@ pmclog_get_event(void *cookie, char **da
 			goto error;					\
 	} while (0)
 
+#define	PMCLOG_GET_CALLCHAIN_SIZE(SZ,E) do {				\
+		(SZ) = ((E) - offsetof(struct pmclog_callchain, pl_pc))	\
+			/ sizeof(uintfptr_t);				\
+	} while (0);
+
 	switch (ev->pl_type = PMCLOG_HEADER_TO_TYPE(h)) {
+	case PMCLOG_TYPE_CALLCHAIN:
+		PMCLOG_READ32(le,ev->pl_u.pl_cc.pl_pid);
+		PMCLOG_READ32(le,ev->pl_u.pl_cc.pl_pmcid);
+		PMCLOG_READ32(le,ev->pl_u.pl_cc.pl_cpuflags);
+		PMCLOG_GET_CALLCHAIN_SIZE(ev->pl_u.pl_cc.pl_npc,evlen);
+		for (npc = 0; npc < ev->pl_u.pl_cc.pl_npc; npc++)
+			PMCLOG_READADDR(le,ev->pl_u.pl_cc.pl_pc[npc]);
+		for (;npc < PMC_CALLCHAIN_DEPTH_MAX; npc++)
+			ev->pl_u.pl_cc.pl_pc[npc] = (uintfptr_t) 0;
+		break;
 	case PMCLOG_TYPE_CLOSELOG:
 	case PMCLOG_TYPE_DROPNOTIFY:
 		/* nothing to do */
@@ -344,7 +365,8 @@ pmclog_get_event(void *cookie, char **da
 		PMCLOG_READ32(le,ev->pl_u.pl_a.pl_event);
 		PMCLOG_READ32(le,ev->pl_u.pl_a.pl_flags);
 		if ((ev->pl_u.pl_a.pl_evname =
-		    pmc_name_of_event(ev->pl_u.pl_a.pl_event)) == NULL)
+		    _pmc_name_of_event(ev->pl_u.pl_a.pl_event, ps->ps_arch))
+		    == NULL)
 			goto error;
 		break;
 	case PMCLOG_TYPE_PMCATTACH:
@@ -387,7 +409,7 @@ pmclog_get_event(void *cookie, char **da
 	default:	/* unknown record type */
 		ps->ps_state = PL_STATE_ERROR;
 		ev->pl_state = PMCLOG_ERROR;
-		return -1;
+		return (-1);
 	}
 
 	ev->pl_offset = (ps->ps_offset += evlen);

Modified: user/kmacy/releng_7_2_fcs/lib/libpmc/pmclog.h
==============================================================================
--- user/kmacy/releng_7_2_fcs/lib/libpmc/pmclog.h	Fri May 22 01:15:07 2009	(r192574)
+++ user/kmacy/releng_7_2_fcs/lib/libpmc/pmclog.h	Fri May 22 04:49:59 2009	(r192575)
@@ -1,7 +1,11 @@
 /*-
- * Copyright (c) 2005-2006 Joseph Koshy
+ * Copyright (c) 2005-2007 Joseph Koshy
+ * Copyright (c) 2007 The FreeBSD Foundation
  * All rights reserved.
  *
+ * Portions of this software were developed by A. Joseph Koshy under
+ * sponsorship from the FreeBSD Foundation and Google, Inc.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -38,6 +42,14 @@ enum pmclog_state {
 	PMCLOG_ERROR
 };
 
+struct pmclog_ev_callchain {
+	uint32_t	pl_pid;
+	uint32_t	pl_pmcid;
+	uint32_t	pl_cpuflags;
+	uint32_t	pl_npc;
+	uintfptr_t	pl_pc[PMC_CALLCHAIN_DEPTH_MAX];
+};
+
 struct pmclog_ev_dropnotify {
 };
 
@@ -125,6 +137,7 @@ struct pmclog_ev {
 	struct timespec   pl_ts;	/* log entry timestamp */
 	enum pmclog_type  pl_type;	/* type of log entry */
 	union { 			/* log entry data */
+		struct pmclog_ev_callchain	pl_cc;
 		struct pmclog_ev_closelog	pl_cl;
 		struct pmclog_ev_dropnotify	pl_dn;
 		struct pmclog_ev_initialize	pl_i;

Modified: user/kmacy/releng_7_2_fcs/sys/amd64/amd64/amd64_mem.c
==============================================================================
--- user/kmacy/releng_7_2_fcs/sys/amd64/amd64/amd64_mem.c	Fri May 22 01:15:07 2009	(r192574)
+++ user/kmacy/releng_7_2_fcs/sys/amd64/amd64/amd64_mem.c	Fri May 22 04:49:59 2009	(r192575)
@@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/smp.h>
 #include <sys/sysctl.h>
 
+#include <machine/cputypes.h>
 #include <machine/md_var.h>
 #include <machine/specialreg.h>
 
@@ -677,8 +678,8 @@ amd64_mem_drvinit(void *unused)
 		return;
 	if ((cpu_id & 0xf00) != 0x600 && (cpu_id & 0xf00) != 0xf00)
 		return;
-	if ((strcmp(cpu_vendor, "GenuineIntel") != 0) &&
-	    (strcmp(cpu_vendor, "AuthenticAMD") != 0))
+	if (cpu_vendor_id != CPU_VENDOR_INTEL &&
+	    cpu_vendor_id != CPU_VENDOR_AMD)
 		return;
 	mem_range_softc.mr_op = &amd64_mrops;
 }

Modified: user/kmacy/releng_7_2_fcs/sys/amd64/amd64/exception.S
==============================================================================
--- user/kmacy/releng_7_2_fcs/sys/amd64/amd64/exception.S	Fri May 22 01:15:07 2009	(r192574)
+++ user/kmacy/releng_7_2_fcs/sys/amd64/amd64/exception.S	Fri May 22 04:49:59 2009	(r192575)
@@ -1,8 +1,12 @@
 /*-
  * Copyright (c) 1989, 1990 William F. Jolitz.
  * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 2007 The FreeBSD Foundation
  * All rights reserved.
  *
+ * Portions of this software were developed by A. Joseph Koshy under
+ * sponsorship from the FreeBSD Foundation and Google, Inc.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -33,6 +37,7 @@
 #include "opt_atpic.h"
 #include "opt_compat.h"
 #include "opt_kdtrace.h"
+#include "opt_hwpmc_hooks.h"
 
 #include <machine/asmacros.h>
 #include <machine/psl.h>
@@ -56,6 +61,9 @@ dtrace_invop_calltrap_addr:
 	.zero	8
 #endif
 	.text
+#ifdef HWPMC_HOOKS
+	ENTRY(start_exceptions)
+#endif
 
 /*****************************************************************************/
 /* Trap handling                                                             */
@@ -388,6 +396,9 @@ IDTVEC(fast_syscall32)
  * execute the NMI handler with interrupts disabled to prevent a
  * nested interrupt from executing an 'iretq' instruction and
  * inadvertently taking the processor out of NMI mode.
+ *
+ * Third, the NMI handler runs on its own stack (tss_ist1), shared
+ * with the double fault handler.
  */
 
 IDTVEC(nmi)
@@ -426,6 +437,61 @@ nmi_calltrap:
 	movq	%rsp, %rdi
 	call	trap
 	MEXITCOUNT
+#ifdef HWPMC_HOOKS
+	/*
+	 * Check if the current trap was from user mode and if so
+	 * whether the current thread needs a user call chain to be
+	 * captured. We are still in NMI mode at this point.
+	 */
+	testb	$SEL_RPL_MASK,TF_CS(%rsp)
+	jz	nocallchain
+	movq	PCPU(CURTHREAD),%rax	/* curthread present? */
+	orq	%rax,%rax
+	jz	nocallchain
+	testl	$TDP_CALLCHAIN,TD_PFLAGS(%rax) /* flagged for capture? */
+	jz	nocallchain
+	/*
+	 * A user callchain is to be captured, so:
+	 * - Move execution to the regular kernel stack, to allow for
+	 *   nested NMI interrupts.
+	 * - Take the processor out of "NMI" mode by faking an "iret".
+	 * - Enable interrupts, so that copyin() can work.
+	 */
+	movq	%rsp,%rsi	/* source stack pointer */
+	movq	$TF_SIZE,%rcx
+	movq	PCPU(RSP0),%rbx
+	subq	%rcx,%rbx
+	movq	%rbx,%rdi	/* destination stack pointer */
+
+	shrq	$3,%rcx		/* trap frame size in long words */
+	cld
+	rep
+	movsq			/* copy trapframe */
+
+	movl	%ss,%eax
+	pushq	%rax		/* tf_ss */
+	pushq	%rbx		/* tf_rsp (on kernel stack) */
+	pushfq			/* tf_rflags */
+	movl	%cs,%eax
+	pushq	%rax		/* tf_cs */
+	pushq	$outofnmi	/* tf_rip */
+	iretq
+outofnmi:
+	/*
+	 * At this point the processor has exited NMI mode and is running
+	 * with interrupts turned off on the normal kernel stack.
+	 * We turn interrupts back on, and take the usual 'doreti' exit
+	 * path.
+	 *
+	 * If a pending NMI gets recognized at or after this point, it 
+	 * will cause a kernel callchain to be traced.  Since this path
+	 * is only taken for NMI interrupts from user space, our `swapgs'
+	 * state is correct for taking the doreti path.
+	 */
+	sti
+	jmp	doreti
+nocallchain:
+#endif
 	testl	%ebx,%ebx
 	jz	nmi_restoreregs
 	swapgs
@@ -593,3 +659,6 @@ doreti_iret_fault:
 	movq	$0,TF_ADDR(%rsp)
 	FAKE_MCOUNT(TF_RIP(%rsp))
 	jmp	calltrap
+#ifdef HWPMC_HOOKS
+	ENTRY(end_exceptions)
+#endif

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200905220450.n4M4o044094085>