Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 24 Apr 2026 15:34:00 +0000
From:      Mitchell Horne <mhorne@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Cc:        Ali Mashtizadeh <ali@mashtizadeh.com>
Subject:   git: 576c6e9620df - main - pmc: Implement the feature bits for recent Zen 4/5
Message-ID:  <69eb8d68.36b92.4722e81@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by mhorne:

URL: https://cgit.FreeBSD.org/src/commit/?id=576c6e9620dff3e92f3c5d1e5be4d92c9eb29828

commit 576c6e9620dff3e92f3c5d1e5be4d92c9eb29828
Author:     Ali Mashtizadeh <ali@mashtizadeh.com>
AuthorDate: 2026-04-08 05:36:53 +0000
Commit:     Mitchell Horne <mhorne@FreeBSD.org>
CommitDate: 2026-04-24 15:33:42 +0000

    pmc: Implement the feature bits for recent Zen 4/5
    
    Ensure that the optional MSRs and the user flags are guarded by the
    cpuid feature flags.  This prevents the user from triggering undefined
    behavior or crashes on AMD processors where some of these features are
    not present.  As part of this, I added the branch target and DATA4 MSRs
    to the IBS op state as those are only present on a subset of the Zen
    chips that I have tested.
    
    Reviewed by:    mhorne
    Sponsored by:   Netflix
    Pull Request:   https://github.com/freebsd/freebsd-src/pull/2133
---
 lib/libpmc/libpmc.c       | 29 ++++++++++++++++++++++++++++-
 lib/libpmc/pmc.ibs.3      | 10 ++++++----
 sys/dev/hwpmc/hwpmc_ibs.c | 12 +++++++++---
 sys/dev/hwpmc/hwpmc_ibs.h | 15 +++++++++------
 4 files changed, 52 insertions(+), 14 deletions(-)

diff --git a/lib/libpmc/libpmc.c b/lib/libpmc/libpmc.c
index ebb642e8d16b..562000aef4e4 100644
--- a/lib/libpmc/libpmc.c
+++ b/lib/libpmc/libpmc.c
@@ -32,6 +32,10 @@
 #include <sys/pmc.h>
 #include <sys/syscall.h>
 
+#if defined(__amd64__) || defined(__i386__)
+#include <machine/cpufunc.h>
+#endif
+
 #include <ctype.h>
 #include <errno.h>
 #include <err.h>
@@ -697,6 +701,8 @@ ibs_allocate_pmc(enum pmc_event pe, char *ctrspec,
 {
 	char *e, *p, *q;
 	uint64_t ctl, ldlat;
+	u_int ibs_features;
+	u_int regs[4];
 
 	pmc_config->pm_caps |=
 	    (PMC_CAP_SYSTEM | PMC_CAP_EDGE | PMC_CAP_PRECISE);
@@ -719,11 +725,22 @@ ibs_allocate_pmc(enum pmc_event pe, char *ctrspec,
 		return (-1);
 	}
 
+	/* Read the ibs feature flags */
+	ibs_features = 0;
+	do_cpuid(0x80000000, regs);
+	if (regs[0] >= CPUID_IBSID) {
+		do_cpuid(CPUID_IBSID, regs);
+		ibs_features = regs[0];
+	}
+
 	/* parse parameters */
 	ctl = 0;
 	if (pe == PMC_EV_IBS_FETCH) {
 		while ((p = strsep(&ctrspec, ",")) != NULL) {
 			if (KWMATCH(p, "l3miss")) {
+				if ((ibs_features & CPUID_IBSID_ZEN4IBSEXTENSIONS) == 0)
+					return (-1);
+
 				ctl |= IBS_FETCH_CTL_L3MISSONLY;
 			} else if (KWMATCH(p, "randomize")) {
 				ctl |= IBS_FETCH_CTL_RANDOMIZE;
@@ -742,6 +759,9 @@ ibs_allocate_pmc(enum pmc_event pe, char *ctrspec,
 			if (KWMATCH(p, "l3miss")) {
 				ctl |= IBS_OP_CTL_L3MISSONLY;
 			} else if (KWPREFIXMATCH(p, "ldlat=")) {
+				if ((ibs_features & CPUID_IBSID_IBSLOADLATENCYFILT) == 0)
+					return (-1);
+
 				q = strchr(p, '=');
 				if (*++q == '\0') /* skip '=' */
 					return (-1);
@@ -765,7 +785,10 @@ ibs_allocate_pmc(enum pmc_event pe, char *ctrspec,
 					return (-1);
 				ctl |= IBS_OP_CTL_LDLAT_TO_CTL(ldlat);
 				ctl |= IBS_OP_CTL_L3MISSONLY | IBS_OP_CTL_LATFLTEN;
-			} else if (KWMATCH(p, "randomize")) {
+			} else if (KWMATCH(p, "opcount")) {
+				if ((ibs_features & CPUID_IBSID_OPCNT) == 0)
+					return (-1);
+
 				ctl |= IBS_OP_CTL_COUNTERCONTROL;
 			} else {
 				return (-1);
@@ -776,6 +799,10 @@ ibs_allocate_pmc(enum pmc_event pe, char *ctrspec,
 		    pmc_config->pm_count > IBS_OP_MAX_RATE)
 			return (-1);
 
+		if (((ibs_features & CPUID_IBSID_OPCNTEXT) == 0) &&
+		    (pmc_config->pm_count > IBS_OP_MAX_RATE_PREEXT))
+			return (-1);
+
 		ctl |= IBS_OP_INTERVAL_TO_CTL(pmc_config->pm_count);
 	}
 
diff --git a/lib/libpmc/pmc.ibs.3 b/lib/libpmc/pmc.ibs.3
index f0534a0955d2..574db4df6fa1 100644
--- a/lib/libpmc/pmc.ibs.3
+++ b/lib/libpmc/pmc.ibs.3
@@ -107,6 +107,8 @@ IBS only supports filtering latencies that are a multiple of 128 and between
 128 and 2048.
 Load latency filtering can only be used with ibs-op events and imply the
 l3miss qualifier.
+.It Li opcount
+Count ops rather than cycles.
 .It Li randomize
 Randomize the sampling rate.
 .El
@@ -124,13 +126,13 @@ qualifier randomly sets the bottom four bits of the sample rate.
 .It Li ibs-op Xo
 .Op ,l3miss
 .Op ,ldlat= Ns Ar ldlat
-.Op ,randomize
+.Op ,opcount
 .Xc
 Collect performance samples during instruction execution.
 The
-.Ar randomize
-qualifier, upon reaching the maximum count, restarts the count with a value
-between 1 and 127.
+.Ar opcount
+qualifier, upon reaching the maximum count, restarts the count with a random
+value between 1 and 127.
 .El
 .Pp
 You may collect both events at the same time.
diff --git a/sys/dev/hwpmc/hwpmc_ibs.c b/sys/dev/hwpmc/hwpmc_ibs.c
index 574df12093f8..56903699ac51 100644
--- a/sys/dev/hwpmc/hwpmc_ibs.c
+++ b/sys/dev/hwpmc/hwpmc_ibs.c
@@ -351,9 +351,9 @@ pmc_ibs_process_fetch(struct pmc *pm, struct trapframe *tf, uint64_t config)
 	memset(&mpd, 0, sizeof(mpd));
 
 	mpd.pl_type = PMC_CC_MULTIPART_IBS_FETCH;
-	mpd.pl_length = 4;
+	mpd.pl_length = PMC_MPIDX_FETCH_MAX;
 	mpd.pl_mpdata[PMC_MPIDX_FETCH_CTL] = config;
-	if (ibs_features) {
+	if ((ibs_features & CPUID_IBSID_IBSFETCHCTLEXTD) != 0) {
 		mpd.pl_mpdata[PMC_MPIDX_FETCH_EXTCTL] = rdmsr(IBS_FETCH_EXTCTL);
 	}
 	mpd.pl_mpdata[PMC_MPIDX_FETCH_CTL] = config;
@@ -382,7 +382,7 @@ pmc_ibs_process_op(struct pmc *pm, struct trapframe *tf, uint64_t config)
 	memset(&mpd, 0, sizeof(mpd));
 
 	mpd.pl_type = PMC_CC_MULTIPART_IBS_OP;
-	mpd.pl_length = 8;
+	mpd.pl_length = PMC_MPIDX_OP_MAX;
 	mpd.pl_mpdata[PMC_MPIDX_OP_CTL] = config;
 	mpd.pl_mpdata[PMC_MPIDX_OP_RIP] = rdmsr(IBS_OP_RIP);
 	mpd.pl_mpdata[PMC_MPIDX_OP_DATA] = rdmsr(IBS_OP_DATA);
@@ -390,6 +390,12 @@ pmc_ibs_process_op(struct pmc *pm, struct trapframe *tf, uint64_t config)
 	mpd.pl_mpdata[PMC_MPIDX_OP_DATA3] = rdmsr(IBS_OP_DATA3);
 	mpd.pl_mpdata[PMC_MPIDX_OP_DC_LINADDR] = rdmsr(IBS_OP_DC_LINADDR);
 	mpd.pl_mpdata[PMC_MPIDX_OP_DC_PHYSADDR] = rdmsr(IBS_OP_DC_PHYSADDR);
+	if ((ibs_features & CPUID_IBSID_BRNTRGT) != 0) {
+		mpd.pl_mpdata[PMC_MPIDX_OP_TGT_RIP] = rdmsr(IBS_OP_TGT_RIP);
+	}
+	if ((ibs_features & CPUID_IBSID_IBSOPDATA4) != 0) {
+		mpd.pl_mpdata[PMC_MPIDX_OP_DATA4] = rdmsr(IBS_OP_DATA4);
+	}
 
 	pmc_process_interrupt_mp(PMC_HR, pm, tf, &mpd);
 
diff --git a/sys/dev/hwpmc/hwpmc_ibs.h b/sys/dev/hwpmc/hwpmc_ibs.h
index 4cb69503bd8b..2b4e111ba171 100644
--- a/sys/dev/hwpmc/hwpmc_ibs.h
+++ b/sys/dev/hwpmc/hwpmc_ibs.h
@@ -45,11 +45,11 @@
 #define	CPUID_IBSID_BRNTRGT		0x00000020 /* Branch Target Address */
 #define	CPUID_IBSID_OPCNTEXT		0x00000040 /* Extend Counter */
 #define	CPUID_IBSID_RIPINVALIDCHK	0x00000080 /* Invalid RIP Indication */
-#define	CPUID_IBSID_OPFUSE		0x00000010 /* Fused Branch Operation */
-#define	CPUID_IBSID_IBSFETCHCTLEXTD	0x00000020 /* IBS Fetch Control Ext */
-#define	CPUID_IBSID_IBSOPDATA4		0x00000040 /* IBS OP DATA4 */
-#define	CPUID_IBSID_ZEN4IBSEXTENSIONS	0x00000080 /* IBS Zen 4 Extensions */
-#define	CPUID_IBSID_IBSLOADLATENCYFILT	0x00000100 /* Load Latency Filtering */
+#define	CPUID_IBSID_OPFUSE		0x00000100 /* Fused Branch Operation */
+#define	CPUID_IBSID_IBSFETCHCTLEXTD	0x00000200 /* IBS Fetch Control Ext */
+#define	CPUID_IBSID_IBSOPDATA4		0x00000400 /* IBS OP DATA4 */
+#define	CPUID_IBSID_ZEN4IBSEXTENSIONS	0x00000800 /* IBS Zen 4 Extensions */
+#define	CPUID_IBSID_IBSLOADLATENCYFILT	0x00001000 /* Load Latency Filtering */
 #define	CPUID_IBSID_IBSUPDTDDTLBSTATS	0x00080000 /* Simplified DTLB Stats */
 
 /*
@@ -77,6 +77,7 @@
 #define IBS_FETCH_MAX_RATE		1048560
 #define IBS_OP_MIN_RATE			65536
 #define IBS_OP_MAX_RATE			134217712
+#define IBS_OP_MAX_RATE_PREEXT		1048560
 
 /* IBS Fetch Control */
 #define IBS_FETCH_CTL			0xC0011030 /* IBS Fetch Control */
@@ -108,6 +109,7 @@
 #define PMC_MPIDX_FETCH_EXTCTL		1
 #define PMC_MPIDX_FETCH_LINADDR		2
 #define PMC_MPIDX_FETCH_PHYSADDR	3
+#define PMC_MPIDX_FETCH_MAX		(PMC_MPIDX_FETCH_PHYSADDR + 1)
 
 /* IBS Execution Control */
 #define IBS_OP_CTL			0xC0011033 /* IBS Execution Control */
@@ -151,7 +153,7 @@
 
 #define IBS_OP_DC_LINADDR		0xC0011038 /* IBS DC Linear Address */
 #define IBS_OP_DC_PHYSADDR		0xC0011039 /* IBS DC Physical Address */
-#define IBS_TGT_RIP			0xC001103B /* IBS Branch Target */
+#define IBS_OP_TGT_RIP			0xC001103B /* IBS Branch Target */
 #define IBS_OP_DATA4			0xC001103D /* IBS Op Data 4 */
 #define IBS_OP_DATA4_LDRESYNC		(1ULL << 0)  /* Load Resync */
 
@@ -164,6 +166,7 @@
 #define PMC_MPIDX_OP_DC_PHYSADDR	6
 #define PMC_MPIDX_OP_TGT_RIP		7
 #define PMC_MPIDX_OP_DATA4		8
+#define PMC_MPIDX_OP_MAX		(PMC_MPIDX_OP_DATA4 + 1)
 
 /*
  * IBS data is encoded as using the multipart flag in the existing callchain


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69eb8d68.36b92.4722e81>