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