diff options
author | 2013-05-06 04:32:12 +0000 | |
---|---|---|
committer | 2013-05-06 04:32:12 +0000 | |
commit | 8d742180d3400a6b35a92d480203714f74d8023e (patch) | |
tree | 2e3ccec7d6710c163786f649fb46b7a3dad10bd3 /sys | |
parent | If the lock is contended, such that the 'sc' fails, then we need to (diff) | |
download | wireguard-openbsd-8d742180d3400a6b35a92d480203714f74d8023e.tar.xz wireguard-openbsd-8d742180d3400a6b35a92d480203714f74d8023e.zip |
the use of modern intel performance counter msrs to measure the number of
cycles per second isnt reliable, particularly inside "virtual" machines.
cpuspeed can be calculated as 0, which causes a divide by zero later on
which is bad.
this goes to more effort to detect if the performance counters are in use
by the hypervisor, or detecting if they gave us a cpuspeed of 0 so we can
fall through to using rdtsc.
the same change as:
src/sys/arch/i386/include/specialreg.h r.45
src/sys/arch/i386/isa/clock.c 1.49
ok jsg@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/amd64/amd64/identcpu.c | 83 | ||||
-rw-r--r-- | sys/arch/amd64/include/specialreg.h | 14 |
2 files changed, 67 insertions, 30 deletions
diff --git a/sys/arch/amd64/amd64/identcpu.c b/sys/arch/amd64/amd64/identcpu.c index a7b3547d42b..94980401f8d 100644 --- a/sys/arch/amd64/amd64/identcpu.c +++ b/sys/arch/amd64/amd64/identcpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: identcpu.c,v 1.46 2013/04/09 01:47:04 guenther Exp $ */ +/* $OpenBSD: identcpu.c,v 1.47 2013/05/06 04:32:12 dlg Exp $ */ /* $NetBSD: identcpu.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $ */ /* @@ -45,6 +45,8 @@ #include <machine/cpufunc.h> void replacesmap(void); +u_int64_t cpu_tsc_freq(struct cpu_info *); +u_int64_t cpu_tsc_freq_ctr(struct cpu_info *); /* sysctl wants this. */ char cpu_model[48]; @@ -321,10 +323,62 @@ via_update_sensor(void *args) } #endif +u_int64_t +cpu_tsc_freq_ctr(struct cpu_info *ci) +{ + u_int64_t count, last_count, msr; + + if ((ci->ci_flags & CPUF_CONST_TSC) == 0 || + (cpu_perf_eax & CPUIDEAX_VERID) <= 1 || + CPUIDEDX_NUM_FC(cpu_perf_edx) <= 1) + return (0); + + msr = rdmsr(MSR_PERF_FIXED_CTR_CTRL); + if (msr & MSR_PERF_FIXED_CTR_FC(1, MSR_PERF_FIXED_CTR_FC_MASK)) { + /* some hypervisor is dicking us around */ + return (0); + } + + msr |= MSR_PERF_FIXED_CTR_FC(1, MSR_PERF_FIXED_CTR_FC_1); + wrmsr(MSR_PERF_FIXED_CTR_CTRL, msr); + + msr = rdmsr(MSR_PERF_GLOBAL_CTRL) | MSR_PERF_GLOBAL_CTR1_EN; + wrmsr(MSR_PERF_GLOBAL_CTRL, msr); + + last_count = rdmsr(MSR_PERF_FIXED_CTR1); + delay(100000); + count = rdmsr(MSR_PERF_FIXED_CTR1); + + msr = rdmsr(MSR_PERF_FIXED_CTR_CTRL); + msr &= MSR_PERF_FIXED_CTR_FC(1, MSR_PERF_FIXED_CTR_FC_MASK); + wrmsr(MSR_PERF_FIXED_CTR_CTRL, msr); + + msr = rdmsr(MSR_PERF_GLOBAL_CTRL); + msr &= ~MSR_PERF_GLOBAL_CTR1_EN; + wrmsr(MSR_PERF_GLOBAL_CTRL, msr); + + return ((count - last_count) * 10); +} + +u_int64_t +cpu_tsc_freq(struct cpu_info *ci) +{ + u_int64_t last_count, count; + + count = cpu_tsc_freq_ctr(ci); + if (count != 0) + return (count); + + last_count = rdtsc(); + delay(100000); + count = rdtsc(); + + return ((count - last_count) * 10); +} + void identifycpu(struct cpu_info *ci) { - u_int64_t last_count, count, msr; u_int32_t dummy, val, pnfeatset; u_int32_t brand[12]; char mycpu_model[48]; @@ -401,30 +455,7 @@ identifycpu(struct cpu_info *ci) } } - if ((ci->ci_flags & CPUF_CONST_TSC) && - (cpu_perf_eax & CPUIDEAX_VERID) > 1 && - CPUIDEDX_NUM_FC(cpu_perf_edx) > 1) { - msr = rdmsr(MSR_PERF_FIXED_CTR_CTRL) | MSR_PERF_FIXED_CTR1_EN; - wrmsr(MSR_PERF_FIXED_CTR_CTRL, msr); - msr = rdmsr(MSR_PERF_GLOBAL_CTRL) | MSR_PERF_GLOBAL_CTR1_EN; - wrmsr(MSR_PERF_GLOBAL_CTRL, msr); - - last_count = rdmsr(MSR_PERF_FIXED_CTR1); - delay(100000); - count = rdmsr(MSR_PERF_FIXED_CTR1); - - msr = rdmsr(MSR_PERF_FIXED_CTR_CTRL); - msr &= ~MSR_PERF_FIXED_CTR1_EN; - wrmsr(MSR_PERF_FIXED_CTR_CTRL, msr); - msr = rdmsr(MSR_PERF_GLOBAL_CTRL); - msr &= ~MSR_PERF_GLOBAL_CTR1_EN; - wrmsr(MSR_PERF_GLOBAL_CTRL, msr); - } else { - last_count = rdtsc(); - delay(100000); - count = rdtsc(); - } - ci->ci_tsc_freq = (count - last_count) * 10; + ci->ci_tsc_freq = cpu_tsc_freq(ci); amd_cpu_cacheinfo(ci); diff --git a/sys/arch/amd64/include/specialreg.h b/sys/arch/amd64/include/specialreg.h index f094f14c7ff..d1efb5ed017 100644 --- a/sys/arch/amd64/include/specialreg.h +++ b/sys/arch/amd64/include/specialreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: specialreg.h,v 1.24 2012/11/10 09:45:05 mglocker Exp $ */ +/* $OpenBSD: specialreg.h,v 1.25 2013/05/06 04:32:12 dlg Exp $ */ /* $NetBSD: specialreg.h,v 1.1 2003/04/26 18:39:48 fvdl Exp $ */ /* $NetBSD: x86/specialreg.h,v 1.2 2003/04/25 21:54:30 fvdl Exp $ */ @@ -340,9 +340,15 @@ #define MSR_MTRRdefType 0x2ff #define MSR_PERF_FIXED_CTR1 0x30a /* CPU_CLK_Unhalted.Core */ #define MSR_PERF_FIXED_CTR2 0x30b /* CPU_CLK.Unhalted.Ref */ -#define MSR_PERF_FIXED_CTR_CTRL 0x38d -#define MSR_PERF_FIXED_CTR1_EN (1 << 4) -#define MSR_PERF_FIXED_CTR2_EN (1 << 8) +#define MSR_PERF_FIXED_CTR_CTRL 0x38d +#define MSR_PERF_FIXED_CTR_FC_DIS 0x0 /* disable counter */ +#define MSR_PERF_FIXED_CTR_FC_1 0x1 /* count ring 1 */ +#define MSR_PERF_FIXED_CTR_FC_123 0x2 /* count rings 1,2,3 */ +#define MSR_PERF_FIXED_CTR_FC_ANY 0x3 /* count everything */ +#define MSR_PERF_FIXED_CTR_FC_MASK 0x3 +#define MSR_PERF_FIXED_CTR_FC(_i, _v) ((_v) << (4 * (_i))) +#define MSR_PERF_FIXED_CTR_ANYTHR(_i) (0x4 << (4 * (_i))) +#define MSR_PERF_FIXED_CTR_INT(_i) (0x8 << (4 * (_i))) #define MSR_PERF_GLOBAL_CTRL 0x38f #define MSR_PERF_GLOBAL_CTR1_EN (1ULL << 33) #define MSR_PERF_GLOBAL_CTR2_EN (1ULL << 34) |