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