cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

header.c (3023B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <sys/types.h>
      3#include <errno.h>
      4#include <unistd.h>
      5#include <stdio.h>
      6#include <stdlib.h>
      7#include <string.h>
      8#include <regex.h>
      9
     10#include "../../../util/debug.h"
     11#include "../../../util/header.h"
     12
     13static inline void
     14cpuid(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
     26static int
     27__get_cpuid(char *buffer, size_t sz, const char *fmt)
     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	}
     55	nb = scnprintf(buffer, sz, fmt, vendor, family, model, step);
     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	}
     62	return ENOBUFS;
     63}
     64
     65int
     66get_cpuid(char *buffer, size_t sz)
     67{
     68	return __get_cpuid(buffer, sz, "%s,%u,%u,%u$");
     69}
     70
     71char *
     72get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
     73{
     74	char *buf = malloc(128);
     75
     76	if (buf && __get_cpuid(buf, 128, "%s-%u-%X-%X$") < 0) {
     77		free(buf);
     78		return NULL;
     79	}
     80	return buf;
     81}
     82
     83/* Full CPUID format for x86 is vendor-family-model-stepping */
     84static 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
    100int 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}