xref: /OK3568_Linux_fs/kernel/tools/perf/arch/x86/util/header.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #include <sys/types.h>
3*4882a593Smuzhiyun #include <errno.h>
4*4882a593Smuzhiyun #include <unistd.h>
5*4882a593Smuzhiyun #include <stdio.h>
6*4882a593Smuzhiyun #include <stdlib.h>
7*4882a593Smuzhiyun #include <string.h>
8*4882a593Smuzhiyun #include <regex.h>
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include "../../../util/debug.h"
11*4882a593Smuzhiyun #include "../../../util/header.h"
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun static inline void
cpuid(unsigned int op,unsigned int * a,unsigned int * b,unsigned int * c,unsigned int * d)14*4882a593Smuzhiyun cpuid(unsigned int op, unsigned int *a, unsigned int *b, unsigned int *c,
15*4882a593Smuzhiyun       unsigned int *d)
16*4882a593Smuzhiyun {
17*4882a593Smuzhiyun 	__asm__ __volatile__ (".byte 0x53\n\tcpuid\n\t"
18*4882a593Smuzhiyun 			      "movl %%ebx, %%esi\n\t.byte 0x5b"
19*4882a593Smuzhiyun 			: "=a" (*a),
20*4882a593Smuzhiyun 			"=S" (*b),
21*4882a593Smuzhiyun 			"=c" (*c),
22*4882a593Smuzhiyun 			"=d" (*d)
23*4882a593Smuzhiyun 			: "a" (op));
24*4882a593Smuzhiyun }
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun static int
__get_cpuid(char * buffer,size_t sz,const char * fmt)27*4882a593Smuzhiyun __get_cpuid(char *buffer, size_t sz, const char *fmt)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun 	unsigned int a, b, c, d, lvl;
30*4882a593Smuzhiyun 	int family = -1, model = -1, step = -1;
31*4882a593Smuzhiyun 	int nb;
32*4882a593Smuzhiyun 	char vendor[16];
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 	cpuid(0, &lvl, &b, &c, &d);
35*4882a593Smuzhiyun 	strncpy(&vendor[0], (char *)(&b), 4);
36*4882a593Smuzhiyun 	strncpy(&vendor[4], (char *)(&d), 4);
37*4882a593Smuzhiyun 	strncpy(&vendor[8], (char *)(&c), 4);
38*4882a593Smuzhiyun 	vendor[12] = '\0';
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun 	if (lvl >= 1) {
41*4882a593Smuzhiyun 		cpuid(1, &a, &b, &c, &d);
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 		family = (a >> 8) & 0xf;  /* bits 11 - 8 */
44*4882a593Smuzhiyun 		model  = (a >> 4) & 0xf;  /* Bits  7 - 4 */
45*4882a593Smuzhiyun 		step   = a & 0xf;
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 		/* extended family */
48*4882a593Smuzhiyun 		if (family == 0xf)
49*4882a593Smuzhiyun 			family += (a >> 20) & 0xff;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 		/* extended model */
52*4882a593Smuzhiyun 		if (family >= 0x6)
53*4882a593Smuzhiyun 			model += ((a >> 16) & 0xf) << 4;
54*4882a593Smuzhiyun 	}
55*4882a593Smuzhiyun 	nb = scnprintf(buffer, sz, fmt, vendor, family, model, step);
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	/* look for end marker to ensure the entire data fit */
58*4882a593Smuzhiyun 	if (strchr(buffer, '$')) {
59*4882a593Smuzhiyun 		buffer[nb-1] = '\0';
60*4882a593Smuzhiyun 		return 0;
61*4882a593Smuzhiyun 	}
62*4882a593Smuzhiyun 	return ENOBUFS;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun int
get_cpuid(char * buffer,size_t sz)66*4882a593Smuzhiyun get_cpuid(char *buffer, size_t sz)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun 	return __get_cpuid(buffer, sz, "%s,%u,%u,%u$");
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun char *
get_cpuid_str(struct perf_pmu * pmu __maybe_unused)72*4882a593Smuzhiyun get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun 	char *buf = malloc(128);
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	if (buf && __get_cpuid(buf, 128, "%s-%u-%X-%X$") < 0) {
77*4882a593Smuzhiyun 		free(buf);
78*4882a593Smuzhiyun 		return NULL;
79*4882a593Smuzhiyun 	}
80*4882a593Smuzhiyun 	return buf;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun /* Full CPUID format for x86 is vendor-family-model-stepping */
is_full_cpuid(const char * id)84*4882a593Smuzhiyun static bool is_full_cpuid(const char *id)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun 	const char *tmp = id;
87*4882a593Smuzhiyun 	int count = 0;
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	while ((tmp = strchr(tmp, '-')) != NULL) {
90*4882a593Smuzhiyun 		count++;
91*4882a593Smuzhiyun 		tmp++;
92*4882a593Smuzhiyun 	}
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	if (count == 3)
95*4882a593Smuzhiyun 		return true;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	return false;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun 
strcmp_cpuid_str(const char * mapcpuid,const char * id)100*4882a593Smuzhiyun int strcmp_cpuid_str(const char *mapcpuid, const char *id)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun 	regex_t re;
103*4882a593Smuzhiyun 	regmatch_t pmatch[1];
104*4882a593Smuzhiyun 	int match;
105*4882a593Smuzhiyun 	bool full_mapcpuid = is_full_cpuid(mapcpuid);
106*4882a593Smuzhiyun 	bool full_cpuid = is_full_cpuid(id);
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	/*
109*4882a593Smuzhiyun 	 * Full CPUID format is required to identify a platform.
110*4882a593Smuzhiyun 	 * Error out if the cpuid string is incomplete.
111*4882a593Smuzhiyun 	 */
112*4882a593Smuzhiyun 	if (full_mapcpuid && !full_cpuid) {
113*4882a593Smuzhiyun 		pr_info("Invalid CPUID %s. Full CPUID is required, "
114*4882a593Smuzhiyun 			"vendor-family-model-stepping\n", id);
115*4882a593Smuzhiyun 		return 1;
116*4882a593Smuzhiyun 	}
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	if (regcomp(&re, mapcpuid, REG_EXTENDED) != 0) {
119*4882a593Smuzhiyun 		/* Warn unable to generate match particular string. */
120*4882a593Smuzhiyun 		pr_info("Invalid regular expression %s\n", mapcpuid);
121*4882a593Smuzhiyun 		return 1;
122*4882a593Smuzhiyun 	}
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	match = !regexec(&re, id, 1, pmatch, 0);
125*4882a593Smuzhiyun 	regfree(&re);
126*4882a593Smuzhiyun 	if (match) {
127*4882a593Smuzhiyun 		size_t match_len = (pmatch[0].rm_eo - pmatch[0].rm_so);
128*4882a593Smuzhiyun 		size_t cpuid_len;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 		/* If the full CPUID format isn't required,
131*4882a593Smuzhiyun 		 * ignoring the stepping.
132*4882a593Smuzhiyun 		 */
133*4882a593Smuzhiyun 		if (!full_mapcpuid && full_cpuid)
134*4882a593Smuzhiyun 			cpuid_len = strrchr(id, '-') - id;
135*4882a593Smuzhiyun 		else
136*4882a593Smuzhiyun 			cpuid_len = strlen(id);
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 		/* Verify the entire string matched. */
139*4882a593Smuzhiyun 		if (match_len == cpuid_len)
140*4882a593Smuzhiyun 			return 0;
141*4882a593Smuzhiyun 	}
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	return 1;
144*4882a593Smuzhiyun }
145