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