// SPDX-License-Identifier: GPL-2.0 #include #include #include #include #include "../../../util/debug.h" #include "../../../util/tsc.h" #include "cpuid.h" u64 rdtsc(void) { unsigned int low, high; asm volatile("rdtsc" : "=a" (low), "=d" (high)); return low | ((u64)high) << 32; } /* * Derive the TSC frequency in Hz from the /proc/cpuinfo, for example: * ... * model name : Intel(R) Xeon(R) Gold 6154 CPU @ 3.00GHz * ... * will return 3000000000. */ static u64 cpuinfo_tsc_freq(void) { u64 result = 0; FILE *cpuinfo; char *line = NULL; size_t len = 0; cpuinfo = fopen("/proc/cpuinfo", "r"); if (!cpuinfo) { pr_err("Failed to read /proc/cpuinfo for TSC frequency\n"); return 0; } while (getline(&line, &len, cpuinfo) > 0) { if (!strncmp(line, "model name", 10)) { char *pos = strstr(line + 11, " @ "); double float_result; if (pos && sscanf(pos, " @ %lfGHz", &float_result) == 1) { float_result *= 1000000000; result = (u64)float_result; goto out; } } } out: if (result == 0) pr_err("Failed to find TSC frequency in /proc/cpuinfo\n"); free(line); fclose(cpuinfo); return result; } u64 arch_get_tsc_freq(void) { unsigned int a, b, c, d, lvl; static bool cached; static double tsc; char vendor[16]; if (cached) return tsc; cached = true; get_cpuid_0(vendor, &lvl); if (!strstr(vendor, "Intel")) return 0; /* * Don't support Time Stamp Counter and * Nominal Core Crystal Clock Information Leaf. */ if (lvl < 0x15) { tsc = cpuinfo_tsc_freq(); return tsc; } cpuid(0x15, 0, &a, &b, &c, &d); /* TSC frequency is not enumerated */ if (!a || !b || !c) { tsc = cpuinfo_tsc_freq(); return tsc; } tsc = (u64)c * (u64)b / (u64)a; return tsc; }